/* ============================================================
   basket.fun — Portfolio / Position + Sell flow + Activity
   ============================================================ */

function sellStepCopy(stepType) {
  const map = {
    units_locked: ['Units locked', 'Backend reserved the units being sold'],
    exit_plan_created: ['Exit plan created', 'Sell routes prepared from live basket holdings'],
    solana_assets_selling: ['Selling Solana assets', 'Jupiter routes are executing'],
    base_assets_selling: ['Selling Base assets', '0x routes are executing'],
    cctp_base_to_solana_burn: ['CCTP burn', 'Moving Base proceeds to Solana'],
    cctp_base_to_solana_attestation_received: ['CCTP attestation', 'Waiting for Circle Iris attestation'],
    cctp_solana_minted: ['Solana USDC minted', 'Base proceeds arrived on Solana'],
    sell_fee_taken: ['Fee taken', 'KOL/platform fee accounted in USDC'],
    solana_usdc_paid_to_user: ['USDC paid out', 'Funds sent to the user wallet'],
    units_burned: ['Units burned', 'Position units reduced'],
    sell_settled: ['Sale settled', 'Final sell accounting complete'],
  };
  return map[stepType] || [stepType.replaceAll('_', ' '), 'Backend execution step'];
}

function LiveSellExecuting({ order, onDone }) {
  const orderId = order && order.order_id;
  const [remoteOrder, setRemoteOrder] = useState(order || null);
  const [steps, setSteps] = useState([]);
  const [transactions, setTransactions] = useState([]);
  const [fills, setFills] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!orderId || !window.BasketAPI) return;
    let stop = false;
    const poll = async () => {
      try {
        const [nextOrder, nextSteps, nextTransactions, nextFills] = await Promise.all([
          window.BasketAPI.order(orderId),
          window.BasketAPI.orderSteps(orderId),
          window.BasketAPI.orderTransactions(orderId).catch(() => ({ items: [] })),
          window.BasketAPI.orderFills(orderId).catch(() => ({ items: [] })),
        ]);
        if (stop) return;
        setRemoteOrder(nextOrder);
        setSteps(nextSteps || []);
        setTransactions((nextTransactions && nextTransactions.items) || []);
        setFills((nextFills && nextFills.items) || []);
        setError(null);
        if (nextOrder && nextOrder.status === 'settled') setTimeout(onDone, 700);
      } catch (e) {
        if (!stop) setError(e.message || 'Could not read sell order status');
      }
    };
    poll();
    const id = setInterval(poll, 3000);
    return () => { stop = true; clearInterval(id); };
  }, [orderId]);

  const shown = steps.length ? steps : [
    { step_type: 'units_locked', status: 'done' },
    { step_type: 'exit_plan_created', status: 'pending' },
  ];
  const doneCount = shown.filter(s => s.status === 'done').length;
  const activeIndex = Math.max(0, shown.findIndex(s => s.status !== 'done'));
  const pct = Math.min(100, Math.round((doneCount / Math.max(1, shown.length)) * 100));
  const status = (remoteOrder && remoteOrder.status) || (order && order.status);

  return (
    <div style={{ animation: 'fadeIn .3s ease .06s forwards' }}>
      <div style={{ textAlign: 'center', marginBottom: 22 }}>
        <div style={{ width: 52, height: 52, borderRadius: 99, margin: '0 auto 12px', background: 'var(--blue-wash)', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid rgba(107,127,255,0.3)' }}><Icon name="swap2" size={24} color="var(--blue)" /></div>
        <h3 style={{ margin: 0, fontSize: 19, fontWeight: 700 }}>Sell order submitted</h3>
        <div className="tnum" style={{ fontSize: 12.5, color: 'var(--text-3)', marginTop: 6 }}>{status}</div>
      </div>
      <div style={{ height: 6, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden', marginBottom: 20 }}>
        <div style={{ width: pct + '%', height: '100%', background: 'linear-gradient(90deg, var(--blue), var(--accent))', borderRadius: 99, transition: 'width .6s ease' }} />
      </div>
      {shown.map((s, i) => {
        const [title, desc] = sellStepCopy(s.step_type);
        const state = s.status === 'done' ? 'done' : i === activeIndex ? 'active' : 'pending';
        return <ExecStep key={s.id || s.step_type} step={{ title, desc: s.last_error || desc, note: state === 'active' ? status : '', last: i === shown.length - 1 }} state={state} />;
      })}
      <OrderChainActivity transactions={transactions} fills={fills} />
      {error && (
        <div style={{ display: 'flex', gap: 9, background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.28)', borderRadius: 12, padding: '11px 13px' }}>
          <Icon name="info" size={15} color="var(--danger)" style={{ marginTop: 1, flexShrink: 0 }} />
          <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>{error}</span>
        </div>
      )}
    </div>
  );
}

function SellModal({ b, position, onClose, onConfirm, auth, dataState, onConnectWallet }) {
  const [pct, setPct] = useState(40);
  const [stage, setStage] = useState('form'); // form | executing | done
  const [quote, setQuote] = useState(null);
  const [quoteState, setQuoteState] = useState({ loading: false, error: null });
  const [order, setOrder] = useState(null);
  const [orderError, setOrderError] = useState(null);
  const [submitting, setSubmitting] = useState(false);
  const live = position.source === 'api' && window.BasketAPI;
  const sellFractionBps = Math.max(1, Math.min(10_000, Math.round(pct * 100)));
  const sellUnits = quote ? +quote.units_to_burn : position.units * pct / 100;
  const gross = quote ? +quote.estimated_gross_usdc : position.value * pct / 100;
  const fee = quote ? +quote.estimated_fee_usdc : gross * b.buyFee / 100;
  const estSlip = live ? 0 : gross * (b.chainSplit.base > 0 ? 0.004 : 0.0022);
  const receive = quote ? +quote.estimated_user_receives_usdc : gross - fee - estSlip;
  const [active, setActive] = useState(0);
  const steps = ['Quote locked', 'Selling underlying', b.chainSplit.base > 0 ? 'Bridging to Solana' : null, 'Settling USDC'].filter(Boolean);
  const authWallet = auth && auth.wallet;
  const hasSolanaWallet = Boolean(
    (dataState && dataState.hasSolanaWallet) ||
    (authWallet && authWallet.chain === 'solana')
  );
  const needsSolanaWallet = live && !hasSolanaWallet;

  useEffect(() => {
    if (!live || stage !== 'form') return;
    let stop = false;
    setQuoteState({ loading: true, error: null });
    const id = setTimeout(async () => {
      try {
        const next = await window.BasketAPI.sellQuote(position, sellFractionBps);
        if (!stop) {
          setQuote(next);
          setQuoteState({ loading: false, error: null });
        }
      } catch (e) {
        if (!stop) {
          setQuote(null);
          setQuoteState({ loading: false, error: e.message || 'Sell quote failed' });
        }
      }
    }, 250);
    return () => { stop = true; clearTimeout(id); };
  }, [live, stage, position.id, sellFractionBps]);

  const submitSell = async () => {
    setOrderError(null);
    if (!live) {
      setStage('executing');
      return;
    }
    if (needsSolanaWallet) {
      setOrderError('Link a Solana wallet first. Sell payouts settle in Solana USDC.');
      return;
    }
    setSubmitting(true);
    try {
      const created = await window.BasketAPI.createSellOrder(position, sellFractionBps);
      setOrder(created);
      setStage('executing');
    } catch (e) {
      setOrderError(e.message || 'Could not create sell order');
    } finally {
      setSubmitting(false);
    }
  };

  useEffect(() => {
    if (stage !== 'executing') return;
    if (live) return;
    if (active >= steps.length) { const t = setTimeout(() => setStage('done'), 600); return () => clearTimeout(t); }
    const t = setTimeout(() => setActive(a => a + 1), active === 0 ? 800 : 1300);
    return () => clearTimeout(t);
  }, [stage, active, live]);

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 80, background: 'rgba(5,6,11,0.72)', backdropFilter: 'blur(6px)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24, animation: 'fadeIn .2s ease .06s forwards' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 440, background: 'var(--surface)', border: '1px solid var(--line-2)', borderRadius: 'var(--r-xl)', boxShadow: 'var(--shadow-lg)', animation: 'scaleIn .25s ease .06s forwards' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '20px 22px', borderBottom: '1px solid var(--line)' }}>
          <div style={{ flex: 1, fontWeight: 700, fontSize: 16 }}>{stage === 'done' ? 'Sale settled' : 'Sell position'}</div>
          <button onClick={onClose} style={{ width: 32, height: 32, borderRadius: 9, border: '1px solid var(--line)', background: 'var(--surface-2)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="x" size={16} color="var(--text-2)" /></button>
        </div>
        <div style={{ padding: 22 }}>
          {stage === 'form' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
              <div style={{ textAlign: 'center' }}>
                <div style={{ fontSize: 12, color: 'var(--text-3)' }}>Selling</div>
                <div className="tnum" style={{ fontSize: 40, fontWeight: 700, letterSpacing: '-0.03em' }}>{pct}%</div>
                <div style={{ fontSize: 13, color: 'var(--text-2)' }}>{sellUnits.toFixed(2)} units · {fmtUsd(gross)}</div>
              </div>
              <input type="range" min="1" max="100" value={pct} onChange={e => setPct(+e.target.value)}
                style={{ width: '100%', accentColor: 'var(--accent)' }} />
              <div style={{ display: 'flex', gap: 8 }}>
                {[25, 50, 75, 100].map(q => (
                  <button key={q} onClick={() => setPct(q)} style={{ flex: 1, padding: '8px 0', borderRadius: 9, border: '1px solid var(--line)', background: pct === q ? 'var(--surface-2)' : 'var(--surface)', color: q === 100 ? 'var(--danger)' : 'var(--text-2)', cursor: 'pointer', fontFamily: 'var(--font)', fontSize: 13, fontWeight: 700 }}>{q === 100 ? 'Close all' : q + '%'}</button>
                ))}
              </div>
              <div style={{
                display: 'flex', alignItems: 'center', gap: 9, padding: '10px 12px', borderRadius: 12,
                background: live ? 'var(--blue-wash)' : 'var(--surface-2)',
                border: '1px solid ' + (quoteState.error ? 'rgba(255,107,107,0.28)' : live ? 'rgba(107,127,255,0.25)' : 'var(--line)'),
              }}>
                <Icon name={quoteState.error ? 'info' : live ? 'bolt' : 'spark'} size={15} color={quoteState.error ? 'var(--danger)' : live ? 'var(--blue)' : 'var(--text-3)'} />
                <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>
                  {quoteState.loading ? 'Fetching live sell quote...' :
                    quoteState.error ? `Backend quote unavailable: ${quoteState.error}` :
                    quote ? 'Live sell quote loaded from basket-fund.' :
                    'Demo estimate. Live positions create backend sell orders.'}
                </span>
              </div>
              <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 12, padding: '6px 14px' }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0' }}><span style={{ fontSize: 13.5, color: 'var(--text-2)' }}>Gross value</span><span className="tnum" style={{ fontSize: 13.5, fontWeight: 600 }}>{fmtUsd(gross)}</span></div>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0' }}><span style={{ fontSize: 13.5, color: 'var(--text-2)', display: 'inline-flex', alignItems: 'center', gap: 8 }}>Est. slippage <EstimateBadge>Est</EstimateBadge></span><span className="tnum" style={{ fontSize: 13.5, fontWeight: 600 }}>−{fmtUsd(estSlip)}</span></div>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0' }}><span style={{ fontSize: 13.5, color: 'var(--text-2)' }}>Sell fee ({b.buyFee}%)</span><span className="tnum" style={{ fontSize: 13.5, fontWeight: 600 }}>−{fmtUsd(fee)}</span></div>
                <div style={{ height: 1, background: 'var(--line)' }} />
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '11px 0' }}><span style={{ fontSize: 14, color: 'var(--text)', fontWeight: 700 }}>You receive</span><span className="tnum" style={{ fontSize: 17, fontWeight: 700, color: 'var(--accent-ink)' }}>{fmtUsd(receive)} <span style={{ fontSize: 12, color: 'var(--text-3)', fontWeight: 500 }}>USDC</span></span></div>
              </div>
              {needsSolanaWallet && (
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', background: 'rgba(255,198,91,0.08)', border: '1px solid rgba(255,198,91,0.25)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="wallet" size={16} color="var(--warning)" />
                  <span style={{ flex: 1, fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>Link a Solana wallet before selling. The backend pays settled USDC to your Solana wallet.</span>
                  <Btn size="sm" variant="ghost" onClick={onConnectWallet}>Link</Btn>
                </div>
              )}
              {orderError && (
                <div style={{ display: 'flex', gap: 9, background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.28)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="info" size={15} color="var(--danger)" style={{ marginTop: 1, flexShrink: 0 }} />
                  <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>{orderError}</span>
                </div>
              )}
              <Btn full size="lg" variant={pct === 100 ? 'danger' : 'primary'} disabled={submitting || needsSolanaWallet} onClick={submitSell}>{submitting ? 'Creating sell order...' : pct === 100 ? 'Close entire position' : `Sell ${pct}%`}</Btn>
            </div>
          )}
          {stage === 'executing' && (
            live ? <LiveSellExecuting order={order} onDone={() => setStage('done')} /> : <div style={{ animation: 'fadeIn .3s ease .06s forwards' }}>
              <div style={{ textAlign: 'center', marginBottom: 22 }}>
                <div style={{ width: 52, height: 52, borderRadius: 99, margin: '0 auto 12px', background: 'var(--blue-wash)', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid rgba(107,127,255,0.3)' }}><Icon name="swap2" size={24} color="var(--blue)" /></div>
                <h3 style={{ margin: 0, fontSize: 19, fontWeight: 700 }}>Selling {pct}%</h3>
              </div>
              {steps.map((s, i) => (
                <ExecStep key={i} step={{ title: s, desc: '', last: i === steps.length - 1 }} state={i < active ? 'done' : i === active ? 'active' : 'pending'} />
              ))}
            </div>
          )}
          {stage === 'done' && (
            <div style={{ textAlign: 'center', animation: 'scaleIn .35s ease .06s forwards' }}>
              <div style={{ width: 60, height: 60, borderRadius: 99, margin: '0 auto 14px', background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 0 30px var(--accent-glow)' }}><Icon name="check" size={30} color="var(--on-accent)" sw={3} /></div>
              <h3 style={{ margin: 0, fontSize: 21, fontWeight: 700 }}>{fmtUsd(receive)} settled</h3>
              <p style={{ margin: '6px 0 20px', fontSize: 13.5, color: 'var(--text-2)' }}>USDC is back in your Solana wallet. {pct < 100 ? `${100 - pct}% of the position stays open and keeps following rebalances.` : 'Position closed.'}</p>
              <Btn full onClick={() => onConfirm(pct)}>Done</Btn>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function PortfolioScreen({ onOpen, onCopyMore, auth, dataState, onConnectWallet }) {
  const { baskets = [], positions = [], position, activity } = window.DB;
  const b = position ? (baskets.find(x => x.id === position.basketId) || baskets[0]) : null;
  const [sell, setSell] = useState(false);
  const series = useMemo(() => window.DB.spark(99, 48, 0.013), []);
  const goExplore = () => window.dispatchEvent(new CustomEvent('basket:navigate', { detail: { view: 'explore' } }));
  const pnlUsd = position ? sign(position.pnl) + fmtUsd(Math.abs(position.pnl)) : '$0.00';
  const pnlPct = position ? sign(position.pnlPct) + Math.abs(position.pnlPct).toFixed(1) + '%' : '0.0%';
  const pnlColor = position && position.pnl < 0 ? 'var(--danger)' : 'var(--accent-ink)';
  if (!position || !b) {
    const live = dataState && (dataState.mode === 'live' || dataState.mode === 'live_empty');
    const walletUsdc = dataState && dataState.walletUsdcBalance != null ? Number(dataState.walletUsdcBalance) || 0 : 0;
    return (
      <div className="page" style={{ padding: '32px 32px 64px', maxWidth: 920, margin: '0 auto', animation: 'fadeIn .35s ease .06s forwards' }}>
        <PageHead
          n="— PORTFOLIO"
          title="Your positions"
          sub={live ? 'No copied baskets yet. Your live wallet session is connected, but there are no backend positions to show.' : 'Connect a wallet or copy a basket to start tracking positions.'}
        />
        <Card pad={26} style={{ display: 'grid', gap: 18 }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
            <div style={{ width: 44, height: 44, borderRadius: 14, background: 'var(--accent-wash)', color: 'var(--accent-ink)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Icon name="wallet" size={21} color="currentColor" />
            </div>
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ fontSize: 18, fontWeight: 850 }}>No open positions</div>
              <div style={{ marginTop: 5, fontSize: 13.5, color: 'var(--text-2)', lineHeight: 1.5 }}>
                {auth && auth.connected
                  ? `Wallet is connected. Live USDC balance: ${fmtUsd(walletUsdc)}.`
                  : 'Connect a wallet first, then copy a live basket to create a position.'}
              </div>
            </div>
          </div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            {!auth || !auth.connected ? <Btn icon="wallet" onClick={onConnectWallet}>Connect wallet</Btn> : null}
            <Btn variant="soft" icon="explore" onClick={goExplore}>Explore baskets</Btn>
          </div>
          {positions && positions.length === 0 && live && (
            <div style={{ borderTop: '1px solid var(--line)', paddingTop: 14, fontSize: 12.5, color: 'var(--text-3)', lineHeight: 1.45 }}>
              This is the expected production-like empty state when `/v1/positions` has no items for the current wallet.
            </div>
          )}
        </Card>
      </div>
    );
  }
  const newVersion = b.version > position.onVersion; // KOL ahead

  return (
    <div className="page" style={{ padding: '32px 32px 64px', maxWidth: 1180, margin: '0 auto', animation: 'fadeIn .35s ease .06s forwards' }}>
      {sell && <Portal><SellModal b={b} position={position} auth={auth} dataState={dataState} onConnectWallet={onConnectWallet} onClose={() => setSell(false)} onConfirm={() => setSell(false)} /></Portal>}

      <PageHead n="— PORTFOLIO" title="Your positions" sub="Copied baskets and open positions, tracking every rebalance." />

      {/* summary band */}
      <div className="pf-summary" style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: 20, marginBottom: 24 }}>
        <Card pad={26} spot style={{ background: 'linear-gradient(150deg, var(--bg-2), var(--hero-2) 80%)', position: 'relative', overflow: 'hidden' }} >
          <div style={{ position: 'absolute', top: -80, right: -40, width: 240, height: 240, borderRadius: '50%', background: 'radial-gradient(circle, var(--accent-glow), transparent 70%)', opacity: 0.4, filter: 'blur(10px)' }} />
          <div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
            <div>
              <div className="eyebrow" style={{ marginBottom: 10 }}>Total value</div>
              <div className="data" style={{ fontSize: 46, fontWeight: 700, letterSpacing: '-0.04em', lineHeight: 0.95 }}>{fmtUsd(position.value)}</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 12 }}>
                <Pct v={position.pnlPct} size={16} weight={700} arrow bg />
                <span className="data" style={{ fontSize: 14, color: pnlColor, fontWeight: 600 }}>{pnlUsd}</span>
                <span className="eyebrow">all time</span>
              </div>
            </div>
            <div className="pf-hero-spark" style={{ width: 180 }}><Sparkline data={series} w={180} h={64} fill /></div>
          </div>
        </Card>
        <Card pad={24} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, alignContent: 'center' }}>
          <Stat label="Invested" value={fmtUsd(position.invested)} />
          <Stat label="Unrealized PnL" value={pnlUsd} accent={position.pnl >= 0} />
          <Stat label="Open positions" value="1" />
          <Stat label="Current NAV" value={'$' + position.nav.toFixed(4)} sub="per unit" />
        </Card>
      </div>

      {/* new version banner */}
      {newVersion && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, background: 'var(--accent-wash)', border: '1px solid rgba(163,255,91,0.3)', borderRadius: 16, padding: '14px 18px', marginBottom: 20 }}>
          <div style={{ width: 36, height: 36, borderRadius: 99, background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="swap" size={18} color="var(--on-accent)" /></div>
          <div style={{ flex: 1 }}>
            <div style={{ fontWeight: 700, fontSize: 14 }}>You're auto-following v{b.version}</div>
            <div style={{ fontSize: 12.5, color: 'var(--text-2)' }}>{b.kol.x} rebalanced to v{b.version} 2 days ago — your basket units already track the new weights. No action needed.</div>
          </div>
          <Btn size="sm" variant="ghost" onClick={() => onOpen(b.id)}>View changes</Btn>
        </div>
      )}

      {/* position card */}
      <Card pad={0}>
        <div className="pos-head" style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '20px 24px', borderBottom: '1px solid var(--line)' }}>
          <KolAvatar kol={b.kol} size={44} />
          <div style={{ flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span className="display" style={{ fontWeight: 800, fontSize: 19 }}>{b.name}</span>
              <span className="data" style={{ fontSize: 11, fontWeight: 700, padding: '3px 8px', borderRadius: 7, background: 'var(--surface-2)', border: '1px solid var(--line-2)', color: 'var(--text-2)' }}>v{b.version}</span>
              <span className="eyebrow">copied {position.copiedAt}</span>
            </div>
            <div style={{ fontSize: 13, color: 'var(--text-3)' }}>by {b.kol.x}</div>
          </div>
          <div className="pos-actions" style={{ display: 'flex', gap: 10 }}>
            <Btn size="sm" variant="soft" icon="plus" onClick={() => onCopyMore(b.id)}>Buy more</Btn>
            <Btn size="sm" variant="ghost" onClick={() => setSell(true)}>Sell</Btn>
            <Btn size="sm" variant="ghost" onClick={() => onOpen(b.id)}>Details</Btn>
          </div>
        </div>

        {/* position stats */}
        <div className="g5" style={{ display: 'grid', gridTemplateColumns: 'repeat(5,1fr)', gap: 16, padding: '20px 24px', borderBottom: '1px solid var(--line)' }}>
          <Stat label="Units" value={position.units.toLocaleString(undefined, { maximumFractionDigits: 2 })} />
          <Stat label="Value" value={fmtUsd(position.value)} />
          <Stat label="PnL" value={pnlPct} accent={position.pnlPct >= 0} sub={pnlUsd} />
          <Stat label="Avg entry NAV" value={'$' + position.avgEntryNav.toFixed(4)} />
          <div>
            <div className="eyebrow" style={{ marginBottom: 6 }}>Liquidation</div>
            <div className="data" style={{ fontSize: 22, fontWeight: 700, color: 'var(--text-2)', letterSpacing: '-0.03em' }}>None</div>
            <div style={{ fontSize: 12, color: 'var(--text-3)', marginTop: 3 }}>spot basket · no leverage</div>
          </div>
        </div>

        {/* holdings */}
        <div className="pf-holdings" style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: 28, padding: 24 }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
            <WeightRing tokens={position.holdings} size={184} thickness={22} centerLabel={fmtCompact(position.value)} centerSub="value" />
            <div style={{ fontSize: 12, color: 'var(--text-3)', marginTop: 14, textAlign: 'center' }}>Live composition mirrors {b.kol.x}'s current weights.</div>
          </div>
          <div>
            <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr 1fr 1fr', gap: 12, padding: '0 8px 10px', borderBottom: '1px solid var(--line)' }} className="eyebrow">
              <div>Token</div><div style={{ textAlign: 'right' }}>Weight</div><div style={{ textAlign: 'right' }}>Value</div><div style={{ textAlign: 'right' }}>PnL</div>
            </div>
            {position.holdings.map((h, i) => (
              <div key={h.sym} style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr 1fr 1fr', gap: 12, alignItems: 'center', padding: '12px 8px', borderBottom: i < position.holdings.length - 1 ? '1px solid var(--line)' : 'none' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <TokenDot color={h.color} sym={h.sym} logoUrl={h.logo_url || h.logoUrl} logoSources={h.logo_sources || h.logoSources} size={28} />
                  <div><div style={{ fontWeight: 700, fontSize: 13.5 }}>{h.sym}</div><div style={{ fontSize: 11, color: 'var(--text-3)' }}>{h.name}</div></div>
                </div>
                <div className="data" style={{ textAlign: 'right', fontWeight: 600, fontSize: 13.5 }}>{h.weight}%</div>
                <div className="data" style={{ textAlign: 'right', fontWeight: 600, fontSize: 13.5 }}>{fmtUsd(h.value)}</div>
                <div style={{ textAlign: 'right' }}><Pct v={h.pnlPct} size={13} /></div>
              </div>
            ))}
          </div>
        </div>
      </Card>
    </div>
  );
}

/* ---------------- Activity screen ---------------- */
function ActivityScreen() {
  const { activity } = window.DB;
  const scope = window.DB && window.DB.api && window.DB.api.activityScope;
  const personal = scope === 'user';
  const iconFor = { rebalance: 'swap', copy: 'copy', fill: 'check', sell: 'arrowDn' };
  return (
    <div className="page" style={{ padding: '32px 32px 64px', maxWidth: 760, margin: '0 auto', animation: 'fadeIn .35s ease .06s forwards' }}>
      <PageHead n="— ACTIVITY" title={personal ? 'Your activity' : 'Live feed'} sub={personal ? 'Your copies, sells, and KOL basket events.' : 'Real-time events across live baskets.'} />
      <Card pad={8}>
        {(activity || []).map((a, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px', borderBottom: i < (activity || []).length - 1 ? '1px solid var(--line)' : 'none' }}>
            <div style={{ width: 38, height: 38, borderRadius: 11, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: a.accent ? 'var(--accent-wash)' : 'var(--surface-2)', border: '1px solid ' + (a.accent ? 'rgba(163,255,91,0.25)' : 'var(--line)') }}>
              <Icon name={iconFor[a.kind] || 'bolt'} size={17} color={a.accent ? 'var(--accent-ink)' : 'var(--text-2)'} />
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 14 }}><strong>{a.who}</strong> <span style={{ color: 'var(--text-2)' }}>{a.what}</span></div>
            </div>
            <span className="data" style={{ fontSize: 11.5, color: 'var(--text-3)' }}>{a.when}</span>
          </div>
        ))}
        {(!activity || activity.length === 0) && (
          <div style={{ padding: '28px 18px', textAlign: 'center', color: 'var(--text-3)', fontSize: 13.5 }}>
            No activity yet.
          </div>
        )}
      </Card>
    </div>
  );
}

Object.assign(window, { PortfolioScreen, ActivityScreen, SellModal });
