// ════════════════════════════════════════════════════════════════
// PEXXIE · WEB BUILDER — Webflow-style visual editor + Lovable/v0 AI
// build mode. Both drive ONE live page model (window state) so AI-
// generated blocks are then fine-tunable on the visual canvas.
// Exported as window.WebBuilder (used by px-website.jsx · Editor).
// ════════════════════════════════════════════════════════════════
const { Icon, Spark, Pex, Avatar, Card, Btn, Pill, Label, Num, Toggle, Field } = window;

// — Honest Loaves brand surface used to render the customer's site —
const BRAND = {
  crust: '#3A2A1C', wheat: '#D9A84C', bake: '#8C4A2A',
  cream: '#F2E2C4', creamCard: '#FBF3E0', creamDk: '#E8D6AE',
  ink: '#3A2A1C', sub: '#6B563C', accent: '#8C4A2A',
};
const SWATCHES = [BRAND.cream, '#FFFFFF', BRAND.creamCard, BRAND.wheat, BRAND.bake, BRAND.crust];
const isDark = (c) => c === BRAND.crust || c === BRAND.bake;
const PADV = { compact: 30, cozy: 52, spacious: 80 };

let __bid = 100;
const nid = () => 'b' + (++__bid);

// — Block definitions: defaults, inspector fields, library metadata —
const DEFS = {
  hero: {
    label: 'Hero', icon: 'layout',
    make: () => ({ eyebrow: 'Brooklyn · since 2019', headline: 'Stone-milled. Hand-shaped. Stubborn.', sub: 'A tiny bakery in Williamsburg. Open Thursday through Sunday.', cta: 'Order for Saturday', bg: BRAND.cream, pad: 'spacious', align: 'left' }),
    fields: [['eyebrow', 'Eyebrow', 'text'], ['headline', 'Headline', 'area'], ['sub', 'Subtext', 'area'], ['cta', 'Button label', 'text']],
  },
  products: {
    label: 'Product grid', icon: 'grid',
    make: () => ({ heading: "This week's bakes", items: [{ name: 'Country bâtard', price: '$8' }, { name: 'Rye & caraway', price: '$9' }, { name: 'Pain de mie', price: '$7' }], bg: '#FFFFFF', pad: 'cozy', align: 'center' }),
    fields: [['heading', 'Heading', 'text']],
  },
  story: {
    label: 'Story / text', icon: 'fileText',
    make: () => ({ heading: 'Our story', body: 'Three generations of stubborn obsession with bread. We mill our own flour, ferment slow, and bake in a single Brooklyn oven — the same way since 2019.', bg: '#FFFFFF', pad: 'cozy', align: 'left' }),
    fields: [['heading', 'Heading', 'text'], ['body', 'Body', 'area']],
  },
  gallery: {
    label: 'Gallery', icon: 'image',
    make: () => ({ heading: 'From the oven', images: [BRAND.wheat, BRAND.bake, BRAND.creamDk, '#C99944', BRAND.wheat, BRAND.bake], bg: BRAND.creamCard, pad: 'cozy', align: 'center' }),
    fields: [['heading', 'Heading', 'text']],
  },
  testimonials: {
    label: 'Testimonials', icon: 'message',
    make: () => ({ heading: 'What Brooklyn says', quotes: [{ q: 'The best loaf in the borough, full stop.', a: 'Marc · Café Bleu' }, { q: 'I drive in from Queens every Saturday for this bread.', a: 'Sofia M.' }], bg: BRAND.cream, pad: 'cozy', align: 'center' }),
    fields: [['heading', 'Heading', 'text']],
  },
  cta: {
    label: 'Call to action', icon: 'megaphone',
    make: () => ({ heading: 'Order for this weekend', sub: 'Pickup Thursday–Sunday. Wholesale welcome.', button: 'Start an order', bg: BRAND.crust, pad: 'cozy', align: 'center' }),
    fields: [['heading', 'Heading', 'text'], ['sub', 'Subtext', 'text'], ['button', 'Button label', 'text']],
  },
  contact: {
    label: 'Contact form', icon: 'mail',
    make: () => ({ heading: 'Say hello', sub: 'Wholesale, classes, or just to talk bread.', button: 'Send message', bg: '#FFFFFF', pad: 'cozy', align: 'left' }),
    fields: [['heading', 'Heading', 'text'], ['sub', 'Subtext', 'text'], ['button', 'Button label', 'text']],
  },
};
const LIB_ORDER = ['hero', 'products', 'story', 'gallery', 'testimonials', 'cta', 'contact'];

const seedPage = () => ([
  { id: nid(), type: 'hero', props: DEFS.hero.make() },
  { id: nid(), type: 'products', props: DEFS.products.make() },
  { id: nid(), type: 'story', props: DEFS.story.make() },
  { id: nid(), type: 'cta', props: DEFS.cta.make() },
]);
const seedAbout = () => ([
  { id: nid(), type: 'story', props: { ...DEFS.story.make(), heading: 'About Honest Loaves' } },
  { id: nid(), type: 'gallery', props: DEFS.gallery.make() },
  { id: nid(), type: 'testimonials', props: DEFS.testimonials.make() },
  { id: nid(), type: 'cta', props: DEFS.cta.make() },
]);
const seedContact = () => ([
  { id: nid(), type: 'contact', props: DEFS.contact.make() },
  { id: nid(), type: 'cta', props: { ...DEFS.cta.make(), heading: 'Prefer to just visit?', sub: 'We’re at 114 Wythe Ave, Brooklyn. Thursday–Sunday, 8am–2pm.' } },
]);
const BUILDER_PAGES = ['Home', 'About', 'Contact'];

// ── Block renderer (used by both the design canvas and the AI preview) ──
function BlockView({ block, brand, narrow, editable, onText }) {
  const P = window.PX;
  const p = block.props;
  const dark = isDark(p.bg);
  const fg = dark ? '#F5E9CE' : brand.ink;
  const fgSub = dark ? 'rgba(245,233,206,0.72)' : brand.sub;
  const padV = PADV[p.pad || 'cozy'];
  const align = p.align || 'left';
  const wrap = { background: p.bg, color: fg, padding: `${padV}px ${narrow ? 22 : 44}px` };
  const serif = "'Cormorant Garamond', Georgia, serif";
  const Edit = ({ k, children, style }) => (
    <span contentEditable={editable} suppressContentEditableWarning
      onBlur={editable ? (e) => onText(block.id, k, e.currentTarget.textContent) : undefined}
      style={{ outline: 'none', cursor: editable ? 'text' : 'inherit', ...style }}>{children}</span>
  );

  if (block.type === 'hero') {
    return (
      <div style={wrap}>
        <div style={{ display: 'grid', gridTemplateColumns: narrow ? '1fr' : '1.1fr 0.9fr', gap: 28, alignItems: 'center' }}>
          <div style={{ textAlign: align }}>
            <div style={{ fontSize: 11, color: brand.accent, textTransform: 'uppercase', letterSpacing: 2, marginBottom: 12 }}><Edit k="eyebrow">{p.eyebrow}</Edit></div>
            <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 38 : 52, lineHeight: 1.02, letterSpacing: -1.2 }}><Edit k="headline">{p.headline}</Edit></div>
            <div style={{ fontSize: 15, color: fgSub, lineHeight: 1.6, marginTop: 16, maxWidth: 420, marginLeft: align === 'center' ? 'auto' : 0, marginRight: align === 'center' ? 'auto' : 0 }}><Edit k="sub">{p.sub}</Edit></div>
            <div style={{ marginTop: 22, display: 'inline-flex', padding: '11px 20px', background: brand.crust, color: '#F5D8A8', fontSize: 13, fontWeight: 600, borderRadius: 3 }}><Edit k="cta">{p.cta}</Edit></div>
          </div>
          {!narrow && <div style={{ aspectRatio: '4/5', background: `repeating-linear-gradient(45deg, ${brand.wheat} 0 14px, #C99944 14px 28px)`, borderRadius: 8 }}/>}
        </div>
      </div>
    );
  }
  if (block.type === 'products') {
    return (
      <div style={wrap}>
        <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 26 : 32, textAlign: align, marginBottom: 22 }}><Edit k="heading">{p.heading}</Edit></div>
        <div style={{ display: 'grid', gridTemplateColumns: narrow ? '1fr 1fr' : 'repeat(3,1fr)', gap: 16 }}>
          {p.items.map((it, i) => (
            <div key={i} style={{ textAlign: 'center' }}>
              <div style={{ aspectRatio: '1', background: [brand.wheat, brand.bake, '#E0C080'][i % 3], borderRadius: 8, marginBottom: 10 }}/>
              <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: 17 }}>{it.name}</div>
              <div style={{ fontSize: 13, color: fgSub, marginTop: 2 }}>{it.price}</div>
            </div>
          ))}
        </div>
      </div>
    );
  }
  if (block.type === 'story') {
    return (
      <div style={wrap}>
        <div style={{ maxWidth: 620, marginLeft: align === 'center' ? 'auto' : 0, marginRight: align === 'center' ? 'auto' : 0, textAlign: align }}>
          <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 26 : 32, marginBottom: 14 }}><Edit k="heading">{p.heading}</Edit></div>
          <div style={{ fontSize: 16, lineHeight: 1.7, color: fgSub }}><Edit k="body">{p.body}</Edit></div>
        </div>
      </div>
    );
  }
  if (block.type === 'gallery') {
    const imgs = p.images || [brand.wheat, brand.bake, brand.creamDk, '#C99944', brand.wheat, brand.bake];
    return (
      <div style={wrap}>
        <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 26 : 32, textAlign: align, marginBottom: 20 }}><Edit k="heading">{p.heading}</Edit></div>
        <div style={{ display: 'grid', gridTemplateColumns: narrow ? 'repeat(2,1fr)' : 'repeat(4,1fr)', gap: 10 }}>
          {imgs.map((c, i) => <div key={i} style={{ aspectRatio: '1', background: c, borderRadius: 6 }}/>)}
        </div>
      </div>
    );
  }
  if (block.type === 'testimonials') {
    return (
      <div style={wrap}>
        <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 26 : 32, textAlign: align, marginBottom: 22 }}><Edit k="heading">{p.heading}</Edit></div>
        <div style={{ display: 'grid', gridTemplateColumns: narrow ? '1fr' : '1fr 1fr', gap: 16 }}>
          {p.quotes.map((q, i) => (
            <div key={i} style={{ background: dark ? 'rgba(255,255,255,0.06)' : '#fff', border: `1px solid ${dark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.06)'}`, borderRadius: 10, padding: 20 }}>
              <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: 19, lineHeight: 1.4 }}>“{q.q}”</div>
              <div style={{ fontSize: 12, color: fgSub, marginTop: 10, letterSpacing: 0.3 }}>{q.a}</div>
            </div>
          ))}
        </div>
      </div>
    );
  }
  if (block.type === 'cta') {
    return (
      <div style={{ ...wrap, textAlign: align }}>
        <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 28 : 38, letterSpacing: -0.8 }}><Edit k="heading">{p.heading}</Edit></div>
        <div style={{ fontSize: 14, color: fgSub, marginTop: 10 }}><Edit k="sub">{p.sub}</Edit></div>
        <div style={{ marginTop: 20, display: 'inline-flex', padding: '12px 24px', background: brand.wheat, color: brand.crust, fontSize: 14, fontWeight: 700, borderRadius: 3 }}><Edit k="button">{p.button}</Edit></div>
      </div>
    );
  }
  if (block.type === 'contact') {
    return (
      <div style={wrap}>
        <div style={{ display: 'grid', gridTemplateColumns: narrow ? '1fr' : '1fr 1fr', gap: 28 }}>
          <div>
            <div style={{ fontFamily: serif, fontStyle: 'italic', fontSize: narrow ? 26 : 32, marginBottom: 10 }}><Edit k="heading">{p.heading}</Edit></div>
            <div style={{ fontSize: 15, color: fgSub, lineHeight: 1.6 }}><Edit k="sub">{p.sub}</Edit></div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {['Name', 'Email'].map(l => <div key={l} style={{ height: 42, border: `1px solid ${dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.12)'}`, borderRadius: 6, display: 'flex', alignItems: 'center', padding: '0 12px', fontSize: 12, color: fgSub }}>{l}</div>)}
            <div style={{ height: 76, border: `1px solid ${dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.12)'}`, borderRadius: 6, padding: '8px 12px', fontSize: 12, color: fgSub }}>Message</div>
            <div style={{ alignSelf: 'flex-start', padding: '10px 18px', background: brand.crust, color: '#F5D8A8', fontSize: 13, fontWeight: 600, borderRadius: 3 }}><Edit k="button">{p.button}</Edit></div>
          </div>
        </div>
      </div>
    );
  }
  return null;
}

// ── The site nav (locked top chrome of the rendered page) ──
function SiteNav({ narrow }) {
  return (
    <div style={{ padding: narrow ? '14px 22px' : '16px 44px', display: 'flex', alignItems: 'center', background: '#fff', borderBottom: '1px solid rgba(0,0,0,0.06)' }}>
      <div style={{ fontFamily: "'Cormorant Garamond', Georgia, serif", fontStyle: 'italic', fontSize: 20, color: BRAND.crust, flex: 1 }}>Honest Loaves</div>
      {!narrow && <div style={{ display: 'flex', gap: 18, fontSize: 12, color: BRAND.sub }}><span>Menu</span><span>Classes</span><span>Shop</span><span>Contact</span></div>}
      {narrow && <Icon name="menu" size={18} color={BRAND.crust}/>}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════
// Main builder component
// ════════════════════════════════════════════════════════════════
window.WebBuilder = function WebBuilder() {
  const P = window.PX; const { toast, pexOpen, setPexOpen, go, sparks, setSparks, openOverlay } = window.useApp();

  // The builder is a full-bleed workspace — collapse the Pex panel while
  // we're in it (still reachable from the topbar), restore it on exit.
  React.useEffect(() => {
    const prev = pexOpen;
    if (prev) setPexOpen(false);
    return () => { if (prev) setPexOpen(true); };
  }, []);


  const [blocks, setBlocks] = React.useState(seedPage);
  const [sel, setSel] = React.useState(null);
  const [device, setDevice] = React.useState('desktop');
  const [mode, setMode] = React.useState('design');       // design | ai
  const [leftTab, setLeftTab] = React.useState('add');     // add | layers
  const [preview, setPreview] = React.useState(false);
  const [insTab, setInsTab] = React.useState('content');   // content | style
  const [pageName, setPageName] = React.useState('Home');
  const [pageMenu, setPageMenu] = React.useState(false);
  const [publishing, setPublishing] = React.useState(false);

  // Other pages are kept in a side store so switching genuinely swaps the
  // canvas model. (Prototype: undo history resets on page switch.)
  const pageStore = React.useRef(null);
  if (!pageStore.current) pageStore.current = { About: seedAbout(), Contact: seedContact() };

  // history
  const hist = React.useRef({ past: [], future: [] });
  const snap = () => JSON.parse(JSON.stringify(blocks));
  const commit = (nextBlocks, opts = {}) => {
    hist.current.past.push(snap());
    if (hist.current.past.length > 60) hist.current.past.shift();
    hist.current.future = [];
    setBlocks(nextBlocks);
  };
  const undo = () => { const h = hist.current; if (!h.past.length) return; h.future.push(snap()); setBlocks(h.past.pop()); };
  const redo = () => { const h = hist.current; if (!h.future.length) return; h.past.push(snap()); setBlocks(h.future.pop()); };

  const narrow = device !== 'desktop';
  const deviceW = device === 'mobile' ? 390 : device === 'tablet' ? 768 : 1080;
  const selBlock = blocks.find(b => b.id === sel) || null;

  // mutations
  const setProp = (id, k, v) => setBlocks(bs => bs.map(b => b.id === id ? { ...b, props: { ...b.props, [k]: v } } : b));
  const setPropCommit = (id, k, v) => commit(blocks.map(b => b.id === id ? { ...b, props: { ...b.props, [k]: v } } : b));
  const addBlock = (type, atEnd) => {
    const nb = { id: nid(), type, props: DEFS[type].make() };
    const idx = atEnd || !sel ? blocks.length : blocks.findIndex(b => b.id === sel) + 1;
    const next = [...blocks.slice(0, idx), nb, ...blocks.slice(idx)];
    commit(next); setSel(nb.id); setLeftTab('layers');
    return nb;
  };
  const removeBlock = (id) => { commit(blocks.filter(b => b.id !== id)); if (sel === id) setSel(null); };
  const dupBlock = (id) => { const b = blocks.find(x => x.id === id); const nb = { id: nid(), type: b.type, props: JSON.parse(JSON.stringify(b.props)) }; const idx = blocks.findIndex(x => x.id === id) + 1; commit([...blocks.slice(0, idx), nb, ...blocks.slice(idx)]); setSel(nb.id); };
  const move = (id, dir) => { const i = blocks.findIndex(b => b.id === id); const j = i + dir; if (j < 0 || j >= blocks.length) return; const next = [...blocks]; [next[i], next[j]] = [next[j], next[i]]; commit(next); };

  // push a history snapshot before a live edit begins (matches inspector fields)
  const beginEdit = () => { hist.current.past.push(snap()); hist.current.future = []; };

  // switch which page the canvas is editing (saves current, loads target)
  const switchPage = (name) => {
    setPageMenu(false);
    if (name === pageName) return;
    pageStore.current[pageName] = JSON.parse(JSON.stringify(blocks));
    const target = pageStore.current[name] || seedPage();
    hist.current = { past: [], future: [] };
    setBlocks(target); setSel(null); setPageName(name);
  };

  // Pex rewrite of a whole section — costs 1 spark, gated on the wallet
  const REWRITES = {
    hero: { headline: 'Bread worth the wait — every single loaf.', sub: 'Slow-fermented, stone-milled, and baked fresh in Williamsburg. Thursday through Sunday.', eyebrow: 'Brooklyn’s stubborn little bakery' },
    products: { heading: 'Fresh out of the oven this week' },
    story: { heading: 'Why we do it the hard way', body: 'We could go faster. We don’t. Every loaf ferments for three days, from flour we mill ourselves — because shortcuts taste like shortcuts.' },
    gallery: { heading: 'Straight from the bakers’ bench' },
    testimonials: { heading: 'Loved across the five boroughs' },
    cta: { heading: 'Reserve your loaves for the weekend', sub: 'Order by Thursday for Saturday pickup. Wholesale inquiries welcome.', button: 'Start your order' },
    contact: { heading: 'Let’s talk bread', sub: 'Wholesale, classes, private events — we read every message.', button: 'Send it over' },
  };
  const rewriteSection = (block) => {
    const cost = 1;
    if (cost > sparks) { openOverlay('creditGate', { needed: cost, balance: sparks }); return; }
    const patch = REWRITES[block.type];
    if (!patch) { toast('Nothing to rewrite here.', { tone: 'neutral' }); return; }
    setSparks(s => Math.max(0, s - cost));
    commit(blocks.map(b => b.id === block.id ? { ...b, props: { ...b.props, ...patch } } : b));
    toast('Pex rewrote this section.', { tone: 'sage', icon: 'sparkles' });
  };

  // ── Top toolbar ──
  const DeviceBtn = ({ k, icon, w }) => (
    <div onClick={() => setDevice(k)} title={k} style={{ padding: '5px 9px', borderRadius: 7, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 6,
      background: device === k ? P.card : 'transparent', boxShadow: device === k ? P.shSm : 'none', color: device === k ? P.ink : P.ink3 }}>
      <Icon name={icon} size={15}/>{w && <span style={{ fontSize: 10.5, fontFamily: P.mono }}>{w}</span>}
    </div>
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', fontFamily: P.sans, background: P.canvas }}>
      {/* toolbar */}
      <div style={{ height: 52, borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', padding: '0 14px', gap: 10, flexShrink: 0, background: P.canvas }}>
        <div onClick={() => go('website/pages')} title="Back to Website" style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '6px 8px', borderRadius: 8, cursor: 'pointer', color: P.ink2, fontSize: 12.5, fontWeight: 500 }}
          onMouseEnter={e => e.currentTarget.style.background = P.hover} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
          <Icon name="chevL" size={15}/>Website
        </div>
        <div style={{ width: 1, height: 22, background: P.line }}/>
        <div style={{ position: 'relative' }}>
          <div onClick={() => setPageMenu(o => !o)} title="Switch page" style={{ display: 'flex', alignItems: 'center', gap: 7, fontSize: 13, color: P.ink, fontWeight: 600, cursor: 'pointer', padding: '4px 6px', borderRadius: 7 }}
            onMouseEnter={e => e.currentTarget.style.background = P.hover} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <Icon name="layout" size={16} color={P.spark}/>{pageName}<Icon name="chevD" size={13} color={P.ink3}/>
          </div>
          {pageMenu && <>
            <div onClick={() => setPageMenu(false)} style={{ position: 'fixed', inset: 0, zIndex: 40 }}/>
            <div style={{ position: 'absolute', top: 34, left: 0, zIndex: 41, background: P.card, border: `1px solid ${P.line}`, borderRadius: 10, boxShadow: P.shPop, padding: 5, width: 184 }}>
              <div style={{ fontSize: 10, color: P.ink4, padding: '4px 8px', letterSpacing: 0.6, fontWeight: 600 }}>SWITCH PAGE</div>
              {BUILDER_PAGES.map(pg => (
                <div key={pg} onClick={() => switchPage(pg)} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '7px 8px', borderRadius: 7, cursor: 'pointer', fontSize: 12.5, color: pg === pageName ? P.ink : P.ink2, fontWeight: pg === pageName ? 600 : 400, background: pg === pageName ? P.sunk : 'transparent' }}
                  onMouseEnter={e => { if (pg !== pageName) e.currentTarget.style.background = P.hover; }} onMouseLeave={e => { if (pg !== pageName) e.currentTarget.style.background = 'transparent'; }}>
                  <Icon name="layout" size={13} color={P.ink3}/><span style={{ flex: 1 }}>{pg}</span>{pg === pageName && <Icon name="check" size={13} color={P.spark}/>}
                </div>
              ))}
            </div>
          </>}
        </div>
        <div style={{ width: 1, height: 22, background: P.line }}/>
        {/* mode switch */}
        <div style={{ display: 'flex', gap: 3, background: P.sunk, borderRadius: 9, padding: 3 }}>
          {[['design', 'Design', 'sliders'], ['ai', 'Build with Pex', 'sparkles']].map(m => {
            const on = mode === m[0];
            return <div key={m[0]} onClick={() => { setMode(m[0]); setPreview(false); }} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 12px', borderRadius: 7, cursor: 'pointer', fontSize: 12.5, fontWeight: 600,
              background: on ? P.card : 'transparent', boxShadow: on ? P.shSm : 'none', color: on ? (m[0] === 'ai' ? P.sparkDim : P.ink) : P.ink3 }}>
              <Icon name={m[2]} size={14} color={on && m[0] === 'ai' ? P.spark : on ? P.spark : P.ink3}/>{m[1]}</div>;
          })}
        </div>
        <div style={{ flex: 1 }}/>
        {mode === 'design' && (
          <div style={{ display: 'flex', gap: 2, background: P.sunk, borderRadius: 9, padding: 3 }}>
            <DeviceBtn k="desktop" icon="layout" w="100%"/><DeviceBtn k="tablet" icon="card" w="768"/><DeviceBtn k="mobile" icon="phone" w="390"/>
          </div>
        )}
        {mode === 'design' && <>
          <div style={{ display: 'flex', gap: 2 }}>
            <div onClick={undo} title="Undo" style={{ padding: 7, borderRadius: 7, cursor: 'pointer', color: hist.current.past.length ? P.ink2 : P.ink4 }}><Icon name="refresh" size={15} style={{ transform: 'scaleX(-1)' }}/></div>
            <div onClick={redo} title="Redo" style={{ padding: 7, borderRadius: 7, cursor: 'pointer', color: hist.current.future.length ? P.ink2 : P.ink4 }}><Icon name="refresh" size={15}/></div>
          </div>
          <Btn kind="default" size="sm" icon="eye" onClick={() => { setPreview(p => !p); setSel(null); }}>{preview ? 'Exit preview' : 'Preview'}</Btn>
        </>}
        <Btn kind="spark" size="sm" icon="ext" onClick={() => setPublishing(true)}>Publish</Btn>
      </div>

      {/* body */}
      {mode === 'ai'
        ? <AIBuild blocks={blocks} setBlocks={setBlocks} commit={commit} addBlock={addBlock} setProp={setProp} deviceW={768} />
        : (
        <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
          {/* left panel */}
          {!preview && (
            <div style={{ width: 248, borderRight: `1px solid ${P.line}`, flexShrink: 0, display: 'flex', flexDirection: 'column', background: P.canvas }}>
              <div style={{ display: 'flex', gap: 3, padding: 10, background: P.canvas }}>
                {[['add', 'Add', 'plus'], ['layers', 'Layers', 'layers']].map(t => {
                  const on = leftTab === t[0];
                  return <div key={t[0]} onClick={() => setLeftTab(t[0])} style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, padding: '6px 0', borderRadius: 8, cursor: 'pointer', fontSize: 12.5, fontWeight: 600,
                    background: on ? P.card : P.sunk, boxShadow: on ? P.shSm : 'none', color: on ? P.ink : P.ink3 }}><Icon name={t[2]} size={14} color={on ? P.spark : P.ink3}/>{t[1]}</div>;
                })}
              </div>
              <div style={{ flex: 1, overflow: 'auto', padding: '4px 10px 12px' }}>
                {leftTab === 'add' ? (
                  <>
                    <Label style={{ padding: '6px 4px' }}>Sections</Label>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                      {LIB_ORDER.map(t => (
                        <div key={t} onClick={() => addBlock(t)} title={`Add ${DEFS[t].label}`} style={{ border: `1px solid ${P.line}`, borderRadius: 10, padding: '14px 8px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7, cursor: 'pointer', background: P.card, transition: 'background .12s' }}
                          onMouseEnter={e => e.currentTarget.style.background = P.hover} onMouseLeave={e => e.currentTarget.style.background = P.card}>
                          <div style={{ width: 30, height: 30, borderRadius: 8, background: P.sunk, color: P.ink2, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name={DEFS[t].icon} size={15}/></div>
                          <span style={{ fontSize: 11.5, color: P.ink2, textAlign: 'center' }}>{DEFS[t].label}</span>
                        </div>
                      ))}
                    </div>
                    <div style={{ marginTop: 12, padding: 12, background: P.sparkWash, border: `1px solid ${P.sparkTint}`, borderRadius: 10, fontSize: 11.5, color: P.ink2, lineHeight: 1.5 }}>
                      <b style={{ color: P.ink }}>Tip:</b> need something custom? Switch to <b style={{ color: P.sparkDim }}>Build with Pex</b> and describe it.
                    </div>
                  </>
                ) : (
                  <>
                    <Label style={{ padding: '6px 4px' }}>Page structure</Label>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 9px', borderRadius: 8, marginBottom: 2, color: P.ink3, background: P.sunk }}>
                      <Icon name="lock" size={12}/><span style={{ flex: 1, fontSize: 12 }}>Header / Nav</span>
                    </div>
                    {blocks.map((b, i) => {
                      const on = sel === b.id;
                      return (
                        <div key={b.id} onClick={() => setSel(b.id)} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 9px', borderRadius: 8, marginBottom: 2, cursor: 'pointer',
                          background: on ? P.card : 'transparent', border: `1px solid ${on ? P.line : 'transparent'}`, boxShadow: on ? P.shSm : 'none' }}>
                          <Icon name={DEFS[b.type].icon} size={13} color={on ? P.spark : P.ink3}/>
                          <span style={{ flex: 1, fontSize: 12.5, color: on ? P.ink : P.ink2, fontWeight: on ? 600 : 400 }}>{DEFS[b.type].label}</span>
                          <span onClick={(e) => { e.stopPropagation(); move(b.id, -1); }} style={{ color: i === 0 ? P.ink4 : P.ink3, cursor: 'pointer', padding: 1 }}><Icon name="chevUp" size={13}/></span>
                          <span onClick={(e) => { e.stopPropagation(); move(b.id, 1); }} style={{ color: i === blocks.length - 1 ? P.ink4 : P.ink3, cursor: 'pointer', padding: 1 }}><Icon name="chevD" size={13}/></span>
                        </div>
                      );
                    })}
                    <div onClick={() => setLeftTab('add')} style={{ padding: 9, border: `1px dashed ${P.lineStrong}`, borderRadius: 8, fontSize: 11.5, color: P.ink3, textAlign: 'center', marginTop: 6, cursor: 'pointer' }}>+ Add section</div>
                  </>
                )}
              </div>
            </div>
          )}

          {/* canvas */}
          <div style={{ flex: 1, overflow: 'auto', background: P.sunk, padding: preview ? 0 : 24, position: 'relative' }}>
            {preview && <div onClick={() => setPreview(false)} style={{ position: 'fixed', bottom: 22, right: 22, zIndex: 30, display: 'flex', alignItems: 'center', gap: 7, padding: '9px 15px', background: P.ink, color: P.canvas, borderRadius: 999, fontSize: 12.5, fontWeight: 600, cursor: 'pointer', boxShadow: P.shPop }}><Icon name="x" size={14} color={P.canvas}/>Exit preview</div>}
            <div style={{ width: preview ? '100%' : deviceW, maxWidth: '100%', margin: '0 auto', transition: 'width .2s ease' }}>
              {!preview && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '0 4px 8px', color: P.ink3, fontSize: 11 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 8, background: P.sage }}/>honestloaves.com · {device}{device !== 'desktop' ? ` · ${deviceW}px` : ''}
                </div>
              )}
              <div style={{ background: '#fff', borderRadius: preview ? 0 : 8, overflow: 'hidden', boxShadow: preview ? 'none' : P.shMd, minHeight: 200 }}>
                <SiteNav narrow={narrow}/>
                {blocks.length === 0 && (
                  <div style={{ padding: '70px 20px', textAlign: 'center', color: P.ink3 }}>
                    <div style={{ fontSize: 14, marginBottom: 12 }}>Empty page. Add a section to begin.</div>
                    <Btn kind="default" size="sm" icon="plus" onClick={() => addBlock('hero', true)}>Add a hero</Btn>
                  </div>
                )}
                {blocks.map(b => {
                  const on = sel === b.id;
                  return (
                    <div key={b.id} onClick={preview ? undefined : (e) => { e.stopPropagation(); setSel(b.id); }}
                      style={{ position: 'relative', cursor: preview ? 'default' : 'pointer', outline: !preview && on ? `2px solid ${P.spark}` : 'none', outlineOffset: -2 }}
                      onMouseEnter={e => { if (!preview && !on) e.currentTarget.style.outline = `2px solid ${P.sparkTint}`, e.currentTarget.style.outlineOffset = '-2px'; }}
                      onMouseLeave={e => { if (!preview && !on) e.currentTarget.style.outline = 'none'; }}>
                      {!preview && on && (
                        <div style={{ position: 'absolute', top: -1, right: -1, zIndex: 5, display: 'flex', alignItems: 'center', gap: 2, background: P.spark, borderRadius: '0 0 0 8px', padding: '3px 5px' }} onClick={e => e.stopPropagation()}>
                          <span style={{ fontSize: 10, color: '#fff', fontWeight: 700, padding: '0 5px' }}>{DEFS[b.type].label}</span>
                          {[['chevUp', () => move(b.id, -1)], ['chevD', () => move(b.id, 1)], ['copy', () => dupBlock(b.id)], ['trash', () => removeBlock(b.id)]].map((a, i) => (
                            <span key={i} onClick={a[1]} style={{ width: 22, height: 20, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', borderRadius: 4, background: 'rgba(255,255,255,0.16)' }}><Icon name={a[0]} size={12} color="#fff"/></span>
                          ))}
                        </div>
                      )}
                      <BlockView block={b} brand={BRAND} narrow={narrow} editable={!preview && on} onText={setPropCommit}/>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>

          {/* inspector */}
          {!preview && (
            <div style={{ width: 296, borderLeft: `1px solid ${P.line}`, flexShrink: 0, display: 'flex', flexDirection: 'column', background: P.canvas }}>
              {selBlock ? (
                <>
                  <div style={{ padding: '12px 16px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 8 }}>
                    <div style={{ width: 28, height: 28, borderRadius: 8, background: P.sparkTint, color: P.spark, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name={DEFS[selBlock.type].icon} size={15}/></div>
                    <span style={{ flex: 1, fontSize: 14, fontWeight: 600, color: P.ink }}>{DEFS[selBlock.type].label}</span>
                    <span onClick={() => dupBlock(selBlock.id)} title="Duplicate" style={{ color: P.ink3, cursor: 'pointer', padding: 3 }}><Icon name="copy" size={15}/></span>
                    <span onClick={() => removeBlock(selBlock.id)} title="Delete" style={{ color: P.rose, cursor: 'pointer', padding: 3 }}><Icon name="trash" size={15}/></span>
                  </div>
                  <div style={{ display: 'flex', gap: 3, padding: '10px 12px 0' }}>
                    {[['content', 'Content'], ['style', 'Style']].map(t => {
                      const on = insTab === t[0];
                      return <div key={t[0]} onClick={() => setInsTab(t[0])} style={{ flex: 1, textAlign: 'center', padding: '6px 0', borderRadius: 7, cursor: 'pointer', fontSize: 12.5, fontWeight: 600, background: on ? P.sunk : 'transparent', color: on ? P.ink : P.ink3 }}>{t[1]}</div>;
                    })}
                  </div>
                  <div style={{ flex: 1, overflow: 'auto', padding: 16 }}>
                    {insTab === 'content' ? (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                        {DEFS[selBlock.type].fields.map(f => (
                          <div key={f[0]}>
                            <Label style={{ marginBottom: 5 }}>{f[1]}</Label>
                            {f[2] === 'area'
                              ? <textarea value={selBlock.props[f[0]]} onFocus={() => { hist.current.past.push(snap()); hist.current.future = []; }} onChange={e => setProp(selBlock.id, f[0], e.target.value)} rows={3} style={{ width: '100%', resize: 'vertical', border: `1px solid ${P.line}`, borderRadius: 8, padding: '8px 10px', fontSize: 12.5, color: P.ink, fontFamily: P.sans, background: P.card, outline: 'none', lineHeight: 1.5 }}/>
                              : <input value={selBlock.props[f[0]]} onFocus={() => { hist.current.past.push(snap()); hist.current.future = []; }} onChange={e => setProp(selBlock.id, f[0], e.target.value)} style={{ width: '100%', border: `1px solid ${P.line}`, borderRadius: 8, padding: '8px 10px', fontSize: 12.5, color: P.ink, fontFamily: P.sans, background: P.card, outline: 'none' }}/>}
                          </div>
                        ))}
                        {selBlock.type === 'products' && <RepeatEditor block={selBlock} keyName="items" label="Products" fields={[['name', 'Name', 'text'], ['price', 'Price', 'text']]} makeBlank={() => ({ name: 'New bake', price: '$0' })} setProp={setProp} setPropCommit={setPropCommit} beginEdit={beginEdit}/>}
                        {selBlock.type === 'testimonials' && <RepeatEditor block={selBlock} keyName="quotes" label="Quotes" fields={[['q', 'Quote', 'area'], ['a', 'Attribution', 'text']]} makeBlank={() => ({ q: 'Best loaf in the borough.', a: 'A happy regular' })} setProp={setProp} setPropCommit={setPropCommit} beginEdit={beginEdit}/>}
                        {selBlock.type === 'gallery' && <RepeatEditor block={selBlock} keyName="images" label="Images" swatch makeBlank={() => BRAND.wheat} setProp={setProp} setPropCommit={setPropCommit} beginEdit={beginEdit}/>}
                        <div style={{ padding: 11, background: P.sparkWash, border: `1px solid ${P.sparkTint}`, borderRadius: 9, display: 'flex', alignItems: 'center', gap: 9 }}>
                          <Pex size={22}/><span style={{ flex: 1, fontSize: 11.5, color: P.ink2, lineHeight: 1.4 }}>Let Pex rewrite this section</span>
                          <Btn kind="default" size="sm" onClick={() => rewriteSection(selBlock)}>1 ⚡</Btn>
                        </div>
                      </div>
                    ) : (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
                        <div>
                          <Label style={{ marginBottom: 7 }}>Background</Label>
                          <div style={{ display: 'flex', gap: 7, flexWrap: 'wrap' }}>
                            {SWATCHES.map(c => (
                              <span key={c} onClick={() => setPropCommit(selBlock.id, 'bg', c)} style={{ width: 30, height: 30, borderRadius: 8, background: c, cursor: 'pointer', border: selBlock.props.bg === c ? `2px solid ${P.spark}` : `1px solid ${P.line}`, boxShadow: selBlock.props.bg === c ? `0 0 0 2px ${P.sparkWash}` : 'none' }}/>
                            ))}
                          </div>
                        </div>
                        <div>
                          <Label style={{ marginBottom: 7 }}>Spacing</Label>
                          <div style={{ display: 'flex', gap: 4, background: P.sunk, borderRadius: 8, padding: 3 }}>
                            {[['compact', 'Compact'], ['cozy', 'Cozy'], ['spacious', 'Spacious']].map(s => {
                              const on = (selBlock.props.pad || 'cozy') === s[0];
                              return <div key={s[0]} onClick={() => setPropCommit(selBlock.id, 'pad', s[0])} style={{ flex: 1, textAlign: 'center', padding: '6px 0', borderRadius: 6, cursor: 'pointer', fontSize: 11.5, fontWeight: 600, background: on ? P.card : 'transparent', boxShadow: on ? P.shSm : 'none', color: on ? P.ink : P.ink3 }}>{s[1]}</div>;
                            })}
                          </div>
                        </div>
                        {['hero', 'products', 'story', 'gallery', 'testimonials', 'cta'].includes(selBlock.type) && (
                          <div>
                            <Label style={{ marginBottom: 7 }}>Alignment</Label>
                            <div style={{ display: 'flex', gap: 4, background: P.sunk, borderRadius: 8, padding: 3 }}>
                              {[['left', 'Left'], ['center', 'Center']].map(s => {
                                const on = (selBlock.props.align || 'left') === s[0];
                                return <div key={s[0]} onClick={() => setPropCommit(selBlock.id, 'align', s[0])} style={{ flex: 1, textAlign: 'center', padding: '6px 0', borderRadius: 6, cursor: 'pointer', fontSize: 11.5, fontWeight: 600, background: on ? P.card : 'transparent', boxShadow: on ? P.shSm : 'none', color: on ? P.ink : P.ink3 }}>{s[1]}</div>;
                              })}
                            </div>
                          </div>
                        )}
                        <div style={{ fontSize: 11, color: P.ink3, lineHeight: 1.5, paddingTop: 4, borderTop: `1px solid ${P.line}` }}>Brand colors and type come from your <b style={{ color: P.ink2 }}>Theme</b>. Changes here only affect this section.</div>
                      </div>
                    )}
                  </div>
                </>
              ) : (
                <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 28, textAlign: 'center', color: P.ink3 }}>
                  <div style={{ width: 44, height: 44, borderRadius: 11, background: P.sunk, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 12 }}><Icon name="sliders" size={20} color={P.ink3}/></div>
                  <div style={{ fontSize: 13, color: P.ink2, lineHeight: 1.5 }}>Select a section on the canvas to edit its content and style.</div>
                </div>
              )}
            </div>
          )}
        </div>
      )}
      {publishing && <PublishFlow pageName={pageName} onClose={() => setPublishing(false)}/>}
    </div>
  );
};

// ── Repeatable-content editor (product items, testimonial quotes, gallery images) ──
function RepeatEditor({ block, keyName, fields, label, makeBlank, swatch, setProp, setPropCommit, beginEdit }) {
  const P = window.PX;
  const items = block.props[keyName] || [];
  const GAL_COLORS = [BRAND.wheat, BRAND.bake, BRAND.creamDk, '#C99944', BRAND.crust, '#E0C080', BRAND.cream];
  const upd = (idx, field, val) => setProp(block.id, keyName, items.map((it, i) => i === idx ? (field == null ? val : { ...it, [field]: val }) : it));
  const remove = (idx) => setPropCommit(block.id, keyName, items.filter((_, i) => i !== idx));
  const add = () => setPropCommit(block.id, keyName, [...items, makeBlank()]);
  const inp = { width: '100%', boxSizing: 'border-box', border: `1px solid ${P.line}`, borderRadius: 7, padding: '6px 8px', fontSize: 12, color: P.ink, fontFamily: P.sans, background: P.card, outline: 'none' };
  const singular = label.replace(/s$/, '');
  return (
    <div style={{ borderTop: `1px solid ${P.line}`, paddingTop: 14 }}>
      <div style={{ display: 'flex', alignItems: 'center', marginBottom: 8 }}>
        <Label style={{ flex: 1 }}>{label}</Label>
        <span style={{ fontSize: 11, color: P.ink3 }}>{items.length}</span>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {items.map((it, idx) => (
          <div key={idx} style={{ border: `1px solid ${P.line}`, borderRadius: 9, padding: 9, background: P.card }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: swatch ? 8 : 7 }}>
              <span style={{ fontSize: 10.5, color: P.ink4, flex: 1 }}>{swatch ? 'Image ' + (idx + 1) : singular + ' ' + (idx + 1)}</span>
              <span onClick={() => remove(idx)} title="Remove" style={{ cursor: 'pointer', color: P.rose, padding: 2 }}><Icon name="trash" size={13}/></span>
            </div>
            {swatch ? (
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <div onClick={() => upd(idx, null, GAL_COLORS[(GAL_COLORS.indexOf(it) + 1) % GAL_COLORS.length])} title="Swap image" style={{ width: 40, height: 40, borderRadius: 7, background: it, cursor: 'pointer', border: `1px solid ${P.line}`, flexShrink: 0 }}/>
                <span style={{ fontSize: 11, color: P.ink3, lineHeight: 1.4 }}>Tap the tile to swap the placeholder.</span>
              </div>
            ) : fields.map(f => (
              <div key={f[0]} style={{ marginBottom: 5 }}>
                <div style={{ fontSize: 10, color: P.ink4, marginBottom: 2 }}>{f[1]}</div>
                {f[2] === 'area'
                  ? <textarea value={it[f[0]] || ''} onFocus={beginEdit} onChange={e => upd(idx, f[0], e.target.value)} rows={2} style={{ ...inp, resize: 'vertical', lineHeight: 1.4 }}/>
                  : <input value={it[f[0]] || ''} onFocus={beginEdit} onChange={e => upd(idx, f[0], e.target.value)} style={inp}/>}
              </div>
            ))}
          </div>
        ))}
      </div>
      <div onClick={add} style={{ padding: 8, border: `1px dashed ${P.lineStrong}`, borderRadius: 8, fontSize: 11.5, color: P.ink3, textAlign: 'center', marginTop: 8, cursor: 'pointer' }}>+ Add {swatch ? 'image' : singular.toLowerCase()}</div>
    </div>
  );
}

// ── Publish flow: confirm → deploy progress → success ──
function PublishFlow({ pageName, onClose }) {
  const P = window.PX;
  const [phase, setPhase] = React.useState('confirm'); // confirm | deploy | done
  const steps = ['Building pages', 'Optimizing images', 'Pushing to the edge', 'Warming the CDN cache'];
  const [step, setStep] = React.useState(0);
  React.useEffect(() => {
    if (phase !== 'deploy') return;
    if (step >= steps.length) { const t = setTimeout(() => setPhase('done'), 350); return () => clearTimeout(t); }
    const t = setTimeout(() => setStep(s => s + 1), 520);
    return () => clearTimeout(t);
  }, [phase, step]);

  return (
    <window.Modal w={460}
      title={phase === 'done' ? 'Published' : phase === 'deploy' ? 'Publishing…' : 'Publish site'}
      sub={phase === 'confirm' ? 'Push your latest changes live to honestloaves.com.' : phase === 'deploy' ? 'Deploying to the edge network.' : 'Your changes are live.'}
      onClose={phase === 'deploy' ? undefined : onClose}
      foot={phase === 'confirm'
        ? <><Btn kind="ghost" size="md" onClick={onClose}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="spark" size="md" icon="ext" onClick={() => setPhase('deploy')}>Publish now</Btn></>
        : phase === 'done'
        ? <><div style={{ flex: 1 }}/><Btn kind="default" size="md" icon="ext" onClick={onClose}>Visit live site</Btn><Btn kind="primary" size="md" icon="check" onClick={onClose}>Done</Btn></>
        : null}>
      {phase === 'confirm' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, background: P.sunk, borderRadius: 11 }}>
            <div style={{ width: 40, height: 40, borderRadius: 10, background: P.sparkTint, color: P.spark, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="layout" size={19}/></div>
            <div style={{ flex: 1 }}><div style={{ fontSize: 13.5, fontWeight: 600, color: P.ink }}>Editing “{pageName}” · 3 sections changed</div><div style={{ fontSize: 11.5, color: P.ink3 }}>honestloaves.com · last published 2h ago</div></div>
          </div>
          <div style={{ fontSize: 12, color: P.ink3, lineHeight: 1.5 }}>Publishing rebuilds every page and refreshes the CDN. Visitors see the update within a few seconds.</div>
        </div>
      )}
      {phase === 'deploy' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ height: 6, background: P.sunk, borderRadius: 6, overflow: 'hidden' }}>
            <div style={{ width: `${Math.min(100, (step / steps.length) * 100)}%`, height: '100%', background: P.spark, transition: 'width .4s ease' }}/>
          </div>
          {steps.map((s, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 12.5, color: i < step ? P.ink : i === step ? P.ink2 : P.ink4 }}>
              {i < step
                ? <span style={{ width: 16, height: 16, borderRadius: 16, background: P.sage, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="check" size={11} color="#fff"/></span>
                : i === step
                ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={P.spark} strokeWidth="2.6" strokeLinecap="round" style={{ animation: 'pxspin .7s linear infinite' }}><path d="M12 3a9 9 0 1 1-9 9"/></svg>
                : <span style={{ width: 16, height: 16, borderRadius: 16, border: `2px solid ${P.line}` }}/>}
              {s}
            </div>
          ))}
        </div>
      )}
      {phase === 'done' && (
        <div style={{ textAlign: 'center', padding: '10px 0' }}>
          <div style={{ width: 56, height: 56, borderRadius: 56, background: P.sageTint, color: P.sage, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 14px' }}><Icon name="check" size={28}/></div>
          <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 22, color: P.ink }}>You’re live.</div>
          <div style={{ fontSize: 12.5, color: P.ink3, marginTop: 4 }}>honestloaves.com updated · deployed to 3 edge regions.</div>
        </div>
      )}
    </window.Modal>
  );
}

// ════════════════════════════════════════════════════════════════
// AI BUILD MODE — Lovable/v0-style: describe it, Pex builds it, live
// preview + version history. Operates on the SAME blocks model.
// ════════════════════════════════════════════════════════════════
function AIBuild({ blocks, setBlocks, commit, addBlock, setProp }) {
  const P = window.PX; const { setSparks } = window.useApp();
  const [attachments, setAttachments] = React.useState([]);
  const addAttach = (kind) => {
    const pool = kind === 'image' ? ['storefront.jpg', 'sourdough.png', 'bakers-bench.jpg'] : ['brand-guide.pdf', 'menu-2026.pdf', 'press-kit.pdf'];
    setAttachments(a => [...a, { id: window.pxid('att'), kind, name: pool[a.length % pool.length] }]);
  };
  const [msgs, setMsgs] = React.useState([
    { who: 'pex', t: "I built this first draft from your brand. Tell me what to change — add a section, rewrite the hero, restyle it — and I'll ship it to the canvas.", time: 'now' },
  ]);
  const [draft, setDraft] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [versions, setVersions] = React.useState([{ id: 'v1', label: 'Initial draft from brand', snap: JSON.parse(JSON.stringify(blocks)), time: 'now', spark: 0 }]);
  const scrollRef = React.useRef(null);
  React.useEffect(() => { if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight; }, [msgs, busy]);

  const pushVersion = (label, spark) => setVersions(vs => [{ id: 'v' + (vs.length + 1), label, snap: JSON.parse(JSON.stringify(blocksRef.current)), time: 'now', spark }, ...vs]);
  // keep a ref so version snapshot captures the post-mutation state
  const blocksRef = React.useRef(blocks);
  React.useEffect(() => { blocksRef.current = blocks; }, [blocks]);

  const interpret = (text) => {
    const t = text.toLowerCase();
    if (/testimonial|review|quote/.test(t)) return { kind: 'add', type: 'testimonials', say: 'Added a Testimonials section with two quotes pulled from your reviews. Edit them on the canvas anytime.', spark: 3 };
    if (/gallery|photo|image/.test(t)) return { kind: 'add', type: 'gallery', say: 'Dropped in a Gallery grid. Replace the placeholders with your own shots in the Files step.', spark: 2 };
    if (/contact|form|reach|get in touch/.test(t)) return { kind: 'add', type: 'contact', say: 'Added a Contact form — submissions land in People → Forms & leads automatically.', spark: 2 };
    if (/about|story/.test(t)) return { kind: 'add', type: 'story', say: 'Added an "Our story" section. I wrote a warm first draft in your voice.', spark: 3 };
    if (/product|menu|bakes|grid|shop/.test(t)) return { kind: 'add', type: 'products', say: 'Added a product grid showing this week\u2019s bakes.', spark: 2 };
    if (/headline|hero|punch|bolder|stronger/.test(t)) return { kind: 'hero', say: 'Rewrote the hero headline to be punchier and more specific to Brooklyn.', spark: 1 };
    if (/dark|night|moody/.test(t)) return { kind: 'dark', say: 'Switched the hero to your dark "Crust" background for a moodier feel.', spark: 1 };
    return { kind: 'note', say: 'Got it — I scoped that. Here\u2019s a first pass on the canvas; tell me what to adjust.', spark: 2 };
  };

  const apply = (r) => {
    if (r.kind === 'add') { addBlock(r.type, true); }
    else if (r.kind === 'hero') {
      const hero = blocksRef.current.find(b => b.type === 'hero');
      if (hero) commit(blocksRef.current.map(b => b.id === hero.id ? { ...b, props: { ...b.props, headline: 'Brooklyn\u2019s most stubborn loaf.', eyebrow: 'Stone-milled daily · Williamsburg' } } : b));
    } else if (r.kind === 'dark') {
      const hero = blocksRef.current.find(b => b.type === 'hero');
      if (hero) commit(blocksRef.current.map(b => b.id === hero.id ? { ...b, props: { ...b.props, bg: BRAND.crust } } : b));
    }
  };

  const send = (textArg) => {
    const text = (textArg != null ? textArg : draft).trim();
    if (!text || busy) return;
    const atts = attachments.map(a => a.name);
    setMsgs(m => [...m, { who: 'you', t: text, time: 'now', atts }]);
    setDraft(''); setBusy(true); setAttachments([]);
    const r = interpret(text);
    setTimeout(() => {
      apply(r);
      setTimeout(() => {
        setMsgs(m => [...m, { who: 'pex', t: r.say, time: 'now', spark: r.spark }]);
        pushVersion(text.length > 42 ? text.slice(0, 42) + '…' : text, r.spark);
        if (r.spark) setSparks(s => Math.max(0, s - r.spark));
        setBusy(false);
      }, 60);
    }, 850);
  };

  const restore = (v) => { commit(JSON.parse(JSON.stringify(v.snap))); setMsgs(m => [...m, { who: 'pex', t: `Restored "${v.label}". The canvas now matches that version.`, time: 'now' }]); };
  const chips = ['Add a testimonials section', 'Make the hero headline bolder', 'Add a contact form', 'Try a dark hero'];

  return (
    <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
      {/* chat */}
      <div style={{ width: 396, borderRight: `1px solid ${P.line}`, display: 'flex', flexDirection: 'column', flexShrink: 0, background: P.card }}>
        <div ref={scrollRef} style={{ flex: 1, overflow: 'auto', padding: 16 }}>
          {msgs.map((m, i) => m.who === 'pex' ? (
            <div key={i} style={{ display: 'flex', gap: 9, marginBottom: 14 }}>
              <Pex size={26}/>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ background: P.canvas, border: `1px solid ${P.line}`, padding: '10px 13px', borderRadius: '4px 13px 13px 13px', fontSize: 12.5, color: P.ink, lineHeight: 1.55 }}>{m.t}</div>
                {m.spark != null && <div style={{ fontSize: 10.5, color: P.ink4, marginTop: 4, display: 'flex', alignItems: 'center', gap: 4 }}><Spark size={9}/>{m.spark} spent · applied to canvas</div>}
              </div>
            </div>
          ) : (
            <div key={i} style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 14 }}>
              <div style={{ maxWidth: '84%', background: P.sparkWash, border: `1px solid ${P.sparkTint}`, color: P.ink, padding: '10px 13px', borderRadius: '13px 4px 13px 13px', fontSize: 12.5, lineHeight: 1.5 }}>
                {m.t}
                {m.atts && m.atts.length > 0 && <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, marginTop: 6 }}>{m.atts.map((a, ai) => <span key={ai} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10.5, color: P.ink3, background: P.card, border: `1px solid ${P.line}`, borderRadius: 999, padding: '2px 7px' }}><Icon name="paperclip" size={10}/>{a}</span>)}</div>}
              </div>
            </div>
          ))}
          {busy && (
            <div style={{ display: 'flex', gap: 9, marginBottom: 14, alignItems: 'center' }}>
              <Pex size={26} glow/>
              <div style={{ display: 'flex', gap: 4, padding: '11px 14px', background: P.canvas, border: `1px solid ${P.line}`, borderRadius: 13 }}>
                {[0, 1, 2].map(i => <span key={i} style={{ width: 6, height: 6, borderRadius: 6, background: P.spark, opacity: 0.4, animation: `pxbounce 1s ${i * 0.15}s infinite` }}/>)}
              </div>
            </div>
          )}
        </div>
        <div style={{ padding: '0 16px 8px', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {chips.map((c, i) => <span key={i} onClick={() => send(c)} style={{ fontSize: 11.5, color: P.ink2, background: P.sunk, border: `1px solid ${P.line}`, padding: '5px 10px', borderRadius: 999, cursor: 'pointer' }}>{c}</span>)}
        </div>
        <div style={{ padding: 14, borderTop: `1px solid ${P.line}` }}>
          <div style={{ background: P.sunk, borderRadius: 11, padding: 10, border: `1px solid ${P.line}` }}>
            {attachments.length > 0 && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
                {attachments.map(a => (
                  <span key={a.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11, color: P.ink2, background: P.card, border: `1px solid ${P.line}`, borderRadius: 999, padding: '3px 4px 3px 8px' }}>
                    <Icon name={a.kind === 'image' ? 'image' : 'paperclip'} size={11}/>{a.name}
                    <span onClick={() => setAttachments(x => x.filter(y => y.id !== a.id))} style={{ cursor: 'pointer', color: P.ink4, display: 'inline-flex' }}><Icon name="x" size={11}/></span>
                  </span>
                ))}
              </div>
            )}
            <input value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); send(); } }} placeholder="Describe a change to your site…" style={{ width: '100%', border: 'none', background: 'transparent', outline: 'none', fontSize: 13, color: P.ink, fontFamily: P.sans }}/>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
              <span onClick={() => addAttach('file')} title="Attach a file" style={{ cursor: 'pointer', display: 'inline-flex', color: P.ink3 }}><Icon name="paperclip" size={15}/></span>
              <span onClick={() => addAttach('image')} title="Attach an image" style={{ cursor: 'pointer', display: 'inline-flex', color: P.ink3 }}><Icon name="image" size={15}/></span>
              <div style={{ flex: 1 }}/>
              <Btn kind="spark" size="sm" iconR="arrowRight" onClick={() => send()}>Build</Btn>
            </div>
          </div>
        </div>
      </div>

      {/* live preview */}
      <div style={{ flex: 1, overflow: 'auto', background: P.sunk, padding: 24 }}>
        <div style={{ width: 768, maxWidth: '100%', margin: '0 auto' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '0 4px 8px', color: P.ink3, fontSize: 11 }}>
            <span style={{ width: 8, height: 8, borderRadius: 8, background: busy ? P.spark : P.sage }}/>{busy ? 'Pex is editing…' : 'Live preview · honestloaves.com'}
          </div>
          <div style={{ background: '#fff', borderRadius: 8, overflow: 'hidden', boxShadow: P.shMd, opacity: busy ? 0.6 : 1, transition: 'opacity .2s' }}>
            <SiteNav narrow={false}/>
            {blocks.map(b => <BlockView key={b.id} block={b} brand={BRAND} narrow={false} editable={false} onText={() => {}}/>)}
          </div>
        </div>
      </div>

      {/* versions */}
      <div style={{ width: 232, borderLeft: `1px solid ${P.line}`, flexShrink: 0, display: 'flex', flexDirection: 'column', background: P.canvas }}>
        <div style={{ padding: '13px 16px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 7 }}>
          <Icon name="clock" size={15} color={P.ink2}/><span style={{ fontSize: 13, fontWeight: 600, color: P.ink }}>Versions</span>
        </div>
        <div style={{ flex: 1, overflow: 'auto', padding: 10 }}>
          {versions.map((v, i) => (
            <div key={v.id} style={{ padding: 11, borderRadius: 10, marginBottom: 7, border: `1px solid ${i === 0 ? P.sparkTint : P.line}`, background: i === 0 ? P.sparkWash : P.card }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
                <span style={{ fontSize: 10.5, fontFamily: P.mono, color: P.ink3 }}>{v.id}</span>
                {i === 0 && <Pill tone="sage" style={{ fontSize: 9.5 }}>current</Pill>}
                {v.spark > 0 && <span style={{ marginLeft: 'auto', fontSize: 10, color: P.ink4, display: 'flex', alignItems: 'center', gap: 3 }}><Spark size={8}/>{v.spark}</span>}
              </div>
              <div style={{ fontSize: 12, color: P.ink, lineHeight: 1.4 }}>{v.label}</div>
              {i !== 0 && <span onClick={() => restore(v)} style={{ fontSize: 11, color: P.spark, cursor: 'pointer', fontWeight: 500, display: 'inline-block', marginTop: 6 }}>Restore</span>}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
