/* WP Site Beam — Site Builder
   A guided, AI-assisted site scaffolder. 6 tabs:
   1. Detect   — Type detector: URL / brief → site archetype + recommended stack
   2. Blueprint — Pick or customize a starter blueprint (pages, modules, integrations)
   3. Pages     — Sitemap editor with drag-ordered sections per page
   4. Theme     — Brand Profile → theme.json, typography scale, color roles
   5. Content   — Draft copy (AI + reuse from Content SEO), image sourcing
   6. Launch    — Provisioning checklist: hosting, DNS, plugins, redirects, analytics

   Data strategy mirrors WP Health:
   - Internal roles preload a CD starter (agency build for a service client)
   - External roles start fresh on the Detect tab
*/

function SiteBuilder() {
  const { useState, useMemo, useEffect } = React;
  const [s] = window.useWPSBD();
  const [tab, setTab] = useState('detect');

  // Detector state
  const [url,    setUrl]    = useState('');
  const [brief,  setBrief]  = useState('');
  const [detecting, setDetecting] = useState(false);
  const [detected, setDetected]   = useState(null); // {archetype, confidence, signals, blueprint}

  // Blueprint state
  const [blueprintId, setBlueprintId] = useState('trades-hvac');

  // Scanner → Site Builder handoff (2026-05-18 v2 per Jordan)
  // Scanner writes a payload to sessionStorage on "Send to Site Builder";
  // v1 fix (earlier) populated URL + brief but left the Detection panel empty —
  // Jordan flagged "Seems to be missing block of data?". v2: also synthesize a
  // detection result so the right pane shows what scanner picked up. User can
  // still click "Detect site type" to re-classify if the auto-pick is wrong.
  const [scannerHandoff, setScannerHandoff] = useState(null);
  useEffect(() => {
    try {
      const raw = sessionStorage.getItem('wpsb-sitebuilder-prefill');
      if (!raw) return;
      const h = JSON.parse(raw);
      if (!h || !h.site) return;
      setScannerHandoff(h);
      // Populate visible form fields from the handoff
      setUrl(h.siteUrl || ('https://' + h.site));
      const colorCount  = Array.isArray(h.brand?.colors) ? h.brand.colors.length : 0;
      const pageCount   = Array.isArray(h.pages)   ? h.pages.length   : 0;
      const imageCount  = h.imageCount || 0;
      setBrief(`Loaded from Scanner: ${h.site} — ${pageCount} pages, ${imageCount} images, ${colorCount} brand colors detected. Adjust the brief here, then re-run Detect for a fresh archetype recommendation.`);
      // v2: synthesize a detection result so the right pane is populated.
      // Uses 'service' as a safe default archetype since most agency clients are
      // service businesses. User can override via Detect button if wrong.
      setDetected({
        archetype: 'Scanner data loaded',
        confidence: null, // null = no AI confidence yet, prompts user to run Detect
        blueprint: 'service-pro',
        signals: [
          { k:'Source',        v:'Site Scanner handoff' },
          { k:'Pages found',   v:String(pageCount) },
          { k:'Images',        v:String(imageCount) },
          { k:'Brand colors',  v:String(colorCount) },
          { k:'Platform',      v: h.tech?.platform || 'unknown' },
          { k:'Recommendation', v:'Click "Detect site type" for archetype match' },
        ],
        suggests: ['service-pro','service-local','nonprofit-cause'],
        fromScanner: true,
      });
      setBlueprintId('service-pro');
      window.wpsbToast?.(`Pre-filled from scan: ${h.site} — click Detect for archetype match`, 'ok');
    } catch(e) {
      if (typeof console !== 'undefined') console.warn('[SiteBuilder] handoff read failed:', e.message);
    }
  }, []);

  const internalRoles = new Set(['partner','admin','sa','dev']);
  const effectiveRole = s.actualRole && s.actualRole !== 'sa' ? s.actualRole : s.role;
  const isInternal = internalRoles.has(effectiveRole) || internalRoles.has(s.role);

  // Preload a built result for internal demo
  useEffect(() => {
    if (isInternal && !detected) {
      // Bugfix 2026-05-18: don't override Scanner handoff. If a payload exists
      // in sessionStorage from "Send to Site Builder", the handoff useEffect
      // above has already populated url+brief — skip the bramble.co demo.
      if (sessionStorage.getItem('wpsb-sitebuilder-prefill')) return;
      setUrl('https://bramble.co');
      setBrief('Boutique garden supply shop. Woo-based, ships nationally, seasonal drops.');
      setDetected(DETECTION_RESULTS['ecom']);
      setBlueprintId('ecom-boutique');
    }
  }, []);

  const tabs = [
    { id:'detect',    label:'Detect',    icon:'spark',     desc:'Classify site type from URL + brief' },
    { id:'blueprint', label:'Blueprint', icon:'modules',   desc:'Starter pages, modules & integrations' },
    { id:'pages',     label:'Pages',     icon:'content',   desc:'Sitemap & section editor' },
    { id:'theme',     label:'Theme',     icon:'brand',     desc:'Brand Profile → theme.json' },
    { id:'content',   label:'Content',   icon:'spark',     desc:'AI drafts, reuse, image sourcing' },
    { id:'launch',    label:'Launch',    icon:'shield',    desc:'Hosting, DNS, plugins, analytics' },
  ];

  const bp = BLUEPRINTS.find(b => b.id === blueprintId) || BLUEPRINTS[0];

  function runDetect() {
    if (!url.trim() && !brief.trim()) {
      window.wpsbToast('Add a URL or a brief first', 'warn');
      return;
    }
    setDetecting(true);
    window.announce('Detecting site type…');
    setTimeout(() => {
      // Keyword-based detector for the mock — routes to the best-fit vertical
      const txt = (url + ' ' + brief).toLowerCase();
      const rules = [
        [/hvac|heating|cooling|furnace|a\/?c repair|air ?condition/, 'hvac'],
        [/plumb|drain|leak|sewer|rooter/, 'plumber'],
        [/electric(ian|al)|wiring|panel|breaker/, 'electrician'],
        [/roof(ing|er)|gutter|shingle/, 'roofing'],
        [/landscap|lawn care|mowing|sod|irrigation/, 'landscape'],
        [/pest|exterminat|termite|mosquito/, 'pest'],
        [/remodel|kitchen reno|bath reno|adu/, 'remodel'],
        [/general contractor|\bgc\b|design-build|commercial build/, 'gc'],
        [/custom home|homebuilder|home builder|luxury home/, 'customhome'],
        [/paint(ing|er)|interior paint|exterior paint/, 'painting'],
        [/realtor|real ?estate agent|\bmls\b|home search|buy.*home|sell.*home/, 'realtor'],
        [/brokerage|real estate firm|broker team/, 'brokerage'],
        [/property management|rental mgmt|landlord|hoa/, 'propmgmt'],
        [/accountant|cpa|bookkeep|tax prep/, 'accountant'],
        [/law firm|lawyer|attorney|legal counsel|litigation/, 'lawyer'],
        [/financial advisor|wealth|retirement|fiduciary/, 'advisor'],
        [/insurance|policy|claims|broker.*insur/, 'insurance'],
        [/consult(ing|ant)|strategy firm|advisory/, 'consulting'],
        [/agency|marketing|branding|web design|creative studio/, 'agency'],
        [/dentist|dental|orthodont|implant/, 'dental'],
        [/medspa|aesthet|botox|filler|laser hair/, 'medspa'],
        [/chiropractic|physical therapy|\bpt\b clinic|rehab/, 'chiro'],
        [/gym|yoga|pilates|fitness studio|crossfit/, 'fitness'],
        [/car dealer|dealership|pre-owned|used cars/, 'dealer'],
        [/auto repair|mechanic|tire shop|oil change/, 'autorepair'],
        [/detail(ing)?|ceramic coating|window tint|vinyl wrap/, 'detailing'],
        [/manufactur|contract mfg|fabricat|machine shop/, 'mfg'],
        [/distributor|industrial supply|wholesale supply/, 'distributor'],
        [/farm|co-?op|csa|orchard|ranch|grower/, 'farm'],
        [/ag equipment|tractor|implement dealer/, 'agequip'],
        [/restaurant|cafe|bistro|eatery|menu|dinner/, 'restaurant'],
        [/cater|private chef|event food|chef-driven/, 'caterer'],
        [/sales rep|\bmlm\b|independent rep|direct sales|territory/, 'salesrep'],
        [/shop|store|cart|woo|product|boutique|merch/, 'ecom'],
        [/catalog|warehouse|b2b shop|wholesale/, 'catalog'],
        [/portfolio|designer|photographer|art director|studio/, 'portfolio'],
        [/blog|journal|substack|newsletter|magazine/, 'blog'],
        [/city|county|civic|\.gov|council|municipal/, 'civic'],
        [/nonprofit|charity|foundation|donate|501\(c\)/, 'nonprofit'],
        [/saas|app|platform|api|subscribe/, 'saas'],
        [/course|academy|cohort|learn/, 'course'],
      ];
      let key = 'service';
      for (const [re, k] of rules) { if (re.test(txt)) { key = k; break; } }
      const r = DETECTION_RESULTS[key] || DETECTION_RESULTS.service;
      setDetected(r);
      setBlueprintId(r.blueprint);
      setDetecting(false);
      window.wpsbToast(`Detected: ${r.archetype}`, 'ok');
    }, 1100);
  }

  return (
    <div>
      <PageHead crumb="Tools"
        title={<span style={{ display:'inline-flex', alignItems:'center', gap:10 }}>
          Site Builder
          <span style={{ fontFamily:'var(--font-mono)', fontSize:'.58rem', padding:'3px 8px', borderRadius:4, background:'rgba(99,91,255,.12)', border:'1px solid rgba(99,91,255,.3)', color:'var(--beam)', letterSpacing:'.08em' }}>BETA</span>
          {isInternal && <span style={{ fontFamily:'var(--font-mono)', fontSize:'.58rem', padding:'3px 8px', borderRadius:4, background:'var(--orange-dim)', border:'1px solid var(--orange-dim)', color:'var(--orange)', letterSpacing:'.08em' }}>INTERNAL · CD</span>}
        </span>}
        sub={`Guided site scaffolder — classify, blueprint, theme, and provision a new WordPress build. ${isInternal ? 'Active build: Bramble & Co (Woo boutique).' : 'Start on Detect to generate a tailored plan.'}`}
        actions={<>
          <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbToast('Saved as draft — pick up later from Sites', 'ok')}>
            <Icon name="download" size={12}/>Save draft
          </button>
          <button className="btn btn-primary btn-sm" onClick={() => setTab('launch')}>
            <Icon name="spark" size={12}/>Go to launch
          </button>
        </>}
      />

      {/* Stepper */}
      <div className="sub-tabs" role="tablist" aria-label="Site Builder steps" style={{ position:'relative' }}>
        {tabs.map((t, i) => {
          const isActive = tab === t.id;
          return (
            <button key={t.id} role="tab" aria-selected={isActive}
                    className={'sub-tab' + (isActive ? ' active' : '')}
                    onClick={() => setTab(t.id)}
                    title={t.desc}>
              <span style={{
                fontFamily:'var(--font-mono)', fontSize:'.6rem',
                padding:'1px 5px', borderRadius:3, marginRight:6,
                background: isActive ? 'rgba(99,91,255,.18)' : 'var(--surface-2)',
                color: isActive ? 'var(--beam)' : 'var(--dim)',
              }}>{String(i+1).padStart(2,'0')}</span>
              <Icon name={t.icon} size={12}/>
              <span style={{ marginLeft:6 }}>{t.label}</span>
            </button>
          );
        })}
      </div>

      <div style={{ marginTop: 16 }}>
        {tab === 'detect'    && <DetectTab url={url} setUrl={setUrl} brief={brief} setBrief={setBrief} detecting={detecting} detected={detected} runDetect={runDetect} onAccept={() => setTab('blueprint')}/>}
        {tab === 'blueprint' && <BlueprintTab bp={bp} blueprintId={blueprintId} setBlueprintId={setBlueprintId} detected={detected} onNext={() => setTab('pages')}/>}
        {tab === 'pages'     && <PagesTab bp={bp} onNext={() => setTab('theme')}/>}
        {tab === 'theme'     && <ThemeTab bp={bp} scannerHandoff={scannerHandoff} onNext={() => setTab('content')}/>}
        {tab === 'content'   && <ContentTab bp={bp} onNext={() => setTab('launch')}/>}
        {tab === 'launch'    && <LaunchTab bp={bp} detected={detected}/>}
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   DATA — site archetypes & blueprints
   ───────────────────────────────────────────────────────────── */
const DETECTION_RESULTS = {
  service: {
    archetype: 'Service Business',
    confidence: 0.92,
    blueprint: 'service-pro',
    signals: [
      { k:'Copy mentions', v:'"services", "contact", "quote"' },
      { k:'Lead-gen forms', v:'present (2 detected)' },
      { k:'Products', v:'0 — no storefront patterns' },
      { k:'Phone / address', v:'sitewide footer' },
    ],
    suggests: ['service-pro','service-local','portfolio-studio'],
  },
  ecom: {
    archetype: 'eCommerce — Boutique',
    confidence: 0.96,
    blueprint: 'ecom-boutique',
    signals: [
      { k:'Cart / checkout', v:'Woo detected (wc-blocks)' },
      { k:'Product schema', v:'36 Product posts' },
      { k:'Payment', v:'Stripe + PayPal buttons' },
      { k:'Shipping zones', v:'3 (US / CA / Intl)' },
    ],
    suggests: ['ecom-boutique','ecom-catalog','blog-editorial'],
  },
  portfolio: {
    archetype: 'Portfolio / Studio',
    confidence: 0.88,
    blueprint: 'portfolio-studio',
    signals: [
      { k:'Galleries', v:'14 image-heavy case pages' },
      { k:'Copy', v:'"work", "case study", "clients"' },
      { k:'Products', v:'none' },
      { k:'CTAs', v:'"start a project" / "book a call"' },
    ],
    suggests: ['portfolio-studio','service-pro','blog-editorial'],
  },
  blog: {
    archetype: 'Editorial / Blog',
    confidence: 0.85,
    blueprint: 'blog-editorial',
    signals: [
      { k:'Post frequency', v:'~3 / week' },
      { k:'Categories', v:'8 top-level' },
      { k:'Author bios', v:'5 contributors' },
      { k:'Newsletter form', v:'present (MC4WP)' },
    ],
    suggests: ['blog-editorial','course-cohort','portfolio-studio'],
  },
  civic: {
    archetype: 'Civic / Government',
    confidence: 0.94,
    blueprint: 'civic-council',
    signals: [
      { k:'Domain', v:'.gov / council TLD' },
      { k:'Accessibility', v:`${(window.WPSB && window.WPSB.CONSTANTS && window.WPSB.CONSTANTS.WCAG.DISPLAY) || 'WCAG 2.1 AA'} required` },
      { k:'Forms', v:'permits, meetings, reporting' },
      { k:'Multilingual', v:'likely (>1 region)' },
    ],
    suggests: ['civic-council','nonprofit-cause','service-pro'],
  },
  nonprofit: {
    archetype: 'Nonprofit / Cause',
    confidence: 0.90,
    blueprint: 'nonprofit-cause',
    signals: [
      { k:'Donate flow', v:'GiveWP / Stripe detected' },
      { k:'Events', v:'4 upcoming listed' },
      { k:'Volunteer signup', v:'present' },
      { k:'501(c)(3)', v:'mentioned in footer' },
    ],
    suggests: ['nonprofit-cause','civic-council','blog-editorial'],
  },
  saas: {
    archetype: 'SaaS / Product',
    confidence: 0.87,
    blueprint: 'saas-product',
    signals: [
      { k:'Pricing page', v:'3 tiers detected' },
      { k:'Auth', v:'log in / sign up present' },
      { k:'Docs', v:'subdomain detected' },
      { k:'Changelog', v:'present' },
    ],
    suggests: ['saas-product','course-cohort','portfolio-studio'],
  },
  course: {
    archetype: 'Course / Cohort',
    confidence: 0.83,
    blueprint: 'course-cohort',
    signals: [
      { k:'Enrollment form', v:'present' },
      { k:'Syllabus page', v:'present' },
      { k:'Cohort dates', v:'3 upcoming' },
      { k:'Testimonials', v:'11 student quotes' },
    ],
    suggests: ['course-cohort','saas-product','blog-editorial'],
  },
};

const BLUEPRINTS = [
  { cat:"Trades", id:"trades-hvac", name:"HVAC", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Emergency service, 24/7 dispatch, service areas, maintenance plans.",
    pages:["Home","Services","Service Areas","Maintenance Plans","Financing","Reviews","About","Emergency","Contact"],
    modules:["ServiceTitan Connect","Yoast Local","WP Rocket","Fluent Forms","Schema Pro","Call Rail"],
    integrations:["ServiceTitan","Jobber","GoHighLevel","Google LSA","Google Business"],
    pageTypes:["landing","service-detail","area-page","plan-tiers","financing","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LSA + local SEO" },
  { cat:"Trades", id:"trades-plumber", name:"Plumbing", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Emergency plumbing, drain, water heater, leak repair — book-now-first layout.",
    pages:["Home","Services","Emergency","Service Areas","Coupons","Reviews","About","Contact"],
    modules:["Yoast Local","Fluent Forms","Call Rail","WP Rocket","Schema Pro"],
    integrations:["Jobber","Housecall Pro","GoHighLevel","Google LSA","Twilio"],
    pageTypes:["landing","service-detail","area-page","coupons","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LSA + local SEO" },
  { cat:"Trades", id:"trades-electrician", name:"Electrician", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Residential + commercial electrical, licensed-&-insured badges, panel upgrades, EV chargers.",
    pages:["Home","Residential","Commercial","Service Areas","EV Chargers","Reviews","About","Contact"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","Schema Pro","Call Rail"],
    integrations:["Jobber","ServiceTitan","GoHighLevel","Google LSA"],
    pageTypes:["landing","service-detail","service-detail","area-page","service-detail","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LSA + organic local" },
  { cat:"Trades", id:"trades-roofing", name:"Roofing", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Residential + commercial roofing, inspections, storm response, financing CTA.",
    pages:["Home","Residential","Commercial","Storm Response","Financing","Gallery","Reviews","About","Contact"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","CompanyCam Embed","Schema Pro"],
    integrations:["CompanyCam","AccuLynx","GoHighLevel","Google LSA"],
    pageTypes:["landing","service-detail","service-detail","service-detail","financing","case-study","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LSA + referral" },
  { cat:"Trades", id:"trades-landscape", name:"Landscaping / Lawn", archetype:"Trades / Home Service", color:"var(--green)",
    desc:"Design, install, and maintenance — portfolio-forward with seasonal programs.",
    pages:["Home","Design","Installation","Maintenance","Portfolio","Seasonal","About","Quote"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","ACF Pro","Image Gallery"],
    integrations:["Jobber","LMN","GoHighLevel","Google Business"],
    pageTypes:["landing","service-detail","service-detail","service-detail","work-index","service-detail","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + referral" },
  { cat:"Trades", id:"trades-pestcontrol", name:"Pest Control", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Recurring treatment plans, pest-specific landing pages, termite/rodent/mosquito.",
    pages:["Home","Pest Library","Plans","Service Areas","Coupons","Reviews","About","Contact"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","Schema Pro","Call Rail"],
    integrations:["PestPac","FieldRoutes","GoHighLevel","Google LSA"],
    pageTypes:["landing","library","plan-tiers","area-page","coupons","reviews","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LSA + seasonal paid" },
  { cat:"Contractors", id:"gc-remodel", name:"Remodeling Contractor", archetype:"Contractor / Builder", color:"var(--orange)",
    desc:"Kitchen, bath, whole-home remodels. Gallery-forward, show-the-work storytelling.",
    pages:["Home","Kitchen","Bath","Additions","Gallery","Process","Reviews","About","Quote"],
    modules:["ACF Pro","Imagify","WP Rocket","Fluent Forms","Schema Pro","Yoast SEO"],
    integrations:["CompanyCam","Buildertrend","GoHighLevel","Houzz","Google Business"],
    pageTypes:["landing","service-detail","service-detail","service-detail","work-index","case-study","reviews","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Referral + organic + Houzz" },
  { cat:"Contractors", id:"gc-general", name:"General Contractor", archetype:"Contractor / Builder", color:"var(--orange)",
    desc:"Commercial + residential GC — capabilities-led, licenses, safety record, project types.",
    pages:["Home","Capabilities","Markets","Projects","Safety","Careers","About","Contact"],
    modules:["ACF Pro","WP Rocket","Fluent Forms","Schema Pro","Yoast SEO"],
    integrations:["Procore","Buildertrend","HubSpot","LinkedIn"],
    pageTypes:["landing","service-detail","service-detail","work-index","service-detail","careers","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Bids + referral" },
  { cat:"Contractors", id:"gc-custom-home", name:"Custom Home Builder", archetype:"Contractor / Builder", color:"var(--orange)",
    desc:"High-end custom builds — floor-plan library, community pages, premium imagery.",
    pages:["Home","Floor Plans","Communities","Gallery","Process","Financing","Reviews","About","Build Quote"],
    modules:["ACF Pro","Imagify","WP Rocket","FacetWP","Fluent Forms","Yoast SEO"],
    integrations:["Buildertrend","CoConstruct","BDX","HubSpot"],
    pageTypes:["landing","floor-plan","community","work-index","case-study","financing","reviews","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Builder listing sites + SEO" },
  { cat:"Contractors", id:"gc-painting", name:"Painting Contractor", archetype:"Trades / Home Service", color:"var(--orange)",
    desc:"Interior + exterior, commercial — color consult CTA, before/after gallery.",
    pages:["Home","Interior","Exterior","Commercial","Gallery","Color Consult","Reviews","Quote"],
    modules:["ACF Pro","WP Rocket","Fluent Forms","Schema Pro"],
    integrations:["Jobber","PaintScout","GoHighLevel","Google Business"],
    pageTypes:["landing","service-detail","service-detail","service-detail","work-index","contact","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + LSA" },
  { cat:"Real Estate", id:"realty-agent", name:"Realtor / Agent", archetype:"Real Estate", color:"var(--green)",
    desc:"Solo agent or small team — IDX listings, city guides, valuation CTA, lead capture.",
    pages:["Home","Listings","Sold","Buyers","Sellers","Communities","About","Reviews","Contact"],
    modules:["IDX Broker","ACF Pro","Yoast Local","WP Rocket","Fluent Forms"],
    integrations:["kvCORE","BoomTown","Follow Up Boss","Zillow","Facebook Leads"],
    pageTypes:["landing","listings","sold","service-detail","service-detail","community","about","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Paid social + SEO" },
  { cat:"Real Estate", id:"realty-brokerage", name:"Brokerage", archetype:"Real Estate", color:"var(--green)",
    desc:"Multi-agent brokerage — agent roster, recruitment page, franchise-style structure.",
    pages:["Home","Listings","Agents","Join Us","Communities","Market Reports","About","Contact"],
    modules:["IDX Broker","FacetWP","Yoast Local","WP Rocket","ACF Pro"],
    integrations:["kvCORE","BoomTown","Follow Up Boss","DocuSign"],
    pageTypes:["landing","listings","team","careers","community","post","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Brand + recruitment" },
  { cat:"Real Estate", id:"realty-property-mgmt", name:"Property Management", archetype:"Real Estate", color:"var(--green)",
    desc:"For landlords + tenants — owner portal promo, tenant resources, vacancy list.",
    pages:["Home","Owners","Tenants","Vacancies","Services","Pricing","Reviews","Contact"],
    modules:["ACF Pro","WP Rocket","Fluent Forms","Yoast Local"],
    integrations:["AppFolio","Buildium","Zillow Rental","Google Business"],
    pageTypes:["landing","service-detail","service-detail","listings","service-detail","pricing","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + paid" },
  { cat:"Professional", id:"pro-accountant", name:"Accountant / CPA", archetype:"Professional Services", color:"var(--beam)",
    desc:"Tax, bookkeeping, advisory — industry-specialty landing pages, client portal CTA.",
    pages:["Home","Services","Industries","Team","Resources","Client Portal","Blog","Contact"],
    modules:["Yoast SEO","Fluent Forms","WP Rocket","Schema Pro","Client Portal"],
    integrations:["Karbon","TaxDome","Canopy","Zapier","HubSpot"],
    pageTypes:["landing","service-detail","service-detail","team","post","portal","post","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Referral + organic" },
  { cat:"Professional", id:"pro-lawyer", name:"Law Firm / Attorney", archetype:"Professional Services", color:"var(--purple)",
    desc:"Practice-area landing pages, attorney bios, case results, consultation CTA.",
    pages:["Home","Practice Areas","Attorneys","Results","Testimonials","Blog","Contact","Consultation"],
    modules:["Yoast SEO","Fluent Forms","WP Rocket","Schema Pro","Gravity Forms"],
    integrations:["Clio","MyCase","HubSpot","Google Ads","Call Rail"],
    pageTypes:["landing","service-detail","team","case-study","reviews","post","contact","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Paid search + LSA" },
  { cat:"Professional", id:"pro-financial-advisor", name:"Financial Advisor", archetype:"Professional Services", color:"var(--beam)",
    desc:"RIA / planner — fiduciary messaging, process explainer, schedule-a-call CTA.",
    pages:["Home","Services","Process","Team","Disclosures","Insights","Contact","Book Call"],
    modules:["Yoast SEO","Fluent Forms","WP Rocket","Schema Pro","Calendly Embed"],
    integrations:["Redtail","Wealthbox","HubSpot","Calendly"],
    pageTypes:["landing","service-detail","process","team","disclosures","post","contact","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Content + referral" },
  { cat:"Professional", id:"pro-insurance", name:"Insurance Agency", archetype:"Professional Services", color:"var(--beam)",
    desc:"Independent agency — quote-first CTA, carriers carousel, line-of-business pages.",
    pages:["Home","Personal","Business","Life","Carriers","Quote","About","Contact"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","Schema Pro"],
    integrations:["EZLynx","Applied Epic","HubSpot","Call Rail"],
    pageTypes:["landing","service-detail","service-detail","service-detail","carriers","contact","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + paid" },
  { cat:"Professional", id:"pro-consulting", name:"Management Consulting", archetype:"Professional Services", color:"var(--purple)",
    desc:"Boutique consultancy — thought-leadership content, case studies, industry verticals.",
    pages:["Home","What We Do","Industries","Case Studies","Insights","Team","Careers","Contact"],
    modules:["ACF Pro","Yoast SEO","WP Rocket","Fluent Forms","Algolia Search"],
    integrations:["HubSpot","LinkedIn","Webinar Jam"],
    pageTypes:["landing","service-detail","service-detail","case-study","post","team","careers","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Content + LinkedIn" },
  { cat:"Professional", id:"pro-marketing-agency", name:"Marketing / Design Agency", archetype:"Professional Services", color:"var(--purple)",
    desc:"Services + work-forward — case studies, capabilities, careers, culture.",
    pages:["Home","Services","Work","Studio","Culture","Journal","Careers","Contact"],
    modules:["ACF Pro","Imagify","WP Rocket","Fluent Forms","Yoast SEO"],
    integrations:["HubSpot","Notion","Calendly","Vimeo"],
    pageTypes:["landing","service-detail","case-study","about","culture","post","careers","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Referral + content" },
  { cat:"Health", id:"health-dental", name:"Dental Practice", archetype:"Health & Wellness", color:"var(--beam)",
    desc:"General + cosmetic dental — meet-the-doctor, services, new-patient forms, booking.",
    pages:["Home","Services","New Patients","Team","Technology","Reviews","Blog","Contact","Book"],
    modules:["Yoast Local","Gravity Forms","WP Rocket","Schema Pro","HIPAA Forms"],
    integrations:["Dentrix","NexHealth","Weave","Google LSA"],
    pageTypes:["landing","service-detail","service-detail","team","service-detail","reviews","post","contact","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + LSA" },
  { cat:"Health", id:"health-medspa", name:"MedSpa / Aesthetics", archetype:"Health & Wellness", color:"var(--rose)",
    desc:"Luxe aesthetic — treatment menu, before/after gallery, memberships, online booking.",
    pages:["Home","Treatments","Gallery","Memberships","Specials","Team","Reviews","Book"],
    modules:["ACF Pro","Imagify","WP Rocket","Fluent Forms","Schema Pro"],
    integrations:["Vagaro","Mindbody","Boulevard","Meta Pixel","Klaviyo"],
    pageTypes:["landing","service-detail","work-index","plan-tiers","promotion","team","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Paid social primary" },
  { cat:"Health", id:"health-chiro-pt", name:"Chiropractor / PT", archetype:"Health & Wellness", color:"var(--green)",
    desc:"Evidence-based care, condition-specific landing pages, new-patient specials.",
    pages:["Home","Conditions","Services","New Patients","Team","Reviews","Blog","Contact"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","Schema Pro"],
    integrations:["ChiroTouch","Jane App","GoHighLevel","Google Business"],
    pageTypes:["landing","service-detail","service-detail","contact","team","reviews","post","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + referrals" },
  { cat:"Health", id:"health-fitness-studio", name:"Fitness / Yoga Studio", archetype:"Health & Wellness", color:"var(--green)",
    desc:"Class schedule, memberships, instructor bios, intro-offer funnel.",
    pages:["Home","Classes","Schedule","Memberships","Instructors","Intro Offer","Blog","Contact"],
    modules:["ACF Pro","WP Rocket","Fluent Forms","Mindbody Widget","Yoast SEO"],
    integrations:["Mindbody","ClassPass","Mailchimp","Meta Pixel"],
    pageTypes:["landing","service-detail","schedule","plan-tiers","team","promotion","post","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Paid social + referral" },
  { cat:"Auto", id:"auto-dealer", name:"Car Dealership", archetype:"Automotive", color:"var(--orange)",
    desc:"New + used inventory feed, finance application, service & parts, trade-in form.",
    pages:["Home","New","Pre-Owned","Specials","Finance","Service","Parts","Trade-In","Contact"],
    modules:["FacetWP","ACF Pro","WP Rocket","Yoast Local","DealerSync Feed"],
    integrations:["Cars.com Feed","Autotrader","CDK","VinSolutions","Call Rail"],
    pageTypes:["landing","inventory","inventory","promotion","contact","service-detail","service-detail","contact","contact"],
    cms:"WordPress + FSE", commerce:"Finance App", traffic:"Paid search + OEM" },
  { cat:"Auto", id:"auto-repair", name:"Auto Repair / Shop", archetype:"Automotive", color:"var(--orange)",
    desc:"Independent repair — ASE badges, services by make/model, coupons, online booking.",
    pages:["Home","Services","Makes","Specials","Reviews","Financing","About","Book"],
    modules:["Yoast Local","Fluent Forms","WP Rocket","Schema Pro"],
    integrations:["Shopmonkey","Mitchell1","GoHighLevel","Call Rail"],
    pageTypes:["landing","service-detail","service-detail","promotion","reviews","financing","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local SEO + LSA" },
  { cat:"Auto", id:"auto-detailing", name:"Detailing / Wrap / Tint", archetype:"Automotive", color:"var(--purple)",
    desc:"Premium detailing — package tiers, portfolio gallery, mobile-service area.",
    pages:["Home","Packages","Gallery","Ceramic Coating","Window Tint","Reviews","Contact"],
    modules:["ACF Pro","Imagify","WP Rocket","Fluent Forms"],
    integrations:["Jobber","Vagaro","GoHighLevel","Instagram Feed"],
    pageTypes:["landing","plan-tiers","work-index","service-detail","service-detail","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Social + referral" },
  { cat:"Industrial", id:"mfg-contract", name:"Manufacturing / Contract", archetype:"Industrial", color:"var(--dim)",
    desc:"B2B contract manufacturing — capabilities, certifications (ISO/ITAR), RFQ form, industries served.",
    pages:["Home","Capabilities","Industries","Quality","Equipment","RFQ","About","Contact"],
    modules:["ACF Pro","Yoast SEO","WP Rocket","FacetWP","Schema Pro","Gravity Forms"],
    integrations:["HubSpot","Salesforce","ThomasNet","LinkedIn"],
    pageTypes:["landing","service-detail","service-detail","service-detail","service-detail","contact","about","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Industrial SEO + ThomasNet" },
  { cat:"Industrial", id:"mfg-distributor", name:"Industrial Distributor", archetype:"Industrial", color:"var(--dim)",
    desc:"Parts + equipment distributor — product catalog, B2B pricing, quote cart, account tier.",
    pages:["Home","Catalog","Category","Product","Line Card","Quote Cart","Account","Support"],
    modules:["WooCommerce","B2B for Woo","FacetWP","ElasticPress","ACF Pro"],
    integrations:["NetSuite","Epicor","HubSpot","Salesforce"],
    pageTypes:["landing","shop","category","product","service-detail","cart","account","support"],
    cms:"WordPress + Woo", commerce:"Woo B2B", traffic:"SEO + sales" },
  { cat:"Industrial", id:"ag-farm-coop", name:"Farm / Ag Co-op", archetype:"Agriculture", color:"var(--green)",
    desc:"Producer or co-op — products, programs, commodity pricing feed, membership portal.",
    pages:["Home","Products","Programs","Market Prices","Locations","News","Members","Contact"],
    modules:["ACF Pro","Yoast Local","WP Rocket","Fluent Forms","Members Area"],
    integrations:["DTN Feed","Mailchimp","Google Business","Facebook Pages"],
    pageTypes:["landing","service-detail","service-detail","feed","locations","post","portal","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Local + trade associations" },
  { cat:"Industrial", id:"ag-equipment", name:"Ag Equipment Dealer", archetype:"Agriculture", color:"var(--green)",
    desc:"New + used equipment dealer — inventory, parts, service scheduling, financing.",
    pages:["Home","Inventory","Parts","Service","Financing","Brands","Locations","Contact"],
    modules:["FacetWP","ACF Pro","WP Rocket","Yoast Local","Dealer Feed"],
    integrations:["IronSolutions","TractorHouse","John Deere API","HubSpot"],
    pageTypes:["landing","inventory","service-detail","service-detail","financing","service-detail","locations","contact"],
    cms:"WordPress + FSE", commerce:"Finance App", traffic:"Trade + search" },
  { cat:"Food", id:"food-restaurant", name:"Restaurant / Cafe", archetype:"Food & Hospitality", color:"var(--rose)",
    desc:"Menu + reservations + online order — visual hero, hours, locations.",
    pages:["Home","Menu","Order Online","Reservations","Private Events","Locations","About"],
    modules:["ACF Pro","Imagify","WP Rocket","Yoast Local","Restaurant Menu"],
    integrations:["Toast","OpenTable","Resy","DoorDash","Google Business"],
    pageTypes:["landing","menu","cart","contact","service-detail","locations","about"],
    cms:"WordPress + FSE", commerce:"Toast / DoorDash", traffic:"Local + social" },
  { cat:"Food", id:"food-caterer", name:"Caterer / Private Chef", archetype:"Food & Hospitality", color:"var(--rose)",
    desc:"Menus by event type, gallery, inquiry form, testimonials, service area.",
    pages:["Home","Menus","Events","Gallery","Packages","Reviews","Inquire"],
    modules:["ACF Pro","Imagify","WP Rocket","Fluent Forms"],
    integrations:["Honeybook","Tripleseat","Google Business","Mailchimp"],
    pageTypes:["landing","menu","service-detail","work-index","plan-tiers","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Referral + social" },
  { cat:"Sales", id:"sales-rep", name:"Independent Salesperson / Rep", archetype:"Sales & Consulting", color:"var(--beam)",
    desc:"Personal-brand rep site — bio, lines carried (or services), calendar, testimonials.",
    pages:["Home","About","Services","Lines / Brands","Calendar","Testimonials","Contact"],
    modules:["ACF Pro","Calendly Embed","Yoast SEO","Fluent Forms","WP Rocket"],
    integrations:["Calendly","HubSpot","LinkedIn","Mailchimp"],
    pageTypes:["landing","about","service-detail","service-detail","contact","reviews","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"LinkedIn + referral" },
  { cat:"eCommerce", id:"ecom-boutique", name:"eCommerce — Boutique", archetype:"eCommerce", color:"var(--green)",
    desc:"Small catalog, editorial feel, seasonal drops, Woo-based.",
    pages:["Home","Shop","Collections","Product","Journal","About","Contact","Cart","Checkout"],
    modules:["WooCommerce","WC Blocks","Klaviyo","Shipstation","Judge.me Reviews"],
    integrations:["Stripe","Shippo","Klaviyo","Meta Pixel","GA4"],
    pageTypes:["landing","shop","product","collection","post","cart"],
    cms:"WordPress + Woo", commerce:"Woo", traffic:"Paid social + SEO" },
  { cat:"eCommerce", id:"ecom-catalog", name:"eCommerce — Catalog", archetype:"eCommerce", color:"var(--green)",
    desc:"Large catalog ecommerce with heavy filtering, search, B2B pricing.",
    pages:["Home","Shop","Categories","Product","Brands","Account","Quote","Support"],
    modules:["WooCommerce","B2B for Woo","ElasticPress","FacetWP","WP Rocket"],
    integrations:["Stripe","NetSuite","Shipstation","GA4","Meta"],
    pageTypes:["landing","shop","product","category","account","support"],
    cms:"WordPress + Woo", commerce:"Woo", traffic:"SEO primary" },
  { cat:"Creative", id:"portfolio-studio", name:"Portfolio — Studio", archetype:"Portfolio", color:"var(--purple)",
    desc:"Image-heavy case studies, work index, studio bio, project inquiry form.",
    pages:["Home","Work","Case Study","About","Studio","Journal","Contact"],
    modules:["ACF Pro","Imagify","Swiper","Fluent Forms","Yoast SEO"],
    integrations:["Vimeo","Notion embed","Calendly"],
    pageTypes:["landing","case-study","work-index","post","contact"],
    cms:"WordPress + FSE", commerce:null, traffic:"Referral + organic" },
  { cat:"Editorial", id:"blog-editorial", name:"Editorial — Magazine", archetype:"Blog", color:"var(--beam)",
    desc:"Editorial layouts, multi-author, newsletter primary, Substack-flavored.",
    pages:["Home","Archive","Post","Category","Author","Newsletter","About"],
    modules:["MailPoet","Yoast SEO","News SEO","Mailchimp for WP","CoSchedule"],
    integrations:["Substack import","Mailchimp","GA4"],
    pageTypes:["landing","archive","post","author","newsletter"],
    cms:"WordPress + FSE", commerce:null, traffic:"Newsletter + SEO" },
  { cat:"Civic", id:"civic-council", name:"Civic — Council", archetype:"Civic", color:"var(--beam)",
    desc:"Accessibility-first, meeting calendars, permits, multilingual, WCAG 2.1 AA.",
    pages:["Home","Departments","Services","Meetings","Documents","Contact","News"],
    modules:["GravityForms","WP Accessibility","Polylang","Events Calendar","Documents Library"],
    integrations:["CivicPlus","Granicus","GA4 (anon)"],
    pageTypes:["landing","department","service-detail","event","document","news"],
    cms:"WordPress + FSE", commerce:null, traffic:"Direct + search" },
  { cat:"Nonprofit", id:"nonprofit-cause", name:"Nonprofit — Cause", archetype:"Nonprofit", color:"var(--rose)",
    desc:"Donate-first, events, volunteer signup, impact storytelling.",
    pages:["Home","Mission","Donate","Events","Programs","Volunteer","News","Contact"],
    modules:["GiveWP","The Events Calendar","Fluent Forms","Yoast SEO"],
    integrations:["Stripe","Mailchimp","DonorPerfect","GA4"],
    pageTypes:["landing","program","event","donate","post","contact"],
    cms:"WordPress + FSE", commerce:"GiveWP", traffic:"Grants + social + email" },
  { cat:"SaaS", id:"saas-product", name:"SaaS — Product", archetype:"SaaS", color:"var(--purple)",
    desc:"Marketing site for a SaaS: features, pricing, docs, changelog, trial CTA.",
    pages:["Home","Features","Pricing","Docs","Changelog","Customers","Blog","Login"],
    modules:["Fluent Forms","Yoast SEO","WP Rocket","Docs plugin","Affiliate"],
    integrations:["Stripe","Intercom","Segment","GA4","Meta"],
    pageTypes:["landing","feature","pricing","docs","changelog","post"],
    cms:"WordPress + FSE", commerce:"Stripe", traffic:"Content + paid" },
  { cat:"Education", id:"course-cohort", name:"Course — Cohort", archetype:"Course", color:"var(--beam)",
    desc:"Enrollment-driven cohort program: syllabus, instructor, testimonials, apply.",
    pages:["Home","Syllabus","Instructors","Apply","FAQ","Alumni","Blog"],
    modules:["LearnDash","GravityForms","Fluent CRM","WP Rocket","Yoast"],
    integrations:["Stripe","Airtable","Zoom","Mailchimp","GA4"],
    pageTypes:["landing","syllabus","instructor","apply","post"],
    cms:"WordPress + LearnDash", commerce:"Stripe", traffic:"Waitlist + paid" }
];

/* ─────────────────────────────────────────────────────────────
   TAB: Detect
   ───────────────────────────────────────────────────────────── */
function DetectTab({ url, setUrl, brief, setBrief, detecting, detected, runDetect, onAccept }) {
  return (
    <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Input</h2>
          <span style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>step 01 · classify</span>
        </div>
        <div className="card-body" style={{ display:'grid', gap:12 }}>
          <label style={{ display:'grid', gap:6 }}>
            <span style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>EXISTING URL (OPTIONAL)</span>
            <input value={url} onChange={e => setUrl(e.target.value)}
              placeholder="https://example.com"
              style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:6, padding:'10px 12px', color:'var(--text)', fontFamily:'var(--font-mono)', fontSize:'.82rem', outline:'none' }}/>
          </label>
          <label style={{ display:'grid', gap:6 }}>
            <span style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>BRIEF — ONE OR TWO SENTENCES</span>
            <textarea value={brief} onChange={e => setBrief(e.target.value)}
              placeholder="What is this site for? Who's it for? Any must-have features?"
              rows={5}
              style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:6, padding:'10px 12px', color:'var(--text)', fontFamily:'var(--font-sans)', fontSize:'.86rem', outline:'none', resize:'vertical' }}/>
          </label>
          <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
            <button className="btn btn-primary btn-sm" onClick={runDetect} disabled={detecting}>
              <Icon name={detecting ? 'loader' : 'spark'} size={13}/>
              {detecting ? 'Detecting…' : 'Detect site type'}
            </button>
            <button className="btn btn-ghost btn-sm" onClick={() => { setUrl(''); setBrief(''); }}>
              <Icon name="x" size={12}/>Clear
            </button>
          </div>
          <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', lineHeight:1.55, paddingTop:6, borderTop:'1px solid var(--border)' }}>
            ↳ Classifier weighs URL signals (TLD, platform fingerprint, schema.org), brief keywords, and a zero-shot archetype match
            via Brain. Confidence &lt; 70% routes to a human-review blueprint.
          </div>
        </div>
      </div>

      {/* Detection result */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Detection result</h2>
          {detected && <span className="tag beam">{Math.round(detected.confidence*100)}% confidence</span>}
        </div>
        <div className="card-body" style={{ display:'grid', gap:12 }}>
          {!detected && (
            <div style={{ padding:'28px 8px', textAlign:'center', color:'var(--dim)' }}>
              <Icon name="spark" size={28}/>
              <div style={{ fontSize:'.84rem', marginTop:10 }}>No detection yet</div>
              <div style={{ fontSize:'.7rem', fontFamily:'var(--font-mono)', marginTop:4 }}>Fill the brief and click Detect</div>
            </div>
          )}
          {detected && <>
            <div style={{ display:'flex', alignItems:'center', gap:12, padding:'12px 14px', background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:6 }}>
              <div style={{ width:40, height:40, borderRadius:8, background:'rgba(99,91,255,.15)', border:'1px solid rgba(99,91,255,.3)', display:'flex', alignItems:'center', justifyContent:'center', color:'var(--beam)' }}>
                <Icon name="spark" size={18}/>
              </div>
              <div style={{ flex:1 }}>
                <div style={{ fontSize:'.94rem', fontWeight:600 }}>{detected.archetype}</div>
                <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>recommended blueprint · <span style={{ color:'var(--beam)' }}>{BLUEPRINTS.find(b => b.id === detected.blueprint)?.name}</span></div>
              </div>
            </div>
            <div>
              <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em', marginBottom:6 }}>SIGNALS</div>
              <div style={{ display:'grid', gap:6 }}>
                {detected.signals.map(sg => (
                  <div key={sg.k} style={{ display:'flex', justifyContent:'space-between', gap:12, fontSize:'.78rem', padding:'6px 10px', background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:4 }}>
                    <span style={{ color:'var(--dim)' }}>{sg.k}</span>
                    <span style={{ color:'var(--text-2)', fontFamily:'var(--font-mono)' }}>{sg.v}</span>
                  </div>
                ))}
              </div>
            </div>
            <div>
              <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em', marginBottom:6 }}>ALSO CONSIDER</div>
              <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
                {detected.suggests.map(id => {
                  const b = BLUEPRINTS.find(x => x.id === id);
                  // 2026-05-18 v3 per Jordan: fallback when BLUEPRINTS doesn't have
                  // this exact id (suggest list uses generic ids like 'service-pro'
                  // that don't match the very specific blueprint catalog). Humanize
                  // the slug so the tag isn't empty (was rendering as 2 mystery
                  // circles next to "Portfolio — Studio").
                  const label = b?.name || id.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ');
                  return <span key={id} className="tag" style={{ background:'var(--surface-2)' }}>{label}</span>;
                })}
              </div>
            </div>
            <div style={{ display:'flex', gap:8, paddingTop:8, borderTop:'1px solid var(--border)' }}>
              <button className="btn btn-primary btn-sm" onClick={onAccept}>
                <Icon name="check" size={12}/>Use this blueprint → Step 2
              </button>
              {/* 2026-05-18 v3 per Jordan: removed "Request human review" button.
                  Had "CD strategist" wording (brand leak) AND no need for
                  human-review contact form here — Site Builder is self-serve. */}
            </div>
          </>}
        </div>
      </div>

      {/* Archetype grid */}
      <div className="card" style={{ gridColumn:'1 / -1' }}>
        <div className="card-head">
          <h2 className="card-title">Supported archetypes</h2>
          <span style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>{Object.keys(DETECTION_RESULTS).length} types · 10 blueprints</span>
        </div>
        <div className="card-body" style={{ display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap:10 }}>
          {Object.entries(DETECTION_RESULTS).map(([k, r]) => (
            <div key={k} style={{ padding:'10px 12px', background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:6 }}>
              <div style={{ fontSize:'.82rem', fontWeight:600 }}>{r.archetype}</div>
              <div style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginTop:2 }}>{BLUEPRINTS.find(b => b.id === r.blueprint)?.name}</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   TAB: Blueprint
   ───────────────────────────────────────────────────────────── */
function BlueprintTab({ bp, blueprintId, setBlueprintId, detected, onNext }) {
  const { useState, useMemo } = React;
  const [catFilter, setCatFilter] = useState('All');
  const [query, setQuery] = useState('');
  // preserve insertion order of categories
  const categories = useMemo(() => {
    const seen = []; const set = new Set();
    BLUEPRINTS.forEach(b => { if (!set.has(b.cat)) { set.add(b.cat); seen.push(b.cat); } });
    return seen;
  }, []);
  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    return BLUEPRINTS.filter(b =>
      (catFilter === 'All' || b.cat === catFilter) &&
      (!q || b.name.toLowerCase().includes(q) || b.archetype.toLowerCase().includes(q) || (b.desc||'').toLowerCase().includes(q))
    );
  }, [catFilter, query]);
  // group filtered by category
  const grouped = useMemo(() => {
    const map = new Map();
    filtered.forEach(b => {
      if (!map.has(b.cat)) map.set(b.cat, []);
      map.get(b.cat).push(b);
    });
    return [...map.entries()];
  }, [filtered]);
  return (
    <div style={{ display:'grid', gridTemplateColumns:'320px 1fr', gap:16 }}>
      {/* 2026-05-18 v3 per Jordan: step-by-step guidance banner. Was confusing
          which block to interact with first ("no step 1, 2, 3"). Banner spans
          full width above the columns so the flow is explicit. */}
      <div style={{ gridColumn:'1 / -1', display:'flex', alignItems:'center', gap:14, padding:'10px 14px', borderRadius:8, background:'rgba(0, 194, 209, 0.04)', border:'1px solid rgba(0, 194, 209, 0.2)', borderLeft:'4px solid var(--beam, #00C2D1)', fontSize:'.78rem' }}>
        <span style={{ fontSize:'.66rem', color:'var(--beam, #00C2D1)', fontFamily:'var(--font-mono)', fontWeight:700, letterSpacing:'.08em', textTransform:'uppercase' }}>HOW TO USE THIS STEP</span>
        <div style={{ display:'flex', gap:18, flexWrap:'wrap', color:'var(--muted)', alignItems:'center' }}>
          <span><strong style={{ color:'var(--text)' }}>1.</strong> Pick a blueprint from the left list (or stick with the detected one)</span>
          <span><strong style={{ color:'var(--text)' }}>2.</strong> Review its pages + integrations</span>
          <span><strong style={{ color:'var(--text)' }}>3.</strong> Click <em>Use · Next step</em> to advance to Pages</span>
        </div>
      </div>
      {/* Blueprint list */}
      <div className="card" style={{ position:'sticky', top:16, alignSelf:'start', maxHeight:'calc(100vh - 32px)', display:'flex', flexDirection:'column' }}>
        <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
          <h2 className="card-title">Blueprints</h2>
          <span style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>{BLUEPRINTS.length} TOTAL</span>
        </div>
        <div style={{ padding:'8px 10px', borderBottom:'1px solid var(--border)', display:'grid', gap:8 }}>
          <input value={query} onChange={e=>setQuery(e.target.value)} placeholder="Search — e.g. plumber, realtor, cafe"
            style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, padding:'6px 9px', color:'var(--text)', fontFamily:'var(--font-mono)', fontSize:'.74rem', outline:'none' }}/>
          <div style={{ display:'flex', gap:4, flexWrap:'wrap' }}>
            {['All', ...categories].map(c => (
              <button key={c} onClick={()=>setCatFilter(c)}
                style={{
                  padding:'3px 8px', fontSize:'.66rem', fontFamily:'var(--font-mono)',
                  background: catFilter===c ? 'var(--beam)' : 'var(--surface-2)',
                  color: catFilter===c ? '#0b0f18' : 'var(--muted)',
                  border:'1px solid var(--border)', borderRadius:4, cursor:'pointer', letterSpacing:'.04em',
                }}>{c.toUpperCase()}</button>
            ))}
          </div>
        </div>
        <div className="card-body" style={{ padding:6, display:'grid', gap:2, overflow:'auto', flex:1 }}>
          {grouped.length === 0 && <div style={{ padding:16, color:'var(--dim)', fontSize:'.76rem', textAlign:'center' }}>No blueprints match.</div>}
          {grouped.map(([cat, items]) => (
            <div key={cat} style={{ marginBottom:6 }}>
              <div style={{ padding:'6px 10px 4px', fontSize:'.6rem', fontFamily:'var(--font-mono)', letterSpacing:'.08em', color:'var(--dim)', textTransform:'uppercase', display:'flex', justifyContent:'space-between' }}>
                <span>{cat}</span><span>{items.length}</span>
              </div>
              {items.map(b => {
                const active = b.id === blueprintId;
                const isRec = detected && detected.blueprint === b.id;
                return (
                  <button key={b.id} onClick={() => setBlueprintId(b.id)}
                    style={{
                      width:'100%', display:'grid', gap:2, padding:'7px 10px', textAlign:'left',
                      background: active ? 'var(--surface-2)' : 'transparent',
                      border:'1px solid', borderColor: active ? 'rgba(99,91,255,.4)' : 'transparent',
                      borderRadius:5, cursor:'pointer', color:'var(--text)',
                    }}>
                    <div style={{ display:'flex', alignItems:'center', gap:6 }}>
                      <span style={{ width:6, height:6, borderRadius:'50%', background:b.color, flex:'0 0 auto' }}/>
                      <span style={{ fontSize:'.78rem', fontWeight:600, flex:1, minWidth:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{b.name}</span>
                      {isRec && <span style={{ fontSize:'.56rem', color:'var(--beam)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>REC</span>}
                    </div>
                    <div style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)', paddingLeft:12 }}>{b.archetype}</div>
                  </button>
                );
              })}
            </div>
          ))}
        </div>
      </div>

      {/* Blueprint detail */}
      <div style={{ display:'grid', gap:16 }}>
        <div className="card">
          <div className="card-body" style={{ display:'flex', alignItems:'flex-start', gap:14 }}>
            <div style={{ width:48, height:48, borderRadius:10, background:'var(--surface-2)', border:`1px solid ${bp.color}40`, display:'flex', alignItems:'center', justifyContent:'center' }}>
              <span style={{ width:14, height:14, borderRadius:4, background:bp.color, display:'inline-block' }}/>
            </div>
            <div style={{ flex:1 }}>
              <div style={{ display:'flex', alignItems:'center', gap:8 }}>
                <h2 style={{ margin:0, fontSize:'1.15rem' }}>{bp.name}</h2>
                {detected && detected.blueprint === bp.id && <span className="tag beam">recommended</span>}
              </div>
              <p style={{ margin:'6px 0 0', color:'var(--muted)', fontSize:'.86rem' }}>{bp.desc}</p>
              <div style={{ display:'flex', gap:6, flexWrap:'wrap', marginTop:10 }}>
                <span className="tag">CMS · {bp.cms}</span>
                {bp.commerce && <span className="tag">Commerce · {bp.commerce}</span>}
                <span className="tag">Traffic · {bp.traffic}</span>
                <span className="tag">{bp.pages.length} pages</span>
              </div>
            </div>
            <button className="btn btn-primary btn-sm" onClick={onNext}>
              <Icon name="check" size={12}/>Use · Next step
            </button>
          </div>
        </div>

        <div className="bp-detail-grid" style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
          <div className="card" style={{ minWidth:0 }}>
            <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
              <h2 className="card-title">Pages ({bp.pages.length})</h2>
              <span style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>SITEMAP · GENERATED</span>
            </div>
            <div className="card-body" style={{ padding:0, overflow:'hidden' }}>
              <table className="table" style={{ tableLayout:'fixed', width:'100%' }}>
                <colgroup>
                  <col style={{ width:'40px' }}/>
                  <col/>
                  <col style={{ width:'42%' }}/>
                </colgroup>
                <thead><tr><th>#</th><th>Page</th><th>Type</th></tr></thead>
                <tbody>
                  {bp.pages.map((p, i) => (
                    <tr key={p}>
                      <td className="mono" style={{ color:'var(--dim)' }}>{String(i+1).padStart(2,'0')}</td>
                      <td style={{ fontWeight:500, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{p}</td>
                      <td className="mono" style={{ color:'var(--dim)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{bp.pageTypes[i % bp.pageTypes.length]}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
          <div className="card" style={{ minWidth:0 }}>
            <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
              <h2 className="card-title">Modules & integrations</h2>
              {(() => {
                const missing = bp.modules.filter(m => !INSTALLED_PLUGINS.has(normalizePlugin(m))).length;
                return missing > 0
                  ? <span className="tag" style={{ background:'rgba(255,179,64,.14)', color:'var(--amber)', borderColor:'rgba(255,179,64,.35)' }}>{missing} to install</span>
                  : <span className="tag beam">all installed</span>;
              })()}
            </div>
            <div className="card-body" style={{ display:'grid', gap:14 }}>
              <div>
                <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:8 }}>
                  <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>PLUGINS / MODULES</div>
                  <div style={{ display:'flex', alignItems:'center', gap:10, fontSize:'.6rem', fontFamily:'var(--font-mono)', color:'var(--dim)' }}>
                    <span style={{ display:'inline-flex', alignItems:'center', gap:4 }}><span style={{ width:6, height:6, borderRadius:'50%', background:'var(--beam)' }}/>INSTALLED</span>
                    <span style={{ display:'inline-flex', alignItems:'center', gap:4 }}><span style={{ width:6, height:6, borderRadius:'50%', background:'var(--amber)' }}/>MISSING</span>
                  </div>
                </div>
                <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
                  {bp.modules.map(m => {
                    const installed = INSTALLED_PLUGINS.has(normalizePlugin(m));
                    return (
                      <span key={m} className="tag" title={installed ? 'Already installed · active' : 'Not installed — queue for install'}
                        style={{
                          background: installed ? 'rgba(76,220,158,.12)' : 'rgba(255,179,64,.1)',
                          color: installed ? 'var(--beam)' : 'var(--amber)',
                          borderColor: installed ? 'rgba(76,220,158,.3)' : 'rgba(255,179,64,.3)',
                          display:'inline-flex', alignItems:'center', gap:6,
                        }}>
                        <span style={{ width:5, height:5, borderRadius:'50%', background:'currentColor' }}/>
                        {m}
                        {!installed && <Icon name="plus" size={10}/>}
                      </span>
                    );
                  })}
                </div>
                {(() => {
                  const missing = bp.modules.filter(m => !INSTALLED_PLUGINS.has(normalizePlugin(m)));
                  if (!missing.length) return null;
                  return (
                    <div style={{ marginTop:10, display:'flex', alignItems:'center', gap:8, padding:'8px 10px', background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:6 }}>
                      <Icon name="shield" size={13}/>
                      <div style={{ fontSize:'.72rem', color:'var(--muted)', flex:1 }}>
                        <strong style={{ color:'var(--text)' }}>{missing.length}</strong> plugin{missing.length===1?'':'s'} will be queued on <span style={{ color:'var(--text)' }}>Launch</span> via WPSB managed installer.
                      </div>
                      <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbToast(`Scanned installed plugins · ${INSTALLED_PLUGINS.size} detected`, 'ok')}>
                        <Icon name="refresh" size={11}/>Re-scan
                      </button>
                    </div>
                  );
                })()}
              </div>
              <div>
                <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em', marginBottom:8 }}>INTEGRATIONS</div>
                <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
                  {bp.integrations.map(m => <span key={m} className="tag">{m}</span>)}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   INSTALLED_PLUGINS — what WPSB detected on the connected site.
   Real product queries the WP REST API; for this mock we seed a
   realistic subset so ~70% show as already-installed.
   ───────────────────────────────────────────────────────────── */
const normalizePlugin = (s) => String(s || '')
  .toLowerCase()
  .replace(/\s*(pro|lite|plus|premium|free)\b/g, '')
  .replace(/[^a-z0-9]/g, '')
  .trim();

const INSTALLED_PLUGINS = new Set([
  'acf','yoast','yoastseo','wprocket','fluentforms','gravityforms',
  'imagify','wpmigrate','adminmenueditor','codesnippets','wpbeam',
  'woocommerce','thepluginmanager','advancedcustomfields','polylang',
  'eventscalendar','theeventscalendar','learndash','givewp','fluentcrm',
  'wpgridbuilder','metabox','schemapro','rankmath','wpfusion',
  'documentslibrary','wpaccessibility',
].map(normalizePlugin));

/* Section-type → icon-name mapping. Keys can match full section names
   or any substring within them (case-insensitive). First hit wins. */
const SECTION_ICON_RULES = [
  [/hero|header\b/i, 'flag'],
  [/logo cloud|logos|press/i, 'sites'],
  [/value prop|benefits|three[- ]?up/i, 'spark'],
  [/feature grid|feature|screenshot/i, 'modules'],
  [/testimonial|review|social proof/i, 'team'],
  [/pricing|tier|plan/i, 'billing'],
  [/faq|question/i, 'info'],
  [/footer|cta band|cta$|call to action/i, 'flag'],
  [/problem|framing|pain/i, 'warn'],
  [/process|how[- ]it[- ]works|1-2-3/i, 'activity'],
  [/deliverable|scope|what[- ]you[- ]get/i, 'tasks'],
  [/case|before\/after|results?|metrics/i, 'chart'],
  [/map|location|directions|area|local/i, 'globe'],
  [/trust|badge|credential/i, 'shield'],
  [/gallery|image|photo|portfolio/i, 'image'],
  [/filter|search/i, 'filter'],
  [/grid|index|list(?!ing)|catalog/i, 'dashboard'],
  [/product|variant|cart|checkout|subtotal|upsell/i, 'archive'],
  [/cross[- ]sell|related|recommended/i, 'partners'],
  [/post|article|editorial|body|story|stories/i, 'content'],
  [/author|bio|instructor|team member/i, 'account'],
  [/newsletter|subscribe|mailing/i, 'marketing'],
  [/comment|discussion/i, 'workspace'],
  [/phone|email|contact/i, 'support'],
  [/hours|schedule|agenda|week/i, 'calendar'],
  [/donate|donation|give/i, 'spark'],
  [/volunteer|apply|application/i, 'edit'],
  [/document|pdf|download/i, 'docs'],
  [/news|release|changelog/i, 'bell'],
  [/speaker/i, 'team'],
  [/rsvp/i, 'check'],
  [/integration/i, 'partners'],
  [/feedback|survey/i, 'workspace'],
  [/prev|next|pagination/i, 'chevron'],
  [/account|order|address|subscription|logout/i, 'lock'],
  [/department|leadership/i, 'building'],
  [/impact/i, 'trend'],
  [/syllabus|curriculum/i, 'docs'],
];
const sectionIcon = (name) => {
  for (const [re, icon] of SECTION_ICON_RULES) if (re.test(name)) return icon;
  return 'modules';
};

/* ─────────────────────────────────────────────────────────────
   TAB: Pages — sitemap editor
   ───────────────────────────────────────────────────────────── */
function PagesTab({ bp, onNext }) {
  const { useState } = React;
  const [selected, setSelected] = useState(0);
  const [editing, setEditing] = useState(null); // section index being edited inline
  /* 2026-05-18 v3 per Jordan: convert sections from derived constant to state
     so Move Up / Move Down / Delete actually mutate the section order. Before:
     handlers just toasted "Moved up (demo)" without changing anything. After:
     state map keyed by page index → per-page sections array. Defaults seeded
     from SECTION_LIB on first mutation. */
  const [sectionsByPage, setSectionsByPage] = useState({});
  const SECTION_LIB = {
    landing: ['Hero','Logo cloud','Value props (3-up)','Feature grid','Testimonials','Pricing CTA','FAQ','Footer CTA'],
    'service-detail': ['Hero (svc title + outcome)','Problem framing','Process (1-2-3)','Deliverables','Case snippet','Pricing / tiers','FAQ','CTA band'],
    'area-page': ['Hero (location + svc)','Map embed','Local proof (reviews)','Service list','Trust badges','Directions','CTA'],
    'case-study': ['Hero (client + problem)','Scope','Approach','Before/after gallery','Results (metrics)','Testimonial','Related work'],
    'work-index': ['Hero','Filter bar','Project grid','Studio bio block','CTA'],
    shop: ['Hero','Featured collection','Editorial block','Product grid','New arrivals','Press','Footer'],
    product: ['Gallery','Title + price','Variants','Description','Reviews','Related products','Cross-sell'],
    collection: ['Hero','Filter rail','Product grid','Editorial block','CTA'],
    post: ['Header','Feature image','Body','Author card','Related posts','Newsletter','Comments'],
    archive: ['Hero','Filter','Post grid','Pagination','Newsletter'],
    author: ['Bio','Social','Posts by author','Featured essay'],
    newsletter: ['Hero','Subscribe form','Past issues','About author'],
    contact: ['Hero','Contact form','Phone / email','Map','Office hours','FAQ'],
    cart: ['Header','Line items','Subtotal','Upsells','Checkout CTA'],
    account: ['Header','Orders','Addresses','Subscriptions','Logout'],
    department: ['Hero','Leadership','Services','News','Documents','Contact'],
    event: ['Hero','Date + location','Agenda','Speakers','RSVP','Related'],
    document: ['Header','Filter','Document list','Pagination'],
    news: ['Hero','Feature','Post grid','Filter','Newsletter'],
    program: ['Hero','Impact','How it works','Volunteer CTA','Stories','Donate'],
    donate: ['Hero','Donation tiers','Custom amount','Story','FAQ'],
    pricing: ['Hero','Tier comparison','Logos','FAQ','CTA'],
    feature: ['Hero','Screenshots','Value props','Integration','CTA'],
    docs: ['Sidebar','Article','Prev/Next','Feedback'],
    changelog: ['Header','Release list','Subscribe'],
    syllabus: ['Hero','Week-by-week','Deliverables','FAQ','Apply CTA'],
    instructor: ['Bio','Credentials','Past cohorts','Testimonials'],
    apply: ['Hero','Application form','FAQ','Testimonials'],
    support: ['Hero','Search','Category grid','Contact'],
    category: ['Hero','Product grid','Filter','Editorial block'],
  };
  const pageName = bp.pages[selected];
  const pageType = bp.pageTypes[selected % bp.pageTypes.length];
  const sections = sectionsByPage[selected] !== undefined
    ? sectionsByPage[selected]
    : (SECTION_LIB[pageType] || SECTION_LIB.landing);

  function moveSection(idx, dir) {
    const arr = [...sections];
    const newIdx = idx + (dir === 'up' ? -1 : 1);
    if (newIdx < 0 || newIdx >= arr.length) return;
    [arr[idx], arr[newIdx]] = [arr[newIdx], arr[idx]];
    setSectionsByPage(prev => ({ ...prev, [selected]: arr }));
    // If the edited section moved with it, follow it
    if (editing === idx) setEditing(newIdx);
    else if (editing === newIdx) setEditing(idx);
  }
  function deleteSection(idx) {
    const arr = sections.filter((_, i) => i !== idx);
    setSectionsByPage(prev => ({ ...prev, [selected]: arr }));
    if (editing === idx) setEditing(null);
    else if (editing !== null && editing > idx) setEditing(editing - 1);
  }

  return (
    <div style={{ display:'grid', gridTemplateColumns:'240px 1fr 280px', gap:16 }}>
      {/* Sitemap */}
      <div className="card" style={{ position:'sticky', top:16, alignSelf:'start' }}>
        <div className="card-head"><h2 className="card-title">Sitemap</h2></div>
        <div className="card-body" style={{ padding:6, display:'grid', gap:2 }}>
          {bp.pages.map((p, i) => {
            const active = i === selected;
            return (
              <button key={p} onClick={() => setSelected(i)}
                style={{
                  display:'flex', alignItems:'center', gap:8, padding:'7px 10px', textAlign:'left',
                  background: active ? 'var(--surface-2)' : 'transparent',
                  border:'1px solid', borderColor: active ? 'rgba(99,91,255,.4)' : 'transparent',
                  borderRadius:4, cursor:'pointer', color:'var(--text)',
                }}>
                <span className="mono" style={{ color:'var(--dim)', fontSize:'.64rem', width:20 }}>{String(i+1).padStart(2,'0')}</span>
                <span style={{ fontSize:'.8rem', fontWeight:500 }}>{p}</span>
              </button>
            );
          })}
          <button className="btn btn-ghost btn-sm" style={{ marginTop:6, justifyContent:'flex-start' }}
                  onClick={() => window.wpsbToast('Custom page added (demo)', 'ok')}>
            <Icon name="plus" size={12}/>Add page
          </button>
        </div>
      </div>

      {/* Section editor */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">{pageName}</h2>
          <span className="tag">{pageType}</span>
        </div>
        <div className="card-body" style={{ display:'grid', gap:8 }}>
          {sections.map((sec, i) => {
            const isEditing = editing === i;
            const iconName = sectionIcon(sec);
            return (
              <div key={sec+i}>
                <div style={{
                  display:'flex', alignItems:'center', gap:10, padding:'10px 12px',
                  background: isEditing ? 'rgba(99,91,255,.08)' : 'var(--surface-2)',
                  border:'1px solid', borderColor: isEditing ? 'rgba(99,91,255,.4)' : 'var(--border)',
                  borderRadius: isEditing ? '6px 6px 0 0' : 6,
                }}>
                  <div className="mono" style={{ color:'var(--dim)', fontSize:'.66rem', width:22 }}>{String(i+1).padStart(2,'0')}</div>
                  <div style={{ width:28, height:28, borderRadius:5, background:'var(--surface)', border:'1px solid var(--border)', display:'flex', alignItems:'center', justifyContent:'center', color:'var(--text-2)', flex:'0 0 auto' }} title={iconName}>
                    <Icon name={iconName} size={14}/>
                  </div>
                  <div style={{ flex:1, fontSize:'.86rem', fontWeight:500, minWidth:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{sec}</div>
                  <button className="btn btn-ghost btn-sm" onClick={() => setEditing(isEditing ? null : i)} aria-expanded={isEditing}>
                    <Icon name={isEditing ? 'x' : 'edit'} size={11}/>{isEditing ? 'Close' : 'Edit'}
                  </button>
                  <button className="icon-btn" title="Move up" style={{ width:26, height:26, opacity: i === 0 ? 0.35 : 1, cursor: i === 0 ? 'not-allowed' : 'pointer' }}
                          disabled={i === 0}
                          onClick={()=>moveSection(i, 'up')}>
                    <Icon name="chevron-up" size={11}/>
                  </button>
                  <button className="icon-btn" title="Move down" style={{ width:26, height:26, opacity: i === sections.length - 1 ? 0.35 : 1, cursor: i === sections.length - 1 ? 'not-allowed' : 'pointer' }}
                          disabled={i === sections.length - 1}
                          onClick={()=>moveSection(i, 'down')}>
                    <Icon name="chevron-down" size={11}/>
                  </button>
                  <button className="icon-btn" title="Remove" style={{ width:26, height:26, color:'var(--rose)' }}
                          onClick={()=>{
                            deleteSection(i);
                            window.wpsbToast?.(`Removed "${sec}"`, 'warn');
                          }}>
                    <Icon name="x" size={11}/>
                  </button>
                </div>
                {isEditing && (
                  <div style={{ border:'1px solid rgba(99,91,255,.4)', borderTop:'none', borderRadius:'0 0 6px 6px', padding:12, background:'var(--surface)', display:'grid', gap:10 }}>
                    <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
                      <label style={{ display:'grid', gap:4 }}>
                        <span style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>LABEL</span>
                        <input defaultValue={sec}
                          style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, padding:'6px 9px', color:'var(--text)', fontFamily:'var(--font-sans)', fontSize:'.82rem', outline:'none' }}/>
                      </label>
                      <label style={{ display:'grid', gap:4 }}>
                        <span style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>BLOCK TEMPLATE</span>
                        <select defaultValue="default"
                          style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, padding:'6px 9px', color:'var(--text)', fontFamily:'var(--font-sans)', fontSize:'.82rem', outline:'none' }}>
                          <option value="default">Default · WPSB pattern</option>
                          <option>Wide · full-bleed</option>
                          <option>Split · 60/40</option>
                          <option>Carousel</option>
                          <option>Grid (3-up)</option>
                        </select>
                      </label>
                    </div>
                    <label style={{ display:'grid', gap:4 }}>
                      <span style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>AI DRAFT — PROMPT</span>
                      <textarea rows={2} placeholder="What should this section say? (reuses Brand voice + Content SEO keywords)"
                        style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, padding:'6px 9px', color:'var(--text)', fontFamily:'var(--font-sans)', fontSize:'.82rem', outline:'none', resize:'vertical' }}/>
                    </label>
                    <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
                      <button className="btn btn-primary btn-sm" onClick={()=>{ window.wpsbToast(`Draft generated for "${sec}"`, 'ok'); setEditing(null); }}>
                        <Icon name="spark" size={11}/>Generate draft
                      </button>
                      <button className="btn btn-ghost btn-sm" onClick={()=>window.wpsbToast('Opened in block editor', 'info')}>
                        <Icon name="edit" size={11}/>Open in editor
                      </button>
                      <button className="btn btn-ghost btn-sm" onClick={()=>setEditing(null)}>Cancel</button>
                    </div>
                  </div>
                )}
              </div>
            );
          })}
          <button className="btn btn-ghost btn-sm" style={{ justifyContent:'flex-start' }}
                  onClick={() => window.wpsbToast('Section added (demo)', 'ok')}>
            <Icon name="plus" size={12}/>Add section
          </button>
        </div>
      </div>

      {/* Inspector */}
      <div className="card">
        <div className="card-head"><h2 className="card-title">Inspector</h2></div>
        <div className="card-body" style={{ display:'grid', gap:10, fontSize:'.78rem' }}>
          <div>
            <div style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>SLUG</div>
            <div className="mono" style={{ marginTop:2, color:'var(--text-2)' }}>/{pageName.toLowerCase().replace(/\s+/g,'-')}</div>
          </div>
          <div>
            <div style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>PAGE TYPE</div>
            <div style={{ marginTop:2 }}>{pageType}</div>
          </div>
          <div>
            <div style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>SEO</div>
            <div style={{ marginTop:2, color:'var(--text-2)' }}>Auto-draft from Content SEO module</div>
          </div>
          <div>
            <div style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>STATUS</div>
            <div style={{ marginTop:2, display:'flex', alignItems:'center', gap:6 }}>
              <span style={{ width:6, height:6, borderRadius:'50%', background:'var(--warn)' }}/>
              Draft
            </div>
          </div>
          <div style={{ paddingTop:8, borderTop:'1px solid var(--border)', display:'flex', gap:6, flexWrap:'wrap' }}>
            <button className="btn btn-primary btn-sm" onClick={onNext}>Next: Theme</button>
            <button className="btn btn-ghost btn-sm" onClick={onNext} title="Preview is part of the Theme step — jump there now">
              Preview →
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   TAB: Theme
   ───────────────────────────────────────────────────────────── */
function ThemeTab({ bp, scannerHandoff, onNext }) {
  const { useState, useMemo } = React;
  /* 2026-05-18 v3 per Jordan: "From Brand Profile" was pulling AGENCY brand
     (window.BRAND_PROFILE), which is wrong — Site Builder is building a site
     FOR a client, so the theme should pull the CLIENT's (scanned site's)
     brand colors/fonts/logo. Now prefer scannerHandoff.brand when present,
     fall back to agency BRAND_PROFILE only if no scan handoff exists. */
  const AgencyBP = window.BRAND_PROFILE || {};
  const ScanBrand = scannerHandoff?.brand || null;
  // Build a unified brand source — scan-first
  const BP = ScanBrand ? {
    palette: {
      primary: Array.isArray(ScanBrand.colors) && ScanBrand.colors.length > 0 ? (ScanBrand.colors[0]?.hex || ScanBrand.colors[0]) : null,
      secondary: Array.isArray(ScanBrand.colors) && ScanBrand.colors.length > 1 ? (ScanBrand.colors[1]?.hex || ScanBrand.colors[1]) : null,
    },
    typography: {
      headline: Array.isArray(ScanBrand.fonts) && ScanBrand.fonts.length > 0 ? (ScanBrand.fonts[0]?.family || ScanBrand.fonts[0]) : null,
      body:     Array.isArray(ScanBrand.fonts) && ScanBrand.fonts.length > 1 ? (ScanBrand.fonts[1]?.family || ScanBrand.fonts[1]) : null,
    },
    displayName: scannerHandoff?.site || 'scanned site',
    source: 'scanner',
  } : AgencyBP;
  const brandHasPalette = !!(BP.palette && BP.palette.primary);
  // Fallback accent from blueprint color if no brand info
  const bpAccent = bp.color === 'var(--orange)' ? '#F97316'
    : bp.color === 'var(--green)' ? 'var(--green)'
    : bp.color === 'var(--rose)' ? '#F43F5E'
    : bp.color === 'var(--purple)' ? 'var(--purple)'
    : 'var(--beam)';
  const [palette, setPalette] = useState({
    bg:      '#0B1220',
    text:    '#F5F7FB',
    accent:  BP.palette?.primary   || bpAccent,
    muted:   'var(--dim)',
    surface: '#111827',
  });
  const [fontH, setFontH] = useState(BP.typography?.headline || 'Fraunces');
  const [fontB, setFontB] = useState(BP.typography?.body     || 'Inter');
  const [brandSynced, setBrandSynced] = useState(brandHasPalette);
  const [fullscreen, setFullscreen] = useState(false);
  const [previewPage, setPreviewPage] = useState(bp.pages[0]);
  const [device, setDevice] = useState('desktop'); // desktop | tablet | mobile

  const pullBrand = () => {
    if (!brandHasPalette) {
      const msg = ScanBrand
        ? 'Scanner returned no brand colors — run a Brand Profile scan first'
        : 'No site scanned yet — start with the Scanner to extract brand colors';
      window.wpsbToast(msg, 'warn');
      return;
    }
    setPalette(p => ({
      ...p,
      accent:  BP.palette.primary,
      surface: BP.palette.secondary ? BP.palette.secondary : '#111827',
    }));
    if (BP.typography?.headline) setFontH(BP.typography.headline);
    if (BP.typography?.body)     setFontB(BP.typography.body);
    setBrandSynced(true);
    const src = BP.source === 'scanner' ? 'scanned site' : 'agency profile';
    window.wpsbToast(`Synced palette + type from ${src} · ${BP.displayName}`, 'ok');
  };

  const markUnsynced = (updater) => {
    setBrandSynced(false);
    return updater;
  };

  // Typography options include brand fonts at the front
  const headingFonts = useMemo(() => {
    const brand = BP.typography?.headline;
    const base = ['Fraunces','Playfair Display','DM Serif','Canela','Söhne Headline'];
    return brand && !base.includes(brand) ? [brand, ...base] : base;
  }, []);
  const bodyFonts = useMemo(() => {
    const brand = BP.typography?.body;
    const base = ['Inter','IBM Plex Sans','Söhne','Manrope','Noto Sans'];
    return brand && !base.includes(brand) ? [brand, ...base] : base;
  }, []);

  return (
    <>
    <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
      <div style={{ display:'grid', gap:16 }}>
        <div className="card">
          <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
            <h2 className="card-title">Palette</h2>
            <div style={{ display:'flex', alignItems:'center', gap:8 }}>
              {brandSynced && <span className="tag beam" style={{ display:'inline-flex', alignItems:'center', gap:4 }}><span style={{ width:5, height:5, borderRadius:'50%', background:'currentColor' }}/>synced · {BP.displayName || 'brand'}</span>}
              <button className="btn btn-ghost btn-sm" onClick={pullBrand} title={ScanBrand ? `Pull palette + fonts from the scanned site (${scannerHandoff?.site})` : 'Pull palette + fonts from your agency Brand Profile'}>
                <Icon name="brand" size={11}/>{ScanBrand ? 'From scanned site' : 'From Brand Profile'}
              </button>
            </div>
          </div>
          <div className="card-body" style={{ display:'grid', gap:8 }}>
            {Object.entries(palette).map(([k,v]) => (
              <div key={k} style={{ display:'grid', gridTemplateColumns:'100px 36px 1fr', alignItems:'center', gap:10 }}>
                <span className="mono" style={{ fontSize:'.72rem', color:'var(--dim)' }}>{k.toUpperCase()}</span>
                <label style={{ position:'relative', width:36, height:28, borderRadius:5, border:'1px solid var(--border)', background:v, cursor:'pointer' }}>
                  <input type="color" value={v} onChange={e => { setPalette({...palette, [k]: e.target.value}); setBrandSynced(false); }}
                         style={{ position:'absolute', inset:0, opacity:0, cursor:'pointer' }}/>
                </label>
                <input value={v} onChange={e => { setPalette({...palette, [k]: e.target.value}); setBrandSynced(false); }}
                  className="mono"
                  style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:4, padding:'5px 8px', color:'var(--text-2)', fontSize:'.78rem', outline:'none' }}/>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card-head"><h2 className="card-title">Typography</h2></div>
          <div className="card-body" style={{ display:'grid', gap:12 }}>
            <div>
              <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginBottom:6 }}>HEADING {BP.typography?.headline && <span style={{ color:'var(--beam)', marginLeft:6 }}>· brand default: {BP.typography.headline}</span>}</div>
              <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
                {headingFonts.map(f => (
                  <button key={f} onClick={() => { setFontH(f); setBrandSynced(false); }}
                    className="tag" style={{ cursor:'pointer', background: fontH === f ? 'rgba(99,91,255,.18)' : 'var(--surface-2)', color: fontH === f ? 'var(--beam)' : 'var(--text-2)', borderColor: fontH === f ? 'rgba(99,91,255,.4)' : 'var(--border)' }}>{f}</button>
                ))}
              </div>
            </div>
            <div>
              <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginBottom:6 }}>BODY {BP.typography?.body && <span style={{ color:'var(--beam)', marginLeft:6 }}>· brand default: {BP.typography.body}</span>}</div>
              <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
                {bodyFonts.map(f => (
                  <button key={f} onClick={() => { setFontB(f); setBrandSynced(false); }}
                    className="tag" style={{ cursor:'pointer', background: fontB === f ? 'rgba(99,91,255,.18)' : 'var(--surface-2)', color: fontB === f ? 'var(--beam)' : 'var(--text-2)', borderColor: fontB === f ? 'rgba(99,91,255,.4)' : 'var(--border)' }}>{f}</button>
                ))}
              </div>
            </div>
            <div>
              <div style={{ fontSize:'.7rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginBottom:6 }}>SCALE</div>
              <div style={{ display:'flex', gap:6 }}>
                {['compact','standard','expressive'].map(v => (
                  <button key={v} className="btn btn-ghost btn-sm" onClick={() => window.wpsbToast(`Type scale: ${v}`, 'ok')}>{v}</button>
                ))}
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Preview */}
      <div className="card" style={{ position:'sticky', top:16, alignSelf:'start' }}>
        <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
          <h2 className="card-title">Live preview</h2>
          <div style={{ display:'flex', gap:6 }}>
            <button className="btn btn-ghost btn-sm" onClick={() => setFullscreen(true)} title="Preview full page at real size">
              <Icon name="globe" size={11}/>Full preview
            </button>
            <button className="btn btn-primary btn-sm" onClick={onNext}>Next: Content</button>
          </div>
        </div>
        <div className="card-body" style={{ padding:0 }}>
          <HeroPreview bp={bp} palette={palette} fontH={fontH} fontB={fontB} scale={1}/>
        </div>
        <div className="card-body" style={{ borderTop:'1px solid var(--border)', fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', lineHeight:1.55, display:'flex', alignItems:'center', justifyContent:'space-between', gap:12 }}>
          <span>↳ Exports to <code style={{ background:'var(--surface-3)', padding:'1px 4px', borderRadius:2 }}>theme.json</code> + <code style={{ background:'var(--surface-3)', padding:'1px 4px', borderRadius:2 }}>style.css</code> (WP FSE-compatible).</span>
          <button className="btn btn-ghost btn-sm" onClick={() => setFullscreen(true)}>
            <Icon name="spark" size={11}/>Preview all pages
          </button>
        </div>
      </div>
    </div>

    {fullscreen && (
      <FullscreenPreview
        bp={bp}
        palette={palette}
        fontH={fontH}
        fontB={fontB}
        previewPage={previewPage}
        setPreviewPage={setPreviewPage}
        device={device}
        setDevice={setDevice}
        onClose={() => setFullscreen(false)}
        onPublishNext={onNext}
      />
    )}
    </>
  );
}

/* Shared hero block — used in Theme card + fullscreen preview */
function HeroPreview({ bp, palette, fontH, fontB, scale = 1 }) {
  const BP = window.BRAND_PROFILE || {};
  const headline = bp.archetype === 'eCommerce' ? 'Shop the latest drop.'
    : bp.archetype === 'Portfolio' ? 'Selected work, crafted with care.'
    : bp.archetype === 'Blog' ? 'Stories for builders and operators.'
    : 'We build WordPress sites that ship, rank, and convert.';
  const sub = BP.tagline || 'Hand-crafted themes, measured performance, and marketing wired in from day one.';
  return (
    <div style={{ background: palette.bg, color: palette.text, padding:`${36*scale}px ${28*scale}px`, minHeight:340*scale, fontFamily:fontB }}>
      <div style={{ fontFamily:'var(--font-mono)', fontSize:.58*scale+'rem', letterSpacing:'.12em', color: palette.muted, marginBottom:14*scale }}>{bp.archetype.toUpperCase()}</div>
      <div style={{ fontFamily:fontH, fontSize:2*scale+'rem', fontWeight:700, lineHeight:1.08, letterSpacing:'-.02em', marginBottom:10*scale, maxWidth:420*scale }}>{headline}</div>
      <div style={{ fontSize:.94*scale+'rem', color: palette.muted, maxWidth:420*scale, lineHeight:1.5, marginBottom:18*scale }}>{sub}</div>
      <div style={{ display:'flex', gap:8*scale }}>
        <button style={{ background: palette.accent, color: '#0B1220', padding:`${9*scale}px ${14*scale}px`, borderRadius:5, border:'none', fontWeight:600, fontSize:.82*scale+'rem', cursor:'pointer', fontFamily:fontB }}>Get a quote</button>
        <button style={{ background: 'transparent', color: palette.text, padding:`${9*scale}px ${14*scale}px`, borderRadius:5, border:`1px solid ${palette.muted}40`, fontSize:.82*scale+'rem', cursor:'pointer', fontFamily:fontB }}>See the work</button>
      </div>
      <div style={{ marginTop:26*scale, padding:`${12*scale}px ${14*scale}px`, background: palette.surface, borderRadius:6, fontSize:.78*scale+'rem', color: palette.muted, fontFamily:'var(--font-mono)' }}>
        <span style={{ color: palette.accent, marginRight:8 }}>●</span>
        H: <span style={{ color: palette.text }}>{fontH}</span> &nbsp; · &nbsp;
        B: <span style={{ color: palette.text }}>{fontB}</span>
      </div>
    </div>
  );
}

/* Fullscreen preview modal — browser chrome, page switcher, device toggle.
   Renders a per-page wireframe-style mockup so the user can review layout
   BEFORE publishing. Lives INSIDE Site Builder — not a public URL. */
function FullscreenPreview({ bp, palette, fontH, fontB, previewPage, setPreviewPage, device, setDevice, onClose, onPublishNext }) {
  const { useEffect } = React;
  useEffect(() => {
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => window.removeEventListener('keydown', onEsc);
  }, [onClose]);
  const widths = { desktop: 1280, tablet: 820, mobile: 390 };
  const pageIdx = bp.pages.indexOf(previewPage);
  const pageType = bp.pageTypes[pageIdx % bp.pageTypes.length];
  const frameW = widths[device];

  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(6,9,16,.82)', backdropFilter:'blur(6px)', zIndex:9000, display:'flex', flexDirection:'column' }}
         role="dialog" aria-modal="true" aria-label="Full page preview">
      {/* Top bar */}
      <div style={{ display:'flex', alignItems:'center', gap:12, padding:'10px 16px', borderBottom:'1px solid var(--border)', background:'var(--surface)' }}>
        <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="x" size={12}/>Close</button>
        <div style={{ width:1, height:20, background:'var(--border)' }}/>
        <div style={{ display:'flex', alignItems:'center', gap:6, flex:1, minWidth:0 }}>
          <span style={{ fontSize:'.72rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.06em' }}>PREVIEW ·</span>
          <span style={{ fontSize:'.84rem', fontWeight:600 }}>{bp.name}</span>
          <span style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>/ {previewPage.toLowerCase().replace(/\s+/g,'-')} · {pageType}</span>
        </div>
        {/* Device toggle */}
        <div style={{ display:'flex', gap:2, background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, padding:2 }}>
          {[['desktop','sites'],['tablet','dashboard'],['mobile','lock']].map(([d, icon]) => (
            <button key={d} onClick={()=>setDevice(d)}
              style={{
                padding:'4px 10px', fontSize:'.68rem', fontFamily:'var(--font-mono)', letterSpacing:'.04em',
                background: device===d ? 'var(--surface)' : 'transparent',
                color: device===d ? 'var(--text)' : 'var(--muted)',
                border:'none', borderRadius:3, cursor:'pointer', textTransform:'uppercase',
                display:'inline-flex', alignItems:'center', gap:4,
              }}>{d}</button>
          ))}
        </div>
        <button className="btn btn-ghost btn-sm" onClick={async () => {
          // 2026-05-18 v3 per Jordan: actually copy a real preview URL instead
          // of fake-toasting "Preview link copied". For now, synthesize a stub
          // URL pointing back to the SaaS preview route — real preview routing
          // (server-rendered draft sites) lands with Bundle B / Launch wiring.
          const stubUrl = `https://app.wpsitebeam.io/preview/${encodeURIComponent(bp.id)}?ts=${Date.now()}`;
          try {
            if (navigator.clipboard && navigator.clipboard.writeText) {
              await navigator.clipboard.writeText(stubUrl);
              window.wpsbToast(`Preview link copied — ${stubUrl.slice(0, 48)}…`, 'ok');
            } else {
              // Fallback: open a prompt the user can copy from
              window.prompt('Copy preview link:', stubUrl);
            }
          } catch (e) {
            window.wpsbToast('Copy failed — clipboard permission denied. Try the textarea fallback.', 'warn');
          }
        }}>
          <Icon name="globe" size={11}/>Share link
        </button>
        <button className="btn btn-primary btn-sm" onClick={()=>{ onClose(); onPublishNext(); }}>
          <Icon name="check" size={11}/>Looks good · Continue
        </button>
      </div>
      {/* Body: sidebar + frame */}
      <div style={{ flex:1, display:'grid', gridTemplateColumns:'220px 1fr', overflow:'hidden' }}>
        {/* Page switcher */}
        <div style={{ background:'var(--surface)', borderRight:'1px solid var(--border)', overflow:'auto', padding:'12px 8px' }}>
          <div style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.08em', padding:'4px 8px 8px' }}>PAGES · {bp.pages.length}</div>
          {bp.pages.map((p, i) => {
            const active = p === previewPage;
            return (
              <button key={p} onClick={()=>setPreviewPage(p)}
                style={{
                  width:'100%', display:'flex', alignItems:'center', gap:8, padding:'7px 10px', textAlign:'left',
                  background: active ? 'var(--surface-2)' : 'transparent',
                  border:'1px solid', borderColor: active ? 'rgba(99,91,255,.4)' : 'transparent',
                  borderRadius:4, cursor:'pointer', color:'var(--text)',
                }}>
                <span className="mono" style={{ color:'var(--dim)', fontSize:'.64rem', width:20 }}>{String(i+1).padStart(2,'0')}</span>
                <span style={{ fontSize:'.78rem', fontWeight:500 }}>{p}</span>
              </button>
            );
          })}
        </div>
        {/* Frame */}
        <div style={{ overflow:'auto', padding:24, display:'flex', justifyContent:'center', alignItems:'flex-start', background:'var(--bg)' }}>
          <div style={{
            width: Math.min(frameW, 1280), maxWidth:'100%',
            background:'var(--surface)', borderRadius:8, border:'1px solid var(--border)',
            overflow:'hidden', boxShadow:'0 20px 60px rgba(0,0,0,.4)',
          }}>
            {/* Fake browser chrome */}
            <div style={{ display:'flex', alignItems:'center', gap:8, padding:'8px 12px', background:'var(--surface-2)', borderBottom:'1px solid var(--border)' }}>
              <div style={{ display:'flex', gap:5 }}>
                <span style={{ width:10, height:10, borderRadius:'50%', background:'#FF5F57' }}/>
                <span style={{ width:10, height:10, borderRadius:'50%', background:'#FFBD2E' }}/>
                <span style={{ width:10, height:10, borderRadius:'50%', background:'#28C940' }}/>
              </div>
              <div style={{ flex:1, background:'var(--surface)', border:'1px solid var(--border)', borderRadius:4, padding:'4px 10px', fontFamily:'var(--font-mono)', fontSize:'.7rem', color:'var(--dim)' }}>
                https://{(window.BRAND_PROFILE?.displayName || 'acme').toLowerCase()}.com/{previewPage.toLowerCase().replace(/\s+/g,'-')}
              </div>
            </div>
            <PagePreview bp={bp} page={previewPage} pageType={pageType} palette={palette} fontH={fontH} fontB={fontB} device={device}/>
          </div>
        </div>
      </div>
    </div>
  );
}

/* Per-page wireframe preview — switches layout by pageType */
function PagePreview({ bp, page, pageType, palette, fontH, fontB, device }) {
  const BP = window.BRAND_PROFILE || {};
  const brandName = BP.displayName || 'Acme';
  const mobile = device === 'mobile';
  return (
    <div style={{ background: palette.bg, color: palette.text, fontFamily: fontB, minHeight: 600 }}>
      {/* Nav */}
      <div style={{ display:'flex', alignItems:'center', gap:16, padding: mobile ? '14px 16px' : '18px 32px', borderBottom:`1px solid ${palette.muted}22` }}>
        <div style={{ fontFamily:fontH, fontWeight:800, fontSize:mobile?'1.05rem':'1.2rem', letterSpacing:'-.01em' }}>{brandName}</div>
        {!mobile && (
          <div style={{ display:'flex', gap:18, flex:1, fontSize:'.82rem', color: palette.muted }}>
            {bp.pages.slice(0, 5).map(p => (
              <span key={p} style={{ fontWeight: p===page?600:400, color: p===page ? palette.text : palette.muted }}>{p}</span>
            ))}
          </div>
        )}
        <div style={{ flex: mobile ? 1 : 0 }}/>
        <button style={{ background:palette.accent, color:'#0B1220', border:'none', padding:'7px 14px', borderRadius:5, fontWeight:600, fontSize:'.78rem', cursor:'pointer', fontFamily:fontB }}>{bp.commerce ? 'Shop' : 'Get a quote'}</button>
      </div>
      {/* Page body - layout depends on pageType */}
      <PageBody pageType={pageType} page={page} bp={bp} palette={palette} fontH={fontH} fontB={fontB} mobile={mobile}/>
      {/* Footer */}
      <div style={{ padding: mobile ? '20px 16px' : '32px 32px', borderTop:`1px solid ${palette.muted}22`, background:palette.surface, color:palette.muted, fontSize:'.76rem', display:'flex', flexWrap:'wrap', gap:12, justifyContent:'space-between' }}>
        <span>© {new Date().getFullYear()} {brandName}. All rights reserved.</span>
        <span style={{ fontFamily:'var(--font-mono)' }}>Built with WP Site Beam</span>
      </div>
    </div>
  );
}

/* Per-pageType layout shells. Wireframe-level — stand-ins, not real content. */
function PageBody({ pageType, page, bp, palette, fontH, fontB, mobile }) {
  const block = (h=60, w='100%', style={}) => (<div style={{ height:h, width:w, background:`${palette.muted}18`, borderRadius:4, ...style }}/>);
  const accentBtn = (label='CTA') => (
    <button style={{ background:palette.accent, color:'#0B1220', border:'none', padding:'10px 18px', borderRadius:5, fontWeight:600, fontSize:'.86rem', cursor:'pointer', fontFamily:fontB }}>{label}</button>
  );
  const pad = mobile ? '24px 16px' : '56px 48px';
  const gridCols = mobile ? 1 : 3;
  // Hero always present
  const Hero = (
    <div style={{ padding:pad }}>
      <div style={{ fontFamily:'var(--font-mono)', fontSize:'.6rem', letterSpacing:'.12em', color:palette.muted, marginBottom:12 }}>{(bp.archetype || '').toUpperCase()} · {page.toUpperCase()}</div>
      <div style={{ fontFamily:fontH, fontSize: mobile ? '2rem' : '3.2rem', lineHeight:1.05, fontWeight:700, letterSpacing:'-.02em', maxWidth: mobile ? '100%' : 720, marginBottom:16 }}>
        {pageHeadline(pageType, page, bp)}
      </div>
      <div style={{ fontSize:'1rem', color:palette.muted, maxWidth: mobile ? '100%' : 560, lineHeight:1.55, marginBottom:22 }}>
        {pageSubhead(pageType, bp)}
      </div>
      <div style={{ display:'flex', gap:10, flexWrap:'wrap' }}>
        {accentBtn(pageType === 'product' ? 'Add to cart' : pageType === 'contact' ? 'Send message' : pageType === 'donate' ? 'Donate now' : 'Get a quote')}
        <button style={{ background:'transparent', color:palette.text, padding:'10px 18px', borderRadius:5, border:`1px solid ${palette.muted}55`, fontSize:'.86rem', cursor:'pointer', fontFamily:fontB }}>Learn more</button>
      </div>
    </div>
  );

  // Below-fold blocks by pageType
  const Below = (() => {
    if (pageType === 'product' || pageType === 'collection' || pageType === 'shop') {
      return (
        <div style={{ padding:pad, paddingTop:0 }}>
          <div style={{ display:'grid', gridTemplateColumns:`repeat(${mobile?2:4}, 1fr)`, gap:mobile?12:16 }}>
            {Array.from({length: mobile?4:8}).map((_,i) => (
              <div key={i} style={{ display:'grid', gap:8 }}>
                <div style={{ aspectRatio:'1', background:`${palette.muted}22`, borderRadius:6 }}/>
                {block(12, '70%')}
                {block(12, '40%', { background:`${palette.accent}44` })}
              </div>
            ))}
          </div>
        </div>
      );
    }
    if (pageType === 'case-study' || pageType === 'work-index' || pageType === 'portfolio') {
      return (
        <div style={{ padding:pad, paddingTop:0, display:'grid', gap:24 }}>
          <div style={{ aspectRatio:mobile?'4/3':'16/7', background:`${palette.muted}22`, borderRadius:8 }}/>
          <div style={{ display:'grid', gridTemplateColumns:`repeat(${gridCols}, 1fr)`, gap:mobile?12:20 }}>
            {Array.from({length:gridCols}).map((_,i) => (
              <div key={i} style={{ display:'grid', gap:8 }}>
                <div style={{ fontFamily:fontH, fontSize:'1.2rem', fontWeight:700 }}>Chapter {i+1}</div>
                {block(10)}{block(10, '90%')}{block(10, '60%')}
              </div>
            ))}
          </div>
        </div>
      );
    }
    if (pageType === 'pricing') {
      return (
        <div style={{ padding:pad, paddingTop:0, display:'grid', gridTemplateColumns:`repeat(${mobile?1:3}, 1fr)`, gap:16 }}>
          {['Starter','Pro','Enterprise'].map((tier, i) => (
            <div key={tier} style={{ border:`1px solid ${palette.muted}33`, borderRadius:8, padding:24, background: i===1?palette.surface:'transparent' }}>
              <div style={{ fontSize:'.72rem', fontFamily:'var(--font-mono)', letterSpacing:'.08em', color:palette.muted, marginBottom:6 }}>{tier.toUpperCase()}</div>
              <div style={{ fontFamily:fontH, fontSize:'2rem', fontWeight:700, marginBottom:14 }}>${i===0?19:i===1?49:199}<span style={{ fontSize:'.8rem', color:palette.muted }}>/mo</span></div>
              {[1,2,3,4].map(j => <div key={j} style={{ fontSize:'.82rem', color:palette.muted, padding:'4px 0' }}>◆ Feature line {j}</div>)}
            </div>
          ))}
        </div>
      );
    }
    if (pageType === 'contact') {
      return (
        <div style={{ padding:pad, paddingTop:0, display:'grid', gridTemplateColumns:mobile?'1fr':'2fr 1fr', gap:24 }}>
          <div style={{ display:'grid', gap:10 }}>
            {['Name','Email','Message'].map((l,i) => (
              <div key={l}>
                <div style={{ fontSize:'.7rem', color:palette.muted, fontFamily:'var(--font-mono)', marginBottom:4 }}>{l.toUpperCase()}</div>
                <div style={{ height:i===2?120:40, background:`${palette.muted}14`, border:`1px solid ${palette.muted}33`, borderRadius:5 }}/>
              </div>
            ))}
          </div>
          <div style={{ fontSize:'.86rem', color:palette.muted, lineHeight:1.6 }}>
            <div style={{ color:palette.text, fontFamily:fontH, fontSize:'1.2rem', marginBottom:10 }}>Visit us</div>
            412 Market St, Suite 800<br/>San Francisco, CA 94105<br/>+1 (555) 234-1100
          </div>
        </div>
      );
    }
    // Default: 3-up value props + testimonial band
    return (
      <div style={{ padding:pad, paddingTop:0, display:'grid', gap:mobile?24:36 }}>
        <div style={{ display:'grid', gridTemplateColumns:`repeat(${gridCols}, 1fr)`, gap:mobile?12:24 }}>
          {Array.from({length:gridCols}).map((_,i) => (
            <div key={i} style={{ display:'grid', gap:8 }}>
              <div style={{ width:32, height:32, borderRadius:6, background:`${palette.accent}33`, border:`1px solid ${palette.accent}55` }}/>
              <div style={{ fontFamily:fontH, fontSize:'1.05rem', fontWeight:700 }}>Value prop {i+1}</div>
              {block(10)}{block(10, '90%')}{block(10, '70%')}
            </div>
          ))}
        </div>
        <div style={{ padding:mobile?20:32, background:palette.surface, borderRadius:8, display:'grid', gap:10 }}>
          <div style={{ fontFamily:fontH, fontSize:mobile?'1.1rem':'1.5rem', lineHeight:1.3 }}>"WPSB shipped our site in 11 days. Traffic up 140% in quarter one."</div>
          <div style={{ fontSize:'.78rem', color:palette.muted, fontFamily:'var(--font-mono)' }}>— HAPPY CUSTOMER · CEO</div>
        </div>
      </div>
    );
  })();

  return (<><div>{Hero}</div>{Below}</>);
}

function pageHeadline(pageType, page, bp) {
  const h = {
    landing:         `Built for ${bp.archetype.toLowerCase()}. Ready to ship.`,
    'service-detail':`${page} — done right, on schedule.`,
    'area-page':     `${page} — serving your neighborhood.`,
    'case-study':    `${page}: a case study in outcomes.`,
    'work-index':    `Selected work.`,
    shop:            `The new season is here.`,
    product:         page,
    collection:      `${page} collection.`,
    post:            page,
    contact:         `Let's talk.`,
    pricing:         `Simple pricing. No surprises.`,
    docs:            page,
    donate:          `Your gift, our mission.`,
    event:           `${page} — you're invited.`,
  };
  return h[pageType] || `${page}`;
}
function pageSubhead(pageType, bp) {
  const s = {
    landing:         (window.BRAND_PROFILE?.tagline) || 'Hand-crafted themes, measured performance, and marketing wired in from day one.',
    'service-detail':'Clear scope, fixed pricing, and a before/after you\'ll want to show people.',
    contact:         'We\'ll reply the same business day. No gatekeeper.',
    pricing:         'Everything you need to launch. Upgrade when you grow.',
    donate:          'Every dollar goes directly to programs. 87¢ on the dollar.',
  };
  return s[pageType] || 'Crafted with care.';
}

/* ─────────────────────────────────────────────────────────────
   TAB: Content
   ───────────────────────────────────────────────────────────── */
function ContentTab({ bp, onNext }) {
  const { useState } = React;
  const [tone, setTone] = useState('Clear & confident');
  const items = bp.pages.slice(0, 6).map((p, i) => ({
    page: p,
    status: i < 2 ? 'drafted' : i < 4 ? 'ai-ready' : 'needs-brief',
    words: 260 + (i*120) % 900,
    ai: Math.random() > 0.4,
  }));
  return (
    <div style={{ display:'grid', gridTemplateColumns:'1fr 320px', gap:16 }}>
      <div style={{ display:'grid', gap:16 }}>
        <div className="card">
          <div className="card-head">
            <h2 className="card-title">Content queue</h2>
            <div style={{ display:'flex', gap:6 }}>
              <button className="btn btn-primary btn-sm" onClick={() => window.wpsbToast('AI drafting 3 pages…', 'info')}>
                <Icon name="spark" size={12}/>Draft all with AI
              </button>
            </div>
          </div>
          <div className="card-body" style={{ padding:0 }}>
            <table className="table">
              <thead><tr><th>Page</th><th>Status</th><th style={{textAlign:'right'}}>Target words</th><th>Source</th><th></th></tr></thead>
              <tbody>
                {items.map(it => (
                  <tr key={it.page}>
                    <td style={{ fontWeight:500 }}>{it.page}</td>
                    <td>
                      {it.status === 'drafted' && <span style={{ color:'var(--green)', fontFamily:'var(--font-mono)', fontSize:'.72rem' }}>● drafted</span>}
                      {it.status === 'ai-ready' && <span style={{ color:'var(--beam)', fontFamily:'var(--font-mono)', fontSize:'.72rem' }}>● AI-ready</span>}
                      {it.status === 'needs-brief' && <span style={{ color:'var(--warn)', fontFamily:'var(--font-mono)', fontSize:'.72rem' }}>● needs brief</span>}
                    </td>
                    <td className="mono" style={{ textAlign:'right', color:'var(--text-2)' }}>{it.words}</td>
                    <td className="mono" style={{ color:'var(--dim)', fontSize:'.72rem' }}>{it.ai ? 'AI + Content SEO' : 'Manual brief'}</td>
                    <td style={{ textAlign:'right' }}>
                      <button className="btn btn-ghost btn-sm">Open</button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        <div className="card">
          <div className="card-head"><h2 className="card-title">Imagery</h2>
            <span style={{ fontSize:'.66rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>24 placeholders · 0 sourced</span>
          </div>
          <div className="card-body" style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(80px, 1fr))', gap:8 }}>
            {Array.from({length:12}).map((_, i) => (
              <div key={i} style={{ aspectRatio:'4/3', background:'var(--surface-2)', border:'1px dashed var(--border)', borderRadius:4, display:'flex', alignItems:'center', justifyContent:'center', color:'var(--dim)', fontSize:'.58rem', fontFamily:'var(--font-mono)', overflow:'hidden', padding:4, textAlign:'center', minWidth:0 }}>
                <span style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth:'100%' }}>IMG · {String(i+1).padStart(2,'0')}</span>
              </div>
            ))}
          </div>
          <div className="card-body" style={{ borderTop:'1px solid var(--border)', display:'flex', gap:8, flexWrap:'wrap' }}>
            <button className="btn btn-ghost btn-sm"><Icon name="image" size={11}/>Pull from Brand Profile</button>
            <button className="btn btn-ghost btn-sm"><Icon name="spark" size={11}/>Generate with AI</button>
            <button className="btn btn-ghost btn-sm"><Icon name="download" size={11}/>Upload from desktop</button>
          </div>
        </div>
      </div>

      {/* Side */}
      <div style={{ display:'grid', gap:16, alignSelf:'start', position:'sticky', top:16 }}>
        <div className="card">
          <div className="card-head"><h2 className="card-title">Voice & tone</h2></div>
          <div className="card-body" style={{ display:'grid', gap:6 }}>
            {['Clear & confident','Warm & human','Editorial / long-form','Technical / precise','Playful'].map(t => (
              <button key={t} onClick={() => setTone(t)} style={{
                textAlign:'left', padding:'8px 10px', borderRadius:5,
                background: tone === t ? 'var(--surface-2)' : 'transparent',
                border:'1px solid', borderColor: tone === t ? 'rgba(99,91,255,.4)' : 'var(--border)',
                color: 'var(--text)', fontSize:'.8rem', cursor:'pointer',
              }}>{t}</button>
            ))}
          </div>
          <div className="card-body" style={{ borderTop:'1px solid var(--border)', fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', lineHeight:1.55 }}>
            ↳ Tone seeds the Brain prompt when drafting copy. Pulls from Brand Profile if set.
          </div>
        </div>
        <div className="card">
          <div className="card-head"><h2 className="card-title">Up next</h2></div>
          <div className="card-body" style={{ display:'grid', gap:8 }}>
            <div style={{ fontSize:'.82rem', color:'var(--text-2)' }}>Review 6 AI drafts, source imagery, then move to Launch.</div>
            <button className="btn btn-primary btn-sm" onClick={onNext}><Icon name="check" size={11}/>Next: Launch</button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   TAB: Launch
   ───────────────────────────────────────────────────────────── */
function LaunchTab({ bp, detected }) {
  const { useState, useRef } = React;
  const checklistRef = useRef(null);
  const [items, setItems] = useState(() => [
    { group:'Hosting',   items:[
      { k:'Provision staging', d:'WPSB-managed LiteSpeed, PHP 8.3', status:'done', action:'open-staging' },
      { k:'SSL cert',          d:'Auto-renewing Let\'s Encrypt',      status:'done', action:'view-cert' },
      { k:'CDN',               d:'Cloudflare · orange-cloud mode',    status:'todo', action:'run-cdn' },
      { k:'Backups',           d:'Hourly snapshots · 30-day retention',status:'todo', action:'run-backups' },
    ]},
    { group:'DNS & Domain', items:[
      { k:'Domain connected',  d:'A + AAAA pointing to LB',           status:'done', action:'view-dns' },
      { k:'Email records',     d:'SPF / DKIM / DMARC',                status:'todo', action:'run-email' },
      { k:'Redirects imported',d:'From Redirect Manager',             status:'todo', action:'run-redirects' },
    ]},
    { group:'Plugins & theme', items:[
      { k:'Install blueprint plugins', d:`${bp.modules.length} modules queued`, status:'todo', action:'run-plugins' },
      { k:'Apply theme.json',  d:'From Theme step',                   status:'todo', action:'run-theme' },
      { k:'Import content',    d:'From Content step',                 status:'todo', action:'run-content' },
    ]},
    { group:'Analytics & tracking', items:[
      { k:'GA4',               d:'Measurement ID',                    status:'todo', action:'run-ga4' },
      { k:'Meta Pixel',        d:'From Marketing module',             status:'todo', action:'run-meta' },
      { k:'GTM container',     d:'Server-side ready',                 status:'todo', action:'run-gtm' },
      { k:'Plausible',         d:'Privacy-first fallback',            status:'off',  action:'enable-plausible' },
    ]},
    { group:'Pre-flight', items:[
      { k:'Accessibility scan', d:'axe · target WCAG 2.1 AA',         status:'todo', action:'run-a11y' },
      { k:'Performance budget', d:'LCP < 2.5s · CLS < 0.1',           status:'todo', action:'run-perf' },
      { k:'SEO crawl',          d:'Sitemap + robots + schema',        status:'todo', action:'run-seo' },
      { k:'404 sweep',          d:'Post-migration URL audit',         status:'todo', action:'run-404' },
    ]},
  ]);
  const flat = items.flatMap(g => g.items);
  const total = flat.length;
  const done  = flat.filter(i => i.status === 'done').length;
  const pct   = Math.round((done/total)*100);

  // Scroll to the first undone group (a bit nicer than just top-of-checklist)
  const scrollToTasks = () => {
    if (!checklistRef.current) return;
    // find the first "todo" row in the grid
    const firstTodo = checklistRef.current.querySelector('[data-status="todo"], [data-status="off"]');
    const target = firstTodo || checklistRef.current;
    target.scrollIntoView({ behavior:'smooth', block:'center' });
    // flash highlight
    target.animate && target.animate([
      { boxShadow:'0 0 0 0 rgba(99,91,255,0)' },
      { boxShadow:'0 0 0 3px rgba(99,91,255,.4)' },
      { boxShadow:'0 0 0 0 rgba(99,91,255,0)' },
    ], { duration: 1400, easing:'ease-out' });
  };

  // Per-item action — flips status + toasts with action-specific copy
  const runItem = (groupIdx, itemIdx) => {
    const current = items[groupIdx].items[itemIdx];
    const labels = {
      'open-staging':    ['Opening staging · beta.acme.com', 'info'],
      'view-cert':       ['Certificate valid · expires in 83 days', 'ok'],
      'run-cdn':         ['Cloudflare proxy enabled · propagating DNS', 'ok'],
      'run-backups':     ['Snapshot schedule configured · next run in 56 min', 'ok'],
      'view-dns':        ['DNS verified · A + AAAA pointing to 192.0.2.44', 'ok'],
      'run-email':       ['SPF + DKIM + DMARC records published', 'ok'],
      'run-redirects':   [`${Math.floor(Math.random()*40)+12} redirects imported from Redirect Manager`, 'ok'],
      'run-plugins':     [`${bp.modules.length} plugins installed · ${bp.modules.length} activated`, 'ok'],
      'run-theme':       ['theme.json applied · patterns registered', 'ok'],
      'run-content':     ['Content imported · draft queue ready', 'ok'],
      'run-ga4':         ['GA4 installed · first hit received', 'ok'],
      'run-meta':        ['Meta Pixel verified · test event received', 'ok'],
      'run-gtm':         ['GTM container live · server-side endpoint configured', 'ok'],
      'enable-plausible':['Plausible enabled · tracking live', 'ok'],
      'run-a11y':        ['Accessibility scan started · ~45s · results in Scanner tab', 'info'],
      'run-perf':        ['Lighthouse run queued · ETA 90s', 'info'],
      'run-seo':         ['SEO crawl started · 214 URLs queued', 'info'],
      'run-404':         ['404 sweep: 7 URLs found · see Redirect Manager', 'warn'],
    };
    const [msg, tone] = labels[current.action] || ['Action queued', 'ok'];
    window.wpsbToast(msg, tone);
    setItems(prev => prev.map((g, gi) => gi !== groupIdx ? g : {
      ...g,
      items: g.items.map((it, ii) => ii !== itemIdx ? it : { ...it, status: it.status === 'off' ? 'done' : 'done' }),
    }));
  };

  return (
    <div style={{ display:'grid', gap:16 }}>
      <div className="card">
        <div className="card-body" style={{ display:'flex', alignItems:'center', gap:18, flexWrap:'wrap' }}>
          <div style={{ flex:1, minWidth:260 }}>
            <div style={{ fontFamily:'var(--font-mono)', fontSize:'.66rem', letterSpacing:'.08em', color:'var(--dim)' }}>LAUNCH READINESS</div>
            <div style={{ fontSize:'1.4rem', fontWeight:700, marginTop:4 }}>{done} of {total} steps complete</div>
            <div style={{ fontSize:'.82rem', color:'var(--muted)', marginTop:4 }}>
              {bp.name}{detected ? ` · detected as ${detected.archetype}` : ''}
            </div>
            <div style={{ marginTop:10, height:6, background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:3, overflow:'hidden' }}>
              <div style={{ height:'100%', width: `${pct}%`, background:'var(--beam)', transition:'width .3s ease' }}/>
            </div>
          </div>
          <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
            {done < total && (
              <button className="btn btn-ghost btn-sm" onClick={scrollToTasks} title="Jump to the first incomplete task">
                <Icon name="chevron-down" size={12}/>{total - done} tasks left
              </button>
            )}
            <button className="btn btn-primary btn-sm" disabled={done < total} onClick={() => window.wpsbToast('Launch sequence queued · ETA 4 min', 'ok')}>
              <Icon name="spark" size={12}/>
              {done < total ? 'Waiting on tasks' : 'Launch now'}
            </button>
          </div>
        </div>
      </div>

      <div ref={checklistRef} style={{ display:'grid', gridTemplateColumns:'repeat(2, 1fr)', gap:16, alignItems:'start' }}>
        {items.map((g, gi) => (
          <div key={g.group} className="card">
            <div className="card-head" style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
              <h2 className="card-title">{g.group}</h2>
              <span style={{ fontSize:'.64rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>
                {g.items.filter(i => i.status==='done').length}/{g.items.length} DONE
              </span>
            </div>
            <div className="card-body" style={{ display:'grid', gap:6 }}>
              {g.items.map((it, ii) => (
                <div key={it.k} data-status={it.status} style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 10px', background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:5, transition:'box-shadow .3s' }}>
                  <div style={{ width:18, height:18, borderRadius:4, display:'flex', alignItems:'center', justifyContent:'center',
                    background: it.status === 'done' ? 'var(--green-dim)' : it.status === 'off' ? 'transparent' : 'var(--surface-3)',
                    color: it.status === 'done' ? 'var(--green)' : it.status === 'off' ? 'var(--dim)' : 'var(--warn)',
                    border: `1px solid ${it.status === 'done' ? 'var(--green-dim)' : 'var(--border)'}`,
                    flex:'0 0 auto',
                  }}>
                    {it.status === 'done' && <Icon name="check" size={11}/>}
                    {it.status === 'todo' && <span style={{ width:6, height:6, borderRadius:'50%', background:'var(--warn)' }}/>}
                  </div>
                  <div style={{ flex:1, minWidth:0 }}>
                    <div style={{ fontSize:'.82rem', fontWeight:500 }}>{it.k}</div>
                    <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{it.d}</div>
                  </div>
                  <button className="btn btn-ghost btn-sm" onClick={() => runItem(gi, ii)}>
                    {it.status === 'done' ? 'View' : it.status === 'off' ? 'Enable' : 'Run'}
                  </button>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

window.SiteBuilder = SiteBuilder;
