// ============== STRATEGIES (v3) ==============
// Sentiment-first, leg-aware construction with width presets, zone payoff viz,
// inline risk callout, and expandable details.

(function() {
  const useStateP = React.useState;
  const useEffectP = React.useEffect;
  const useMemoP = React.useMemo;

  // Format a strike for the asset's price magnitude
  const fmtStrike = (sym, v) => {
    if (sym === 'BTC')  return '$' + (Math.round(v / 100) / 10).toFixed(1) + 'K';
    if (sym === 'ETH')  return '$' + (Math.round(v / 10) / 100).toFixed(2) + 'K';
    if (sym === 'SPX')  return Math.round(v).toLocaleString();
    if (sym === 'GOLD') return '$' + Math.round(v).toLocaleString();
    if (sym === 'NVDA') return '$' + Math.round(v);
    return '$' + (Math.round(v * 100) / 100).toFixed(2);
  };

  function StrategiesV3({ openTicket }) {
    const VD = window.VD;
    const { AssetGlyph } = window.VDIcons;
    const [sym, setSym] = useStateP('BTC');
    const [pickedId, setPickedId] = useStateP(null);
    const [showDetails, setShowDetails] = useStateP(false);

    // width default re-syncs when strategy changes
    const all = VD.VD_STRATEGIES;
    const picked = all.find(s => s.id === pickedId);
    const [width, setWidth] = useStateP('standard');
    useEffectP(() => { if (picked) setWidth(picked.defaultWidth); }, [pickedId]);

    const asset = VD.VD_ASSETS.find(a => a.sym === sym);

    return (
      <div style={{ maxWidth: 920, margin: '0 auto', padding: '24px 32px 80px' }}>
        {/* Header */}
        <div style={{ marginBottom: 28 }}>
          <div className="cap-sm" style={{ marginBottom: 8, color: 'var(--text-3)' }}>↳ Strategy picker</div>
          <h1 className="serif" style={{ fontSize: 56, fontWeight: 400, letterSpacing: '-0.035em', lineHeight: 1, margin: 0 }}>
            What do you <em style={{ color: 'var(--acid)' }}>think</em> happens?
          </h1>
        </div>

        {/* Step 1: Asset selector */}
        <div style={{ marginBottom: 32 }}>
          <div className="cap-sm" style={{ marginBottom: 12, color: 'var(--text-3)' }}>① Pick an asset</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 8 }}>
            {VD.VD_ASSETS.map(a => (
              <button key={a.sym} onClick={() => { setSym(a.sym); setPickedId(null); }}
                style={{
                  padding: '14px 12px',
                  background: sym === a.sym ? 'var(--bg-elev-2)' : 'var(--bg-elev)',
                  border: `1px solid ${sym === a.sym ? 'var(--acid)' : 'var(--line-subtle)'}`,
                  display: 'flex', alignItems: 'center', gap: 10,
                  cursor: 'pointer', transition: 'all 120ms var(--ease)',
                }}>
                <AssetGlyph sym={a.sym} size={28} />
                <div style={{ textAlign: 'left' }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{a.sym}</div>
                  <div className="num" style={{ fontSize: 10, color: a.change >= 0 ? 'var(--mint)' : 'var(--coral)' }}>
                    {a.change >= 0 ? '+' : ''}{a.change.toFixed(2)}%
                  </div>
                </div>
              </button>
            ))}
          </div>
        </div>

        {/* Step 2: Sentiment picker with leg-count badges */}
        <div style={{ marginBottom: 24 }}>
          <div className="cap-sm" style={{ marginBottom: 12, color: 'var(--text-3)' }}>② What do you think happens to {sym}?</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10 }}>
            {all.map(s => <SentimentCard key={s.id} s={s} picked={pickedId === s.id} onPick={() => setPickedId(s.id)} />)}
          </div>
        </div>

        {/* Step 3: The trade */}
        {picked && <TradeCard picked={picked} sym={sym} asset={asset} width={width} setWidth={setWidth} showDetails={showDetails} setShowDetails={setShowDetails} openTicket={openTicket} />}
      </div>
    );
  }

  // ============== Sentiment card ==============
  function SentimentCard({ s, picked, onPick }) {
    const sentColor = s.sentiment === 'bullish' ? 'var(--mint)'
                    : s.sentiment === 'bearish' ? 'var(--coral)'
                    : s.sentiment === 'volatile' ? 'var(--acid)'
                    : 'var(--text-2)';
    const legLabel = s.kind === '1-leg' ? '1-leg'
                   : s.kind === '2-leg-range' ? '2-leg range'
                   : '2-leg break';
    const std = s.widths.standard;
    return (
      <button onClick={onPick}
        style={{
          padding: '18px 18px 16px',
          background: picked ? 'var(--bg-elev-2)' : 'var(--bg-elev)',
          border: `1px solid ${picked ? sentColor : 'var(--line-subtle)'}`,
          textAlign: 'left', cursor: 'pointer', transition: 'all 120ms var(--ease)',
          display: 'flex', flexDirection: 'column', gap: 8,
          position: 'relative',
        }}
        onMouseEnter={e => { if (!picked) e.currentTarget.style.borderColor = 'var(--line)'; }}
        onMouseLeave={e => { if (!picked) e.currentTarget.style.borderColor = 'var(--line-subtle)'; }}>
        {/* Top row: leg badge + sentiment */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{
            fontSize: 9, color: 'var(--text-3)', fontFamily: 'JetBrains Mono, monospace',
            textTransform: 'uppercase', letterSpacing: '0.12em',
            padding: '3px 6px', border: '1px solid var(--line-subtle)', borderRadius: 2,
          }}>{legLabel}</span>
          <span style={{ fontSize: 9, color: sentColor, fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 600 }}>
            {s.sentiment === 'volatile' ? 'Vol' : s.sentiment} · {s.strength}
          </span>
        </div>

        {/* Emoji + headline */}
        <div style={{ marginTop: 4 }}>
          <span style={{ fontSize: 22 }}>{s.emoji}</span>
        </div>
        <div className="serif" style={{ fontSize: 22, fontWeight: 400, letterSpacing: '-0.015em', lineHeight: 1.1 }}>{s.headline}</div>
        <div style={{ fontSize: 11, color: 'var(--text-3)', display: 'flex', gap: 8 }}>
          <span><span className="num">~{std.win}¢</span> if right</span>
          <span style={{ color: 'var(--text-4)' }}>·</span>
          <span><span className="num">~{std.cost}¢</span> if wrong</span>
        </div>
      </button>
    );
  }

  // ============== Trade card (the heavy one) ==============
  function TradeCard({ picked, sym, asset, width, setWidth, showDetails, setShowDetails, openTicket }) {
    const w = picked.widths[width];
    const spot = asset.spot;

    // Build legs from offsets: 1 leg uses one strike; 2-leg uses two
    const strikes = w.offsets.map(o => spot * (1 + o));

    // Build leg description and zone visualization based on strategy kind
    const tradeMeta = useMemoP(() => {
      const sk = strikes;
      if (picked.kind === '1-leg') {
        const isYes = picked.sentiment === 'bullish';
        return {
          legs: [
            { side: isYes ? 'YES' : 'NO', action: 'Buy', strike: sk[0], price: w.cost },
          ],
          // 2-zone: lose | win for YES (lose left of K, win right). Reverse for NO.
          zones: isYes
            ? [{ kind: 'lose', from: spot * 0.85, to: sk[0], label: '< ' + fmtStrike(sym, sk[0]) },
               { kind: 'win',  from: sk[0], to: spot * 1.15, label: '> ' + fmtStrike(sym, sk[0]) }]
            : [{ kind: 'win',  from: spot * 0.85, to: sk[0], label: '< ' + fmtStrike(sym, sk[0]) },
               { kind: 'lose', from: sk[0], to: spot * 1.15, label: '> ' + fmtStrike(sym, sk[0]) }],
          breakevens: [sk[0]],
          question: `${sym} ${isYes ? '>' : '<'} ${fmtStrike(sym, sk[0])} by Friday`,
        };
      }
      if (picked.kind === '2-leg-range') {
        const [Klo, Khi] = sk;
        return {
          legs: [
            { side: 'YES', action: 'Buy', strike: Klo, price: Math.round(w.cost / 2) },
            { side: 'NO',  action: 'Buy', strike: Khi, price: w.cost - Math.round(w.cost / 2) },
          ],
          zones: [
            { kind: 'lose', from: spot * 0.85, to: Klo, label: 'breaks down' },
            { kind: 'win',  from: Klo, to: Khi, label: 'stays inside' },
            { kind: 'lose', from: Khi, to: spot * 1.15, label: 'breaks up' },
          ],
          breakevens: [Klo, Khi],
          question: `${sym} stays between ${fmtStrike(sym, Klo)}–${fmtStrike(sym, Khi)} by Friday`,
        };
      }
      // 2-leg-strangle (breaks)
      const [Klo, Khi] = sk;
      return {
        legs: [
          { side: 'NO',  action: 'Buy', strike: Klo, price: Math.round(w.cost / 2) },
          { side: 'YES', action: 'Buy', strike: Khi, price: w.cost - Math.round(w.cost / 2) },
        ],
        zones: [
          { kind: 'win',  from: spot * 0.85, to: Klo, label: 'breaks down' },
          { kind: 'lose', from: Klo, to: Khi, label: 'stays inside' },
          { kind: 'win',  from: Khi, to: spot * 1.15, label: 'breaks up' },
        ],
        breakevens: [Klo, Khi],
        question: `${sym} breaks outside ${fmtStrike(sym, Klo)}–${fmtStrike(sym, Khi)} by Friday`,
      };
    }, [picked.id, width, sym]);

    const onPlace = () => {
      const leg = tradeMeta.legs[0];
      openTicket && openTicket({
        sym, side: leg.side, action: leg.action, strike: leg.strike,
        expiryKey: 'fri', price: w.cost, mid: w.cost, fromStrategy: picked.id,
      });
    };

    return (
      <div className="card" style={{ padding: 28, position: 'relative', borderColor: 'var(--acid)' }}>
        <div style={{ position: 'absolute', top: 14, right: 20, fontSize: 9, color: 'var(--text-4)', fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.18em' }}>
          {picked.id.toUpperCase()} · {picked.kind.toUpperCase()}
        </div>
        <div className="cap-sm" style={{ marginBottom: 10, color: 'var(--acid)' }}>③ Here's the trade</div>

        {/* Auto-generated question */}
        <div className="serif" style={{ fontSize: 28, fontWeight: 400, letterSpacing: '-0.025em', lineHeight: 1.15, marginBottom: 6 }}>
          "{tradeMeta.question}"
        </div>
        <div style={{ color: 'var(--text-2)', fontSize: 13.5, marginBottom: 24, maxWidth: 700, lineHeight: 1.55 }}>
          {picked.plain}
        </div>

        {/* Strategy construction (the legs in plain text) */}
        <div style={{ marginBottom: 22, padding: '14px 16px', background: 'var(--bg-elev-2)', border: '1px solid var(--line-subtle)' }}>
          <div className="cap-sm" style={{ marginBottom: 8, fontSize: 9 }}>Construction</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {tradeMeta.legs.map((leg, i) => (
              <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 13, fontFamily: 'JetBrains Mono, monospace' }}>
                <span style={{
                  display: 'inline-block', minWidth: 36, padding: '2px 6px',
                  background: leg.action === 'Buy' ? 'var(--mint-bg10)' : 'var(--coral-bg10)',
                  color: leg.action === 'Buy' ? 'var(--mint)' : 'var(--coral)',
                  textAlign: 'center', fontSize: 10, fontWeight: 600, letterSpacing: '0.06em',
                }}>{leg.action.toUpperCase()}</span>
                <span style={{
                  display: 'inline-block', minWidth: 32, padding: '2px 6px',
                  border: `1px solid ${leg.side === 'YES' ? 'var(--mint)' : 'var(--coral)'}`,
                  color: leg.side === 'YES' ? 'var(--mint)' : 'var(--coral)',
                  textAlign: 'center', fontSize: 10, fontWeight: 600, letterSpacing: '0.06em',
                }}>{leg.side}</span>
                <span style={{ color: 'var(--text-3)' }}>@</span>
                <span style={{ color: 'var(--text)', fontWeight: 600 }}>{fmtStrike(sym, leg.strike)}</span>
              </div>
            ))}
          </div>
        </div>

        {/* Strike width preset */}
        <div style={{ marginBottom: 22 }}>
          <div className="cap-sm" style={{ marginBottom: 10, fontSize: 9 }}>Strike width — wider = bigger payout, lower hit rate</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
            {['tight', 'standard', 'wide'].map(k => {
              const wp = picked.widths[k];
              const active = width === k;
              return (
                <button key={k} onClick={() => setWidth(k)}
                  style={{
                    padding: '10px 12px',
                    background: active ? 'var(--acid-bg10)' : 'var(--bg-elev-2)',
                    border: `1px solid ${active ? 'var(--acid)' : 'var(--line-subtle)'}`,
                    textAlign: 'left', cursor: 'pointer', transition: 'all 120ms var(--ease)',
                    display: 'flex', flexDirection: 'column', gap: 3,
                  }}>
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <span style={{ fontSize: 12, fontWeight: 600, textTransform: 'capitalize', color: active ? 'var(--acid)' : 'var(--text)' }}>{k}</span>
                    <span className="num" style={{ fontSize: 11, color: 'var(--text-3)' }}>{Math.round(wp.hit * 100)}%</span>
                  </div>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, fontSize: 10, color: 'var(--text-3)' }}>
                    <span>${wp.cost} → <span style={{ color: 'var(--mint)', fontWeight: 600 }}>${wp.win}</span></span>
                    <span style={{ color: 'var(--acid-dim)', marginLeft: 'auto', fontWeight: 600 }}>{wp.ratio.toFixed(2)}×</span>
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        {/* Zone visualization */}
        <ZoneViz zones={tradeMeta.zones} spot={spot} sym={sym} breakevens={tradeMeta.breakevens} />

        {/* Outcome P&L — slider + pillars + table */}
        <OutcomePanel picked={picked} sym={sym} spot={spot} w={w} strikes={strikes} />

        {/* Inline risk callout */}
        <div style={{
          marginTop: 22, padding: '12px 14px',
          background: 'rgba(255,107,107,0.06)', border: '1px solid rgba(255,107,107,0.25)',
          display: 'flex', gap: 10, alignItems: 'flex-start',
        }}>
          <span style={{ color: 'var(--coral)', fontSize: 16, lineHeight: 1, marginTop: 1 }}>⚠</span>
          <div>
            <div style={{ fontSize: 11, color: 'var(--coral)', fontWeight: 600, fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: 4 }}>
              The risk
            </div>
            <div style={{ color: 'var(--text)', fontSize: 13, lineHeight: 1.5 }}>{picked.riskShort}</div>
          </div>
        </div>

        {/* Pay → win/lose breakdown */}
        <div style={{ marginTop: 22, display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 0, alignItems: 'stretch', borderTop: '1px solid var(--line-subtle)', borderBottom: '1px solid var(--line-subtle)' }}>
          <div style={{ padding: '16px 0', borderRight: '1px solid var(--line-subtle)' }}>
            <div className="cap-sm" style={{ marginBottom: 4 }}>You pay</div>
            <div className="num" style={{ fontSize: 28, fontWeight: 600 }}>${w.cost}</div>
            <div style={{ fontSize: 11, color: 'var(--text-3)' }}>per 100 shares · max loss</div>
          </div>
          <div style={{ padding: '16px 16px', borderRight: '1px solid var(--line-subtle)' }}>
            <div className="cap-sm" style={{ marginBottom: 4, color: 'var(--mint)' }}>If right</div>
            <div className="num" style={{ fontSize: 28, fontWeight: 600, color: 'var(--mint)' }}>+${w.win}</div>
            <div style={{ fontSize: 11, color: 'var(--text-3)' }}>{w.ratio.toFixed(2)}× your stake · {Math.round(w.hit * 100)}% hit rate</div>
          </div>
          <div style={{ padding: '16px 16px' }}>
            <div className="cap-sm" style={{ marginBottom: 4, color: 'var(--coral)' }}>If wrong</div>
            <div className="num" style={{ fontSize: 28, fontWeight: 600, color: 'var(--coral)' }}>−${w.cost}</div>
            <div style={{ fontSize: 11, color: 'var(--text-3)' }}>capped, no margin call</div>
          </div>
        </div>

        {/* Expandable details */}
        <button onClick={() => setShowDetails(!showDetails)}
          style={{
            marginTop: 14, padding: '10px 0',
            background: 'transparent', border: 'none',
            color: 'var(--text-3)', fontSize: 11, fontWeight: 600,
            fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.12em',
            cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 6,
            width: '100%',
          }}>
          <span style={{ display: 'inline-block', transition: 'transform 200ms', transform: showDetails ? 'rotate(90deg)' : 'rotate(0)' }}>▸</span>
          Show all risk details
        </button>
        {showDetails && (
          <div style={{ marginTop: 6, padding: '14px 16px', background: 'var(--bg-elev-2)', border: '1px solid var(--line-subtle)', display: 'flex', flexDirection: 'column', gap: 10 }}>
            <DetailRow k="Max loss" v={`$${w.cost} per 100 shares`} hint="Your premium. Capped — no margin call." />
            <DetailRow k="Max gain" v={`$${w.win} per 100 shares`} hint={`${w.ratio.toFixed(2)}× return on premium.`} />
            <DetailRow k="Breakeven" v={tradeMeta.breakevens.map(b => fmtStrike(sym, b)).join(' / ')} hint="Price level(s) at which P&L = 0 at expiry." />
            <DetailRow k="Settlement" v="Friday 4:00 PM ET" hint="Cash-settled to USDC at expiry. No assignment, no exercise." />
            <DetailRow k="Oracle" v="Pyth + Chainlink TWAP" hint="60-min TWAP across 6 venues, dual-feed validation." />
            <DetailRow k="Time decay" v={picked.kind === '2-leg-range' ? 'Works for you' : picked.kind === '2-leg-strangle' ? 'Works against you' : 'Neutral until ITM'} hint="Premium erodes toward expiry." />
            <DetailRow k="Liquidity" v="Top 5 / 38 markets" hint="Tight spreads, MM quotes refresh ~150ms." />
          </div>
        )}

        {/* Place trade CTA */}
        <button onClick={onPlace} className="btn btn-primary"
          style={{ marginTop: 18, width: '100%', padding: '16px', fontSize: 15 }}>
          Place trade — ${w.cost} →
        </button>
      </div>
    );
  }

  function DetailRow({ k, v, hint }) {
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: 16, fontSize: 12, alignItems: 'baseline' }}>
        <div className="cap-sm" style={{ fontSize: 10, color: 'var(--text-3)' }}>{k}</div>
        <div>
          <div style={{ color: 'var(--text)', fontWeight: 600, fontFamily: 'JetBrains Mono, monospace' }}>{v}</div>
          {hint && <div style={{ color: 'var(--text-3)', fontSize: 11, marginTop: 2 }}>{hint}</div>}
        </div>
      </div>
    );
  }

  // ============== Outcome P&L panel ==============
  // Per-strategy payoff function. Returns $ per 100 shares (i.e. per contract).
  // All strategies are pure BUY: cost = w.cost (cents), max win = w.win (cents).
  function payoffAt(picked, strikes, w, finalPrice) {
    const cost = w.cost; // cents per contract (1 contract = 100 shares, $1 settlement)
    const maxWin = w.win;
    if (picked.kind === '1-leg') {
      const K = strikes[0];
      const isYes = picked.sentiment === 'bullish';
      const wins = isYes ? finalPrice > K : finalPrice < K;
      return wins ? maxWin : -cost;
    }
    if (picked.kind === '2-leg-range') {
      const [Klo, Khi] = strikes;
      const wins = finalPrice >= Klo && finalPrice <= Khi;
      return wins ? maxWin : -cost;
    }
    // 2-leg-strangle (breaks)
    const [Klo, Khi] = strikes;
    const wins = finalPrice < Klo || finalPrice > Khi;
    return wins ? maxWin : -cost;
  }

  function OutcomePanel({ picked, sym, spot, w, strikes }) {
    // Default the slider to spot
    const [pct, setPct] = useStateP(0); // % move from spot
    const finalPrice = spot * (1 + pct / 100);
    const pnl = payoffAt(picked, strikes, w, finalPrice);
    const wins = pnl > 0;
    const pnlColor = wins ? 'var(--mint)' : 'var(--coral)';

    // Pillars: 5 fixed price points
    const pillars = [-10, -5, 0, +5, +10].map(p => {
      const fp = spot * (1 + p / 100);
      const pl = payoffAt(picked, strikes, w, fp);
      return { p, fp, pl };
    });
    const maxAbs = Math.max(...pillars.map(x => Math.abs(x.pl)), w.win, w.cost);

    return (
      <div style={{ marginTop: 24, padding: '16px 18px', background: 'var(--bg-elev-2)', border: '1px solid var(--line-subtle)' }}>
        <div className="cap-sm" style={{ marginBottom: 12, fontSize: 9 }}>What you make / lose by outcome</div>

        {/* Slider hero */}
        <div style={{ marginBottom: 18 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6 }}>
            <div>
              <div style={{ fontSize: 11, color: 'var(--text-3)', fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 4 }}>
                If {sym} ends at
              </div>
              <div className="num" style={{ fontSize: 22, fontWeight: 600, color: 'var(--text)' }}>
                {fmtStrike(sym, finalPrice)} <span style={{ fontSize: 13, color: 'var(--text-3)', fontWeight: 400, marginLeft: 6 }}>
                  ({pct >= 0 ? '+' : ''}{pct.toFixed(1)}%)
                </span>
              </div>
            </div>
            <div style={{ textAlign: 'right' }}>
              <div style={{ fontSize: 11, color: 'var(--text-3)', fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 4 }}>
                You {wins ? 'win' : 'lose'}
              </div>
              <div className="num" style={{ fontSize: 22, fontWeight: 700, color: pnlColor }}>
                {pnl >= 0 ? '+' : ''}${Math.abs(pnl)}
              </div>
            </div>
          </div>
          <input
            type="range" min={-15} max={15} step={0.5} value={pct}
            onChange={e => setPct(parseFloat(e.target.value))}
            style={{
              width: '100%', accentColor: pnlColor, height: 4, marginTop: 8,
              cursor: 'pointer',
            }}
          />
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--text-4)', fontFamily: 'JetBrains Mono, monospace', marginTop: 4 }}>
            <span>−15%</span>
            <span style={{ color: 'var(--text-3)' }}>spot {fmtStrike(sym, spot)}</span>
            <span>+15%</span>
          </div>
        </div>

        {/* Pillars */}
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', height: 100, marginBottom: 8, padding: '0 4px' }}>
          {pillars.map((b, i) => {
            const h = (Math.abs(b.pl) / maxAbs) * 80; // px max bar height
            const win = b.pl > 0;
            return (
              <div key={i} style={{
                flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center',
                justifyContent: 'flex-end', height: '100%', position: 'relative',
              }}>
                <div className="num" style={{
                  fontSize: 10, fontWeight: 700,
                  color: win ? 'var(--mint)' : 'var(--coral)',
                  marginBottom: 4,
                }}>
                  {win ? '+' : '−'}${Math.abs(b.pl)}
                </div>
                <div style={{
                  width: '70%', maxWidth: 38, height: h,
                  background: win ? 'var(--mint)' : 'var(--coral)',
                  opacity: 0.85,
                  transformOrigin: 'bottom',
                  borderRadius: '2px 2px 0 0',
                }} />
                <div style={{
                  position: 'absolute', bottom: -22,
                  fontSize: 10, color: 'var(--text-3)',
                  fontFamily: 'JetBrains Mono, monospace',
                  textAlign: 'center',
                }}>
                  {b.p > 0 ? '+' : ''}{b.p}%
                </div>
              </div>
            );
          })}
        </div>
        <div style={{ height: 1, background: 'var(--line-subtle)', marginTop: 28, marginBottom: 12 }} />

        {/* Detail table */}
        <div className="cap-sm" style={{ fontSize: 9, marginBottom: 8 }}>Outcome table</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 0, fontSize: 11, fontFamily: 'JetBrains Mono, monospace' }}>
          <div style={{ color: 'var(--text-3)', padding: '6px 8px', borderBottom: '1px solid var(--line-subtle)', textTransform: 'uppercase', letterSpacing: '0.08em', fontSize: 9 }}>{sym} ends at</div>
          <div style={{ color: 'var(--text-3)', padding: '6px 8px', borderBottom: '1px solid var(--line-subtle)', textTransform: 'uppercase', letterSpacing: '0.08em', fontSize: 9, textAlign: 'right' }}>P&L per contract</div>
          <div style={{ color: 'var(--text-3)', padding: '6px 8px', borderBottom: '1px solid var(--line-subtle)', textTransform: 'uppercase', letterSpacing: '0.08em', fontSize: 9, textAlign: 'right' }}>×10 contracts</div>
          {pillars.map((b, i) => {
            const win = b.pl > 0;
            return (
              <React.Fragment key={i}>
                <div style={{ padding: '7px 8px', color: 'var(--text)' }}>
                  {fmtStrike(sym, b.fp)} <span style={{ color: 'var(--text-4)' }}>({b.p > 0 ? '+' : ''}{b.p}%)</span>
                </div>
                <div style={{ padding: '7px 8px', textAlign: 'right', color: win ? 'var(--mint)' : 'var(--coral)', fontWeight: 600 }}>
                  {win ? '+' : '−'}${Math.abs(b.pl)}
                </div>
                <div style={{ padding: '7px 8px', textAlign: 'right', color: win ? 'var(--mint)' : 'var(--coral)', fontWeight: 600 }}>
                  {win ? '+' : '−'}${Math.abs(b.pl) * 10}
                </div>
              </React.Fragment>
            );
          })}
        </div>
      </div>
    );
  }

  // ============== Zone visualization ==============
  // 2-3 colored zones representing payoff at each price band, with strike labels.
  function ZoneViz({ zones, spot, sym, breakevens }) {
    // Compute total range based on min/max across zones
    const min = Math.min(...zones.map(z => z.from));
    const max = Math.max(...zones.map(z => z.to));
    const span = max - min;

    return (
      <div>
        <div className="cap-sm" style={{ marginBottom: 10, fontSize: 9 }}>Payoff zones at expiry — where {sym} can land</div>
        <div style={{ position: 'relative', height: 96, marginBottom: 28 }}>
          {/* Zones */}
          <div style={{ display: 'flex', height: 56, border: '1px solid var(--line-subtle)' }}>
            {zones.map((z, i) => {
              const pct = ((z.to - z.from) / span) * 100;
              const bg = z.kind === 'win' ? 'rgba(151,252,228,0.16)'
                       : z.kind === 'win-cap' ? 'rgba(151,252,228,0.08)'
                       : 'rgba(255,107,107,0.10)';
              const border = z.kind === 'win' ? 'rgba(151,252,228,0.45)'
                            : z.kind === 'win-cap' ? 'rgba(151,252,228,0.25)'
                            : 'rgba(255,107,107,0.35)';
              const txt = z.kind === 'lose' ? 'var(--coral)'
                        : z.kind === 'win' ? 'var(--mint)'
                        : 'rgba(151,252,228,0.65)';
              return (
                <div key={i} style={{
                  width: pct + '%', position: 'relative',
                  background: bg, borderRight: i < zones.length - 1 ? `1px dashed ${border}` : 'none',
                  display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
                  padding: '0 4px',
                }}>
                  <div style={{
                    fontSize: 10, color: txt, fontWeight: 700,
                    fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.12em',
                    marginBottom: 2,
                  }}>
                    {z.kind === 'win' ? '✓ WIN' : z.kind === 'win-cap' ? '✓ WIN (capped)' : '✗ LOSE'}
                  </div>
                  <div style={{ fontSize: 10, color: 'var(--text-3)', textAlign: 'center', lineHeight: 1.3 }}>{z.label}</div>
                </div>
              );
            })}
          </div>

          {/* Strike labels (boundaries between zones) */}
          <div style={{ position: 'relative', height: 18, marginTop: 6 }}>
            {zones.slice(0, -1).map((z, i) => {
              const x = ((z.to - min) / span) * 100;
              return (
                <div key={i} style={{
                  position: 'absolute', left: x + '%', transform: 'translateX(-50%)',
                  fontSize: 10, color: 'var(--text-2)', fontFamily: 'JetBrains Mono, monospace', fontWeight: 600,
                }}>
                  {fmtStrike(sym, z.to)}
                </div>
              );
            })}
            {/* Spot marker */}
            <div style={{
              position: 'absolute', left: ((spot - min) / span) * 100 + '%', transform: 'translateX(-50%)',
              top: -56 - 6, height: 56 + 24,
              borderLeft: '1px dashed var(--text-2)',
            }} />
            <div style={{
              position: 'absolute', left: ((spot - min) / span) * 100 + '%', transform: 'translateX(-50%)',
              top: -68, fontSize: 9, color: 'var(--text-3)',
              fontFamily: 'JetBrains Mono, monospace', textTransform: 'uppercase', letterSpacing: '0.1em',
              background: 'var(--bg-elev)', padding: '0 4px',
            }}>
              spot
            </div>
          </div>

          {/* Breakeven dots on the bar */}
          {breakevens.map((b, i) => {
            const x = ((b - min) / span) * 100;
            return (
              <div key={'be' + i} style={{
                position: 'absolute', left: x + '%', top: 56 - 6,
                width: 12, height: 12, borderRadius: 999,
                background: 'var(--mint)', border: '2px solid var(--bg)',
                transform: 'translateX(-50%)',
              }} title={`Breakeven: ${fmtStrike(sym, b)}`} />
            );
          })}
        </div>
      </div>
    );
  }

  window.VDStrategiesV3 = { Strategies: StrategiesV3 };
})();
