// v-campaign.jsx — full campaign operations drawer + areas for development.

const CD_SEV = {
  high:{ bg:'rgba(193,59,31,0.10)', dot:'#C13B1F', label:'Act now',  tone:'red' },
  med: { bg:'rgba(224,153,42,0.12)', dot:'#E0992A', label:'Improve', tone:'amber' },
  low: { bg:'rgba(46,139,78,0.10)', dot:'#2E8B4E', label:'Optimise', tone:'green' },
};
const CAMP_STATUS = {
  live:   { tone:'purple', label:'Live' },
  ending: { tone:'amber',  label:'Ending' },
  paused: { tone:'grey',   label:'Paused' },
  ended:  { tone:'grey',   label:'Ended' },
};

// ─── A/B offer-test modal ────────────────────────────────────────────
const OFFER_PRESETS = [
  { short:'Free delivery', label:'Free delivery over £20', tag:'Lifts conversion', icon:'truck' },
  { short:'Free side',     label:'Free side with any pizza', tag:'Lifts basket size', icon:'gift' },
  { short:'25% off',       label:'25% off (vs current 30%)', tag:'Protects margin', icon:'tag' },
  { short:'£5 off £25',    label:'£5 off orders over £25', tag:'Lifts order value', icon:'pound' },
  { short:'Custom',        label:'Write your own', tag:'Define A/B challenger', icon:'sparkle' },
];

function OfferTestModal({ app, c, onClose, onLaunch }) {
  const [pick, setPick] = React.useState(0);
  const [custom, setCustom] = React.useState('');
  const [splitB, setSplitB] = React.useState(50);
  const [days, setDays] = React.useState(7);
  const preset = OFFER_PRESETS[pick];
  const isCustom = preset.short==='Custom';
  const variantLabel = isCustom ? (custom.trim()||'Custom offer') : preset.label;
  const variantShort = isCustom ? 'Custom' : preset.short;
  const valid = !isCustom || custom.trim().length>0;

  const ordersPerDay = Math.max(1, Math.round(c.orders/Math.max(1,c.elapsed)));
  const bShare = Math.round(ordersPerDay*days*splitB/100);
  const sigDays = Math.max(3, Math.ceil(240/Math.max(1, ordersPerDay*splitB/100)));

  return (
    <div onClick={onClose} style={{ position:'fixed', inset:0, zIndex:340, background:'rgba(27,18,13,0.5)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'center', alignItems:'flex-start', padding:'40px 22px', overflowY:'auto', animation:'v-fade 180ms' }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:540, background:'var(--bg-surface)', borderRadius:20, boxShadow:'var(--shadow-lg)', 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)' }}>
          <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.filter c="var(--brand-orange)" s={18}/></div>
            <div>
              <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:900, fontSize:17, color:'var(--fg-primary)' }}>A/B test an offer</h2>
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>{c.name} · {c.area}</div>
            </div>
          </div>
          <button onClick={onClose} 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={{ padding:'18px 22px', display:'flex', flexDirection:'column', gap:18 }}>
          {/* control vs challenger heads */}
          <div style={{ display:'flex', gap:12 }}>
            <div style={{ flex:1, background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:13, padding:'12px 14px' }}>
              <div style={{ display:'flex', alignItems:'center', gap:6, marginBottom:6 }}>
                <span style={{ width:18, height:18, borderRadius:6, background:'var(--dark-chocolate)', color:'var(--dust-cream)', display:'flex', alignItems:'center', justifyContent:'center', fontFamily:'var(--font-display)', fontWeight:900, fontSize:10 }}>A</span>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.04em', textTransform:'uppercase', color:'var(--warm-stone)' }}>Current · control</span>
              </div>
              <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:14, color:'var(--fg-primary)' }}>{c.offer}</div>
            </div>
            <div style={{ flex:1, background:'rgba(216,90,20,0.06)', border:'1px solid rgba(216,90,20,0.3)', borderRadius:13, padding:'12px 14px' }}>
              <div style={{ display:'flex', alignItems:'center', gap:6, marginBottom:6 }}>
                <span style={{ width:18, height:18, borderRadius:6, background:'var(--brand-orange)', color:'#fff', display:'flex', alignItems:'center', justifyContent:'center', fontFamily:'var(--font-display)', fontWeight:900, fontSize:10 }}>B</span>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.04em', textTransform:'uppercase', color:'var(--brand-orange)' }}>Challenger</span>
              </div>
              <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:14, color:'var(--fg-primary)' }}>{variantLabel}</div>
            </div>
          </div>

          {/* pick challenger */}
          <div>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', marginBottom:9 }}>Choose the challenger offer</div>
            <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
              {OFFER_PRESETS.map((p,i)=>{
                const on=i===pick; const PIcon=I[p.icon]||I.gift;
                return (
                  <button key={i} onClick={()=>setPick(i)} style={{ display:'flex', alignItems:'center', gap:11, padding:'11px 13px', borderRadius:11, cursor:'pointer', textAlign:'left',
                    background: on?'var(--bg-warm)':'var(--bg-app)', border:'1px solid', borderColor: on?'var(--brand-orange)':'var(--soft-line)' }}>
                    <div style={{ width:30, height:30, borderRadius:8, background: on?'var(--brand-orange)':'var(--bg-surface)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}><PIcon c={on?'#fff':'var(--warm-stone)'} s={16}/></div>
                    <div style={{ flex:1 }}>
                      <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13, color:'var(--fg-primary)' }}>{p.label}</div>
                      <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{p.tag}</div>
                    </div>
                    <span style={{ width:18, height:18, borderRadius:'50%', border:'2px solid', borderColor: on?'var(--brand-orange)':'var(--soft-line)', background: on?'var(--brand-orange)':'transparent', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>{on && <I.check c="#fff" s={11}/>}</span>
                  </button>
                );
              })}
              {isCustom && <input autoFocus value={custom} onChange={e=>setCustom(e.target.value)} maxLength={48} placeholder="e.g. Buy 1 pizza, get wings free"
                style={{ width:'100%', boxSizing:'border-box', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:10, padding:'11px 13px', fontFamily:'var(--font-body)', fontSize:13, color:'var(--fg-primary)', outline:'none', marginTop:2 }}/>}
            </div>
          </div>

          {/* split + duration */}
          <div style={{ display:'flex', gap:18, flexWrap:'wrap' }}>
            <div style={{ flex:1, minWidth:200 }}>
              <div style={{ display:'flex', justifyContent:'space-between', marginBottom:8 }}>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)' }}>Traffic split</span>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12, color:'var(--fg-primary)' }}>A {100-splitB}% · B {splitB}%</span>
              </div>
              <Slider value={splitB} min={10} max={90} step={5} onChange={setSplitB}/>
            </div>
            <div>
              <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', marginBottom:8 }}>Run for</div>
              <Segmented size="sm" options={[{value:3,label:'3d'},{value:7,label:'7d'},{value:14,label:'14d'}]} value={days} onChange={setDays}/>
            </div>
          </div>

          {/* projection */}
          <div style={{ display:'flex', alignItems:'center', gap:10, padding:'12px 14px', background:'rgba(46,139,78,0.09)', borderRadius:11 }}>
            <I.trendUp c="#247a41" s={16}/>
            <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--horse-brown)', lineHeight:1.4 }}>
              Variant B sees <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>~{bShare} orders</strong> over {days} days. If it lifts conversion you'll see a clear winner in <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>~{sigDays} days</strong>.
            </span>
          </div>
        </div>

        {/* footer */}
        <div style={{ display:'flex', alignItems:'center', justifyContent:'flex-end', gap:10, padding:'14px 22px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          <Btn kind="white" onClick={onClose}>Cancel</Btn>
          <Btn kind="accent" disabled={!valid} icon={<I.play c="#fff" s={15}/>} onClick={()=>onLaunch({ label:variantLabel, short:variantShort, splitB, days })}>Launch A/B test</Btn>
        </div>
      </div>
    </div>
  );
}

function CDStat({ value, label, sub, accent }) {
  return (
    <div style={{ background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:12, padding:'12px 13px' }}>
      <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:19, color: accent||'var(--fg-primary)', lineHeight:1 }}>{value}</div>
      <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)', marginTop:4 }}>{label}</div>
      {sub && <div style={{ fontFamily:'var(--font-body)', fontSize:10, color:'var(--fg-muted)', marginTop:1 }}>{sub}</div>}
    </div>
  );
}

// ─── Scale-budget modal — forecasts what extra spend buys ────────────
function BudgetScaleModal({ app, c, onClose, onConfirm }) {
  const ops = React.useMemo(()=>campaignOps(c), [c.id]);
  const presets = [
    { label:'+25%', add: Math.round(c.budget*0.25/10)*10 },
    { label:'+50%', add: Math.round(c.budget*0.5/10)*10 },
    { label:'2×',   add: c.budget },
  ];
  const [add, setAdd] = React.useState(presets[1].add);
  const effFactor = 0.85;                                   // gentle diminishing returns
  const extraOrders = Math.max(1, Math.round(add/ops.cpa*effFactor));
  const extraRev = Math.round(extraOrders*ops.aov);
  const newBudget = c.budget + add;
  const projOrders = c.orders + extraOrders;
  const projRev = c.revenue + extraRev;
  const incRoas = +(extraRev/add).toFixed(1);
  const matchPreset = presets.find(p=>p.add===add);

  return (
    <div onClick={onClose} style={{ position:'fixed', inset:0, zIndex:340, background:'rgba(27,18,13,0.5)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'center', alignItems:'flex-start', padding:'48px 22px', overflowY:'auto', animation:'v-fade 180ms' }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:520, background:'var(--bg-surface)', borderRadius:20, boxShadow:'var(--shadow-lg)', overflow:'hidden', animation:'v-pop 240ms var(--ease-out)' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'16px 22px', borderBottom:'1px solid var(--soft-line)' }}>
          <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.trendUp c="var(--brand-orange)" s={18}/></div>
            <div>
              <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:900, fontSize:17, color:'var(--fg-primary)' }}>Scale this campaign</h2>
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>{c.name} · beating benchmark at {ops.roas}× ROAS</div>
            </div>
          </div>
          <button onClick={onClose} 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={{ padding:'18px 22px', display:'flex', flexDirection:'column', gap:18 }}>
          {/* why scale */}
          <div style={{ display:'flex', alignItems:'center', gap:10, padding:'11px 13px', background:'rgba(46,139,78,0.09)', borderRadius:11 }}>
            <I.zap c="#247a41" s={16} f/>
            <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--horse-brown)', lineHeight:1.4 }}>Every £1 here is returning <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>£{ops.roas}</strong> at <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>£{ops.cpa}</strong>/order — well above your {c.benchmarkRoi}× benchmark. More budget = more of the same.</span>
          </div>

          {/* choose how much */}
          <div>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:9 }}>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)' }}>Add to budget</span>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:14, color:'var(--brand-orange)' }}>+£{add}</span>
            </div>
            <div style={{ display:'flex', gap:8, marginBottom:13 }}>
              {presets.map(p=>{
                const on = p.add===add;
                return <button key={p.label} onClick={()=>setAdd(p.add)} style={{ flex:1, padding:'9px 8px', borderRadius:10, 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:800, fontSize:13 }}>{p.label} <span style={{ opacity:0.7, fontWeight:600, fontSize:11 }}>·£{p.add}</span></button>;
              })}
            </div>
            <Slider value={add} min={20} max={c.budget*2} step={10} onChange={(v)=>setAdd(Math.round(v/10)*10)}/>
            <div style={{ display:'flex', justifyContent:'space-between', marginTop:6 }}>
              <span style={{ fontFamily:'var(--font-mono)', fontSize:10, color:'var(--warm-stone)' }}>Budget £{c.budget}</span>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'var(--fg-primary)' }}>New budget £{newBudget}</span>
            </div>
          </div>

          {/* projected return */}
          <div style={{ border:'1px solid var(--soft-line)', borderRadius:13, overflow:'hidden' }}>
            <div style={{ padding:'10px 14px', background:'var(--bg-app)', borderBottom:'1px solid var(--soft-line)', fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)' }}>Projected from this extra spend</div>
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:1, background:'var(--soft-line)' }}>
              {[['+'+extraOrders,'extra orders'],['+£'+extraRev.toLocaleString(),'extra revenue'],[incRoas+'×','on new spend']].map(([v,l])=>(
                <div key={l} style={{ background:'var(--bg-surface)', padding:'13px 12px', textAlign:'center' }}>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:19, color:'#247a41', lineHeight:1 }}>{v}</div>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)', marginTop:3 }}>{l}</div>
                </div>
              ))}
            </div>
            <div style={{ display:'flex', justifyContent:'space-between', padding:'11px 14px', background:'var(--bg-app)' }}>
              <span style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>Projected campaign total</span>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>{projOrders} orders · £{projRev.toLocaleString()}</span>
            </div>
          </div>
          <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--fg-muted)', lineHeight:1.4 }}>Estimate at current efficiency with mild diminishing returns. Actuals update live as orders come in.</div>
        </div>

        <div style={{ display:'flex', alignItems:'center', justifyContent:'flex-end', gap:10, padding:'14px 22px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          <Btn kind="white" onClick={onClose}>Cancel</Btn>
          <Btn kind="accent" icon={<I.check c="#fff" s={16}/>} onClick={()=>onConfirm({ add, extraOrders, extraRev, newBudget, incRoas })}>Add £{add} &amp; scale</Btn>
        </div>
      </div>
    </div>
  );
}

// dual daily chart — revenue bars + orders line
function CDPerf({ series }) {
  const [hover, setHover] = React.useState(null);
  const maxRev = Math.max(...series.map(s=>s.rev), 1);
  const maxOrd = Math.max(...series.map(s=>s.orders), 1);
  return (
    <div style={{ position:'relative', height:150 }}>
      <div style={{ position:'absolute', inset:0, display:'flex', alignItems:'flex-end', gap:6 }}>
        {series.map((s,i)=>{
          const on = hover===i;
          return (
            <div key={i} onMouseEnter={()=>setHover(i)} onMouseLeave={()=>setHover(null)} style={{ flex:1, height:'100%', display:'flex', flexDirection:'column', justifyContent:'flex-end', alignItems:'center', position:'relative', cursor:'default' }}>
              {on && <div style={{ position:'absolute', bottom:`${s.rev/maxRev*82+6}%`, background:'var(--dark-chocolate)', color:'var(--dust-cream)', borderRadius:7, padding:'5px 8px', whiteSpace:'nowrap', zIndex:4, pointerEvents:'none' }}>
                <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11 }}>£{s.rev} · {s.orders} orders</div>
                <div style={{ fontFamily:'var(--font-body)', fontSize:9.5, color:'#B6A595' }}>Day {s.d}</div></div>}
              <div style={{ width:'100%', maxWidth:30, height:`${s.rev/maxRev*82}%`, background: on?'var(--brand-orange)':'rgba(216,90,20,0.34)', borderRadius:'4px 4px 0 0', transition:'background 150ms' }}/>
            </div>
          );
        })}
      </div>
      {/* orders line overlay */}
      <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ position:'absolute', inset:0, width:'100%', height:'100%', pointerEvents:'none', overflow:'visible' }}>
        <polyline points={series.map((s,i)=>`${(i+0.5)/series.length*100},${100-(s.orders/maxOrd*78)-8}`).join(' ')} fill="none" stroke="#2E8B4E" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke"/>
      </svg>
      <div style={{ position:'absolute', top:-2, right:0, display:'flex', gap:12 }}>
        <span style={{ display:'inline-flex', alignItems:'center', gap:4, fontFamily:'var(--font-body)', fontSize:10, color:'var(--warm-stone)' }}><span style={{ width:9, height:9, borderRadius:2, background:'rgba(216,90,20,0.6)' }}/>Revenue</span>
        <span style={{ display:'inline-flex', alignItems:'center', gap:4, fontFamily:'var(--font-body)', fontSize:10, color:'var(--warm-stone)' }}><span style={{ width:9, height:3, borderRadius:2, background:'#2E8B4E' }}/>Orders</span>
      </div>
    </div>
  );
}

// reach → views → orders funnel
function CDFunnel({ ops, c }) {
  const steps = [
    { label:'Impressions', value:ops.impressions, color:'#3E7CB0' },
    { label:'Menu views',  value:ops.views,       color:'#7A57C9' },
    { label:'Orders',      value:c.orders,         color:'#D85A14' },
  ];
  const max = steps[0].value;
  return (
    <div style={{ display:'flex', flexDirection:'column', gap:9 }}>
      {steps.map((s,i)=>(
        <div key={s.label}>
          <div style={{ display:'flex', justifyContent:'space-between', marginBottom:4 }}>
            <span style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>{s.label}</span>
            <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>{s.value.toLocaleString()}{i>0 && <span style={{ color:'var(--warm-stone)', fontWeight:600, fontSize:10.5 }}> · {Math.round(s.value/steps[i-1].value*100)}%</span>}</span>
          </div>
          <Bar pct={s.value/max*100} color={s.color} h={9}/>
        </div>
      ))}
    </div>
  );
}

// ─── Targeting modal — choose audience segments + estates, see reach ──
const TARGET_SEGMENTS = [
  { id:'new',     label:'New customers',     frac:0.31, desc:'never ordered from you' },
  { id:'repeat',  label:'Repeat customers',  frac:0.47, desc:'ordered 2+ times' },
  { id:'lapsed1', label:'Lapsed 14–30 days', frac:0.12, desc:'cooling off' },
  { id:'lapsed2', label:'Lapsed 30–60 days', frac:0.10, desc:'win-back window' },
  { id:'vip',     label:'VIP spenders',      frac:0.05, desc:'top 5% by spend' },
];
const DEFAULT_SEGS = {
  firstorder:['new'], dormant:['lapsed1','lapsed2'], family:['new','repeat'],
  freedeliv:['new','repeat'], lunch:['repeat'], newitem:['new','repeat'], highvalue:['vip'], payday:['repeat','new'],
};

function TargetingModal({ app, c, onClose, onApply }) {
  const homeEstate = ESTATES.find(e=>e.name===c.area) || ESTATES[0];
  const nearby = [...ESTATES].filter(e=>e.id!==homeEstate.id).sort((a,b)=>b.opportunity-a.opportunity).slice(0,4);
  const [segs, setSegs] = React.useState(()=>new Set(DEFAULT_SEGS[c.type]||['new','repeat']));
  const [estates, setEstates] = React.useState(()=>new Set([homeEstate.id]));
  const toggle = (set, setter, id)=> setter(prev=>{ const n=new Set(prev); n.has(id)?n.delete(id):n.add(id); return n; });

  const selEstates = ESTATES.filter(e=>estates.has(e.id));
  const segFrac = TARGET_SEGMENTS.filter(s=>segs.has(s.id)).reduce((a,s)=>a+s.frac,0);
  const reach = Math.round(selEstates.reduce((a,e)=>a+e.customers,0)*segFrac);
  const segNames = TARGET_SEGMENTS.filter(s=>segs.has(s.id)).map(s=>s.label.replace(/ customers| spenders/,'').replace('Lapsed ','lapsed '));
  const tighter = reach < c.reach*1.2;
  const valid = segs.size>0 && estates.size>0;

  const apply = ()=>{
    const segShort = segNames.length>2 ? `${segNames.slice(0,2).join(', ')} +${segNames.length-2}` : segNames.join(' & ');
    const estShort = selEstates.length>1 ? `${selEstates[0].name} +${selEstates.length-1}` : selEstates[0].name;
    onApply({ summary:`${segShort} · ${estShort}`, reach, segCount:segs.size, estCount:estates.size, tighter });
  };

  return (
    <div onClick={onClose} style={{ position:'fixed', inset:0, zIndex:340, background:'rgba(27,18,13,0.5)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'center', alignItems:'flex-start', padding:'40px 22px', overflowY:'auto', animation:'v-fade 180ms' }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:540, background:'var(--bg-surface)', borderRadius:20, boxShadow:'var(--shadow-lg)', overflow:'hidden', animation:'v-pop 240ms var(--ease-out)' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'16px 22px', borderBottom:'1px solid var(--soft-line)' }}>
          <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.target c="var(--brand-orange)" s={18}/></div>
            <div>
              <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:900, fontSize:17, color:'var(--fg-primary)' }}>Adjust targeting</h2>
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>Choose who sees {c.name}</div>
            </div>
          </div>
          <button onClick={onClose} 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={{ padding:'18px 22px', display:'flex', flexDirection:'column', gap:18 }}>
          {/* segments */}
          <div>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', marginBottom:9 }}>Customer segments</div>
            <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
              {TARGET_SEGMENTS.map(s=>{
                const on=segs.has(s.id);
                return (
                  <button key={s.id} onClick={()=>toggle(segs,setSegs,s.id)} style={{ display:'flex', alignItems:'center', gap:11, padding:'10px 13px', borderRadius:11, cursor:'pointer', textAlign:'left',
                    background: on?'var(--bg-warm)':'var(--bg-app)', border:'1px solid', borderColor: on?'var(--brand-orange)':'var(--soft-line)' }}>
                    <span style={{ width:20, height:20, borderRadius:6, border:'2px solid', borderColor: on?'var(--brand-orange)':'var(--soft-line)', background: on?'var(--brand-orange)':'transparent', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>{on && <I.check c="#fff" s={13}/>}</span>
                    <div style={{ flex:1 }}>
                      <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13, color:'var(--fg-primary)' }}>{s.label}</span>
                      <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}> · {s.desc}</span>
                    </div>
                    <span style={{ fontFamily:'var(--font-mono)', fontSize:10.5, color:'var(--warm-stone)' }}>{Math.round(s.frac*100)}%</span>
                  </button>
                );
              })}
            </div>
          </div>

          {/* estates */}
          <div>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', marginBottom:9 }}>Estates · tap to add</div>
            <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
              {[homeEstate, ...nearby].map(e=>{
                const on=estates.has(e.id); const es=NODE_STATE[e.state];
                return (
                  <button key={e.id} onClick={()=>toggle(estates,setEstates,e.id)} style={{ display:'inline-flex', alignItems:'center', gap:7, padding:'8px 12px', borderRadius:10, 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 }}>
                    <span style={{ width:8, height:8, borderRadius:'50%', background:es.fill, flexShrink:0 }}/>{e.name}
                    {e.id===homeEstate.id && <span style={{ fontFamily:'var(--font-body)', fontSize:9.5, opacity:0.7 }}>home</span>}
                    {on ? <I.check c={on?'var(--dust-cream)':'var(--brand-orange)'} s={13}/> : <I.plus c="var(--brand-orange)" s={13}/>}
                  </button>
                );
              })}
            </div>
          </div>

          {/* live reach */}
          <div style={{ display:'flex', alignItems:'center', gap:14, padding:'13px 15px', background: tighter?'rgba(62,124,176,0.08)':'rgba(46,139,78,0.09)', borderRadius:12 }}>
            <div style={{ flexShrink:0 }}>
              <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:26, color:'var(--fg-primary)', lineHeight:1 }}>{reach.toLocaleString()}</div>
              <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)' }}>people reached</div>
            </div>
            <div style={{ width:1, alignSelf:'stretch', background:'var(--soft-line)' }}/>
            <span style={{ flex:1, fontFamily:'var(--font-body)', fontSize:12, color:'var(--horse-brown)', lineHeight:1.45 }}>
              {segs.size} segment{segs.size!==1?'s':''} across {estates.size} estate{estates.size!==1?'s':''}. {tighter ? 'A tighter audience usually lifts conversion and lowers cost-per-order.' : 'A broader audience grows reach — watch cost-per-order as it scales.'}
            </span>
          </div>
        </div>

        <div style={{ display:'flex', alignItems:'center', justifyContent:'flex-end', gap:10, padding:'14px 22px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          <Btn kind="white" onClick={onClose}>Cancel</Btn>
          <Btn kind="accent" disabled={!valid} icon={<I.check c="#fff" s={16}/>} onClick={apply}>Apply targeting</Btn>
        </div>
      </div>
    </div>
  );
}

// ─── Photo upload modal — attach a hero image to the campaign offer ──
function PhotoUploadModal({ app, c, onClose, onSave }) {
  const [url, setUrl] = React.useState(null);
  const [drag, setDrag] = React.useState(false);
  const fileRef = React.useRef(null);
  const read = (f)=>{ if(!f || !/^image\//.test(f.type)) return; const r=new FileReader(); r.onload=()=>setUrl(r.result); r.readAsDataURL(f); };
  return (
    <div onClick={onClose} style={{ position:'fixed', inset:0, zIndex:340, background:'rgba(27,18,13,0.5)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'center', alignItems:'flex-start', padding:'52px 22px', overflowY:'auto', animation:'v-fade 180ms' }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:480, background:'var(--bg-surface)', borderRadius:20, boxShadow:'var(--shadow-lg)', overflow:'hidden', animation:'v-pop 240ms var(--ease-out)' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'16px 22px', borderBottom:'1px solid var(--soft-line)' }}>
          <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.image c="var(--brand-orange)" s={18}/></div>
            <div>
              <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:900, fontSize:17, color:'var(--fg-primary)' }}>Add a hero photo</h2>
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>for {c.hero}</div>
            </div>
          </div>
          <button onClick={onClose} 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={{ padding:'20px 22px' }}>
          <button onClick={()=>fileRef.current&&fileRef.current.click()}
            onDragOver={(e)=>{ e.preventDefault(); setDrag(true); }} onDragLeave={()=>setDrag(false)}
            onDrop={(e)=>{ e.preventDefault(); setDrag(false); read(e.dataTransfer.files&&e.dataTransfer.files[0]); }}
            style={{ width:'100%', aspectRatio:'16/10', borderRadius:14, cursor:'pointer', overflow:'hidden', position:'relative', padding:0,
              border: url?'1px solid var(--soft-line)':`1.5px dashed ${drag?'var(--brand-orange)':'var(--warm-stone)'}`, background: url?'#000':(drag?'var(--bg-warm)':'var(--bg-app)'),
              display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:9 }}>
            {url ? <img src={url} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/> : <>
              <I.image c="var(--warm-stone)" s={32}/>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13.5, color:'var(--fg-primary)' }}>Drop an image or click to upload</span>
              <span style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>JPG or PNG · landscape works best</span>
            </>}
          </button>
          <input ref={fileRef} type="file" accept="image/*" onChange={(e)=>read(e.target.files&&e.target.files[0])} style={{ display:'none' }}/>
          {url && <button onClick={()=>setUrl(null)} style={{ marginTop:9, background:'none', border:'none', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:700, fontSize:11.5, color:'var(--warm-stone)' }}>Choose a different photo</button>}
          <div style={{ marginTop:13, display:'flex', alignItems:'center', gap:8, padding:'9px 12px', background:'rgba(46,139,78,0.09)', borderRadius:10 }}>
            <I.trendUp c="#247a41" s={14}/>
            <span style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--horse-brown)' }}>Offers with a photo convert about <strong style={{ fontFamily:'var(--font-display)' }}>2× better</strong>.</span>
          </div>
        </div>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'flex-end', gap:10, padding:'14px 22px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          <Btn kind="white" onClick={onClose}>Cancel</Btn>
          <Btn kind="accent" disabled={!url} icon={<I.check c="#fff" s={16}/>} onClick={()=>onSave(url)}>Use this photo</Btn>
        </div>
      </div>
    </div>
  );
}

// ─── Customer preview — how the promo looks to a diner in the Lasso app ──
function offerPrice(offer, price){
  if(!price) return null;
  const pct = offer.match(/(\d+)\s*%/); if(pct) return +(price*(1-(+pct[1])/100)).toFixed(2);
  const off = offer.match(/£\s*(\d+)/); if(off) return Math.max(0, +(price-(+off[1])).toFixed(2));
  return null;
}
function offerBadge(offer){
  const pct = offer.match(/(\d+)\s*%/); if(pct) return pct[1]+'% OFF';
  const off = offer.match(/£\s*(\d+)/); if(off) return '£'+off[1]+' OFF';
  if(/free deliver/i.test(offer)) return 'FREE DELIVERY';
  return 'OFFER';
}

function CampaignPreview({ c, onAddPhoto }) {
  const heroItem = MENU.flatMap(x=>x.items).find(it=>it.name===c.hero);
  const price = heroItem ? heroItem.price : null;
  const now = price!=null ? offerPrice(c.offer, price) : null;
  const photo = c.heroPhoto || (heroItem && heroItem.photoUrl) || null;
  const badge = offerBadge(c.offer);
  const freeDeliv = /deliver/i.test(c.offer);
  const rating = (typeof REVIEWS!=='undefined' && REVIEWS.rating) || 4.6;

  return (
    <div style={{ marginBottom:20 }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:11 }}>
        <Eyebrow><I.users c="var(--brand-orange)" s={13}/> &nbsp;Customer preview</Eyebrow>
        <span style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)' }}>what diners see in {c.area}</span>
      </div>

      {/* phone-style backdrop */}
      <div style={{ background:'linear-gradient(160deg,#241812,#15100c)', borderRadius:16, padding:'18px 16px', display:'flex', gap:14, justifyContent:'center', flexWrap:'wrap' }}>
        {/* storefront listing card */}
        <div style={{ width:236, background:'#FFFCF8', borderRadius:15, overflow:'hidden', boxShadow:'0 10px 26px -8px rgba(0,0,0,0.5)' }}>
          <div style={{ position:'relative', height:124, background: photo?'#000':'linear-gradient(135deg,#F8A640,#D85A14)', display:'flex', alignItems:'center', justifyContent:'center' }}>
            {photo
              ? <img src={photo} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/>
              : <button onClick={onAddPhoto} style={{ background:'rgba(0,0,0,0.22)', border:'1px dashed rgba(255,255,255,0.6)', borderRadius:10, padding:'8px 12px', cursor:'pointer', display:'flex', flexDirection:'column', alignItems:'center', gap:4 }}>
                  <I.image c="#fff" s={20}/><span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, color:'#fff' }}>Add a photo</span>
                </button>}
            {/* promo ribbon */}
            <div style={{ position:'absolute', top:10, left:10, background:'var(--brand-orange)', color:'#fff', borderRadius:7, padding:'4px 9px', fontFamily:'var(--font-display)', fontWeight:900, fontSize:11, letterSpacing:'0.02em', boxShadow:'0 3px 8px rgba(216,90,20,0.5)' }}>{badge}</div>
            <div style={{ position:'absolute', top:9, right:9, width:26, height:26, borderRadius:'50%', background:'rgba(255,255,255,0.92)', display:'flex', alignItems:'center', justifyContent:'center' }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#C13B1F" strokeWidth="2.2"><path d="M12 21S4 14.5 4 8.8A4.2 4.2 0 0 1 12 6a4.2 4.2 0 0 1 8 2.8C20 14.5 12 21 12 21z"/></svg>
            </div>
          </div>
          <div style={{ padding:'11px 13px 13px' }}>
            <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:8 }}>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:14.5, color:'#1B120D' }}>Fire &amp; Dough</span>
              <span style={{ display:'inline-flex', alignItems:'center', gap:3, background:'#1B120D', color:'#fff', borderRadius:6, padding:'2px 6px', fontFamily:'var(--font-display)', fontWeight:800, fontSize:10.5 }}><I.star c="#F8A640" s={10}/>{rating}</span>
            </div>
            <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'#8A7A6C', marginTop:2 }}>Pizza · Wings · Loaded Fries</div>
            <div style={{ display:'flex', alignItems:'center', gap:7, marginTop:7, fontFamily:'var(--font-body)', fontSize:10.5, color:'#5C4A3D' }}>
              <span style={{ display:'inline-flex', alignItems:'center', gap:3 }}><I.clock c="#8A7A6C" s={11}/>25–35 min</span>
              <span style={{ color:'#D8CFC4' }}>·</span>
              <span style={{ color: freeDeliv?'#247a41':'#5C4A3D', fontWeight: freeDeliv?700:400, fontFamily: freeDeliv?'var(--font-display)':'var(--font-body)' }}>{freeDeliv?'Free delivery':'£1.99 delivery'}</span>
            </div>
            <div style={{ marginTop:10, display:'flex', alignItems:'center', gap:7, padding:'7px 10px', background:'rgba(216,90,20,0.1)', borderRadius:9 }}>
              <I.gift c="var(--brand-orange)" s={14}/>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'#c0500f' }}>{c.offer}</span>
            </div>
          </div>
        </div>

        {/* voucher tile */}
        <div style={{ width:206, background:'#FFFCF8', borderRadius:15, overflow:'hidden', boxShadow:'0 10px 26px -8px rgba(0,0,0,0.5)', display:'flex', flexDirection:'column' }}>
          <div style={{ background:'linear-gradient(135deg,#F28C1B,#C8430F)', padding:'16px 15px', color:'#fff', position:'relative' }}>
            <I.gift c="rgba(255,255,255,0.9)" s={20}/>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:22, lineHeight:1.05, marginTop:8 }}>{c.offer}</div>
            <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'rgba(255,255,255,0.85)', marginTop:4 }}>at Fire &amp; Dough · {c.area}</div>
            {/* perforation notches */}
            <span style={{ position:'absolute', bottom:-8, left:-8, width:16, height:16, borderRadius:'50%', background:'#15100c' }}/>
            <span style={{ position:'absolute', bottom:-8, right:-8, width:16, height:16, borderRadius:'50%', background:'#15100c' }}/>
          </div>
          <div style={{ padding:'13px 15px', borderTop:'2px dashed #E6DCD0', flex:1, display:'flex', flexDirection:'column' }}>
            {now!=null && price!=null ? (
              <div style={{ display:'flex', alignItems:'center', gap:8 }}>
                <div style={{ width:38, height:38, borderRadius:9, flexShrink:0, overflow:'hidden', background: photo?'#000':'linear-gradient(135deg,#E8956A,#C24A1E)' }}>{photo && <img src={photo} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/>}</div>
                <div style={{ minWidth:0 }}>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'#1B120D', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{c.hero}</div>
                  <div style={{ display:'flex', alignItems:'baseline', gap:6 }}>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:13, color:'#c0500f' }}>£{now.toFixed(2)}</span>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'#8A7A6C', textDecoration:'line-through' }}>£{price.toFixed(2)}</span>
                  </div>
                </div>
              </div>
            ) : (
              <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'#5C4A3D', lineHeight:1.4 }}>Applied automatically at checkout for eligible orders.</div>
            )}
            <button style={{ marginTop:'auto', width:'100%', marginTop:12, padding:'9px', borderRadius:9, border:'none', background:'#1B120D', color:'#fff', fontFamily:'var(--font-display)', fontWeight:800, fontSize:12, cursor:'default' }}>Order now</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function CampaignDetail({ app, c, onClose }) {
  const ct = CAMPAIGN_TYPES.find(t=>t.id===c.type);
  const CIcon = (ct && I[ct.icon]) || I.megaphone;
  const [ver, setVer] = React.useState(0);
  const [done, setDone] = React.useState({});   // title -> result line
  const [offerArea, setOfferArea] = React.useState(null);   // area awaiting A/B config
  const [budgetArea, setBudgetArea] = React.useState(null);  // area awaiting budget scale
  const [targetArea, setTargetArea] = React.useState(null);  // area awaiting targeting edit
  const [photoArea, setPhotoArea] = React.useState(null);    // area awaiting photo upload
  const ops = React.useMemo(()=>campaignOps(c), [c.id, ver]);
  const spentPct = Math.round(c.spend/c.budget*100);
  const topItemMax = Math.max(...ops.topItems.map(t=>t.share));
  const markDone = (a, result)=>{ setDone(d=>({ ...d, [a.title]:result })); };
  const doAction = (a, bulk)=>{
    if (a.kind==='extend'){
      c.total += 7; c.status='live'; c.ends='7 days left';
      markDone(a, `Extended to ${c.total} days · now live`); setVer(v=>v+1);
      app.toast(`“${c.name}” extended by 7 days`);
    } else if (a.kind==='budget'){
      if (bulk){ c.budget += 120; markDone(a, `Budget raised to £${c.budget}`); setVer(v=>v+1); app.toast(`Budget topped up +£120 → £${c.budget}`); }
      else setBudgetArea(a);
    } else if (a.kind==='photo'){
      if (bulk){ c.hasPhoto=true; const hero=MENU.flatMap(x=>x.items).find(it=>it.name===c.hero); if(hero) hero.photo=true; markDone(a, 'Hero photo attached'); setVer(v=>v+1); app.toast(`Photo added to “${c.hero}”`); }
      else setPhotoArea(a);
    } else if (a.kind==='edit' && /offer/i.test(a.action)){
      if (bulk){ c.abTest={ label:'Free delivery over £20', short:'Free delivery', splitB:50, days:7 }; markDone(a, 'A/B test live · Free delivery vs current'); setVer(v=>v+1); app.toast('A/B offer test launched'); }
      else setOfferArea(a);
    } else if (a.kind==='edit'){
      if (bulk){ c.audience='Tightened · lapsed 14–30d'; markDone(a, 'Audience tightened · lapsed 14–30d'); setVer(v=>v+1); app.toast('Targeting updated'); }
      else setTargetArea(a);
    } else if (a.kind==='clone'){
      const e=ESTATES.find(x=>x.name===c.area);
      onClose(); app.openBuilder(e?e.id:null);
    } else { markDone(a, 'Done'); app.toast(`${a.action}…`); }
  };
  const launchTest = (variant)=>{
    c.abTest = variant;
    if (offerArea) markDone(offerArea, `A/B test live · ${variant.short} vs current`);
    setOfferArea(null); setVer(v=>v+1);
    app.toast(`A/B test launched — ${variant.short} vs current`);
  };
  const confirmScale = (r)=>{
    c.budget = r.newBudget;
    c.scaled = { add:r.add, extraOrders:r.extraOrders, extraRev:r.extraRev };
    if (budgetArea) markDone(budgetArea, `+£${r.add} budget · projected +£${r.extraRev.toLocaleString()}`);
    setBudgetArea(null); setVer(v=>v+1);
    app.toast(`Scaled +£${r.add} → projected +${r.extraOrders} orders`);
  };
  const applyTargeting = (r)=>{
    c.audience = r.summary; c.targeting = r;
    if (targetArea) markDone(targetArea, `Audience set · ${r.reach.toLocaleString()} reached`);
    setTargetArea(null); setVer(v=>v+1);
    app.toast(`Targeting updated — ${r.reach.toLocaleString()} people, ${r.estCount} estate${r.estCount!==1?'s':''}`);
  };
  const applyPhoto = (dataUrl)=>{
    c.hasPhoto=true; c.heroPhoto=dataUrl;
    const hero=MENU.flatMap(x=>x.items).find(it=>it.name===c.hero); if(hero){ hero.photo=true; hero.photoUrl=dataUrl; }
    if (photoArea) markDone(photoArea, 'Hero photo added to the offer');
    setPhotoArea(null); setVer(v=>v+1);
    app.toast(`Photo added to “${c.hero}”`);
  };
  const daysLeftStr = ()=> `${Math.max(1,(c.total||7)-(c.elapsed||1))} days left`;
  const pause = ()=>{ c.status='paused'; setVer(v=>v+1); app.toast(`“${c.name}” paused — spend stopped`); };
  const resume = ()=>{ c.status='live'; c.ends=daysLeftStr(); setVer(v=>v+1); app.toast(`“${c.name}” resumed — back live`); };
  const endCampaign = ()=>{ c.status='ended'; c.ends='Ended'; setVer(v=>v+1); app.toast(`“${c.name}” ended`); };
  const reactivate = ()=>{ c.status='live'; c.ends=daysLeftStr(); setVer(v=>v+1); app.toast(`“${c.name}” reactivated — live again`); };
  const saveTemplateFromCampaign = ()=>{ const e=ESTATES.find(x=>x.name===c.area); CAMPAIGN_TEMPLATES.unshift({ id:'t'+Date.now().toString().slice(-6), name:c.name, typeId:c.type, estateId:e?e.id:'bletchley', budget:c.budget, duration:c.total||7, minOrder:0, newOnly:(c.newPct||0)>=70, copy:{}, lastUsed:`From “${c.name}”` }); app.toast(`Saved “${c.name}” to templates`); };

  return (
    <div onClick={onClose} style={{ position:'fixed', inset:0, zIndex:300, background:'rgba(27,18,13,0.46)', backdropFilter:'blur(3px)', display:'flex', justifyContent:'flex-end', animation:'v-fade 200ms' }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:560, height:'100%', background:'var(--bg-surface)', boxShadow:'var(--shadow-lg)', display:'flex', flexDirection:'column', animation:'v-slidein 280ms var(--ease-out)' }}>
        {/* header */}
        <div style={{ padding:'18px 24px 16px', borderBottom:'1px solid var(--soft-line)' }}>
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:13 }}>
            <Eyebrow>Campaign operations</Eyebrow>
            <button onClick={onClose} style={{ width:32, height:32, borderRadius:9, 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={16}/></button>
          </div>
          <div style={{ display:'flex', gap:14 }}>
            <div style={{ width:50, height:50, borderRadius:13, background:'var(--bg-warm)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}><CIcon c="var(--brand-orange)" s={24}/></div>
            <div style={{ flex:1, minWidth:0 }}>
              <h2 style={{ margin:'0 0 5px', fontFamily:'var(--font-display)', fontWeight:900, fontSize:20, color:'var(--fg-primary)', lineHeight:1.1 }}>{c.name}</h2>
              <div style={{ display:'flex', alignItems:'center', gap:8, flexWrap:'wrap' }}>
                <Pill tone={(CAMP_STATUS[c.status]||CAMP_STATUS.live).tone} dot>{(CAMP_STATUS[c.status]||CAMP_STATUS.live).label}</Pill>
                <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}><I.pin c="var(--warm-stone)" s={12}/> {c.area}</span>
                <span style={{ color:'var(--soft-line)' }}>·</span>
                <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>Day {c.elapsed} of {c.total}</span>
              </div>
            </div>
          </div>
          <div style={{ marginTop:13, display:'flex', gap:8, flexWrap:'wrap' }}>
            <span style={{ display:'inline-flex', alignItems:'center', gap:6, padding:'5px 10px', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:9, fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--horse-brown)' }}><I.gift c="var(--brand-orange)" s={13}/> {c.offer}</span>
            <span style={{ display:'inline-flex', alignItems:'center', gap:6, padding:'5px 10px', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:9, fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--horse-brown)' }}><I.users c="var(--warm-stone)" s={13}/> {c.audience}</span>
            {c.abTest && <Pill tone="purple" dot style={{ padding:'5px 10px', fontSize:11 }}>A/B test running</Pill>}
          </div>
          {c.heroPhoto && (
            <div style={{ marginTop:11, display:'flex', alignItems:'center', gap:11, padding:'9px 11px', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:11 }}>
              <div style={{ width:46, height:46, borderRadius:9, overflow:'hidden', flexShrink:0, background:'#000' }}><img src={c.heroPhoto} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/></div>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>Hero photo live</div>
                <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{c.hero} · shown on the offer</div>
              </div>
            </div>
          )}
          {c.abTest && (
            <div style={{ marginTop:11, display:'flex', alignItems:'center', gap:11, padding:'11px 13px', background:'rgba(122,87,201,0.08)', border:'1px solid rgba(122,87,201,0.25)', borderRadius:11 }}>
              <I.filter c="#6243ad" s={16}/>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>Testing: {c.abTest.short} <span style={{ color:'var(--warm-stone)', fontWeight:600 }}>vs current</span></div>
                <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{100-c.abTest.splitB}% A / {c.abTest.splitB}% B · {c.abTest.days}-day test · collecting results</div>
              </div>
              <button onClick={()=>{ c.abTest=null; setVer(v=>v+1); app.toast('A/B test stopped'); }} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, color:'#6243ad', background:'none', border:'none', cursor:'pointer' }}>Stop</button>
            </div>
          )}
        </div>

        {/* body */}
        <div style={{ flex:1, minHeight:0, overflowY:'auto', padding:'18px 24px 22px' }}>
          <CampaignPreview c={c} onAddPhoto={()=>setPhotoArea({ title:'__preview' })}/>
          {/* budget pacing */}
          <div style={{ marginBottom:18 }}>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:6 }}>
              <Eyebrow><I.pound c="var(--brand-orange)" s={13}/> &nbsp;Budget pacing</Eyebrow>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>£{c.spend} <span style={{ color:'var(--warm-stone)', fontWeight:600 }}>/ £{c.budget}</span></span>
            </div>
            <Bar pct={spentPct} color={spentPct>=90?'#E0992A':'var(--brand-orange)'} h={10}/>
            <div style={{ marginTop:7, fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)' }}>£{ops.dailyBurn}/day burn · {ops.daysLeft} day{ops.daysLeft!==1?'s':''} left · projected spend £{ops.projSpend}</div>
            {c.scaled && (
              <div style={{ marginTop:10, display:'flex', alignItems:'center', gap:10, padding:'10px 13px', background:'rgba(46,139,78,0.10)', border:'1px solid rgba(46,139,78,0.28)', borderRadius:11 }}>
                <I.trendUp c="#247a41" s={16}/>
                <span style={{ flex:1, fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--horse-brown)', lineHeight:1.4 }}>Scaled <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>+£{c.scaled.add}</strong> · projected <strong style={{ fontFamily:'var(--font-display)', color:'var(--fg-primary)' }}>+{c.scaled.extraOrders} orders / +£{c.scaled.extraRev.toLocaleString()}</strong> as new spend lands.</span>
              </div>
            )}
          </div>

          {/* ops KPI grid */}
          <Eyebrow style={{ marginBottom:11 }}>Operations</Eyebrow>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr 1fr', gap:10, marginBottom:18 }}>
            <CDStat value={`£${c.revenue.toLocaleString()}`} label="Revenue" accent="#247a41"/>
            <CDStat value={`${ops.roas}×`} label="ROAS" sub={`bench ${c.benchmarkRoi}×`} accent={c.roi>=c.benchmarkRoi?'#247a41':'#b0341a'}/>
            <CDStat value={c.orders} label="Orders" sub={`${ops.redemptions} redeemed`}/>
            <CDStat value={`£${ops.cpa}`} label="Cost / order"/>
            <CDStat value={`${ops.conv}%`} label="Conversion" sub={`bench ${ops.benchConv}%`} accent={ops.conv>=ops.benchConv?'#247a41':'#b0341a'}/>
            <CDStat value={`£${ops.aov}`} label="Campaign AOV"/>
            <CDStat value={ops.newCust} label="New customers" sub={`${c.newPct}% of orders`}/>
            <CDStat value={`£${ops.incremental.toLocaleString()}`} label="Incremental rev" sub="vs baseline"/>
          </div>

          {/* performance over time */}
          <div style={{ marginBottom:18 }}>
            <Eyebrow style={{ marginBottom:12 }}><I.trendUp c="var(--brand-orange)" s={13}/> &nbsp;Daily performance</Eyebrow>
            <CDPerf series={ops.series}/>
            <div style={{ display:'flex', justifyContent:'space-between', marginTop:5, fontFamily:'var(--font-mono)', fontSize:9.5, color:'var(--warm-stone)' }}><span>Day 1</span><span>Day {c.elapsed}</span></div>
          </div>

          {/* funnel + items */}
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:18, marginBottom:18 }}>
            <div>
              <Eyebrow style={{ marginBottom:12 }}><I.filter c="var(--brand-orange)" s={13}/> &nbsp;Conversion funnel</Eyebrow>
              <CDFunnel ops={ops} c={c}/>
            </div>
            <div>
              <Eyebrow style={{ marginBottom:12 }}><I.utensils c="var(--brand-orange)" s={13}/> &nbsp;Items driven</Eyebrow>
              <div style={{ display:'flex', flexDirection:'column', gap:9 }}>
                {ops.topItems.map((t,i)=>(
                  <div key={i} style={{ display:'flex', alignItems:'center', gap:9 }}>
                    <span style={{ flex:1, minWidth:0, fontFamily:'var(--font-display)', fontWeight:700, fontSize:11.5, color:'var(--fg-primary)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{t.name}</span>
                    <div style={{ width:42 }}><Bar pct={t.share/topItemMax*100} color="var(--brand-orange)" h={6}/></div>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11, color:'var(--fg-primary)', width:30, textAlign:'right' }}>{t.orders}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* areas for development */}
          <div style={{ background:'var(--bg-app)', borderRadius:14, padding:'16px 16px 6px', border:'1px solid var(--soft-line)' }}>
            <Eyebrow style={{ marginBottom:4 }}><I.zap c="var(--brand-orange)" s={13} f/> &nbsp;Areas for development</Eyebrow>
            {(()=>{ const openCount=ops.areas.filter(a=>!done[a.title]).length; return (
            <div style={{ fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)', marginBottom:13 }}>{openCount>0 ? `${openCount} way${openCount>1?'s':''} to get more from this campaign.` : 'All actions applied — nice work.'}</div>
            ); })()}
            {ops.areas.map((a,i)=>{
              const sv = CD_SEV[a.sev]; const AIcon = I[a.icon] || I.info;
              const res = done[a.title];
              return (
                <div key={i} style={{ display:'flex', gap:12, padding:'13px', background:'var(--bg-surface)', border:'1px solid', borderColor: res?'rgba(46,139,78,0.4)':'var(--soft-line)', borderRadius:12, marginBottom:10, opacity: res?0.92:1, transition:'border-color 200ms' }}>
                  <div style={{ width:34, height:34, borderRadius:9, background: res?'rgba(46,139,78,0.12)':sv.bg, display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>{res ? <I.check c="#247a41" s={18}/> : <AIcon c={sv.dot} s={17}/>}</div>
                  <div style={{ flex:1, minWidth:0 }}>
                    <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:3 }}>
                      <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13, color:'var(--fg-primary)', lineHeight:1.25 }}>{a.title}</span>
                    </div>
                    <p style={{ margin:'0 0 9px', fontFamily:'var(--font-body)', fontSize:11.5, color:'var(--warm-stone)', lineHeight:1.45 }}>{a.detail}</p>
                    <div style={{ display:'flex', alignItems:'center', gap:10 }}>
                      {res ? (
                        <span style={{ display:'inline-flex', alignItems:'center', gap:5, fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'#247a41' }}><I.check c="#247a41" s={13}/>{res}</span>
                      ) : (
                        <>
                          <Pill tone={sv.tone} dot style={{ fontSize:9.5, padding:'2px 7px' }}>{sv.label}</Pill>
                          <button onClick={()=>doAction(a)} style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:11.5, color:'var(--brand-orange)', background:'none', border:'none', cursor:'pointer', display:'inline-flex', alignItems:'center', gap:4 }}>{a.action} <I.arrow c="var(--brand-orange)" s={13}/></button>
                        </>
                      )}
                    </div>
                  </div>
                </div>
              );
            })}
            {(()=>{ const openAreas=ops.areas.filter(a=>!done[a.title]); return openAreas.length>1 ? (
              <button onClick={()=>openAreas.forEach(a=>{ if(a.kind!=='clone') doAction(a, true); })} style={{ width:'100%', margin:'2px 0 12px', padding:'11px', borderRadius:11, border:'1px dashed var(--brand-orange)', background:'rgba(216,90,20,0.06)', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--brand-orange)', display:'inline-flex', alignItems:'center', justifyContent:'center', gap:7 }}><I.zap c="var(--brand-orange)" s={15} f/> Apply all {openAreas.filter(a=>a.kind!=='clone').length} fixes</button>
            ) : null; })()}
          </div>
        </div>

        {/* footer */}
        <div style={{ display:'flex', flexDirection:'column', gap:10, padding:'14px 24px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          {c.status==='ended' ? (
            <Btn kind="accent" full icon={<I.play c="#fff" s={15}/>} onClick={reactivate}>Reactivate campaign</Btn>
          ) : c.status==='paused' ? (
            <div style={{ display:'flex', gap:10 }}>
              <Btn kind="accent" full icon={<I.play c="#fff" s={15}/>} onClick={resume}>Resume campaign</Btn>
              <Btn kind="white" icon={<I.stop c="#b0341a" s={15}/>} onClick={endCampaign}>End</Btn>
            </div>
          ) : (
            <div style={{ display:'flex', gap:10 }}>
              <Btn kind="white" full icon={<I.pause c="var(--fg-primary)" s={15}/>} onClick={pause}>Pause campaign</Btn>
              <Btn kind="white" icon={<I.stop c="#b0341a" s={15}/>} onClick={endCampaign}>End</Btn>
            </div>
          )}
          <div style={{ display:'flex', gap:10 }}>
            <Btn kind="white" full icon={<I.pound c="var(--fg-primary)" s={15}/>} onClick={()=>setBudgetArea({ title:'__editbudget' })}>Edit budget</Btn>
            <Btn kind="white" full icon={<I.bookmark c="var(--fg-primary)" s={15}/>} onClick={saveTemplateFromCampaign}>Save as template</Btn>
          </div>
        </div>
      </div>
      {offerArea && <OfferTestModal app={app} c={c} onClose={()=>setOfferArea(null)} onLaunch={launchTest}/>}
      {budgetArea && <BudgetScaleModal app={app} c={c} onClose={()=>setBudgetArea(null)} onConfirm={confirmScale}/>}
      {targetArea && <TargetingModal app={app} c={c} onClose={()=>setTargetArea(null)} onApply={applyTargeting}/>}
      {photoArea && <PhotoUploadModal app={app} c={c} onClose={()=>setPhotoArea(null)} onSave={applyPhoto}/>}
    </div>
  );
}

Object.assign(window, { CampaignDetail });
