// Shared primitives used by both Variants A and B.
// Tiny SVGs for icons (no emoji).

const Icon = {
  back:    (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>,
  plus:    (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>,
  close:   (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round"><path d="M18 6L6 18M6 6l12 12"/></svg>,
  copy:    (c='currentColor', s=14) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>,
  scan:    (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2M7 12h10"/></svg>,
  search:  (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>,
  chev:    (c='currentColor', s=14) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18l6-6-6-6"/></svg>,
  trash:   (c='currentColor', s=14) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>,
  bolt:    (c='currentColor', s=12) => <svg width={s} height={s} viewBox="0 0 24 24" fill={c}><path d="M13 2L3 14h7l-1 8 11-12h-7l1-8z"/></svg>,
  cog:     (c='currentColor', s=18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3h0a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8v0a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg>,
  sun:     (c='currentColor', s=16) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>,
  moon:    (c='currentColor', s=16) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>,
  auto:    (c='currentColor', s=16) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3v18" fill={c}/><path d="M12 3a9 9 0 0 1 0 18z" fill={c}/></svg>,
  // Tab bar glyphs
  home:    (c='currentColor', s=22) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12l9-8 9 8M5 10v10h14V10"/></svg>,
  bars:    (c='currentColor', s=22) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round"><path d="M5 19V11M12 19V5M19 19v-6"/></svg>,
  list:    (c='currentColor', s=22) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round"><path d="M4 6h16M4 12h16M4 18h16"/></svg>,
  wallet:  (c='currentColor', s=22) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="14" rx="2"/><path d="M3 10h18M16 15h2"/></svg>,
};

// Mini SVG sparkline driven by a numeric series. Falls back to a deterministic
// scribble (window.spark) when fewer than 2 points are available, so the row
// still reads as a sparkline before the first WS push lands.
function LiveSpark({ points, w=50, h=20, color='#50d2c1', strokeW=1.4, fill=true }) {
  if (!points || points.length < 2) {
    return <Spark sym="LIVE" w={w} h={h} color={color} strokeW={strokeW} fill={fill}/>;
  }
  let mn = Infinity, mx = -Infinity;
  for (let i = 0; i < points.length; i++) {
    const v = points[i]; if (v < mn) mn = v; if (v > mx) mx = v;
  }
  // Avoid a flat line when min === max (no recent change).
  const range = (mx - mn) || Math.max(1e-9, Math.abs(mx) * 0.001);
  const N = points.length;
  const stepX = w / Math.max(1, N - 1);
  let path = '';
  for (let i = 0; i < N; i++) {
    const x = (i * stepX).toFixed(2);
    const y = (h - ((points[i] - mn) / range) * (h - 2) - 1).toFixed(2);
    path += (i === 0 ? 'M' : 'L') + x + ',' + y + ' ';
  }
  const id = 'lsp-' + Math.abs(((mx + mn) * 1000) | 0);
  return (
    <svg width={w} height={h} style={{ display:'block' }}>
      {fill && (
        <>
          <defs>
            <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity="0.32"/>
              <stop offset="100%" stopColor={color} stopOpacity="0"/>
            </linearGradient>
          </defs>
          <path d={path + ` L${w},${h} L0,${h} Z`} fill={`url(#${id})`}/>
        </>
      )}
      <path d={path} stroke={color} strokeWidth={strokeW} fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// Mini SVG sparkline using deterministic data.
function Spark({ sym, up=true, w=72, h=22, color='#50d2c1', strokeW=1.5, fill=true }) {
  const d = window.spark(sym, w, h, up);
  const id = 'sp-' + sym + (up?'u':'d');
  return (
    <svg width={w} height={h} style={{ display: 'block' }}>
      {fill && (
        <>
          <defs>
            <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity="0.32"/>
              <stop offset="100%" stopColor={color} stopOpacity="0"/>
            </linearGradient>
          </defs>
          <path d={d + ` L${w},${h} L0,${h} Z`} fill={`url(#${id})`} />
        </>
      )}
      <path d={d} stroke={color} strokeWidth={strokeW} fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// Top-50 token color palette (used for monogram fallback + ring tint)
const TOKEN_PALETTE = {
  BTC:{bg:'#f7931a22',fg:'#f7931a'}, ETH:{bg:'#8b5cf622',fg:'#a78bfa'},
  SOL:{bg:'#9945ff22',fg:'#a974ff'}, HYPE:{bg:'#50d2c122',fg:'#50d2c1'},
  ARB:{bg:'#28a0f022',fg:'#60a5fa'}, AVAX:{bg:'#e84a4222',fg:'#e84a42'},
  DOGE:{bg:'#c2a63322',fg:'#e0c34d'}, BNB:{bg:'#f3ba2f22',fg:'#f3ba2f'},
  XRP:{bg:'#23292f22',fg:'#94a3b8'}, MATIC:{bg:'#8247e522',fg:'#a78bfa'},
  POL:{bg:'#8247e522',fg:'#a78bfa'}, LINK:{bg:'#2a5ada22',fg:'#60a5fa'},
  OP:{bg:'#ff042022',fg:'#ff4d63'}, SUI:{bg:'#4ca2ff22',fg:'#4ca2ff'},
  INJ:{bg:'#00f1c022',fg:'#00f1c0'}, TIA:{bg:'#7b2bf922',fg:'#a974ff'},
  SEI:{bg:'#9c1f4422',fg:'#e879a8'}, ATOM:{bg:'#2e3148bb',fg:'#a3aed4'},
  NEAR:{bg:'#00ec9722',fg:'#00ec97'}, APT:{bg:'#13b5ec22',fg:'#56cdf2'},
  DYDX:{bg:'#6966ff22',fg:'#a3a1ff'}, LDO:{bg:'#00a3ff22',fg:'#56b8ff'},
  AAVE:{bg:'#b6509e22',fg:'#d77ec1'}, UNI:{bg:'#ff007a22',fg:'#ff5fae'},
  ENA:{bg:'#1f1f1fbb',fg:'#cbd5e1'}, WIF:{bg:'#dc94f422',fg:'#dc94f4'},
  PEPE:{bg:'#1aa04022',fg:'#33c860'}, BONK:{bg:'#fbbf2422',fg:'#fbbf24'},
  SHIB:{bg:'#ffa40922',fg:'#ffb84d'}, FET:{bg:'#1f2937bb',fg:'#94a3b8'},
  TAO:{bg:'#ffffff14',fg:'#e5e7eb'}, RUNE:{bg:'#33ff9922',fg:'#33ff99'},
  KAS:{bg:'#70c7ba22',fg:'#70c7ba'}, ORDI:{bg:'#0a1929bb',fg:'#fbbf24'},
  JTO:{bg:'#7eafe522',fg:'#7eafe5'}, JUP:{bg:'#c7f284ff22',fg:'#c7f284'},
  PYTH:{bg:'#a72fff22',fg:'#c674ff'}, ARK:{bg:'#fb212922',fg:'#fb6470'},
  MKR:{bg:'#1aab9b22',fg:'#3edcc8'}, FTM:{bg:'#13b5ec22',fg:'#13b5ec'},
  TRX:{bg:'#ff060a22',fg:'#ff5054'}, LTC:{bg:'#345d9d22',fg:'#7da2d8'},
  BCH:{bg:'#0ac18e22',fg:'#0ac18e'}, ETC:{bg:'#34844422',fg:'#5dbb6e'},
  FIL:{bg:'#0090ff22',fg:'#54b6ff'}, ADA:{bg:'#0033ad22',fg:'#5b8def'},
  DOT:{bg:'#e6007a22',fg:'#ff5fae'}, SAND:{bg:'#00aceaff22',fg:'#36c8ff'},
  AXS:{bg:'#0055d422',fg:'#5b8def'}, MANA:{bg:'#ff2d5522',fg:'#ff5e79'},
  GMX:{bg:'#2d42fcff22',fg:'#7080ff'}, RENDER:{bg:'#cf133eff22',fg:'#ef5071'},
  RNDR:{bg:'#cf133eff22',fg:'#ef5071'}, IMX:{bg:'#0d6cdfff22',fg:'#52a3ff'},
  STX:{bg:'#5546ffff22',fg:'#7d72ff'}, ICP:{bg:'#3b00b922',fg:'#7d56ff'},
  W:{bg:'#3b82f622',fg:'#60a5fa'}, EIGEN:{bg:'#1a0c6dbb',fg:'#a3a1ff'},
  ONDO:{bg:'#0066ff22',fg:'#3a8cff'}, STRK:{bg:'#ec796b22',fg:'#ec796b'},
};

// Token logo — Hyperliquid's official icon CDN first, then coincap, then a
// colored monogram tile. Cross-origin caching is handled by the service
// worker (sw.js / ICON_CACHE), so subsequent visits paint from local cache
// without re-fetching the network.
const COINCAP_ALIAS = { POL:'matic', RNDR:'render', RENDER:'render' };

function TokenGlyph({ sym, size=34, radius=10, bg, fg, mono=false }) {
  const sources = React.useMemo(() => {
    const cdnSym = (COINCAP_ALIAS[sym] || sym || '').toLowerCase();
    return [
      `https://app.hyperliquid.xyz/coins/${sym}.svg`,
      `https://assets.coincap.io/assets/icons/${cdnSym}@2x.png`,
    ];
  }, [sym]);
  const [stage, setStage] = React.useState(0);
  React.useEffect(() => { setStage(0); }, [sym]);

  // Skeleton sits behind the image. Cached SW responses paint the image on
  // the first frame so the skeleton is never seen; uncached first loads see
  // it briefly until network resolves. No fade — instant swap.
  const skeletonBg = 'rgba(127,127,127,0.10)';

  if (stage < sources.length) {
    const src = sources[stage];
    return (
      <span style={{
        display:'inline-block', position:'relative', flexShrink: 0,
        width: size, height: size, borderRadius: radius,
        background: skeletonBg,
        overflow:'hidden',
      }}>
        <img
          src={src}
          alt={sym}
          width={size} height={size}
          decoding="sync"
          loading="eager"
          onError={() => setStage(s => s + 1)}
          style={{
            width: size, height: size, borderRadius: radius,
            objectFit:'contain', display:'block',
          }}
        />
      </span>
    );
  }

  // Monogram fallback — colored tile for legibility when no CDN succeeds.
  const palette = TOKEN_PALETTE[sym] || { bg:'#ffffff10', fg:'#e5e7eb' };
  const _bg = bg ?? palette.bg;
  const _fg = fg ?? palette.fg;
  return (
    <div style={{
      width: size, height: size, borderRadius: radius,
      background: _bg, color: _fg,
      display:'flex', alignItems:'center', justifyContent:'center',
      fontFamily: mono ? 'JetBrains Mono, ui-monospace, monospace' : 'inherit',
      fontWeight: 700, fontSize: size*0.36, letterSpacing: '-0.02em',
      flexShrink: 0, overflow:'hidden',
    }}>
      <span>{sym === 'HYPE' ? 'HY' : sym.slice(0,3)}</span>
    </div>
  );
}

// Wallet avatar — single Hyperliquid logo for every tracked address. Past
// versions used a per-address colored gradient + glyph; the user prefers a
// uniform brand icon since every entry in the list is an HL account.
const HL_LOGO_URL = 'https://app.hyperliquid.xyz/apple-touch-icon.png';
function HLWalletAvatar({ size=32, radius=10 }) {
  return (
    <img
      src={HL_LOGO_URL}
      alt="Hyperliquid"
      width={size} height={size}
      style={{
        width: size, height: size, borderRadius: radius,
        objectFit:'cover', display:'block', flexShrink: 0, background:'transparent',
      }}
      loading="lazy"
    />
  );
}

// PnL coloring resolver — driven by a tweak.
window.pnlColor = function(pnl, mode='rg', opts={}) {
  // mode: rg (red/green), gr (swap), neon (cyan/pink)
  const isPos = pnl >= 0;
  if (mode === 'gr') return isPos ? '#ef4444' : '#22c55e';
  if (mode === 'neon') return isPos ? '#22d3ee' : '#f472b6';
  return isPos ? '#22c55e' : '#ef4444'; // default rg: green up / red down
};

// useTick was a mock-time flicker for the design phase; live updates now come
// from hl-store via WebSocket pushes, so it's been removed.

Object.assign(window, { Icon, Spark, LiveSpark, TokenGlyph, HLWalletAvatar });
