// v-builder.jsx — Campaign Builder overlay: offer mechanics + editable card copy
// + live customer-promo preview and discount-aware estimates.

const DURATIONS = [{value:3,label:'3 days'},{value:7,label:'7 days'},{value:14,label:'14 days'}];
const DUR_MULT = { 3:0.62, 7:1, 14:1.68 };

const MECHANICS = [
  { id:'percent',   label:'% off' },
  { id:'amount',    label:'£ off' },
  { id:'freedeliv', label:'Free delivery' },
  { id:'bundle',    label:'Bundle price' },
  { id:'bogo',      label:'2-for-1' },
];

// sensible starting offer per campaign type
const TYPE_DEFAULTS = {
  firstorder:{ mechanic:'percent',   val:30, minOrder:15, newOnly:true  },
  freedeliv: { mechanic:'freedeliv', val:0,  minOrder:12, newOnly:false },
  lunch:     { mechanic:'amount',    val:2,  minOrder:8,  newOnly:false },
  family:    { mechanic:'bundle',    val:24, minOrder:0,  newOnly:false },
  dormant:   { mechanic:'percent',   val:25, minOrder:12, newOnly:false },
  newitem:   { mechanic:'percent',   val:15, minOrder:10, newOnly:false },
  highvalue: { mechanic:'percent',   val:15, minOrder:25, newOnly:false },
  payday:    { mechanic:'percent',   val:20, minOrder:15, newOnly:false },
};

const VAL_CFG = {
  percent: { min:5,  max:60, step:5,   fmt:v=>`${v}% off` },
  amount:  { min:1,  max:15, step:0.5, fmt:v=>`£${v} off` },
  bundle:  { min:8,  max:45, step:1,   fmt:v=>`£${v} bundle price` },
};

// £ discount handed to the customer per order, for a given mechanic
function discountPerOrder(mechanic, val, aovMid) {
  if (mechanic==='percent')   return aovMid*val/100;
  if (mechanic==='amount')    return val;
  if (mechanic==='freedeliv') return 2.6;
  if (mechanic==='bundle')    return Math.max(2, aovMid - val*0.8);
  if (mechanic==='bogo')      return Math.min(aovMid*0.5, 8);
  return 0;
}

// Suggested card copy (used until the vendor types their own)
function suggestCopy(mechanic, val, minOrder, typeId, item) {
  const hero = item ? item.name : 'Pepperoni Storm';
  const minTxt = minOrder>0 ? `min £${minOrder}` : 'no minimum';
  const tag = typeId==='firstorder'?'NEW HERE?': typeId==='dormant'?'WE MISS YOU':
              typeId==='payday'?'PAYDAY': typeId==='highvalue'?'VIP':
              typeId==='lunch'?'LUNCH': typeId==='newitem'?'JUST DROPPED':'OFFER';
  if (mechanic==='percent') return { tag, head:`${val}% off`+(typeId==='firstorder'?' your first order':typeId==='dormant'?' — come back':''), sub: minOrder>0?`On orders over £${minOrder}`:'On any order' };
  if (mechanic==='amount')  return { tag, head:`£${val} off`, sub:`Spend £${minOrder>0?minOrder:8} or more` };
  if (mechanic==='freedeliv') return { tag:'TONIGHT', head:'Free delivery', sub:`No delivery fee · ${minTxt}` };
  if (mechanic==='bundle')  return { tag:'BUNDLE', head:`${hero} deal £${val}`, sub:'Limited-time bundle price' };
  if (mechanic==='bogo')    return { tag:'2 FOR 1', head:`Buy one ${hero}, get one free`, sub:minTxt };
  return { tag:'OFFER', head:'Special offer', sub:minTxt };
}

function PromoPreview({ copy, estate }) {
  return (
    <div style={{ background:'var(--bg-app)', borderRadius:18, padding:16, border:'1px solid var(--soft-line)' }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:11 }}>
        <Eyebrow style={{ fontSize:9.5 }}>Customer sees</Eyebrow>
        <span style={{ display:'inline-flex', alignItems:'center', gap:5, fontFamily:'var(--font-body)', fontSize:10, color:'var(--warm-stone)' }}><I.pin c="var(--warm-stone)" s={11}/>{estate?estate.name:'—'}</span>
      </div>
      <div style={{ borderRadius:20, overflow:'hidden', background:'var(--bg-surface)', boxShadow:'var(--shadow-md)', border:'1px solid var(--soft-line)' }}>
        <div style={{ height:118, position:'relative', background:'linear-gradient(135deg,#E8956A 0%,#D85A14 70%,#A8420C 100%)', overflow:'hidden' }}>
          <div style={{ position:'absolute', inset:0, background:'radial-gradient(ellipse at 70% 30%, rgba(255,255,255,0.22), transparent 60%)' }}/>
          <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ position:'absolute', right:-10, bottom:-20, width:130, height:130, opacity:0.22 }}><path d="M50 12 L82 80 L18 80 Z" fill="#1B120D"/></svg>
          <div style={{ position:'absolute', top:12, left:13 }}>
            <span style={{ display:'inline-block', background:'#1B120D', color:'#fff', fontFamily:'var(--font-display)', fontWeight:800, fontSize:9.5, letterSpacing:'0.12em', padding:'4px 9px', borderRadius:7, maxWidth:200, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{copy.tag||' '}</span>
          </div>
          <div style={{ position:'absolute', bottom:11, left:13, right:13 }}>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:19, color:'#fff', lineHeight:1.05, letterSpacing:'-0.01em', textShadow:'0 1px 8px rgba(0,0,0,0.3)', overflowWrap:'anywhere' }}>{copy.head||' '}</div>
          </div>
        </div>
        <div style={{ padding:'12px 14px', display:'flex', alignItems:'center', gap:11 }}>
          <div style={{ width:36, height:36, borderRadius:10, background:'linear-gradient(135deg,#F28C1B,#D85A14)', display:'flex', alignItems:'center', justifyContent:'center', fontFamily:'var(--font-display)', fontWeight:900, fontSize:13, color:'#fff', flexShrink:0 }}>{VENDOR.initials}</div>
          <div style={{ flex:1, minWidth:0 }}>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13.5, color:'var(--fg-primary)' }}>{VENDOR.name}</div>
            <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{copy.sub||' '}</div>
          </div>
          <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'#fff', background:'var(--brand-orange)', padding:'7px 12px', borderRadius:10, whiteSpace:'nowrap' }}>Order now</span>
        </div>
      </div>
      <div style={{ marginTop:11, display:'flex', gap:8, alignItems:'flex-start' }}>
        <I.lock c="var(--warm-stone)" s={13}/>
        <span style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)', lineHeight:1.4 }}>Delivered through Lasso to opted-in customers in {estate?estate.name:'this area'}. You never see who receives it.</span>
      </div>
    </div>
  );
}

function BuilderField({ label, children, hint }) {
  return (
    <div style={{ marginBottom:22 }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:11 }}>
        <Eyebrow>{label}</Eyebrow>
        {hint && <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{hint}</span>}
      </div>
      {children}
    </div>
  );
}

// editable text field for the promo card
function CardInput({ label, value, placeholder, onChange, maxLength, custom }) {
  return (
    <div style={{ marginBottom:10 }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:5 }}>
        <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.04em', textTransform:'uppercase', color:'var(--warm-stone)' }}>{label}</span>
        <span style={{ fontFamily:'var(--font-mono)', fontSize:9.5, color: custom?'var(--brand-orange)':'var(--fg-muted)' }}>{custom?'edited':'auto'}</span>
      </div>
      <input value={value} placeholder={placeholder} maxLength={maxLength} onChange={(e)=>onChange(e.target.value)}
        style={{ width:'100%', boxSizing:'border-box', background:'var(--bg-app)', border:'1px solid', borderColor: custom?'var(--brand-orange)':'var(--soft-line)', borderRadius:9, padding:'9px 11px',
          fontFamily:'var(--font-body)', fontSize:13, color:'var(--fg-primary)', outline:'none' }}/>
    </div>
  );
}

// Estate picker with search — operator can reach ALL estates, not just the top 8
function EstatePicker({ estateId, setEstateId }) {
  const [q, setQ] = React.useState('');
  const query = q.trim().toLowerCase();
  const ranked = [...ESTATES].sort((a,b)=>b.opportunity-a.opportunity);
  let shown;
  if (query) {
    shown = ranked.filter(e=>e.name.toLowerCase().includes(query));
  } else {
    shown = ranked.slice(0,8);
    const sel = ESTATES.find(e=>e.id===estateId);
    if (sel && !shown.includes(sel)) shown = [sel, ...shown.slice(0,7)];
  }
  return (
    <div>
      <div style={{ display:'flex', alignItems:'center', gap:8, height:38, background:'var(--bg-surface)', border:'1px solid var(--soft-line)', borderRadius:10, padding:'0 12px', marginBottom:10, boxShadow:'var(--shadow-sm)' }}>
        <I.search c="var(--warm-stone)" s={15}/>
        <input value={q} onChange={e=>setQ(e.target.value)} placeholder={`Search all ${ESTATES.length} estates…`}
          style={{ border:'none', outline:'none', background:'transparent', flex:1, fontFamily:'var(--font-body)', fontSize:12.5, color:'var(--fg-primary)' }}/>
        {q && <button onClick={()=>setQ('')} style={{ background:'none', border:'none', cursor:'pointer', display:'flex', padding:0 }}><I.x c="var(--warm-stone)" s={13}/></button>}
        {!q && <span style={{ fontFamily:'var(--font-mono)', fontSize:10, color:'var(--fg-muted)', whiteSpace:'nowrap' }}>top 8 shown</span>}
      </div>
      {shown.length===0 ? (
        <div style={{ padding:'14px 4px', fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>No estate matches “{q.trim()}”.</div>
      ) : (
        <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
          {shown.map(e=>{
            const on = e.id===estateId; const s = NODE_STATE[e.state];
            return <button key={e.id} onClick={()=>setEstateId(e.id)} style={{ display:'inline-flex', alignItems:'center', gap:7, padding:'8px 12px', borderRadius:10, cursor:'pointer',
              background: on?'var(--dark-chocolate)':'var(--bg-surface)', color: on?'var(--dust-cream)':'var(--fg-primary)', border:'1px solid', borderColor: on?'var(--dark-chocolate)':'var(--soft-line)',
              fontFamily:'var(--font-display)', fontWeight:700, fontSize:12.5 }}>
              <span style={{ width:8, height:8, borderRadius:'50%', background:s.fill }}/>{e.name}<span style={{ fontFamily:'var(--font-mono)', fontSize:10.5, opacity:0.7 }}>{e.opportunity}</span>
            </button>;
          })}
        </div>
      )}
    </div>
  );
}

function CampaignBuilder({ app }) {
  const b = app.builder;
  const tpl = b.template;
  const initType = tpl ? tpl.typeId : (b.item ? 'newitem' : 'firstorder');
  const initDef = TYPE_DEFAULTS[initType];
  const [estateId, setEstateId] = React.useState(tpl ? tpl.estateId : (b.estateId || 'bletchley'));
  const [typeId, setTypeId] = React.useState(initType);
  const [budget, setBudget] = React.useState(tpl ? tpl.budget : 200);
  const [duration, setDuration] = React.useState(tpl ? tpl.duration : 7);
  const [mechanic, setMechanic] = React.useState(tpl ? (tpl.mechanic||initDef.mechanic) : initDef.mechanic);
  const [val, setVal] = React.useState(tpl ? (tpl.val??initDef.val) : initDef.val);
  const [minOrder, setMinOrder] = React.useState(tpl ? (tpl.minOrder??initDef.minOrder) : initDef.minOrder);
  const [newOnly, setNewOnly] = React.useState(tpl ? !!tpl.newOnly : initDef.newOnly);
  const [custom, setCustom] = React.useState(tpl ? (tpl.copy||{}) : {});       // overrides for card copy

  const estate = ESTATES.find(e=>e.id===estateId);
  const type = CAMPAIGN_TYPES.find(t=>t.id===typeId);

  const pickType = (id)=>{ const d = TYPE_DEFAULTS[id]; setTypeId(id); setMechanic(d.mechanic); setVal(d.val); setMinOrder(d.minOrder); setNewOnly(d.newOnly); setCustom({}); };
  const pickMechanic = (m)=>{ setMechanic(m); setVal(m==='percent'?25:m==='amount'?3:m==='bundle'?24:0); };

  // ── discount-aware economics ──
  const aovMid = (estate.aov[0]+estate.aov[1])/2;
  const discPer = Math.max(0, discountPerOrder(mechanic, val, aovMid));
  const f = Math.min(0.6, discPer/aovMid);
  const lift = 1 + f*1.25;                               // deeper discount → more orders
  const base = estimateFor(estate, budget);
  const mult = DUR_MULT[duration];
  const reach = Math.round(base.reach * (0.7 + mult*0.3) * (newOnly?0.7:1));
  const orders = Math.round(base.orders * mult * lift * (newOnly?0.82:1));
  const revenue = Math.round(orders * Math.max(aovMid - discPer, aovMid*0.25));  // net of discount
  const roi = +(revenue / Math.max(budget,1)).toFixed(1);
  const audience = Math.round(estate.interest * (newOnly?0.5:0.92));

  const suggested = suggestCopy(mechanic, val, minOrder, typeId, b.item);
  const shown = { tag: custom.tag ?? suggested.tag, head: custom.head ?? suggested.head, sub: custom.sub ?? suggested.sub };
  const edited = Object.keys(custom).length>0;
  const valCfg = VAL_CFG[mechanic];

  return (
    <div data-campaign-builder="" style={{ position:'absolute', inset:0, zIndex:200, background:'rgba(27,18,13,0.42)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'center', alignItems:'stretch', padding:'22px', animation:'v-fade 200ms' }}
      onClick={app.closeBuilder}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:1060, background:'var(--bg-app)', borderRadius:20, boxShadow:'var(--shadow-lg)', display:'flex', flexDirection:'column', overflow:'hidden', animation:'v-pop 240ms var(--ease-out)' }}>
        {/* header */}
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'16px 22px', borderBottom:'1px solid var(--soft-line)', background:'var(--bg-surface)' }}>
          <div style={{ display:'flex', alignItems:'center', gap:11 }}>
            <div style={{ width:36, height:36, borderRadius:10, background:'var(--bg-warm)', display:'flex', alignItems:'center', justifyContent:'center' }}><I.megaphone c="var(--brand-orange)" s={19}/></div>
            <div>
              <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:900, fontSize:18, color:'var(--fg-primary)' }}>Campaign Builder</h2>
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>{b.item ? `Promoting ${b.item.name}` : 'Create a local marketing push'}</div>
            </div>
          </div>
          <button data-campaign-builder-close="" onClick={app.closeBuilder} style={{ width:34, height:34, borderRadius:10, border:'1px solid var(--soft-line)', background:'var(--bg-app)', display:'flex', alignItems:'center', justifyContent:'center', cursor:'pointer' }}><I.x c="var(--warm-stone)" s={17}/></button>
        </div>

        <div style={{ flex:1, minHeight:0, display:'flex' }}>
          {/* left: config */}
          <div style={{ flex:1, minWidth:0, overflowY:'auto', padding:'22px 26px' }}>
            <BuilderField label="Selected estate" hint={`${estate.customers.toLocaleString()} customers · ${estate.interest} interested`}>
              <EstatePicker estateId={estateId} setEstateId={setEstateId}/>
            </BuilderField>

            <BuilderField label="Campaign type">
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:9 }}>
                {CAMPAIGN_TYPES.map(t=>{
                  const on = t.id===typeId; const Icon = I[t.icon]||I.gift;
                  return (
                    <button key={t.id} onClick={()=>pickType(t.id)} style={{ display:'flex', alignItems:'center', gap:11, padding:'11px 13px', borderRadius:12, cursor:'pointer', textAlign:'left',
                      background:'var(--bg-surface)', border:'1.5px solid', borderColor: on?'var(--brand-orange)':'var(--soft-line)',
                      boxShadow: on?'var(--shadow-md)':'var(--shadow-sm)', transition:'all 150ms' }}>
                      <div style={{ width:34, height:34, borderRadius:9, flexShrink:0, background: on?'var(--brand-orange)':'var(--bg-warm)', display:'flex', alignItems:'center', justifyContent:'center' }}><Icon c={on?'#fff':'var(--horse-brown)'} s={17}/></div>
                      <div style={{ minWidth:0 }}>
                        <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)', lineHeight:1.15 }}>{t.name}</div>
                        <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)', marginTop:2 }}>{t.blurb}</div>
                      </div>
                      {on && <I.check c="var(--brand-orange)" s={17}/>}
                    </button>
                  );
                })}
              </div>
            </BuilderField>

            {/* OFFER — the mechanics + how much */}
            <div style={{ marginBottom:22, background:'var(--bg-surface)', border:'1px solid var(--soft-line)', borderRadius:14, padding:'16px 17px' }}>
              <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:12 }}>
                <Eyebrow><I.tag c="var(--brand-orange)" s={12}/> &nbsp;Offer &amp; discount</Eyebrow>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'var(--brand-orange)' }}>≈ £{discPer.toFixed(2)}/order to customer</span>
              </div>

              <div style={{ display:'flex', flexWrap:'wrap', gap:7, marginBottom:16 }}>
                {MECHANICS.map(m=>{
                  const on = m.id===mechanic;
                  return <button key={m.id} onClick={()=>pickMechanic(m.id)} style={{ padding:'7px 12px', borderRadius:9, cursor:'pointer',
                    background: on?'var(--dark-chocolate)':'var(--bg-app)', color: on?'var(--dust-cream)':'var(--fg-primary)', border:'1px solid', borderColor: on?'var(--dark-chocolate)':'var(--soft-line)',
                    fontFamily:'var(--font-display)', fontWeight:700, fontSize:12.5 }}>{m.label}</button>;
                })}
              </div>

              {valCfg && (
                <div style={{ marginBottom:16 }}>
                  <div style={{ display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:9 }}>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>{mechanic==='bundle'?'Bundle price':mechanic==='percent'?'Discount':'Amount off'}</span>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:20, color:'var(--fg-primary)' }}>{mechanic==='percent'?`${val}%`:`£${val}`}</span>
                  </div>
                  <Slider value={val} min={valCfg.min} max={valCfg.max} step={valCfg.step} onChange={setVal}/>
                  <div style={{ display:'flex', justifyContent:'space-between', marginTop:6 }}>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)' }}>{mechanic==='percent'?`${valCfg.min}%`:`£${valCfg.min}`}</span>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)' }}>{mechanic==='percent'?`${valCfg.max}%`:`£${valCfg.max}`}</span>
                  </div>
                </div>
              )}
              {!valCfg && (
                <div style={{ marginBottom:16, padding:'10px 12px', background:'var(--bg-app)', borderRadius:10, fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>
                  {mechanic==='freedeliv'?'Lasso waives the delivery fee for the customer — no percentage to set.':'Customer gets a second item free. Pricing handled at checkout.'}
                </div>
              )}

              <div style={{ marginBottom:15 }}>
                <div style={{ display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:9 }}>
                  <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>Minimum order</span>
                  <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:14, color:'var(--fg-primary)' }}>{minOrder>0?`£${minOrder}`:'No minimum'}</span>
                </div>
                <Slider value={minOrder} min={0} max={35} step={5} onChange={setMinOrder} color="var(--horse-brown)"/>
              </div>

              <div onClick={()=>setNewOnly(v=>!v)} role="button" style={{ display:'flex', alignItems:'center', gap:11, cursor:'pointer', paddingTop:13, borderTop:'1px solid var(--soft-line)' }}>
                <Toggle on={newOnly} onChange={()=>setNewOnly(v=>!v)}/>
                <div>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12.5, color:'var(--fg-primary)' }}>New customers only</div>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>Restrict to people who've never ordered from you</div>
                </div>
              </div>
            </div>

            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24 }}>
              <BuilderField label="Budget" hint={`£${budget}`}>
                <Slider value={budget} min={50} max={500} step={10} onChange={setBudget}/>
                <div style={{ display:'flex', justifyContent:'space-between', marginTop:6 }}>
                  <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>£50</span>
                  <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>£500</span>
                </div>
              </BuilderField>
              <BuilderField label="Duration">
                <Segmented options={DURATIONS} value={duration} onChange={setDuration}/>
              </BuilderField>
            </div>

            <BuilderField label="Target audience size" hint="Opted-in, anonymised">
              <div style={{ display:'flex', alignItems:'center', gap:14, background:'var(--bg-surface)', border:'1px solid var(--soft-line)', borderRadius:12, padding:'13px 16px' }}>
                <I.users c="var(--brand-orange)" s={20}/>
                <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:22, color:'var(--fg-primary)' }}>{audience.toLocaleString()}</div>
                <div style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)', flex:1 }}>{newOnly?'first-time':'matching'} customers in {estate.name} who fit this campaign and opted into offers.</div>
              </div>
            </BuilderField>

            <div style={{ display:'flex', gap:10, alignItems:'center', padding:'12px 15px', background:'rgba(224,153,42,0.10)', borderRadius:12 }}>
              <I.clock c="#a86d12" s={18}/>
              <span style={{ fontFamily:'var(--font-body)', fontSize:12.5, color:'var(--horse-brown)' }}>
                <strong style={{ fontFamily:'var(--font-display)' }}>Launch recommendation:</strong> {estate.name} peaks {estate.peak}. Go live {duration>=7?'Friday 16:00':'today 16:30'} to catch the dinner rush.
              </span>
            </div>
          </div>

          {/* right: estimates + preview + editable copy */}
          <div style={{ width:368, flexShrink:0, borderLeft:'1px solid var(--soft-line)', background:'var(--bg-surface)', overflowY:'auto', padding:'22px 22px 0', display:'flex', flexDirection:'column' }}>
            <Eyebrow style={{ marginBottom:13 }}><I.zap c="var(--brand-orange)" s={12} f/> &nbsp;Projected impact</Eyebrow>
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10, marginBottom:12 }}>
              {[['Estimated reach', reach.toLocaleString(), I.users],['New orders', '+'+orders, I.receipt],['Net revenue', '£'+revenue.toLocaleString(), I.pound],['ROI estimate', roi+'×', I.trendUp]].map(([l,v,Ic])=>(
                <div key={l} style={{ background:'var(--bg-app)', borderRadius:12, padding:'13px 14px' }}>
                  <Ic c="var(--brand-orange)" s={16}/>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:22, color:'var(--fg-primary)', marginTop:7, lineHeight:1 }}>{v}</div>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)', marginTop:3 }}>{l}</div>
                </div>
              ))}
            </div>
            <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'11px 14px', background:'rgba(46,139,78,0.10)', borderRadius:11, marginBottom:18 }}>
              <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--horse-brown)' }}>Net profit after discount</span>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:17, color: revenue-budget>=0?'#247a41':'#b0341a' }}>{revenue-budget>=0?'+':'−'}£{Math.abs(revenue-budget).toLocaleString()}</span>
            </div>

            <PromoPreview copy={shown} estate={estate}/>

            {/* editable card copy */}
            <div style={{ marginTop:16, marginBottom:6 }}>
              <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:11 }}>
                <Eyebrow><I.image c="var(--warm-stone)" s={12}/> &nbsp;Edit card copy</Eyebrow>
                {edited && <button onClick={()=>setCustom({})} style={{ display:'inline-flex', alignItems:'center', gap:4, background:'none', border:'none', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, color:'var(--brand-orange)' }}><I.refresh c="var(--brand-orange)" s={12}/> Reset to suggested</button>}
              </div>
              <CardInput label="Badge" value={shown.tag} placeholder="e.g. NEW HERE?" maxLength={18} custom={custom.tag!=null} onChange={(v)=>setCustom(c=>({ ...c, tag:v }))}/>
              <CardInput label="Headline" value={shown.head} placeholder="e.g. 30% off your first order" maxLength={42} custom={custom.head!=null} onChange={(v)=>setCustom(c=>({ ...c, head:v }))}/>
              <CardInput label="Subtext" value={shown.sub} placeholder="e.g. On orders over £15" maxLength={52} custom={custom.sub!=null} onChange={(v)=>setCustom(c=>({ ...c, sub:v }))}/>
            </div>

            <div style={{ position:'sticky', bottom:0, marginTop:'auto', paddingTop:16, paddingBottom:18, background:'linear-gradient(180deg,transparent,var(--bg-surface) 26%)' }}>
              <Btn kind="accent" full size="lg" icon={<I.rocket c="#fff" s={17}/>}
                onClick={()=>{
                  const offerText = mechanic==='percent'?`${val}% off${minOrder>0?` over £${minOrder}`:''}`
                    : mechanic==='amount'?`£${val} off${minOrder>0?` over £${minOrder}`:''}`
                    : mechanic==='freedeliv'?`Free delivery${minOrder>0?` over £${minOrder}`:''}`
                    : mechanic==='bundle'?`${b.item?b.item.name:'Bundle'} £${val}`
                    : '2-for-1';
                  const day1Orders = Math.max(1, Math.round(orders/duration));
                  const netAov = Math.max(aovMid-discPer, aovMid*0.25);
                  const day1Spend = Math.max(8, Math.round(budget/duration));
                  const day1Rev = Math.round(day1Orders*netAov);
                  const newC = {
                    id:'c'+Date.now().toString().slice(-6), name: (shown.head||type.name).slice(0,40), area: estate.name, type: typeId,
                    status:'live', spend: day1Spend, budget, reach: Math.max(20, Math.round(reach/duration*1.3)),
                    orders: day1Orders, revenue: day1Rev, roi:+(day1Rev/day1Spend).toFixed(1),
                    ends:`${Math.max(1,duration-1)} days left`, offer: offerText, hero: b.item?b.item.name:'Smoky Pepperoni Storm',
                    audience:`${newOnly?'New':'All'} customers in ${estate.name}`, hasPhoto: !!(b.item&&b.item.photo), heroPhoto: (b.item&&b.item.photoUrl)||undefined,
                    elapsed:1, total:duration, benchmarkRoi:4.0, newPct: newOnly?85:40,
                  };
                  ACTIVE_CAMPAIGNS.unshift(newC);
                  app.closeBuilder();
                  app.toast(`Launched in ${estate.name} — now live in your campaigns`);
                  app.openCampaign(newC.id);
                }}>
                Launch campaign · £{budget}
              </Btn>
              <Btn kind="white" full style={{ marginTop:10 }} icon={<I.bookmark c="var(--fg-primary)" s={15}/>}
                onClick={()=>{
                  const tplObj = { id:'t'+Date.now().toString().slice(-6), name:(shown.head||type.name).slice(0,40), typeId, estateId, budget, duration, mechanic, val, minOrder, newOnly, copy:custom, lastUsed:'Not used yet' };
                  CAMPAIGN_TEMPLATES.unshift(tplObj);
                  app.closeBuilder();
                  app.toast(`Saved “${tplObj.name}” to templates — reuse it anytime`);
                  app.nav('campaigns');
                }}>
                Save as template (don't launch)
              </Btn>
              <div style={{ textAlign:'center', marginTop:9, fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)' }}>Launch goes live now · save keeps these settings for later</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CampaignBuilder });
