// leaderboard.jsx — Weekly XP leaderboard (compact card + full screen)

const { useState: useStateLB } = React;
const { Card, Chip, TopBar, IconBtn, DisplayHeading, Icon } = window.LAUNCH_SCREENS_1;

// Competitors — the rest of the field. The signed-in user is injected at render time
// (see buildLeaders) so their real handle, XP and streak slot into the ranking.
const OTHER_LEADERS = [
  { name: 'sasha.vee',  lbl: 'SV', color: '#CAFF33', xp: 4820, delta: '+12', streak: 64 },
  { name: 'kai.park',   lbl: 'KP', color: '#C72820', xp: 3940, delta: '+3',  streak: 21 },
  { name: 'isla.loop',  lbl: 'IL', color: '#FBBF24', xp: 3210, delta: '-1',  streak: 15 },
  { name: 'theo.m',     lbl: 'TM', color: '#7A5AE0', xp: 2880, delta: '+8',  streak: 8  },
  { name: 'jordan.ek',  lbl: 'JE', color: '#22C55E', xp: 2410, delta: '-2',  streak: 12 },
  { name: 'nova.b',     lbl: 'NB', color: '#EC4899', xp: 2180, delta: '+1',  streak: 19 },
  { name: 'rae.lou',    lbl: 'RL', color: '#06B6D4', xp: 1960, delta: '+5',  streak: 6  },
  { name: 'milo.s',     lbl: 'ML', color: '#A855F7', xp: 1720, delta: '-3',  streak: 4  },
  { name: 'aria.q',     lbl: 'AQ', color: '#F97316', xp: 1540, delta: '+2',  streak: 22 },
];

// Inject the signed-in user into the field and re-rank by weekly XP.
// In live mode, pass `liveRows` (already from the DB, including the user's row).
function buildLeaders(user, liveRows) {
  if (liveRows && liveRows.length) {
    // Ensure the current user is present even if outside the fetched page.
    let field = liveRows.map(l => ({ ...l, lbl: l.initials }));
    if (!field.some(l => l.you)) {
      field.push({
        name: user.handle, handle: user.handle, lbl: user.initials, initials: user.initials,
        color: user.color, xp: user.xpThisWeek, streak: user.streak,
        delta: '+' + Math.max(1, Math.round(user.xpEarnedToday / 80)), you: true,
      });
    }
    field = field.map(l => ({ ...l, name: l.name || l.handle }));
    field.sort((a, b) => b.xp - a.xp);
    return field.map((l, i) => ({ ...l, rank: i + 1 }));
  }
  const youRow = {
    name: user.handle, lbl: user.initials, color: user.color,
    xp: user.xpThisWeek, delta: '+' + Math.max(1, Math.round(user.xpEarnedToday / 80)),
    streak: user.streak, you: true,
  };
  const field = [...OTHER_LEADERS.map(l => ({ ...l, you: false })), youRow];
  field.sort((a, b) => b.xp - a.xp);
  return field.map((l, i) => ({ ...l, rank: i + 1 }));
}

// XP breakdown proportions — DEMO fallback only (no live ledger). Scaled to the
// user's weekly XP so the parts sum to the whole.
const XP_PROPORTIONS = [
  { src: 'Daily streak',     w: 740, icon: '🔥' },
  { src: 'Sessions booked',  w: 920, icon: '🎙' },
  { src: 'Songs logged',     w: 480, icon: '🎵' },
  { src: 'Feedback given',   w: 320, icon: '💬' },
  { src: 'Assignment bonus', w: 180, icon: '⚡' },
];
// Real point categories (points_ledger.action) → friendly label + icon.
const XP_ACTION_META = {
  like:    { src: 'Likes given',     icon: '💛' },
  comment: { src: 'Comments',        icon: '💬' },
  post:    { src: 'Posts shared',    icon: '📢' },
  song:    { src: 'Songs submitted', icon: '🎵' },
  track:   { src: 'Songs uploaded',  icon: '🎶' },
  rate:    { src: 'Tracks rated',    icon: '⭐' },
};
// Prefer REAL per-category ledger data (liveXp = [{action, points}]); fall back
// to demo proportions when it's null/empty.
function buildXpSources(user, liveXp) {
  if (liveXp && liveXp.length) {
    return liveXp.map(r => {
      const m = XP_ACTION_META[r.action] || { src: r.action, icon: '⚡' };
      return { src: m.src, icon: m.icon, n: r.points };
    });
  }
  const totalW = XP_PROPORTIONS.reduce((a, b) => a + b.w, 0);
  return XP_PROPORTIONS.map(p => ({ src: p.src, icon: p.icon, n: Math.round(user.xpThisWeek * p.w / totalW) }));
}

// ── weekly reset countdown helpers ──────────────────────────────────────────
// Next Monday 00:00 (local approximation) → ms until reset. The full screen uses
// the server's exact ET bounds when available; this keeps things roughly right
// (compact card + demo mode).
function msToNextMondayLocal() {
  const now = new Date();
  const d = new Date(now);
  const day = d.getDay();                       // 0 Sun … 6 Sat
  const daysUntilMon = (8 - (day === 0 ? 7 : day)) % 7 || 7;  // 1 … 7
  d.setDate(d.getDate() + daysUntilMon);
  d.setHours(0, 0, 0, 0);
  return d.getTime() - now.getTime();
}
function fmtCountdown(ms) {
  if (ms == null || ms < 0) ms = 0;
  const totalMin = Math.floor(ms / 60000);
  const days = Math.floor(totalMin / (60 * 24));
  const hours = Math.floor((totalMin % (60 * 24)) / 60);
  const mins = totalMin % 60;
  return days > 0 ? `${days}D · ${hours}H` : `${hours}H · ${mins}M`;
}
// Human label for the week being viewed (uses server bounds when present).
function weekRangeLabel(bounds, week) {
  if (!bounds) return week === 'previous' ? 'LAST WEEK' : 'THIS WEEK';
  const shift = week === 'previous' ? -7 * 864e5 : 0;
  const s = new Date(bounds.start + shift);
  const e = new Date(bounds.end + shift - 864e5); // inclusive Sunday
  const fmt = d => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }).toUpperCase();
  return `${week === 'previous' ? 'LAST WEEK' : 'THIS WEEK'} · ${fmt(s)} — ${fmt(e)}`;
}

// The profile's xp_this_week column isn't wired up yet, so for live users it's 0.
// Until it is, surface the community points the user actually earns (likes,
// comments, posts, songs, ratings) as their weekly XP so the board reflects real
// activity instead of all-zeros. `points` comes from usePoints().
function withXp(user, points) {
  if (!user) return user;
  if (user.xpThisWeek > 0) return user;
  const xp = (points && (points.earned || points.balance)) || 0;
  return { ...user, xpThisWeek: xp };
}

// Fetch live competitors from Supabase when configured; null otherwise.
// `week` ∈ 'current' | 'previous' — refetches when it changes.
function useLiveLeaders(week = 'current') {
  const [rows, setRows] = useStateLB(null);
  React.useEffect(() => {
    let alive = true;
    setRows(null);
    if (window.LAUNCH_USER && window.LAUNCH_USER.isConfigured()) {
      window.LAUNCH_USER.fetchLeaderboard(20, week).then(r => { if (alive && r) setRows(r); });
    }
    return () => { alive = false; };
  }, [week]);
  return rows;
}

// ────────────────────────────────────────────────────────
// PodiumTile — for top 3 with crown shapes
// ────────────────────────────────────────────────────────
function PodiumTile({ leader, place, theme, onTap }) {
  // Empty podium slot (e.g. a scope filter left fewer than 3 people) → keep the
  // column for layout but render nothing, instead of crashing on leader.color.
  if (!leader) return <div style={{ flex: 1 }} />;
  const isFirst = place === 1;
  const heights = { 1: 130, 2: 104, 3: 88 };
  const medalColors = {
    1: { bg: '#FFD700', glow: '#FFF7C2', label: '#5C4A00' },
    2: { bg: '#C0C7CF', glow: '#E8EDF2', label: '#3D464D' },
    3: { bg: '#CD7F32', glow: '#E8B988', label: '#4A2A00' },
  };
  const m = medalColors[place];

  return (
    <button onClick={onTap} style={{
      flex: 1, padding: 0, border: 'none', cursor: 'pointer',
      background: 'transparent', display: 'flex', flexDirection: 'column',
      alignItems: 'center', gap: 10,
    }}>
      {/* Crown for #1 */}
      {isFirst && (
        <svg width="28" height="20" viewBox="0 0 28 20" style={{ marginBottom: -4 }}>
          <path d="M2 18l2-12 5 6 5-10 5 10 5-6 2 12H2z" fill={m.bg} stroke={m.label} strokeWidth="1.2" strokeLinejoin="round"/>
        </svg>
      )}
      {/* Avatar */}
      <div style={{ position: 'relative' }}>
        <div style={{
          width: isFirst ? 72 : 60, height: isFirst ? 72 : 60,
          borderRadius: 99, background: leader.color,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: theme.fontDisplay, color: '#0A0A0A',
          fontSize: isFirst ? 24 : 20,
          border: `3px solid ${m.bg}`,
          boxShadow: `0 0 0 4px ${m.glow}30, 0 8px 24px ${m.bg}40`,
        }}>{leader.lbl}</div>
        <div style={{
          position: 'absolute', bottom: -6, right: -6,
          width: 24, height: 24, borderRadius: 99,
          background: m.bg, color: m.label,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: theme.fontDisplay, fontSize: 13,
          border: `2px solid ${theme.bg}`,
        }}>{place}</div>
      </div>
      <div style={{ textAlign: 'center' }}>
        <div style={{
          fontFamily: theme.fontMono, fontSize: 10, color: theme.text,
          fontWeight: 700, letterSpacing: 0.3,
        }}>{leader.name}</div>
        <div style={{
          fontFamily: theme.fontDisplay, fontSize: isFirst ? 22 : 18,
          color: theme.accent, lineHeight: 1, marginTop: 4, letterSpacing: -0.2,
        }}>{leader.xp.toLocaleString()}</div>
        <div style={{
          fontFamily: theme.fontMono, fontSize: 8, color: theme.muted,
          letterSpacing: 0.8, fontWeight: 600, marginTop: 2,
        }}>XP</div>
      </div>
      {/* Pedestal */}
      <div style={{
        width: '100%', height: heights[place], borderRadius: '8px 8px 0 0',
        background: `linear-gradient(180deg, ${m.bg} 0%, ${m.label} 100%)`,
        display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
        paddingTop: 12, position: 'relative', overflow: 'hidden',
      }}>
        <span style={{
          fontFamily: theme.fontDisplay, fontSize: isFirst ? 40 : 32,
          color: 'rgba(255,255,255,0.4)', lineHeight: 1,
        }}>{place}</span>
        {/* shine */}
        <div style={{
          position: 'absolute', inset: 0,
          background: 'linear-gradient(180deg, rgba(255,255,255,0.25), transparent 40%)',
        }} />
      </div>
    </button>
  );
}

// ────────────────────────────────────────────────────────
// LeaderboardCard — compact card for Home screen
// ────────────────────────────────────────────────────────
function LeaderboardCard({ theme, onOpen }) {
  const user = withXp(window.LAUNCH_USER.useUser(), window.LAUNCH_USER.usePoints());
  const liveRows = useLiveLeaders();
  const LEADERS = buildLeaders(user, liveRows);
  const top3 = LEADERS.slice(0, 3);
  const you = LEADERS.find(l => l.you);

  return (
    <Card theme={theme} style={{
      overflow: 'hidden', cursor: 'pointer',
    }}>
      <button onClick={onOpen} style={{
        width: '100%', padding: 14, background: 'transparent',
        border: 'none', cursor: 'pointer', textAlign: 'left',
      }}>
        {/* header */}
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          marginBottom: 12,
        }}>
          <div>
            <div style={{
              fontFamily: theme.fontMono, fontSize: 10, color: theme.muted,
              letterSpacing: 1, fontWeight: 700,
            }}>WEEKLY LEADERBOARD</div>
            <div style={{
              fontFamily: theme.fontDisplay, fontSize: 22, color: theme.text,
              textTransform: 'uppercase', letterSpacing: 0.2,
              lineHeight: 1, marginTop: 4,
            }}>
              YOU'RE <span style={{ color: theme.accent }}>#{you.rank}</span> THIS WEEK
            </div>
          </div>
          <div style={{
            fontFamily: theme.fontMono, fontSize: 9, color: theme.muted,
            letterSpacing: 0.8, fontWeight: 700, textAlign: 'right',
          }}>
            <div>RESETS IN</div>
            <div style={{ color: theme.accent, fontSize: 11, marginTop: 2 }}>{fmtCountdown(msToNextMondayLocal())}</div>
          </div>
        </div>

        {/* top 3 strip */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {top3.map((l, i) => (
            <div key={l.rank} style={{
              display: 'flex', alignItems: 'center', gap: 10,
              padding: '8px 10px', borderRadius: 10,
              background: i === 0 ? `${theme.accent}12` : theme.surface2,
              border: i === 0 ? `1px solid ${theme.accent}40` : '1px solid transparent',
            }}>
              <div style={{
                width: 22, height: 22, borderRadius: 99,
                background: i === 0 ? '#FFD700' : i === 1 ? '#C0C7CF' : '#CD7F32',
                color: '#0A0A0A',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: theme.fontDisplay, fontSize: 11,
                flexShrink: 0,
              }}>{l.rank}</div>
              <div style={{
                width: 28, height: 28, borderRadius: 99, background: l.color,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: theme.fontDisplay, color: '#0A0A0A', fontSize: 11,
                flexShrink: 0,
              }}>{l.lbl}</div>
              <div style={{ flex: 1, minWidth: 0, fontFamily: theme.fontBody, fontSize: 13, color: theme.text, fontWeight: 600 }}>
                {l.name}
              </div>
              <div style={{
                fontFamily: theme.fontDisplay, fontSize: 16, color: theme.text,
                letterSpacing: -0.2,
              }}>{l.xp.toLocaleString()}</div>
              <div style={{
                fontFamily: theme.fontMono, fontSize: 9, color: theme.muted,
                letterSpacing: 0.5, fontWeight: 700, width: 22, textAlign: 'right',
              }}>XP</div>
            </div>
          ))}
        </div>

        {/* you row separator */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '10px 10px', borderRadius: 10, marginTop: 8,
          background: theme.accent, color: theme.onAccent,
        }}>
          <div style={{
            width: 22, height: 22, borderRadius: 99,
            background: theme.onAccent, color: theme.accent,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontFamily: theme.fontDisplay, fontSize: 11,
            flexShrink: 0,
          }}>{you.rank}</div>
          <div style={{
            fontFamily: theme.fontMono, fontSize: 10, fontWeight: 700,
            letterSpacing: 0.8, flex: 1,
          }}>YOU · {you.name.toUpperCase()}</div>
          <div style={{
            fontFamily: theme.fontDisplay, fontSize: 16, letterSpacing: -0.2,
          }}>{you.xp.toLocaleString()}</div>
          <div style={{
            fontFamily: theme.fontMono, fontSize: 9, opacity: 0.7,
            letterSpacing: 0.5, fontWeight: 700, width: 22, textAlign: 'right',
          }}>XP</div>
        </div>

        <div style={{
          marginTop: 10, fontFamily: theme.fontMono, fontSize: 10,
          color: theme.accent, letterSpacing: 1, fontWeight: 700,
          textAlign: 'center',
        }}>
          SEE FULL RANKINGS →
        </div>
      </button>
    </Card>
  );
}

// ────────────────────────────────────────────────────────
// LeaderboardScreen — full ranked list + podium + breakdown
// ────────────────────────────────────────────────────────
function LeaderboardScreen({ theme, onBack }) {
  const [scope, setScope] = useStateLB('global'); // 'global' | 'friends' | 'genre'
  const [week, setWeek] = useStateLB('current');  // 'current' | 'previous'
  const user = withXp(window.LAUNCH_USER.useUser(), window.LAUNCH_USER.usePoints());
  const liveRows = useLiveLeaders(week);
  // Who you follow (for the FOLLOWING tab). Handles; empty in demo.
  const [following, setFollowing] = useStateLB([]);
  React.useEffect(() => {
    let alive = true;
    const U = window.LAUNCH_USER;
    if (U && U.fetchFollowing) {
      Promise.resolve(U.fetchFollowing()).then(f => { if (alive && f) setFollowing(f); });
    }
    return () => { alive = false; };
  }, []);
  // REAL per-category XP for the selected week (live) — null in demo.
  const [liveXp, setLiveXp] = useStateLB(null);
  React.useEffect(() => {
    let alive = true;
    setLiveXp(null);
    const U = window.LAUNCH_USER;
    if (U && U.fetchMyWeeklyXp) U.fetchMyWeeklyXp(week).then(x => { if (alive) setLiveXp(x); });
    return () => { alive = false; };
  }, [week]);
  // Exact reset time (server ET bounds) + a live-ticking countdown.
  const [bounds, setBounds] = useStateLB(null);
  const [nowMs, setNowMs] = useStateLB(() => Date.now());
  React.useEffect(() => {
    let alive = true;
    const U = window.LAUNCH_USER;
    if (U && U.fetchWeekBounds) U.fetchWeekBounds().then(b => { if (alive && b) setBounds(b); });
    const t = setInterval(() => { if (alive) setNowMs(Date.now()); }, 60000);
    return () => { alive = false; clearInterval(t); };
  }, []);
  const resetMs = bounds ? (bounds.end - nowMs) : msToNextMondayLocal();
  // Weekly prize (top-3 of the last FINISHED week — independent of the toggle).
  const [prize, setPrize] = useStateLB(null);
  const [claiming, setClaiming] = useStateLB(false);
  const [claimMsg, setClaimMsg] = useStateLB(null);
  const loadPrize = () => {
    const U = window.LAUNCH_USER;
    if (U && U.weeklyPrizeStatus) U.weeklyPrizeStatus().then(p => setPrize(p));
  };
  React.useEffect(() => { loadPrize(); }, []);
  const onClaimPrize = async () => {
    const U = window.LAUNCH_USER;
    if (!U || !U.claimWeeklyPrize || claiming) return;
    setClaiming(true); setClaimMsg(null);
    const res = await U.claimWeeklyPrize();
    setClaiming(false);
    if (res && res.ok) {
      setClaimMsg({ ok: true, text: 'Claimed! $40 credit added — free on your next In-Depth eval.' });
      loadPrize();
    } else {
      setClaimMsg({ ok: false, text: (res && (res.message || res.error)) || 'Could not claim.' });
    }
  };
  // Per-category breakdown + weekly total (real when live).
  const XP_SOURCES = buildXpSources(user, liveXp);
  const totalYouXP = XP_SOURCES.reduce((a, b) => a + b.n, 0);
  // Keep the injected "you" row consistent with the weekly total in live mode.
  const userForBoard = (liveXp && liveXp.length) ? { ...user, xpThisWeek: totalYouXP } : user;
  const ALL = buildLeaders(userForBoard, liveRows);
  // Apply the scope filter, then re-rank. You always stay visible.
  const followSet = new Set((following || []).map(h => String(h).toLowerCase()));
  const myGenre = String((user && (user.genre || (user.genres && user.genres[0]))) || '').toLowerCase();
  const LEADERS = ALL.filter(l => {
    if (l.you) return true;
    const h = String(l.handle || l.name || '').toLowerCase();
    if (scope === 'friends') return followSet.has(h);
    if (scope === 'genre')   return myGenre && String(l.genre || '').toLowerCase() === myGenre;
    return true; // global
  }).map((l, i) => ({ ...l, rank: i + 1 }));
  const top3 = LEADERS.slice(0, 3);
  const rest = LEADERS.slice(3);
  const you = LEADERS.find(l => l.you);

  return (
    <div style={{ paddingBottom: 110 }}>
      {/* Top bar */}
      <div style={{
        paddingTop: 58, paddingBottom: 8, paddingLeft: theme.pad, paddingRight: theme.pad,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <button onClick={onBack} style={{
          width: 38, height: 38, borderRadius: 12,
          background: theme.surface, border: `1px solid ${theme.border}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer',
        }}>
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
            <path d="M9 2L4 7l5 5" stroke={theme.text} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </button>
        <div style={{ textAlign: 'right' }}>
          <div style={{
            fontFamily: theme.fontMono, fontSize: 9, color: theme.muted,
            letterSpacing: 1, fontWeight: 700,
          }}>{week === 'previous' ? 'STATUS' : 'RESETS IN'}</div>
          <div style={{
            fontFamily: theme.fontDisplay, fontSize: 14, color: theme.accent,
            letterSpacing: 0.5,
          }}>{week === 'previous' ? 'ENDED' : fmtCountdown(resetMs)}</div>
        </div>
      </div>

      {/* Hero */}
      <div style={{ padding: `4px ${theme.pad}px 0` }}>
        <div style={{
          fontFamily: theme.fontMono, fontSize: 10, color: theme.accent,
          letterSpacing: 1, fontWeight: 700,
        }}>★ {weekRangeLabel(bounds, week)}</div>
        <DisplayHeading theme={theme} size={36} style={{ marginTop: 6 }}>
          THE WEEKLY<br/>LEADERBOARD
        </DisplayHeading>
      </div>

      {/* Week toggle — this week vs the previous (finished) week */}
      <div style={{ display: 'flex', gap: 6, padding: `${theme.gap}px ${theme.pad}px 0` }}>
        {[
          { id: 'current',  l: 'THIS WEEK' },
          { id: 'previous', l: 'LAST WEEK' },
        ].map(w => (
          <button key={w.id} onClick={() => setWeek(w.id)} style={{
            flex: 1, padding: '9px 14px', borderRadius: 99, cursor: 'pointer', border: 'none',
            background: week === w.id ? theme.accent : 'transparent',
            color: week === w.id ? theme.onAccent : theme.text,
            fontFamily: theme.fontMono, fontSize: 11, fontWeight: 700,
            letterSpacing: 0.8, textTransform: 'uppercase',
            boxShadow: week === w.id ? 'none' : `inset 0 0 0 1px ${theme.border}`,
          }}>{w.l}</button>
        ))}
      </div>

      {/* Scope tabs */}
      <div style={{
        display: 'flex', gap: 6, padding: `${theme.gap}px ${theme.pad}px 0`,
      }}>
        {[
          { id: 'global', l: 'GLOBAL' },
          { id: 'friends', l: 'FOLLOWING' },
          { id: 'genre', l: 'YOUR GENRE' },
        ].map(s => (
          <button key={s.id} onClick={() => setScope(s.id)} style={{
            padding: '8px 14px', borderRadius: 99, cursor: 'pointer',
            border: 'none',
            background: scope === s.id ? theme.text : 'transparent',
            color: scope === s.id ? theme.bg : theme.text,
            fontFamily: theme.fontMono, fontSize: 11, fontWeight: 700,
            letterSpacing: 0.8, textTransform: 'uppercase',
            boxShadow: scope === s.id ? 'none' : `inset 0 0 0 1px ${theme.border}`,
          }}>{s.l}</button>
        ))}
      </div>

      {/* Podium */}
      <div style={{
        padding: `${theme.gap + 6}px ${theme.pad}px 0`,
      }}>
        <div style={{
          display: 'flex', alignItems: 'flex-end', gap: 8,
          padding: '0 0',
        }}>
          <PodiumTile leader={top3[1]} place={2} theme={theme} />
          <PodiumTile leader={top3[0]} place={1} theme={theme} />
          <PodiumTile leader={top3[2]} place={3} theme={theme} />
        </div>
      </div>

      {/* Rest of rankings */}
      <div style={{ padding: `${theme.gap + 6}px ${theme.pad}px 0` }}>
        <div style={{
          fontFamily: theme.fontMono, fontSize: 11, color: theme.muted,
          letterSpacing: 1, fontWeight: 600, marginBottom: 10,
        }}>RANKINGS · 4 → {LEADERS.length}</div>
        <Card theme={theme} style={{ padding: 4 }}>
          {rest.map((l, i, arr) => (
            <div key={l.rank} style={{
              padding: '12px', display: 'flex', alignItems: 'center', gap: 10,
              borderBottom: i < arr.length - 1 ? `1px solid ${theme.border}` : 'none',
              background: l.you ? `${theme.accent}10` : 'transparent',
              borderRadius: l.you ? 10 : 0,
              border: l.you ? `1px solid ${theme.accent}30` : 'none',
              borderBottom: i < arr.length - 1 ? `1px solid ${theme.border}` : 'none',
              margin: l.you ? '4px 0' : 0,
            }}>
              <div style={{
                width: 28, height: 28, borderRadius: 8,
                background: l.you ? theme.accent : theme.surface2,
                color: l.you ? theme.onAccent : theme.text,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: theme.fontDisplay, fontSize: 13,
                flexShrink: 0, letterSpacing: -0.2,
              }}>{l.rank}</div>
              <div style={{
                width: 36, height: 36, borderRadius: 99, background: l.color,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: theme.fontDisplay, color: '#0A0A0A', fontSize: 13,
                flexShrink: 0,
              }}>{l.lbl}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{
                  fontFamily: theme.fontBody, fontSize: 14,
                  color: theme.text, fontWeight: l.you ? 700 : 600,
                }}>
                  {l.name} {l.you && <span style={{ color: theme.accent, fontFamily: theme.fontMono, fontSize: 10, marginLeft: 4, letterSpacing: 1, fontWeight: 700 }}>YOU</span>}
                </div>
                <div style={{
                  fontFamily: theme.fontMono, fontSize: 10, color: theme.muted,
                  letterSpacing: 0.5, marginTop: 1, fontWeight: 600,
                }}>
                  🔥 {l.streak}D STREAK
                </div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div style={{
                  fontFamily: theme.fontDisplay, fontSize: 18, color: theme.text,
                  letterSpacing: -0.2, lineHeight: 1,
                }}>{l.xp.toLocaleString()}</div>
                <div style={{
                  fontFamily: theme.fontMono, fontSize: 9, fontWeight: 700,
                  letterSpacing: 0.5, marginTop: 2,
                  color: (l.delta && l.delta.startsWith('+')) ? '#22C55E' : (l.delta && l.delta.startsWith('-')) ? '#EF4444' : theme.muted,
                }}>{l.delta ? `${l.delta} POS` : 'PTS'}</div>
              </div>
            </div>
          ))}
        </Card>
      </div>

      {/* XP breakdown */}
      <div style={{ padding: `${theme.gap + 6}px ${theme.pad}px 0` }}>
        <div style={{
          display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
          marginBottom: 10,
        }}>
          <span style={{ fontFamily: theme.fontMono, fontSize: 11, color: theme.muted, letterSpacing: 1, fontWeight: 600 }}>
            YOUR XP · {week === 'previous' ? 'LAST WEEK' : 'THIS WEEK'}
          </span>
          <span style={{ fontFamily: theme.fontDisplay, fontSize: 22, color: theme.accent, letterSpacing: -0.2, lineHeight: 1 }}>
            {totalYouXP.toLocaleString()}
          </span>
        </div>
        <Card theme={theme} style={{ padding: 14 }}>
          {XP_SOURCES.length === 0 && (
            <div style={{ fontFamily: theme.fontBody, fontSize: 13, color: theme.muted, textAlign: 'center', padding: '6px 0' }}>
              No XP {week === 'previous' ? 'last' : 'yet this'} week — like, comment, post & upload to climb.
            </div>
          )}
          {XP_SOURCES.map((s, i) => {
            const pct = totalYouXP ? (s.n / totalYouXP) * 100 : 0;
            return (
              <div key={i} style={{ marginBottom: i < XP_SOURCES.length - 1 ? 12 : 0 }}>
                <div style={{
                  display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                  marginBottom: 5,
                }}>
                  <span style={{
                    fontFamily: theme.fontBody, fontSize: 13, color: theme.text,
                    fontWeight: 500, display: 'inline-flex', alignItems: 'center', gap: 8,
                  }}>
                    <span>{s.icon}</span> {s.src}
                  </span>
                  <span style={{
                    fontFamily: theme.fontMono, fontSize: 11, color: theme.text,
                    fontWeight: 700,
                  }}>+{s.n}</span>
                </div>
                <div style={{
                  height: 5, borderRadius: 99, background: theme.surface2,
                  overflow: 'hidden',
                }}>
                  <div style={{
                    width: `${pct}%`, height: '100%',
                    background: theme.accent, borderRadius: 99,
                  }} />
                </div>
              </div>
            );
          })}
        </Card>
      </div>

      {/* Prize callout — actionable when you placed top-3 last (finished) week */}
      <div style={{ padding: `${theme.gap + 6}px ${theme.pad}px 0` }}>
        {(() => {
          const won = prize && prize.eligible;
          const claimed = prize && prize.alreadyClaimed;
          return (
        <Card theme={theme} style={{
          padding: 16,
          background: won
            ? `linear-gradient(135deg, #FFD70033 0%, ${theme.accent}22 100%)`
            : `linear-gradient(135deg, ${theme.accent}25 0%, transparent 100%)`,
          borderColor: won ? '#FFD70066' : `${theme.accent}40`,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{
              width: 44, height: 44, borderRadius: 12,
              background: won ? '#FFD700' : theme.accent, color: won ? '#5C4A00' : theme.onAccent,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              flexShrink: 0, fontSize: 22,
            }}>🏆</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{
                fontFamily: theme.fontMono, fontSize: 10, color: theme.accent,
                letterSpacing: 1, fontWeight: 700,
              }}>WEEKLY PRIZE</div>
              <div style={{
                fontFamily: theme.fontDisplay, fontSize: 18, color: theme.text,
                textTransform: 'uppercase', letterSpacing: 0.2, lineHeight: 1, marginTop: 4,
              }}>{won
                ? `YOU PLACED #${prize.rank} LAST WEEK`
                : 'TOP 3 GET A FREE IN-DEPTH EVAL'}</div>
              <div style={{
                fontFamily: theme.fontBody, fontSize: 12, color: theme.muted,
                marginTop: 4, lineHeight: 1.4,
              }}>{won
                ? (claimed
                    ? 'Prize claimed ✓ — $40 credit is on your account for an In-Depth eval.'
                    : 'Claim your free $40 In-Depth eval below.')
                : 'Finish the week in the top 3 to unlock a free $40 In-Depth eval.'}</div>
            </div>
          </div>

          {won && !claimed && (
            <button onClick={onClaimPrize} disabled={claiming} style={{
              width: '100%', marginTop: 14, padding: '13px', borderRadius: 12, border: 'none',
              background: claiming ? theme.surface2 : '#FFD700', color: claiming ? theme.muted : '#5C4A00',
              cursor: claiming ? 'wait' : 'pointer',
              fontFamily: theme.fontDisplay, fontSize: 14, letterSpacing: 0.8, textTransform: 'uppercase',
            }}>{claiming ? 'CLAIMING…' : '🏆 CLAIM FREE IN-DEPTH EVAL ($40)'}</button>
          )}
          {claimMsg && (
            <div style={{
              marginTop: 10, padding: '9px 12px', borderRadius: 10,
              background: claimMsg.ok ? 'rgba(34,197,94,0.12)' : theme.surface2,
              border: `1px solid ${claimMsg.ok ? 'rgba(34,197,94,0.4)' : theme.border}`,
              fontFamily: theme.fontBody, fontSize: 12, color: claimMsg.ok ? '#22C55E' : theme.text,
            }}>{claimMsg.text}</div>
          )}
        </Card>
          );
        })()}
      </div>
    </div>
  );
}

window.LAUNCH_SCREENS_6 = { LeaderboardCard, LeaderboardScreen };
