// v-iteminsight.jsx — full item-insight slide-over (added date, performance
// since launch, top estates, inline edit) + estate ranking lookup view.

const II_MARGIN = { high:{tone:'green',label:'High margin'}, med:{tone:'amber',label:'Medium margin'}, low:{tone:'red',label:'Low margin'} };

// small weekly-orders area chart
function PerfChart({ series, color='var(--brand-orange)' }) {
  const [hover, setHover] = React.useState(null);
  const max = Math.max(...series, 1);
  const W = 100, H = 100;
  return (
    <div style={{ position:'relative', height:120 }}>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width:'100%', height:'100%', display:'block', overflow:'visible' }}>
        <defs><linearGradient id="ii-grad" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={color} stopOpacity="0.34"/><stop offset="100%" stopColor={color} stopOpacity="0"/></linearGradient></defs>
        {(()=>{ const pts=series.map((d,i)=>[ (i/(series.length-1||1))*W, H-(d/max)*(H-10)-4 ]);
          const line=pts.map(p=>p.join(',')).join(' ');
          const area=`0,${H} ${line} ${W},${H}`;
          return <><polygon points={area} fill="url(#ii-grad)"/><polyline points={line} fill="none" stroke={color} strokeWidth="1.6" strokeLinejoin="round" strokeLinecap="round" vectorEffect="non-scaling-stroke"/></>;
        })()}
      </svg>
      {/* hover hit areas */}
      <div style={{ position:'absolute', inset:0, display:'flex' }}>
        {series.map((d,i)=>(
          <div key={i} onMouseEnter={()=>setHover(i)} onMouseLeave={()=>setHover(null)} style={{ flex:1, position:'relative' }}>
            {hover===i && (
              <div style={{ position:'absolute', bottom:'100%', left:'50%', transform:'translateX(-50%)', marginBottom:4, background:'var(--dark-chocolate)', color:'var(--dust-cream)', borderRadius:7, padding:'4px 8px', whiteSpace:'nowrap', fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, pointerEvents:'none', zIndex:3 }}>{d} orders</div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

function IIStat({ value, label, sub }) {
  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:'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>
  );
}

const II_FLD = { width:'100%', boxSizing:'border-box', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:9, padding:'9px 11px', fontFamily:'var(--font-body)', fontSize:13, color:'var(--fg-primary)', outline:'none' };
const II_LBL = { fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', marginBottom:6, display:'block' };

function ItemInsightDrawer({ app, it, cat, onClose, onSave }) {
  const [editing, setEditing] = React.useState(false);
  const [assetsOpen, setAssetsOpen] = React.useState(false);
  const [, bumpVer] = React.useState(0);
  const [name, setName] = React.useState(it.name);
  const [price, setPrice] = React.useState(String(it.price));
  const [desc, setDesc] = React.useState(it.desc || '');
  const [margin, setMargin] = React.useState(it.margin);
  const [avail, setAvail] = React.useState(it.avail);
  const ins = React.useMemo(()=>itemInsights(it), [it.id]);
  const mtone = II_MARGIN[margin] || II_MARGIN.high;
  const addedStr = ins.added.toLocaleDateString('en-GB',{ day:'numeric', month:'short', year:'numeric' });
  const ageStr = ins.daysLive>=365 ? `${(ins.daysLive/365).toFixed(1)} yr` : `${ins.daysLive} days`;
  const topMax = Math.max(...ins.topEstates.map(e=>e.share));

  const save = ()=>{
    const p = parseFloat(price)||it.price;
    it.name = name.trim()||it.name; it.price = p; it.desc = desc.trim(); it.margin = margin; it.avail = avail;
    setEditing(false); onSave && onSave();
    app.toast(`“${it.name}” updated`);
  };

  return ReactDOM.createPortal(
    <div data-item-insight="" 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' }}>
      {assetsOpen && <AssetPanel app={app} it={it} onAssign={()=>{ bumpVer(v=>v+1); onSave && onSave(); }} onClose={()=>setAssetsOpen(false)}/>}
      <div onClick={(e)=>e.stopPropagation()} style={{ width:'100%', maxWidth:500, height:'100%', background:'var(--bg-surface)', boxShadow:'var(--shadow-lg)', display:'flex', flexDirection:'column', animation:'v-slidein 280ms var(--ease-out)' }}>
        {/* header */}
        <div style={{ position:'relative', padding:'18px 22px 16px', borderBottom:'1px solid var(--soft-line)' }}>
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:14 }}>
            <Eyebrow>Item insight</Eyebrow>
            <button data-item-insight-close="" 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={{ display:'flex', flexDirection:'column', alignItems:'center', gap:6, flexShrink:0 }}>
              <div style={{ width:64, height:64, borderRadius:13, overflow:'hidden', background: it.photoUrl?'#000': it.photo?'linear-gradient(135deg,#E8956A,#C24A1E)':'repeating-linear-gradient(135deg,#EDE3D6,#EDE3D6 5px,#E3D7C6 5px,#E3D7C6 10px)', display:'flex', alignItems:'center', justifyContent:'center' }}>
                {it.photoUrl ? <img src={it.photoUrl} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/> : !it.photo && <I.image c="#B6A595" s={22}/>}
              </div>
              <button data-item-insight-edit-image="" onClick={()=>setAssetsOpen(o=>!o)} style={{ display:'inline-flex', alignItems:'center', gap:4, padding:'3px 8px', borderRadius:8, border:'1px solid var(--soft-line)', background: assetsOpen?'var(--bg-warm)':'var(--bg-app)', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, color:'var(--fg-primary)', whiteSpace:'nowrap' }}>
                <I.image c="var(--brand-orange)" s={11}/> Edit image
              </button>
            </div>
            <div style={{ flex:1, minWidth:0 }}>
              {editing ? (
                <input value={name} onChange={e=>setName(e.target.value)} style={{ ...II_FLD, fontFamily:'var(--font-display)', fontWeight:800, fontSize:16, padding:'7px 10px', marginBottom:7 }}/>
              ) : (
                <h2 style={{ margin:'0 0 5px', fontFamily:'var(--font-display)', fontWeight:900, fontSize:20, color:'var(--fg-primary)', lineHeight:1.1 }}>{it.name}</h2>
              )}
              <div style={{ display:'flex', alignItems:'center', gap:7, flexWrap:'wrap' }}>
                <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>{cat}</span>
                <span style={{ color:'var(--soft-line)' }}>·</span>
                <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:14, color:'var(--fg-primary)' }}>£{(parseFloat(price)||it.price).toFixed(2)}</span>
                {it.best && <Pill tone="orange" icon={<I.flame c="#c0500f" s={10} f/>} style={{ fontSize:9.5, padding:'2px 6px' }}>Best seller</Pill>}
                <Pill tone={mtone.tone} style={{ fontSize:9.5, padding:'2px 7px' }}>{mtone.label}</Pill>
                {avail ? <Pill tone="green" dot style={{ fontSize:9.5, padding:'2px 7px' }}>Available</Pill> : <Pill tone="red" dot style={{ fontSize:9.5, padding:'2px 7px' }}>Off</Pill>}
              </div>
            </div>
          </div>
          <div style={{ marginTop:13, display:'flex', alignItems:'center', gap:7, fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)' }}>
            <I.calendar c="var(--warm-stone)" s={14}/> Added <strong style={{ color:'var(--fg-primary)', fontFamily:'var(--font-display)' }}>{addedStr}</strong> · live for {ageStr}
            {it.isNew && <Pill tone="blue" style={{ fontSize:9.5, padding:'2px 7px' }}>New</Pill>}
          </div>
        </div>

        {/* body */}
        <div style={{ flex:1, minHeight:0, overflowY:'auto', padding:'18px 22px 22px' }}>
          {editing ? (
            <div style={{ display:'flex', flexDirection:'column', gap:16 }}>
              <div style={{ display:'flex', gap:14 }}>
                <div style={{ flex:1 }}>
                  <span style={II_LBL}>Price</span>
                  <div style={{ position:'relative' }}>
                    <span style={{ position:'absolute', left:11, top:'50%', transform:'translateY(-50%)', fontFamily:'var(--font-display)', fontWeight:800, fontSize:13, color:'var(--warm-stone)' }}>£</span>
                    <input value={price} onChange={e=>setPrice(e.target.value.replace(/[^0-9.]/g,''))} inputMode="decimal" style={{ ...II_FLD, paddingLeft:24 }}/>
                  </div>
                </div>
                <div style={{ flex:1.4 }}>
                  <span style={II_LBL}>Profit margin</span>
                  <Segmented size="sm" options={[{value:'low',label:'Low'},{value:'med',label:'Med'},{value:'high',label:'High'}]} value={margin} onChange={setMargin}/>
                </div>
              </div>
              <div>
                <span style={II_LBL}>Description</span>
                <textarea value={desc} onChange={e=>setDesc(e.target.value)} rows={3} maxLength={140} placeholder="Short, appetising description…" style={{ ...II_FLD, resize:'vertical', lineHeight:1.45 }}/>
              </div>
              <div onClick={()=>setAvail(v=>!v)} role="button" style={{ display:'flex', alignItems:'center', gap:12, padding:'12px 14px', background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:12, cursor:'pointer' }}>
                <Toggle on={avail} onChange={()=>setAvail(v=>!v)} color="var(--live-green)"/>
                <div style={{ flex:1 }}>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'var(--fg-primary)' }}>Available to order</div>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{avail?'Customers can order this now':'Hidden from the menu'}</div>
                </div>
              </div>
            </div>
          ) : (
            <>
              {/* lifetime stats */}
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:10, marginBottom:18 }}>
                <IIStat value={ins.lifeOrders.toLocaleString()} label="Orders since launch"/>
                <IIStat value={`£${ins.lifeRev.toLocaleString()}`} label="Revenue since launch"/>
                <IIStat value={`${ins.ordersPerWeek}/wk`} label="Orders per week" sub={`avg ${ins.avgWeek}`}/>
                <IIStat value={ins.rating.toFixed(1)} label="Avg item rating" sub="★ from reviews"/>
                <IIStat value={`${ins.reorder}%`} label="From repeat buyers"/>
                <IIStat value={`${ins.attach}%`} label="Attach rate" sub="ordered w/ extras"/>
              </div>

              {/* performance since */}
              <div style={{ marginBottom:18 }}>
                <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:10 }}>
                  <Eyebrow><I.trendUp c="var(--brand-orange)" s={13}/> &nbsp;Performance since launch</Eyebrow>
                  <Trend dir={it.trendDir} pct={it.trendPct} size={12}/>
                </div>
                <PerfChart series={ins.series} color={it.trendDir==='down'?'#C13B1F':'#2E8B4E'}/>
                <div style={{ display:'flex', justifyContent:'space-between', marginTop:4, fontFamily:'var(--font-mono)', fontSize:9.5, color:'var(--warm-stone)' }}>
                  <span>{ins.series.length} weeks ago</span><span>this week</span>
                </div>
              </div>

              {/* top estates */}
              <div style={{ marginBottom:6 }}>
                <Eyebrow style={{ marginBottom:11 }}><I.pin c="var(--brand-orange)" s={13}/> &nbsp;Where it sells best</Eyebrow>
                {ins.topEstates.map((e,i)=>(
                  <div key={e.id} onClick={()=>{ app.setSelected(e.id); onClose(); app.nav('map'); }} style={{ display:'flex', alignItems:'center', gap:11, padding:'8px 0', borderBottom: i<ins.topEstates.length-1?'1px solid var(--soft-line)':'none', cursor:'pointer' }}>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:12, color:'var(--warm-stone)', width:14, textAlign:'center' }}>{i+1}</span>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'var(--fg-primary)', flex:1, minWidth:0, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{e.name}</span>
                    <div style={{ width:90 }}><Bar pct={e.share/topMax*100} color="var(--brand-orange)" h={6}/></div>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)', width:34, textAlign:'right' }}>{e.share}%</span>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>

        {/* footer */}
        <div style={{ display:'flex', alignItems:'center', gap:10, padding:'14px 22px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-app)' }}>
          {editing ? (
            <>
              <Btn kind="white" onClick={()=>{ setEditing(false); setName(it.name); setPrice(String(it.price)); setDesc(it.desc||''); setMargin(it.margin); setAvail(it.avail); }}>Cancel</Btn>
              <Btn kind="accent" full icon={<I.check c="#fff" s={16}/>} onClick={save}>Save changes</Btn>
            </>
          ) : (
            <>
              <Btn kind="white" icon={<I.settings c="var(--fg-primary)" s={15}/>} onClick={()=>setEditing(true)}>Edit details</Btn>
              <Btn kind="accent" full icon={<I.rocket c="#fff" s={16}/>} onClick={()=>{ onClose(); app.openBuilder(null, it); }}>Promote this item</Btn>
            </>
          )}
        </div>
      </div>
    </div>,
    document.body
  );
}

// ─── Estate ranking lookup ───────────────────────────────────────────
function EstateRankingView({ app }) {
  const [q, setQ] = React.useState('');
  const [estId, setEstId] = React.useState('central');
  const [openList, setOpenList] = React.useState(false);
  const est = ESTATES.find(e=>e.id===estId) || ESTATES[0];
  const matches = ESTATES.filter(e=>e.name.toLowerCase().includes(q.toLowerCase()));
  const ranked = React.useMemo(()=>estateTopItems(est, 8), [estId]);
  const s = NODE_STATE[est.state];
  const topShare = Math.max(...ranked.map(r=>r.share));
  const estOrders = ranked.reduce((sum,r)=>sum+r.orders,0);

  return (
    <Card pad={0} style={{ overflow:'hidden' }}>
      <div style={{ padding:'18px 22px', borderBottom:'1px solid var(--soft-line)', display:'flex', alignItems:'flex-end', justifyContent:'space-between', gap:16, flexWrap:'wrap' }}>
        <div style={{ flex:1, minWidth:240 }}>
          <Eyebrow style={{ marginBottom:8 }}><I.trophy c="var(--brand-orange)" s={13}/> &nbsp;Top orders by estate</Eyebrow>
          <div style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--warm-stone)', lineHeight:1.45, maxWidth:440 }}>Type an estate to see what its customers order most from you — rank, share of orders and where to push next.</div>
        </div>
        {/* estate search */}
        <div style={{ position:'relative', width:260 }}>
          <div style={{ display:'flex', alignItems:'center', gap:8, background:'var(--bg-app)', border:'1px solid var(--soft-line)', borderRadius:11, padding:'9px 12px' }}>
            <I.search c="var(--warm-stone)" s={16}/>
            <input value={openList?q:est.name} onChange={e=>{ setQ(e.target.value); setOpenList(true); }} onFocus={()=>{ setQ(''); setOpenList(true); }} placeholder="Search estate…"
              style={{ flex:1, border:'none', background:'transparent', outline:'none', fontFamily:'var(--font-display)', fontWeight:700, fontSize:13.5, color:'var(--fg-primary)', minWidth:0 }}/>
            <I.chevD c="var(--warm-stone)" s={15}/>
          </div>
          {openList && (
            <>
              <div onClick={()=>setOpenList(false)} style={{ position:'fixed', inset:0, zIndex:40 }}/>
              <div style={{ position:'absolute', top:'calc(100% + 6px)', left:0, right:0, maxHeight:260, overflowY:'auto', background:'var(--bg-surface)', border:'1px solid var(--soft-line)', borderRadius:12, boxShadow:'var(--shadow-lg)', zIndex:41, padding:6 }}>
                {(matches.length?matches:ESTATES).sort((a,b)=>b.opportunity-a.opportunity).map(e=>{
                  const es = NODE_STATE[e.state];
                  return (
                    <button key={e.id} onClick={()=>{ setEstId(e.id); setOpenList(false); setQ(''); }} style={{ width:'100%', display:'flex', alignItems:'center', gap:10, padding:'9px 10px', borderRadius:9, border:'none', cursor:'pointer', background: e.id===estId?'var(--bg-warm)':'transparent', textAlign:'left' }}>
                      <span style={{ width:9, height:9, borderRadius:'50%', background:es.fill, flexShrink:0 }}/>
                      <span style={{ flex:1, fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'var(--fg-primary)' }}>{e.name}</span>
                      <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--warm-stone)' }}>{e.customers.toLocaleString()} cust.</span>
                    </button>
                  );
                })}
              </div>
            </>
          )}
        </div>
      </div>

      {/* estate summary strip */}
      <div style={{ display:'flex', gap:24, padding:'14px 22px', background:'var(--bg-app)', borderBottom:'1px solid var(--soft-line)', flexWrap:'wrap' }}>
        <div style={{ display:'flex', alignItems:'center', gap:9 }}>
          <span style={{ width:11, height:11, borderRadius:'50%', background:s.fill }}/>
          <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:16, color:'var(--fg-primary)' }}>{est.name}</span>
          <Pill tone={est.state==='grey'?'grey':est.state}>{s.label}</Pill>
        </div>
        {[['Active customers',est.customers.toLocaleString()],['Want your cuisine',est.interest],['Your influence',est.influence+'%'],['Avg order','£'+((est.aov[0]+est.aov[1])/2).toFixed(0)],['Est. orders/mo','~'+estOrders]].map(([l,v])=>(
          <div key={l}>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:16, color:'var(--fg-primary)', lineHeight:1 }}>{v}</div>
            <div style={{ fontFamily:'var(--font-body)', fontSize:10.5, color:'var(--warm-stone)', marginTop:2 }}>{l}</div>
          </div>
        ))}
      </div>

      {/* ranked items */}
      <div style={{ display:'grid', gridTemplateColumns:'0.5fr 2.4fr 1.4fr 1fr 1fr', gap:12, padding:'10px 22px', borderBottom:'1px solid var(--soft-line)' }}>
        {['#','Item','Share of orders','Orders/mo','Trend'].map((h,i)=>(
          <span key={h} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--warm-stone)', textAlign:i===4?'right':'left' }}>{h}</span>
        ))}
      </div>
      {ranked.map((r,i)=>(
        <div key={r.item.id} style={{ display:'grid', gridTemplateColumns:'0.5fr 2.4fr 1.4fr 1fr 1fr', gap:12, alignItems:'center', padding:'12px 22px', borderBottom: i<ranked.length-1?'1px solid var(--soft-line)':'none' }}>
          <span style={{ fontFamily:'var(--font-display)', fontWeight:900, fontSize:15, color: i===0?'var(--brand-orange)':'var(--warm-stone)' }}>{r.rank}</span>
          <div style={{ display:'flex', alignItems:'center', gap:9, minWidth:0 }}>
            <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:13.5, color:'var(--fg-primary)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{r.item.name}</span>
            {r.item.best && <I.flame c="var(--brand-orange)" s={13} f/>}
          </div>
          <div style={{ display:'flex', alignItems:'center', gap:9 }}>
            <div style={{ flex:1, maxWidth:90 }}><Bar pct={r.share/topShare*100} color="var(--brand-orange)" h={7}/></div>
            <span style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:12.5, color:'var(--fg-primary)' }}>{r.share}%</span>
          </div>
          <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'var(--fg-primary)' }}>{r.orders}</span>
          <div style={{ textAlign:'right' }}><Trend dir={r.item.trendDir} pct={r.item.trendPct} size={11}/></div>
        </div>
      ))}

      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:14, padding:'14px 22px', background:'var(--bg-app)' }}>
        <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--warm-stone)', display:'inline-flex', alignItems:'center', gap:7 }}>
          <I.zap c="var(--brand-orange)" s={14} f/> Push <strong style={{ color:'var(--fg-primary)', fontFamily:'var(--font-display)' }}>{ranked[0].item.name}</strong> to win more share in {est.name}.
        </span>
        <Btn kind="accent" size="sm" icon={<I.rocket c="#fff" s={15}/>} onClick={()=>app.openBuilder(est.id, ranked[0].item)}>Build campaign</Btn>
      </div>
    </Card>
  );
}

// ─── Left asset panel — pick or upload an image for a menu item ──────
// Uploads go to the private lasso-media bucket (validated). Assigning an
// asset to an item needs the media-ownership link contract — marked pending.
function AssetPanel({ app, it, onAssign, onClose }) {
  const [assets, setAssets] = React.useState(MEDIA_ASSETS.filter(a=>a.status!=='archived'));
  const fileRef = React.useRef(null);
  const addFiles = (files) => {
    const list = Array.from(files||[]).filter(f=>f.type.startsWith('image/'));
    if (!list.length) { app.toast('Choose image files (JPG / PNG / WebP)'); return; }
    list.forEach(f=>{
      const id = 'md-'+Math.random().toString(16).slice(2,6);
      const url = URL.createObjectURL(f);
      setAssets(a=>[{ id, name:f.name, kind:'Item photo', size:Math.round(f.size/1024)+' KB', path:'fd-2841/menu/'+f.name, status:'uploading', url }, ...a]);
      setTimeout(()=> setAssets(a=>a.map(x=>x.id===id?{...x,status:'live'}:x)), 1600);
    });
    app.toast('Uploading to your private media bucket…');
  };
  const assign = (a) => {
    if (a.status!=='live') { app.toast('Still processing — one moment'); return; }
    it.photoUrl = a.url || null; it.photo = true;
    onAssign();
    app.toast(`“${a.name}” selected — item-image assignment persists once the ownership contract lands`);
  };
  return (
    <div data-asset-panel="left" onClick={e=>e.stopPropagation()} style={{ width:320, height:'100%', background:'var(--bg-app)', borderRight:'1px solid var(--soft-line)', boxShadow:'-18px 0 40px -22px rgba(27,18,13,0.5)', display:'flex', flexDirection:'column', animation:'v-fade 220ms ease-out' }}>
      <div style={{ padding:'18px 18px 14px', borderBottom:'1px solid var(--soft-line)', background:'var(--bg-surface)' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:5 }}>
          <div style={{ display:'flex', alignItems:'center', gap:8 }}>
            <Eyebrow><I.image c="var(--brand-orange)" s={13}/> &nbsp;Assets</Eyebrow>
            <Wire kind="partial"/>
          </div>
          <button onClick={onClose} style={{ width:28, height:28, borderRadius:8, 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={14}/></button>
        </div>
        <div style={{ fontFamily:'var(--font-mono)', fontSize:10, color:'var(--warm-stone)', marginBottom:12 }}>lasso-media / fd-2841 · private bucket</div>
        <span data-asset-upload="">
          <input ref={fileRef} type="file" accept="image/*" multiple style={{ display:'none' }} onChange={e=>{ addFiles(e.target.files); e.target.value=''; }}/>
          <Btn kind="accent" full size="sm" icon={<I.plus c="#fff" s={14}/>} onClick={()=>fileRef.current && fileRef.current.click()}>Upload asset</Btn>
        </span>
      </div>
      <div data-asset-grid="" style={{ flex:1, minHeight:0, overflowY:'auto', padding:14, display:'grid', gridTemplateColumns:'1fr 1fr', gap:10, alignContent:'start' }}>
        {assets.map(a=>(
          <div key={a.id} onClick={()=>assign(a)} role="button" title={a.path} style={{ borderRadius:12, overflow:'hidden', border:'1px solid var(--soft-line)', background:'var(--bg-surface)', cursor:'pointer' }}>
            <div style={{ height:76, background: a.url?'#000':'linear-gradient(135deg,#E8956A,#C24A1E)', display:'flex', alignItems:'center', justifyContent:'center', position:'relative' }}>
              {a.url ? <img src={a.url} alt="" style={{ width:'100%', height:'100%', objectFit:'cover' }}/> : <I.image c="rgba(255,255,255,0.75)" s={22}/>}
              {a.status!=='live' && (
                <span style={{ position:'absolute', inset:0, background:'rgba(27,18,13,0.55)', display:'flex', alignItems:'center', justifyContent:'center' }}>
                  <span style={{ display:'inline-flex', animation:'v-spin 900ms linear infinite' }}><I.refresh c="#fff" s={16}/></span>
                </span>
              )}
            </div>
            <div style={{ padding:'7px 9px 8px' }}>
              <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10.5, color:'var(--fg-primary)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{a.name}</div>
              <div style={{ fontFamily:'var(--font-body)', fontSize:9, color:'var(--warm-stone)', marginTop:2 }}>{a.kind} · {a.size}</div>
            </div>
          </div>
        ))}
      </div>
      <div style={{ padding:'10px 14px', borderTop:'1px solid var(--soft-line)', background:'var(--bg-surface)', display:'flex', gap:7, alignItems:'flex-start' }}>
        <I.info c="var(--warm-stone)" s={12}/>
        <span style={{ fontFamily:'var(--font-body)', fontSize:10, lineHeight:1.5, color:'var(--warm-stone)' }}>Uploads are live to your private bucket. Item-image <em>assignment</em> is pending the media-ownership contract — selection previews locally, honestly labelled.</span>
      </div>
    </div>
  );
}

Object.assign(window, { ItemInsightDrawer, EstateRankingView, AssetPanel });
