/* screen-brand-aff-report.jsx — Brand AFF Performance & Creator Evaluation
   Data-dense report: funnel + quadrant + leaderboard + payout pipeline.
   Tabs: Brand-side ‖ Creator self view. */
/* global React, AppSidebar, AppTopbar, useRouter, useT, useTweaks,
   Icon, Pill, Avatar, Counter, Sparkline, formatCompact, formatMoney */

const { useState, useMemo } = React;

// ── i18n (inline; keeps the file self-contained) ───────────────────
const AFF_I18N = {
  en: {
    title: 'AFF performance', subtitle: 'Track every click, order and payout — and decide who to re-book.',
    tabBrand: 'Brand view', tabCreator: 'Creator view',
    eyebrow: 'Affiliate · Live · last sync 2 min ago',
    filter: { campaign: 'Campaign', period: 'Period', channel: 'Channel', tier: 'Tier', all: 'All', reset: 'Reset' },
    period: { d7: 'Last 7d', d30: 'Last 30d', d90: 'Last 90d', qtd: 'Q2 to date' },
    kpi: { gmv: 'GMV', orders: 'Orders', cr: 'Click→Order', roas: 'ROAS', aov: 'AOV', commission: 'Commission paid', vsPrev: 'vs prev', creators: 'Active creators' },
    funnel: { title: 'AFF flow · last 30d', subtitle: 'Impression → Click → Cart → Order → Payout', dropoff: 'drop-off', cvr: 'CVR' },
    funnelStages: ['Impressions', 'Clicks', 'Added to cart', 'Orders', 'Payouts cleared'],
    funnelByChannel: 'Channel split · clicks',
    salesChannels: 'Connected sales channels', salesSubtitle: 'Where orders actually close — brand seller accounts you’ve authorised.',
    connected: 'Connected', notConnected: 'Not connected',
    connectCta: 'Connect', syncedAt: 'synced',
    campaignPicker: 'Campaign', allCampaigns: 'All AFF campaigns',
    channelMix: 'Channel mix', perChannel: 'Orders by sales channel',
    quadrant: { title: 'Creator quadrant', subtitle: 'Reach × Conversion · last 30d',
      stars: 'Stars · re-book first', reachers: 'Reach machines · push offers',
      gems: 'Hidden gems · scale up', watch: 'Watchlist · evaluate' },
    table: { title: 'Creator leaderboard', subtitle: 'Sorted by selected metric · click row for detail',
      headRank: '#', headCreator: 'Creator', headTier: 'Tier', headChan: 'Channel',
      headGmv: 'GMV', headOrders: 'Orders', headCr: 'CR', headRoas: 'ROAS', headComm: 'Commission',
      headTrend: '7d trend', headStatus: 'Status', headAction: '' },
    actions: { rebook: 'Re-book', message: 'Message', pause: 'Pause AFF', adjust: 'Adjust %', detail: 'View detail', approvePayout: 'Approve' },
    pipeline: { title: 'Commission pipeline', subtitle: 'Where each dollar of payout sits right now',
      pendingReview: 'Pending review', processing: 'Processing', paid: 'Paid this period',
      ready: 'Ready', held: 'Held', cleared: 'Cleared' },
    status: { active: 'Active', paused: 'Paused', warmup: 'Warming up', risk: 'At risk' },
    tierDesc: { A: 'Top 10% — re-book on auto', B: 'Reliable — keep in rotation', C: 'Mixed — coach or re-brief', D: 'Underperforming — pause or cut' },
    creator: { mineTitle: 'My AFF earnings', mineSub: 'Every link, every order, every payout — yours alone.',
      myFunnel: 'My funnel · last 30d', myLinks: 'Top performing links', payoutQueue: 'Payout queue',
      copyLink: 'Copy link', shareKit: 'Share kit', tax: 'Tax doc' },
    cta: { export: 'Export CSV', share: 'Share report', compare: 'Compare periods' }
  },
  vi: {
    title: 'Hiệu suất AFF', subtitle: 'Theo dõi từng click, đơn và payout — và quyết định re-book ai.',
    tabBrand: 'Góc nhìn Brand', tabCreator: 'Góc nhìn Creator',
    eyebrow: 'Tiếp thị liên kết · Trực tiếp · cập nhật 2 phút trước',
    filter: { campaign: 'Chiến dịch', period: 'Khoảng thời gian', channel: 'Kênh', tier: 'Hạng', all: 'Tất cả', reset: 'Đặt lại' },
    period: { d7: '7 ngày', d30: '30 ngày', d90: '90 ngày', qtd: 'Q2 tới nay' },
    kpi: { gmv: 'GMV', orders: 'Đơn hàng', cr: 'Click→Đơn', roas: 'ROAS', aov: 'Giá trị TB', commission: 'Hoa hồng đã trả', vsPrev: 'so kỳ trước', creators: 'Creator active' },
    funnel: { title: 'Luồng AFF · 30 ngày', subtitle: 'Hiển thị → Click → Cart → Đơn → Tiền về', dropoff: 'rớt', cvr: 'CVR' },
    funnelStages: ['Hiển thị', 'Click', 'Vào giỏ', 'Đơn hàng', 'Đã trả'],
    funnelByChannel: 'Phân chia kênh · click',
    salesChannels: 'Kênh bán hàng đã kết nối', salesSubtitle: 'Nơi đơn chốt — tài khoản seller brand đã cấp quyền.',
    connected: 'Đã kết nối', notConnected: 'Chưa kết nối',
    connectCta: 'Kết nối', syncedAt: 'đồng bộ',
    campaignPicker: 'Chiến dịch', allCampaigns: 'Tất cả chiến dịch AFF',
    channelMix: 'Phân biệt kênh', perChannel: 'Đơn theo kênh bán hàng',
    quadrant: { title: 'Bản đồ creator', subtitle: 'Reach × Conversion · 30 ngày qua',
      stars: 'Ngôi sao · re-book đầu tiên', reachers: 'Máy reach · đẩy ưu đãi',
      gems: 'Ngọc thô · scale up', watch: 'Theo dõi · cần đánh giá' },
    table: { title: 'BXH Creator', subtitle: 'Sắp xếp theo chỉ số · click để xem chi tiết',
      headRank: '#', headCreator: 'Creator', headTier: 'Hạng', headChan: 'Kênh',
      headGmv: 'GMV', headOrders: 'Đơn', headCr: 'CR', headRoas: 'ROAS', headComm: 'Hoa hồng',
      headTrend: 'Xu hướng 7d', headStatus: 'Trạng thái', headAction: '' },
    actions: { rebook: 'Re-book', message: 'Nhắn tin', pause: 'Tạm dừng', adjust: 'Chỉnh %', detail: 'Chi tiết', approvePayout: 'Duyệt' },
    pipeline: { title: 'Pipeline hoa hồng', subtitle: 'Mỗi đồng đang ở đâu',
      pendingReview: 'Chờ duyệt', processing: 'Đang xử lý', paid: 'Đã trả kỳ này',
      ready: 'Sẵn sàng', held: 'Tạm giữ', cleared: 'Đã trả' },
    status: { active: 'Đang chạy', paused: 'Tạm dừng', warmup: 'Khởi động', risk: 'Cần chú ý' },
    tierDesc: { A: 'Top 10% — re-book auto', B: 'Ổn — giữ trong rotation', C: 'Hỗn hợp — cần coach', D: 'Yếu — pause hoặc cắt' },
    creator: { mineTitle: 'AFF của tôi', mineSub: 'Từng link, từng đơn, từng payout — của riêng bạn.',
      myFunnel: 'Funnel của tôi · 30 ngày', myLinks: 'Link hiệu quả nhất', payoutQueue: 'Hàng chờ payout',
      copyLink: 'Copy link', shareKit: 'Chia sẻ kit', tax: 'Hóa đơn thuế' },
    cta: { export: 'Xuất CSV', share: 'Chia sẻ báo cáo', compare: 'So sánh kỳ' }
  }
};
const useAff = () => {
  const { locale } = useRouter();
  return AFF_I18N[locale] || AFF_I18N.en;
};

// ── Sales channels (where orders close — brand seller account auth) ──
const SALES_CHANNELS = [
  { id: 'TTS', name: 'TikTok Shop', short: 'TT Shop', color: '#002B50',
    badgeBg: '#002B50', badgeFg: 'white',
    icon: <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-5.2 1.74 2.89 2.89 0 0 1 2.31-4.64 2.93 2.93 0 0 1 .88.13V9.4a6.84 6.84 0 0 0-1-.05A6.33 6.33 0 0 0 5.8 20.1a6.34 6.34 0 0 0 10.86-4.43V8.97a8.16 8.16 0 0 0 4.77 1.52V7.04a4.85 4.85 0 0 1-1.84-.35z"/></svg>,
    connected: true,  seller: '@aurorabeauty.vn',      orders: 9120, gmv: 1124000, sync: '2 min ago' },
  { id: 'SHP', name: 'Shopee',      short: 'Shopee',  color: '#FF7A59',
    badgeBg: '#FF7A59', badgeFg: 'white',
    icon: <span style={{ fontWeight: 800, fontSize: 11, fontFamily: 'Space Grotesk' }}>S</span>,
    connected: true,  seller: 'aurora_official',       orders: 4380, gmv: 540000,  sync: '4 min ago' },
  { id: 'LZD', name: 'Lazada',      short: 'Lazada',  color: '#0F056B',
    badgeBg: '#0F056B', badgeFg: 'white',
    icon: <span style={{ fontWeight: 800, fontSize: 11, fontFamily: 'Space Grotesk' }}>L</span>,
    connected: false, seller: null, orders: 0, gmv: 0, sync: null },
  { id: 'WEB', name: 'Brand site',  short: 'Web',     color: '#1FD6B4',
    badgeBg: '#1FD6B4', badgeFg: 'white',
    icon: <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2.5"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20"/></svg>,
    connected: true,  seller: 'aurorabeauty.com',      orders: 1100, gmv: 176000,  sync: '1 min ago' },
];

// ── AFF-enabled campaigns ─────────────────────────────────────────
const AFF_CAMPAIGNS = [
  { id: 'CMP-201', name: 'Vitamin C Skin Glow', period: 'May 1 → Jun 17', creators: 12, gmv: 1840000, orders: 14600, status: 'live',   commission: 12, accent: 'var(--cyan)' },
  { id: 'CMP-198', name: 'SPF Glow Tour',       period: 'Apr 12 → Jun 8',  creators: 8,  gmv: 920000,  orders: 7200,  status: 'live',   commission: 10, accent: 'var(--coral)' },
  { id: 'CMP-186', name: 'Coffee morning drop', period: 'Mar 8 → Apr 28',  creators: 14, gmv: 1240000, orders: 9800,  status: 'closed', commission: 8,  accent: 'var(--lavender-deep)' },
  { id: 'CMP-179', name: 'Cafe Affiliate · HN', period: 'Mar 1 → ongoing', creators: 6,  gmv: 380000,  orders: 2900,  status: 'live',   commission: 15, accent: 'var(--yellow-deep)' },
];

// ── Mock data ──────────────────────────────────────────────────────
const CHANNEL_ICON = { TT: Icon.tiktok, IG: Icon.instagram, YT: Icon.youtube,
  SHP: <span style={{ fontWeight: 800, fontSize: 9, letterSpacing: 0.4 }}>SHP</span> };
const CHANNEL_COLOR = { TT: '#002B50', IG: '#FF6FA3', YT: '#FF4444', SHP: '#FF7A59' };

// Tier scoring is derived from ROAS + CR but pre-baked for the mock.
const AFF_CREATORS = [
  { id: 'c01', name: 'Linh Châu',     handle: '@linhchau',   channels: ['TT','IG'], tier: 'A',
    reach: 1240, clicks: 48200, orders: 3120, gmv: 412800, aov: 132.3, cr: 6.47, roas: 6.8,
    commission: 49536, commRate: 12, status: 'active', delta: 18.4, campaigns: 3,
    spark: [3.2,4.1,5.3,4.8,6.1,6.9,8.8], note: 'Top of cohort.' },
  { id: 'c02', name: 'Mai T.',        handle: '@maitng',     channels: ['TT'],      tier: 'A',
    reach: 920, clicks: 36400, orders: 2480, gmv: 318600, aov: 128.5, cr: 6.81, roas: 6.2,
    commission: 38232, commRate: 12, status: 'active', delta: 12.1, campaigns: 2,
    spark: [2.4,3.0,3.8,3.5,4.5,5.1,6.2] },
  { id: 'c03', name: 'Trang Lê',      handle: '@trangtt',    channels: ['IG','YT'], tier: 'B',
    reach: 1820, clicks: 52100, orders: 1820, gmv: 248400, aov: 136.5, cr: 3.49, roas: 4.2,
    commission: 29808, commRate: 12, status: 'active', delta: 6.4, campaigns: 4,
    spark: [3.8,4.0,4.2,3.9,4.3,4.6,5.1] },
  { id: 'c04', name: 'Phương Anh',    handle: '@paskin',     channels: ['TT','SHP'],tier: 'A',
    reach: 680, clicks: 28400, orders: 2410, gmv: 295200, aov: 122.5, cr: 8.49, roas: 7.1,
    commission: 35424, commRate: 12, status: 'active', delta: 22.7, campaigns: 2,
    spark: [1.4,1.9,2.6,3.2,3.8,4.4,5.3], note: 'Hidden gem — highest CR.' },
  { id: 'c05', name: 'Quốc Bảo',      handle: '@bao.review', channels: ['YT'],      tier: 'B',
    reach: 1140, clicks: 18200, orders: 920, gmv: 142800, aov: 155.2, cr: 5.05, roas: 4.8,
    commission: 17136, commRate: 12, status: 'active', delta: -2.4, campaigns: 1,
    spark: [2.1,2.4,2.0,1.9,2.3,2.0,1.8] },
  { id: 'c06', name: 'Hà Vy',         handle: '@havy',       channels: ['IG'],      tier: 'C',
    reach: 1480, clicks: 32400, orders: 720, gmv: 96800, aov: 134.4, cr: 2.22, roas: 2.1,
    commission: 11616, commRate: 12, status: 'warmup', delta: 4.8, campaigns: 1,
    spark: [1.2,1.0,1.4,1.6,1.5,1.8,1.6] },
  { id: 'c07', name: 'Duy Khang',     handle: '@duykhang',   channels: ['TT','YT'], tier: 'B',
    reach: 980, clicks: 22600, orders: 1180, gmv: 168200, aov: 142.5, cr: 5.22, roas: 4.4,
    commission: 20184, commRate: 12, status: 'active', delta: 9.2, campaigns: 2,
    spark: [2.0,2.4,2.8,3.0,2.7,3.2,3.5] },
  { id: 'c08', name: 'Khánh My',      handle: '@kmybeauty',  channels: ['TT'],      tier: 'C',
    reach: 740, clicks: 14200, orders: 420, gmv: 52400, aov: 124.8, cr: 2.96, roas: 2.6,
    commission: 6288, commRate: 12, status: 'active', delta: 1.8, campaigns: 1,
    spark: [0.8,0.9,0.7,1.0,1.1,1.0,0.9] },
  { id: 'c09', name: 'Sơn Tùng K.',   handle: '@sontungk',   channels: ['IG','TT'], tier: 'B',
    reach: 1620, clicks: 28800, orders: 1340, gmv: 192600, aov: 143.7, cr: 4.65, roas: 4.0,
    commission: 23112, commRate: 12, status: 'active', delta: 7.6, campaigns: 2,
    spark: [2.8,3.0,3.2,3.4,3.1,3.6,3.9] },
  { id: 'c10', name: 'Bích Phương',   handle: '@bphuong',    channels: ['YT','IG'], tier: 'D',
    reach: 560, clicks: 6400, orders: 120, gmv: 15200, aov: 126.7, cr: 1.88, roas: 1.4,
    commission: 1824, commRate: 12, status: 'risk', delta: -14.6, campaigns: 1,
    spark: [0.6,0.5,0.4,0.5,0.3,0.4,0.3], note: 'Falling — schedule call.' },
  { id: 'c11', name: 'Tú Anh',        handle: '@tuanh.derm', channels: ['TT','SHP'],tier: 'B',
    reach: 820, clicks: 19800, orders: 980, gmv: 132600, aov: 135.3, cr: 4.95, roas: 4.3,
    commission: 15912, commRate: 12, status: 'active', delta: 11.3, campaigns: 2,
    spark: [1.8,2.0,2.2,2.4,2.3,2.6,2.9] },
  { id: 'c12', name: 'Minh Đăng',     handle: '@mdang',      channels: ['YT'],      tier: 'D',
    reach: 420, clicks: 4800, orders: 80, gmv: 9600, aov: 120.0, cr: 1.67, roas: 1.1,
    commission: 1152, commRate: 12, status: 'paused', delta: -22.4, campaigns: 1,
    spark: [0.4,0.3,0.4,0.3,0.2,0.2,0.1] },
];

// Totals derived from creators
const TOTALS = AFF_CREATORS.reduce((acc, c) => ({
  reach: acc.reach + c.reach * 1000,
  clicks: acc.clicks + c.clicks,
  orders: acc.orders + c.orders,
  gmv: acc.gmv + c.gmv,
  commission: acc.commission + c.commission,
  active: acc.active + (c.status === 'active' ? 1 : 0),
}), { reach: 0, clicks: 0, orders: 0, gmv: 0, commission: 0, active: 0 });

// Funnel computed: impressions=reach, clicks, cart=clicks*0.18, orders, payouts=commission cleared
const FUNNEL = {
  stages: [
    { label: 0, value: TOTALS.reach,                      color: 'var(--lavender-deep)' },
    { label: 1, value: TOTALS.clicks,                     color: 'var(--cyan)' },
    { label: 2, value: Math.round(TOTALS.clicks * 0.184), color: 'var(--indigo-soft)' },
    { label: 3, value: TOTALS.orders,                     color: 'var(--mint-deep)' },
    { label: 4, value: Math.round(TOTALS.commission * 0.78), color: 'var(--coral)', isMoney: true },
  ],
  aov: Math.round(TOTALS.gmv / TOTALS.orders),
};
const CHANNEL_SPLIT = SALES_CHANNELS.filter(s => s.connected).map(s => ({
  ch: s.id, pct: Math.round((s.orders / SALES_CHANNELS.reduce((a, x) => a + x.orders, 0)) * 100),
  color: s.color, name: s.short, icon: s.icon
}));

// Per-creator sales-channel mix (% of THIS creator's orders by sales channel)
function channelMixFor(c) {
  const ttsHeavy = { TTS: 62, SHP: 24, WEB: 14 };
  const balanced = { TTS: 48, SHP: 34, WEB: 18 };
  const shpHeavy = { TTS: 30, SHP: 56, WEB: 14 };
  const weakMix  = { TTS: 36, SHP: 48, WEB: 16 };
  // YT-only creators skew to brand site (long-form review viewers)
  if (c.channels.length === 1 && c.channels[0] === 'YT') return { TTS: 24, SHP: 22, WEB: 54 };
  return ({ A: ttsHeavy, B: balanced, C: shpHeavy, D: weakMix })[c.tier];
}

const PAYOUT_QUEUE = [
  { lane: 'pendingReview', items: [
    { id: 'P-2418', name: 'Phương Anh', amt: 4320, age: '6h', risk: false },
    { id: 'P-2417', name: 'Linh Châu',  amt: 5816, age: '14h', risk: false },
    { id: 'P-2412', name: 'Sơn Tùng K.', amt: 2880, age: '1d',  risk: true, reason: 'Order ID mismatch · 2 lines' },
  ]},
  { lane: 'processing', items: [
    { id: 'P-2401', name: 'Trang Lê',   amt: 3216, age: '2d', eta: 'Today' },
    { id: 'P-2399', name: 'Mai T.',     amt: 4720, age: '2d', eta: 'Today' },
    { id: 'P-2391', name: 'Duy Khang',  amt: 2280, age: '3d', eta: 'Tomorrow' },
    { id: 'P-2386', name: 'Tú Anh',     amt: 1840, age: '3d', eta: 'Tomorrow' },
  ]},
  { lane: 'paid', items: [
    { id: 'P-2374', name: 'Linh Châu',  amt: 5240, age: 'May 12' },
    { id: 'P-2371', name: 'Mai T.',     amt: 3640, age: 'May 10' },
    { id: 'P-2368', name: 'Phương Anh', amt: 2860, age: 'May 10' },
    { id: 'P-2364', name: 'Hà Vy',      amt: 1180, age: 'May 06' },
  ]},
];

// Tier visual config
const TIER = {
  A: { bg: 'rgba(31,214,180,0.18)', fg: '#0a8a72', border: '#1FD6B4' },
  B: { bg: 'rgba(0,156,255,0.14)',  fg: '#0066a8', border: '#009CFF' },
  C: { bg: 'rgba(242,196,17,0.20)', fg: '#856200', border: '#F2C411' },
  D: { bg: 'rgba(255,68,68,0.14)',  fg: '#B12B2B', border: '#FF4444' },
};

// ── Atom: tier badge ───────────────────────────────────────────────
function TierBadge({ tier, size = 'md' }) {
  const t = TIER[tier];
  const dim = size === 'sm' ? 22 : 28;
  return (
    <span style={{
      width: dim, height: dim, borderRadius: 8,
      display: 'inline-grid', placeItems: 'center',
      background: t.bg, color: t.fg,
      boxShadow: `inset 0 0 0 1.5px ${t.border}`,
      fontFamily: 'Space Grotesk', fontWeight: 800, fontSize: size === 'sm' ? 11 : 13,
      letterSpacing: '-0.02em',
    }}>{tier}</span>
  );
}

function ChannelChip({ ch }) {
  const c = CHANNEL_COLOR[ch] || '#000';
  return (
    <span style={{
      width: 20, height: 20, borderRadius: 5,
      background: c, color: 'white',
      display: 'inline-grid', placeItems: 'center', flexShrink: 0
    }}>{CHANNEL_ICON[ch]}</span>
  );
}

function StatusDot({ status }) {
  const map = {
    active: { c: 'var(--mint-deep)', l: 'active' },
    paused: { c: 'var(--ink-soft)',  l: 'paused' },
    warmup: { c: 'var(--yellow-deep)', l: 'warmup' },
    risk:   { c: 'var(--coral)',     l: 'risk' },
  };
  const s = map[status] || map.active;
  return (
    <span className="row items-center gap-6" style={{ fontSize: 11, fontWeight: 700, color: 'var(--ink)' }}>
      <span style={{ width: 7, height: 7, borderRadius: 999, background: s.c, boxShadow: `0 0 0 3px ${s.c}33` }} />
      <span style={{ textTransform: 'capitalize' }}>{s.l}</span>
    </span>
  );
}

// ── ChannelMix · horizontal stacked bar (per creator) ─────────────
function ChannelMix({ mix, width = 110, height = 8, showLabels = false }) {
  const channels = SALES_CHANNELS.filter(s => mix[s.id] !== undefined && mix[s.id] > 0);
  return (
    <div style={{ width }}>
      <div style={{ display: 'flex', height, borderRadius: 999, overflow: 'hidden', background: 'var(--bg-soft)' }}>
        {channels.map(c => (
          <div key={c.id} title={`${c.short} · ${mix[c.id]}%`} style={{
            flexBasis: mix[c.id] + '%', background: c.color,
            animation: `growW .8s cubic-bezier(.4,0,.2,1) backwards`, transformOrigin: 'left'
          }} />
        ))}
      </div>
      {showLabels && (
        <div className="row gap-6" style={{ marginTop: 4, fontSize: 9.5, fontWeight: 700 }}>
          {channels.map(c => (
            <span key={c.id} className="row items-center gap-4" style={{ color: c.color }}>
              <span style={{ width: 6, height: 6, borderRadius: 999, background: c.color }} />
              {c.short} {mix[c.id]}%
            </span>
          ))}
        </div>
      )}
    </div>
  );
}

// ── Connect-channel modal ───────────────────────────────────────
function ConnectChannelModal({ channel, onClose, onConnect }) {
  if (!channel) return null;
  const [step, setStep] = useState('intro'); // intro | redirecting | success
  const handleConnect = () => {
    setStep('redirecting');
    setTimeout(() => { setStep('success'); }, 1400);
    setTimeout(() => { onConnect(channel.id); onClose(); }, 2400);
  };
  return (
    <>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,43,80,0.50)', zIndex: 90, backdropFilter: 'blur(4px)' }} />
      <div style={{
        position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
        width: 'min(440px, 92vw)', background: 'white', borderRadius: 18, zIndex: 91,
        boxShadow: '0 32px 80px rgba(0,43,80,0.32)', overflow: 'hidden',
        animation: 'modalIn .3s cubic-bezier(.2,.7,.2,1)'
      }}>
        <div style={{ padding: 24, background: channel.color, color: 'white', position: 'relative' }}>
          <div className="row items-center gap-12">
            <div style={{ width: 44, height: 44, borderRadius: 12, background: 'rgba(255,255,255,0.20)', display: 'grid', placeItems: 'center', backdropFilter: 'blur(8px)' }}>
              {channel.icon}
            </div>
            <div>
              <div className="font-display" style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-0.02em' }}>{channel.name}</div>
              <div style={{ fontSize: 12, opacity: 0.85 }}>Authorize seller account</div>
            </div>
          </div>
        </div>
        <div style={{ padding: 24 }}>
          {step === 'intro' && <>
            <div className="title-md mb-2">Connect your {channel.name} seller</div>
            <div className="muted" style={{ fontSize: 12.5, lineHeight: 1.5 }}>
              Prime will redirect you to {channel.name} to sign in with your seller account.
              Once approved, we sync orders, GMV and commission attribution every <b style={{ color: 'var(--ink)' }}>5 minutes</b>.
            </div>
            <div className="col gap-8 mt-4">
              {[
                ['Read-only access', 'We never modify your listings or fulfilment'],
                ['Order data only',  'Customer PII stays inside ' + channel.name],
                ['One-click revoke', 'Disconnect anytime from settings']
              ].map(([t, s], i) => (
                <div key={i} className="row items-start gap-10" style={{ padding: '8px 0' }}>
                  <span style={{ width: 22, height: 22, borderRadius: 999, background: 'var(--mint)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 800, flexShrink: 0 }}>✓</span>
                  <div><div className="bold" style={{ fontSize: 12.5 }}>{t}</div><div className="muted" style={{ fontSize: 11 }}>{s}</div></div>
                </div>
              ))}
            </div>
            <div className="row gap-8 mt-6">
              <button onClick={onClose} className="btn btn-ghost btn-sm flex-1">Cancel</button>
              <button onClick={handleConnect} className="btn btn-primary btn-sm flex-1">Continue → {channel.name}</button>
            </div>
          </>}
          {step === 'redirecting' && (
            <div className="text-center" style={{ padding: '24px 0' }}>
              <div className="ai-thinking" style={{ justifyContent: 'center' }}><span className="dot"/><span className="dot"/><span className="dot"/></div>
              <div className="title-md mt-3">Redirecting to {channel.name}…</div>
              <div className="muted" style={{ fontSize: 12, marginTop: 6 }}>Sign in with your seller credentials</div>
            </div>
          )}
          {step === 'success' && (
            <div className="text-center" style={{ padding: '24px 0' }}>
              <div style={{ width: 56, height: 56, margin: '0 auto', borderRadius: '50%', background: 'var(--mint)', color: 'var(--ink)', display: 'grid', placeItems: 'center', fontSize: 26, fontWeight: 800, animation: 'modalIn .4s cubic-bezier(.2,.7,.2,1)' }}>✓</div>
              <div className="title-md mt-3">{channel.name} connected</div>
              <div className="muted" style={{ fontSize: 12, marginTop: 6 }}>First sync starts in 30 seconds</div>
            </div>
          )}
        </div>
        <style>{`@keyframes modalIn { from { opacity: 0; transform: translate(-50%, -45%) scale(.96); } to { opacity: 1; transform: translate(-50%, -50%) scale(1); } }`}</style>
      </div>
    </>
  );
}

// ── CampaignContextBar · picker + connected sales channels ───────────
function CampaignContextBar({ T, campaignId, onChangeCampaign, channels, onConnect }) {
  const [open, setOpen] = useState(false);
  const [connecting, setConnecting] = useState(null);
  const ref = React.useRef(null);
  const cmp = AFF_CAMPAIGNS.find(c => c.id === campaignId) || AFF_CAMPAIGNS[0];
  const aggregate = campaignId === 'all';
  const display = aggregate
    ? { name: T.allCampaigns, period: AFF_CAMPAIGNS.length + ' campaigns', creators: AFF_CAMPAIGNS.reduce((s, c) => s + c.creators, 0),
        gmv: AFF_CAMPAIGNS.reduce((s, c) => s + c.gmv, 0), commission: '8–15', accent: 'var(--ink)' }
    : cmp;

  return (
    <div className="card-elevated mb-4" style={{ padding: 18, position: 'relative', overflow: 'visible' }}>
      <div className="row items-center gap-16" style={{ flexWrap: 'wrap' }}>
        {/* Campaign picker */}
        <div ref={ref} style={{ position: 'relative', minWidth: 280 }}>
          <button onClick={() => setOpen(o => !o)} style={{
            width: '100%', padding: '8px 12px', borderRadius: 12,
            background: 'var(--bg-soft)', border: '1px solid var(--line)',
            cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit',
            display: 'flex', alignItems: 'center', gap: 10
          }}>
            <div style={{ width: 34, height: 34, borderRadius: 9, background: display.accent, color: 'white',
              display: 'grid', placeItems: 'center', fontFamily: 'Space Grotesk', fontWeight: 800, fontSize: 13, letterSpacing: '-0.02em' }}>
              {aggregate ? Icon.spark : (cmp.name.split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase())}
            </div>
            <div className="flex-1" style={{ minWidth: 0 }}>
              <div className="cap-label" style={{ fontSize: 9 }}>{T.campaignPicker}</div>
              <div className="bold" style={{ fontSize: 14, lineHeight: 1.2 }}>{display.name}</div>
              <div className="muted" style={{ fontSize: 10.5 }}>
                {aggregate ? display.period : (cmp.period + ' · ' + cmp.creators + ' creators · ' + cmp.commission + '% comm.')}
              </div>
            </div>
            <span style={{ color: 'var(--ink-soft)' }}>{Icon.arrowDown}</span>
          </button>
          {open && (
            <>
              <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
              <div style={{
                position: 'absolute', top: 'calc(100% + 6px)', left: 0, zIndex: 51,
                background: 'white', border: '1px solid var(--line)', borderRadius: 12,
                boxShadow: 'var(--shadow-md)', overflow: 'hidden', width: 340
              }}>
                <button onClick={() => { onChangeCampaign('all'); setOpen(false); }} style={{
                  display: 'flex', width: '100%', alignItems: 'center', gap: 10,
                  padding: 12, border: 0, background: campaignId === 'all' ? 'var(--bg-soft)' : 'white',
                  cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left',
                  borderBottom: '1px solid var(--line)'
                }}>
                  <span style={{ width: 28, height: 28, borderRadius: 8, background: 'var(--ink)', color: 'white', display: 'grid', placeItems: 'center' }}>{Icon.spark}</span>
                  <div className="flex-1"><div className="bold" style={{ fontSize: 12.5 }}>{T.allCampaigns}</div>
                    <div className="muted" style={{ fontSize: 10.5 }}>Aggregate across {AFF_CAMPAIGNS.length} campaigns</div></div>
                </button>
                {AFF_CAMPAIGNS.map(c => (
                  <button key={c.id} onClick={() => { onChangeCampaign(c.id); setOpen(false); }} style={{
                    display: 'flex', width: '100%', alignItems: 'center', gap: 10,
                    padding: 12, border: 0, background: campaignId === c.id ? 'var(--bg-soft)' : 'white',
                    cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left'
                  }}>
                    <span style={{ width: 28, height: 28, borderRadius: 8, background: c.accent, color: 'white', display: 'grid', placeItems: 'center',
                      fontFamily: 'Space Grotesk', fontWeight: 800, fontSize: 11, letterSpacing: '-0.02em' }}>
                      {c.name.split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase()}
                    </span>
                    <div className="flex-1">
                      <div className="bold" style={{ fontSize: 12.5 }}>{c.name}</div>
                      <div className="muted" style={{ fontSize: 10.5 }}>{c.creators} creators · ${formatCompact(c.gmv)} GMV · {c.commission}%</div>
                    </div>
                    <span style={{ fontSize: 9.5, fontWeight: 800, padding: '2px 7px', borderRadius: 999,
                      background: c.status === 'live' ? 'rgba(31,214,180,0.18)' : 'rgba(0,43,80,0.08)',
                      color: c.status === 'live' ? '#0a8a72' : 'var(--ink-soft)',
                      letterSpacing: '0.08em', textTransform: 'uppercase' }}>{c.status}</span>
                  </button>
                ))}
              </div>
            </>
          )}
        </div>

        {/* Connected channels strip */}
        <div style={{ flex: 1, minWidth: 360, paddingLeft: 16, borderLeft: '1px solid var(--line)' }}>
          <div className="row items-center justify-between mb-2">
            <div>
              <div className="cap-label" style={{ fontSize: 9 }}>{T.salesChannels}</div>
              <div className="muted" style={{ fontSize: 10.5 }}>{T.salesSubtitle}</div>
            </div>
            <button style={{
              background: 'transparent', border: 0, cursor: 'pointer', fontFamily: 'inherit',
              fontSize: 10.5, fontWeight: 700, color: 'var(--cyan-dark)'
            }}>Manage</button>
          </div>
          <div className="row gap-6" style={{ flexWrap: 'wrap' }}>
            {channels.map(s => (
              <div key={s.id} style={{
                display: 'flex', alignItems: 'center', gap: 8,
                padding: '7px 10px', borderRadius: 10,
                background: s.connected ? 'white' : 'rgba(255,68,68,0.04)',
                border: '1px solid ' + (s.connected ? 'var(--line)' : 'rgba(255,68,68,0.18)'),
                flex: '1 1 auto', minWidth: 156
              }}>
                <div style={{
                  width: 30, height: 30, borderRadius: 8, background: s.badgeBg, color: s.badgeFg,
                  display: 'grid', placeItems: 'center', opacity: s.connected ? 1 : 0.5, flexShrink: 0
                }}>{s.icon}</div>
                <div className="flex-1" style={{ minWidth: 0 }}>
                  <div className="row items-center gap-4">
                    <span className="bold" style={{ fontSize: 11.5 }}>{s.short}</span>
                    {s.connected
                      ? <span style={{ width: 7, height: 7, borderRadius: 999, background: 'var(--mint-deep)' }} />
                      : <span style={{ width: 7, height: 7, borderRadius: 999, background: 'var(--coral)' }} />}
                  </div>
                  <div className="muted tabular" style={{ fontSize: 10, lineHeight: 1.2 }}>
                    {s.connected ? s.seller : T.notConnected}
                  </div>
                  {s.connected && <div className="muted" style={{ fontSize: 9.5, marginTop: 1 }}>{T.syncedAt} {s.sync}</div>}
                </div>
                {!s.connected && (
                  <button onClick={() => setConnecting(s)} style={{
                    padding: '4px 10px', borderRadius: 999, border: 0,
                    background: 'var(--ink)', color: 'white', cursor: 'pointer',
                    fontFamily: 'inherit', fontSize: 10.5, fontWeight: 700, flexShrink: 0
                  }}>{T.connectCta}</button>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>

      {connecting && <ConnectChannelModal channel={connecting} onClose={() => setConnecting(null)} onConnect={onConnect} />}
    </div>
  );
}

// ── Funnel viz · horizontal trapezoidal ────────────────────────────
function FunnelHorizontal({ T }) {
  const stages = FUNNEL.stages;
  const max = stages[0].value;
  const W = 920, H = 240, padX = 20, gap = 6;
  const stageW = (W - padX * 2 - gap * (stages.length - 1)) / stages.length;

  return (
    <svg viewBox={`0 0 ${W} ${H + 70}`} style={{ width: '100%', height: 'auto' }}>
      <defs>
        {stages.map((s, i) => (
          <linearGradient key={i} id={`fgrad-${i}`} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={s.color} stopOpacity="0.92" />
            <stop offset="100%" stopColor={s.color} stopOpacity="0.55" />
          </linearGradient>
        ))}
      </defs>
      {stages.map((s, i) => {
        const next = stages[i + 1];
        const x = padX + i * (stageW + gap);
        const h = (s.value / max) * H;
        const y = (H - h) / 2 + 16;
        const hNext = next ? (next.value / max) * H : h;
        const yNext = next ? (H - hNext) / 2 + 16 : y;
        // Only compute CVR when both stages are count-based (drop annotation across unit change)
        const isUnitBreak = next && (s.isMoney || next.isMoney);
        const drop = next && !isUnitBreak ? 100 - Math.round((next.value / s.value) * 100) : 0;
        const cvr  = next && !isUnitBreak ? Math.round((next.value / s.value) * 1000) / 10 : null;
        // Show AOV across the order → money break
        const showAov = isUnitBreak && i === 3;

        return (
          <g key={i}>
            {/* stage block as trapezoid */}
            <path
              d={`M${x},${y} L${x + stageW},${y + (yNext - y) * 0.15} L${x + stageW},${y + h - (yNext - y - (hNext - h)) * 0.15} L${x},${y + h} Z`}
              fill={`url(#fgrad-${i})`}
              style={{ animation: `funnelIn .6s ${i * 0.1}s backwards ease-out`, transformOrigin: 'center', }}
            />
            {/* connector arrow between stages */}
            {next && (
              <g opacity="0.85">
                <path d={`M${x + stageW + 1},${y + h / 2 - 8} L${x + stageW + gap - 1},${y + h / 2 - 8} L${x + stageW + gap - 1},${y + h / 2 + 8} L${x + stageW + 1},${y + h / 2 + 8} Z`}
                  fill={s.color} opacity="0.45" />
              </g>
            )}
            {/* value label */}
            <text x={x + stageW / 2} y={y + h / 2 - 8} textAnchor="middle"
              style={{ fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 22, letterSpacing: '-0.02em', fill: 'white' }}>
              {s.isMoney ? '$' + formatCompact(s.value) : formatCompact(s.value)}
            </text>
            <text x={x + stageW / 2} y={y + h / 2 + 12} textAnchor="middle"
              style={{ fontSize: 10, fill: 'white', fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', opacity: 0.86 }}>
              {T.funnelStages[i]}
            </text>

            {/* drop-off annotation between i and i+1 */}
            {next && cvr !== null && (
              <g>
                <text x={x + stageW + gap / 2} y={H + 38} textAnchor="middle"
                  style={{ fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14, fill: 'var(--ink)' }}>
                  {cvr}%
                </text>
                <text x={x + stageW + gap / 2} y={H + 54} textAnchor="middle"
                  style={{ fontSize: 9, fill: 'var(--ink-soft)', fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase' }}>
                  {T.funnel.cvr}
                </text>
                <text x={x + stageW + gap / 2} y={H + 68} textAnchor="middle"
                  style={{ fontSize: 9, fill: 'var(--coral)', fontWeight: 700 }}>
                  −{drop}% {T.funnel.dropoff}
                </text>
              </g>
            )}
            {showAov && (
              <g>
                <text x={x + stageW + gap / 2} y={H + 38} textAnchor="middle"
                  style={{ fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14, fill: 'var(--ink)' }}>
                  ${FUNNEL.aov}
                </text>
                <text x={x + stageW + gap / 2} y={H + 54} textAnchor="middle"
                  style={{ fontSize: 9, fill: 'var(--ink-soft)', fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase' }}>
                  AOV
                </text>
                <text x={x + stageW + gap / 2} y={H + 68} textAnchor="middle"
                  style={{ fontSize: 9, fill: 'var(--mint-deep)', fontWeight: 700 }}>
                  12% commission
                </text>
              </g>
            )}
          </g>
        );
      })}
      <style>{`@keyframes funnelIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }`}</style>
    </svg>
  );
}

// ── Funnel viz · sankey-flow alt ───────────────────────────────────
function FunnelSankey({ T }) {
  const stages = FUNNEL.stages;
  const max = stages[0].value;
  const W = 920, H = 260, padX = 20;
  const stageW = 110;
  const linkW = (W - padX * 2 - stages.length * stageW) / (stages.length - 1);

  return (
    <svg viewBox={`0 0 ${W} ${H + 40}`} style={{ width: '100%', height: 'auto' }}>
      {stages.map((s, i) => {
        const x = padX + i * (stageW + linkW);
        const h = (s.value / max) * H;
        const y = (H - h) / 2 + 10;
        const next = stages[i + 1];

        return (
          <g key={i}>
            {next && (() => {
              const x2 = x + stageW + linkW;
              const h2 = (next.value / max) * H;
              const y2 = (H - h2) / 2 + 10;
              // smooth path link
              return (
                <path
                  d={`M${x + stageW},${y}
                      C${x + stageW + linkW / 2},${y} ${x2 - linkW / 2},${y2} ${x2},${y2}
                      L${x2},${y2 + h2}
                      C${x2 - linkW / 2},${y2 + h2} ${x + stageW + linkW / 2},${y + h} ${x + stageW},${y + h} Z`}
                  fill={s.color} opacity="0.22"
                  style={{ animation: `funnelIn .8s ${i * 0.1 + 0.2}s backwards ease-out` }}
                />
              );
            })()}
            <rect x={x} y={y} width={stageW} height={h} rx="10" fill={s.color}
              style={{ animation: `funnelIn .6s ${i * 0.1}s backwards ease-out` }} />
            <text x={x + stageW / 2} y={y + h / 2 - 4} textAnchor="middle"
              style={{ fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 18, fill: 'white', letterSpacing: '-0.02em' }}>
              {s.isMoney ? '$' + formatCompact(s.value) : formatCompact(s.value)}
            </text>
            <text x={x + stageW / 2} y={y + h / 2 + 12} textAnchor="middle"
              style={{ fontSize: 9, fill: 'white', fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', opacity: 0.85 }}>
              {T.funnelStages[i]}
            </text>
          </g>
        );
      })}
    </svg>
  );
}

// ── Quadrant chart · Reach × Conversion ────────────────────────────
function QuadrantChart({ T, creators }) {
  const W = 540, H = 360;
  const padL = 36, padR = 16, padT = 16, padB = 30;
  const maxReach = 2000;     // K
  const maxCR = 10;          // %
  const midReach = 1000;
  const midCR = 4.5;
  const xScale = (cr) => padL + (cr / maxCR) * (W - padL - padR);
  const yScale = (r)  => H - padB - (r / maxReach) * (H - padT - padB);

  const quadStyles = {
    'q-stars':    { label: T.quadrant.stars,    color: 'var(--mint-deep)',    bg: 'rgba(31,214,180,0.08)' },
    'q-reachers': { label: T.quadrant.reachers, color: 'var(--cyan)',         bg: 'rgba(0,156,255,0.06)' },
    'q-gems':     { label: T.quadrant.gems,     color: 'var(--yellow-deep)',  bg: 'rgba(242,196,17,0.10)' },
    'q-watch':    { label: T.quadrant.watch,    color: 'var(--coral)',        bg: 'rgba(255,122,89,0.08)' },
  };
  const xMid = xScale(midCR);
  const yMid = yScale(midReach);

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto' }}>
      {/* quadrant fills */}
      <rect x={xMid} y={padT}     width={W - padR - xMid} height={yMid - padT} fill={quadStyles['q-stars'].bg} />
      <rect x={padL} y={padT}     width={xMid - padL}     height={yMid - padT} fill={quadStyles['q-reachers'].bg} />
      <rect x={xMid} y={yMid}     width={W - padR - xMid} height={H - padB - yMid} fill={quadStyles['q-gems'].bg} />
      <rect x={padL} y={yMid}     width={xMid - padL}     height={H - padB - yMid} fill={quadStyles['q-watch'].bg} />
      {/* mid lines */}
      <line x1={xMid} x2={xMid} y1={padT} y2={H - padB} stroke="var(--ink)" strokeOpacity="0.18" strokeDasharray="3 4" />
      <line x1={padL} x2={W - padR} y1={yMid} y2={yMid} stroke="var(--ink)" strokeOpacity="0.18" strokeDasharray="3 4" />
      {/* axes */}
      <line x1={padL} x2={W - padR} y1={H - padB} y2={H - padB} stroke="var(--line-strong)" />
      <line x1={padL} x2={padL} y1={padT} y2={H - padB} stroke="var(--line-strong)" />

      {/* quadrant labels */}
      <text x={W - padR - 10} y={padT + 18} textAnchor="end"
        style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.1em', textTransform: 'uppercase', fill: quadStyles['q-stars'].color }}>
        {T.quadrant.stars}
      </text>
      <text x={padL + 10} y={padT + 18}
        style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.1em', textTransform: 'uppercase', fill: quadStyles['q-reachers'].color }}>
        {T.quadrant.reachers}
      </text>
      <text x={W - padR - 10} y={H - padB - 8} textAnchor="end"
        style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.1em', textTransform: 'uppercase', fill: quadStyles['q-gems'].color }}>
        {T.quadrant.gems}
      </text>
      <text x={padL + 10} y={H - padB - 8}
        style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.1em', textTransform: 'uppercase', fill: quadStyles['q-watch'].color }}>
        {T.quadrant.watch}
      </text>

      {/* axis labels */}
      <text x={(padL + W - padR) / 2} y={H - 8} textAnchor="middle"
        style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', fill: 'var(--ink-soft)' }}>
        Click → Order rate
      </text>
      <text x={12} y={(padT + H - padB) / 2} textAnchor="middle"
        transform={`rotate(-90 12 ${(padT + H - padB) / 2})`}
        style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', fill: 'var(--ink-soft)' }}>
        Reach (K)
      </text>

      {/* dots */}
      {creators.map((c, i) => {
        const cx = xScale(c.cr);
        const cy = yScale(c.reach);
        const r = Math.max(8, Math.min(22, Math.sqrt(c.gmv) / 24));
        const tierC = TIER[c.tier].border;
        return (
          <g key={c.id} style={{ animation: `dotIn .5s ${i * 0.06 + 0.3}s backwards cubic-bezier(.4,0,.2,1)`, transformOrigin: `${cx}px ${cy}px` }}>
            <circle cx={cx} cy={cy} r={r + 4} fill={tierC} opacity="0.18" />
            <circle cx={cx} cy={cy} r={r} fill="white" stroke={tierC} strokeWidth="2.5" />
            <text x={cx} y={cy + 4} textAnchor="middle"
              style={{ fontFamily: 'Space Grotesk', fontWeight: 800, fontSize: 11, fill: 'var(--ink)' }}>
              {c.name.split(' ').slice(-1)[0].slice(0, 2)}
            </text>
          </g>
        );
      })}
      <style>{`@keyframes dotIn { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: scale(1); } }`}</style>
    </svg>
  );
}

// ── Filter chip ────────────────────────────────────────────────────
function FilterChip({ label, value, options, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = React.useRef(null);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button onClick={() => setOpen(o => !o)} style={{
        display: 'inline-flex', alignItems: 'center', gap: 8,
        padding: '8px 12px', borderRadius: 10,
        background: 'white', border: '1px solid var(--line)',
        fontFamily: 'inherit', cursor: 'pointer', fontSize: 12, fontWeight: 600,
      }}>
        <span className="cap-label" style={{ fontSize: 9 }}>{label}</span>
        <span style={{ color: 'var(--ink)' }}>{value}</span>
        <span style={{ color: 'var(--ink-soft)' }}>{Icon.arrowDown}</span>
      </button>
      {open && (
        <>
          <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
          <div style={{
            position: 'absolute', top: 'calc(100% + 6px)', left: 0, zIndex: 51,
            background: 'white', border: '1px solid var(--line)', borderRadius: 10,
            boxShadow: 'var(--shadow-md)', overflow: 'hidden', minWidth: 160
          }}>
            {options.map(o => (
              <button key={o} onClick={() => { onChange(o); setOpen(false); }} style={{
                display: 'block', width: '100%', textAlign: 'left',
                padding: '8px 12px', border: 0, background: o === value ? 'var(--bg-soft)' : 'white',
                cursor: 'pointer', fontFamily: 'inherit', fontSize: 12,
                fontWeight: o === value ? 700 : 500
              }}>{o}</button>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

// ── KPI cell ───────────────────────────────────────────────────────
function KpiCell({ label, value, prefix, suffix, delta, color, sub, sparkData }) {
  const isUp = delta >= 0;
  return (
    <div style={{
      padding: '16px 18px', background: 'white',
      border: '1px solid var(--line)', borderRadius: 14,
      position: 'relative', overflow: 'hidden',
      transition: 'transform .25s, box-shadow .25s',
    }}
      onMouseEnter={e => { e.currentTarget.style.boxShadow = 'var(--shadow-md)'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
      onMouseLeave={e => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}>
      <div className="row items-center justify-between">
        <span className="cap-label" style={{ fontSize: 9.5 }}>{label}</span>
        {delta !== undefined && (
          <span style={{
            fontSize: 10, fontWeight: 800, padding: '2px 7px', borderRadius: 999,
            background: isUp ? 'rgba(31,214,180,0.18)' : 'rgba(255,68,68,0.12)',
            color: isUp ? '#0a8a72' : '#B12B2B', letterSpacing: '-0.005em'
          }}>{isUp ? '+' : ''}{delta}%</span>
        )}
      </div>
      <div className="font-display tabular" style={{ fontSize: 28, fontWeight: 700, marginTop: 8, letterSpacing: '-0.025em', lineHeight: 1 }}>
        {prefix}<Counter to={value} suffix={suffix} decimals={value < 100 && !Number.isInteger(value) ? 1 : 0} duration={1100} />
      </div>
      {sub && <div className="muted" style={{ fontSize: 10.5, marginTop: 5, fontWeight: 500 }}>{sub}</div>}
      {sparkData && (
        <div style={{ marginTop: 10, marginLeft: -4, marginRight: -4 }}>
          <Sparkline data={sparkData} color={color || 'var(--cyan)'} fillId={`kp-${label}`} height={30} />
        </div>
      )}
    </div>
  );
}

// ── Tab pill ───────────────────────────────────────────────────────
function TabPill({ tabs, value, onChange }) {
  return (
    <div className="row" style={{ background: 'white', border: '1px solid var(--line)', borderRadius: 999, padding: 3, gap: 2 }}>
      {tabs.map(t => (
        <button key={t.id} onClick={() => onChange(t.id)} style={{
          padding: '7px 16px', borderRadius: 999, border: 0,
          background: value === t.id ? 'var(--ink)' : 'transparent',
          color: value === t.id ? 'white' : 'var(--ink-soft)',
          fontFamily: 'inherit', fontWeight: 700, fontSize: 12.5, cursor: 'pointer',
          transition: 'background .2s, color .2s'
        }}>{t.label}</button>
      ))}
    </div>
  );
}

// ── Drawer for creator detail ──────────────────────────────────────
function CreatorDetailDrawer({ creator, T, onClose }) {
  if (!creator) return null;
  const c = creator;
  const fStages = [
    { l: 'Reach',  v: c.reach * 1000, color: 'var(--lavender-deep)' },
    { l: 'Clicks', v: c.clicks,        color: 'var(--cyan)' },
    { l: 'Orders', v: c.orders,        color: 'var(--mint-deep)' },
    { l: 'GMV',    v: c.gmv,           color: 'var(--coral)', isMoney: true },
  ];
  return (
    <>
      <div onClick={onClose} style={{
        position: 'fixed', inset: 0, background: 'rgba(0,43,80,0.40)', zIndex: 80,
        backdropFilter: 'blur(2px)', animation: 'fade .25s ease-out'
      }} />
      <div style={{
        position: 'fixed', top: 0, right: 0, bottom: 0, width: 'min(560px, 100vw)',
        background: 'var(--bg-canvas)', zIndex: 81, overflowY: 'auto',
        boxShadow: '-20px 0 60px rgba(0,43,80,0.18)',
        animation: 'slideR .35s cubic-bezier(.2,.7,.2,1)',
      }}>
        {/* header */}
        <div style={{ padding: 24, background: 'linear-gradient(135deg, #002B50, #1C1CC9)', color: 'white', position: 'relative', overflow: 'hidden' }}>
          <div style={{ position: 'absolute', top: -40, right: -40, width: 200, height: 200, borderRadius: '50%',
            background: 'radial-gradient(circle, ' + TIER[c.tier].border + '55, transparent 60%)', filter: 'blur(20px)' }} />
          <div className="row items-center justify-between" style={{ position: 'relative' }}>
            <button onClick={onClose} style={{
              background: 'rgba(255,255,255,0.12)', border: 0, color: 'white', cursor: 'pointer',
              width: 32, height: 32, borderRadius: 10, display: 'grid', placeItems: 'center', fontSize: 16
            }}>✕</button>
            <div className="row gap-6">
              <button className="btn btn-ghost btn-sm" style={{ color: 'white', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,0.3)' }}>{T.actions.message}</button>
              <button className="btn btn-yellow btn-sm">{T.actions.rebook}</button>
            </div>
          </div>
          <div className="row items-center gap-16 mt-4" style={{ position: 'relative' }}>
            <Avatar name={c.name} size={64} />
            <div className="flex-1">
              <div className="row items-center gap-8">
                <div className="font-display" style={{ fontSize: 26, fontWeight: 700, letterSpacing: '-0.02em' }}>{c.name}</div>
                <TierBadge tier={c.tier} />
              </div>
              <div style={{ fontSize: 12.5, opacity: 0.85, marginTop: 2 }}>
                {c.handle} · {c.channels.join(' · ')} · {c.campaigns} campaign{c.campaigns > 1 ? 's' : ''}
              </div>
              <div className="row gap-6 mt-2">
                <StatusDot status={c.status} />
                <span style={{ fontSize: 11, opacity: 0.7 }}>· {T.tierDesc[c.tier]}</span>
              </div>
            </div>
          </div>
        </div>

        {/* metric grid */}
        <div style={{ padding: 18, display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 }}>
          {[
            { l: T.kpi.gmv, v: '$' + formatCompact(c.gmv), d: c.delta },
            { l: T.kpi.orders, v: formatCompact(c.orders), d: c.delta - 4 },
            { l: T.kpi.cr,  v: c.cr.toFixed(2) + '%', d: c.delta - 2 },
            { l: T.kpi.roas, v: c.roas.toFixed(1) + 'x', d: c.delta + 1 },
          ].map((k, i) => (
            <div key={i} style={{ padding: 12, background: 'white', border: '1px solid var(--line)', borderRadius: 12 }}>
              <div className="cap-label" style={{ fontSize: 9 }}>{k.l}</div>
              <div className="font-display tabular" style={{ fontSize: 20, fontWeight: 700, marginTop: 4 }}>{k.v}</div>
              <div style={{ fontSize: 10, fontWeight: 700, color: k.d >= 0 ? '#0a8a72' : '#B12B2B' }}>
                {k.d >= 0 ? '+' : ''}{k.d.toFixed(1)}% {T.kpi.vsPrev}
              </div>
            </div>
          ))}
        </div>

        {/* per-creator funnel */}
        <div style={{ padding: '0 18px 18px' }}>
          <div className="card-elevated">
            <div className="title-md mb-3">Personal AFF flow</div>
            <div className="col gap-12">
              {fStages.map((s, i) => {
                const next = fStages[i + 1];
                const max = fStages[0].v;
                const pct = (s.v / max) * 100;
                const isUnitBreak = next && (s.isMoney || next.isMoney);
                const cvr = next && !isUnitBreak ? Math.round((next.v / s.v) * 1000) / 10 : null;
                const aov = isUnitBreak && i === 2 ? Math.round(c.gmv / c.orders) : null;
                return (
                  <div key={i}>
                    <div className="row items-center justify-between mb-1">
                      <span className="cap-label" style={{ fontSize: 10 }}>{s.l}</span>
                      <span className="font-display tabular bold" style={{ fontSize: 16 }}>
                        {s.isMoney ? '$' + formatCompact(s.v) : formatCompact(s.v)}
                      </span>
                    </div>
                    <div style={{ height: 10, borderRadius: 999, background: 'var(--bg-soft)', overflow: 'hidden' }}>
                      <div style={{
                        height: '100%', width: pct + '%',
                        background: s.color, borderRadius: 999,
                        animation: `growW .8s ${i * 0.1}s backwards cubic-bezier(.4,0,.2,1)`, transformOrigin: 'left',
                      }} />
                    </div>
                    {cvr !== null && (
                      <div className="muted" style={{ fontSize: 10, marginTop: 4 }}>
                        → next stage: <b style={{ color: 'var(--ink)' }}>{cvr}%</b> conversion · −{(100 - cvr).toFixed(1)}% drop-off
                      </div>
                    )}
                    {aov !== null && (
                      <div className="muted" style={{ fontSize: 10, marginTop: 4 }}>
                        → AOV: <b style={{ color: 'var(--ink)' }}>${aov}</b> per order
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
            <style>{`@keyframes growW { from { transform: scaleX(0); } to { transform: scaleX(1); } }`}</style>
          </div>

          {/* commission */}
          <div className="card-elevated mt-4">
            <div className="row items-center justify-between mb-3">
              <div>
                <div className="title-md">Commission</div>
                <div className="muted" style={{ fontSize: 11 }}>{c.commRate}% of GMV · cleared on T+3</div>
              </div>
              <button className="btn btn-ghost btn-sm">{T.actions.adjust}</button>
            </div>
            <div className="row gap-6">
              {[['Earned', c.commission, 'var(--mint-deep)'],
                ['Pending', Math.round(c.commission * 0.18), 'var(--yellow-deep)'],
                ['Held', Math.round(c.commission * 0.04), 'var(--coral)']].map(([l, v, col], i) => (
                <div key={i} style={{ flex: 1, padding: 12, background: 'var(--bg-soft)', borderRadius: 10 }}>
                  <div className="cap-label" style={{ fontSize: 9 }}>{l}</div>
                  <div className="font-display tabular" style={{ fontSize: 18, fontWeight: 700, marginTop: 4, color: col }}>
                    ${formatCompact(v)}
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* Per-channel order breakdown */}
          {(() => {
            const mix = channelMixFor(c);
            const channels = SALES_CHANNELS.filter(s => mix[s.id] !== undefined && mix[s.id] > 0);
            return (
              <div className="card-elevated mt-4">
                <div className="title-md mb-1">{T.perChannel}</div>
                <div className="muted mb-3" style={{ fontSize: 11 }}>Where this creator’s orders are closing</div>
                <ChannelMix mix={mix} width={'100%'} height={12} />
                <div className="col gap-8 mt-4">
                  {channels.map(ch => {
                    const orders = Math.round(c.orders * mix[ch.id] / 100);
                    const gmv = Math.round(c.gmv * mix[ch.id] / 100);
                    return (
                      <div key={ch.id} className="row items-center gap-12" style={{
                        padding: '8px 10px', background: 'var(--bg-soft)', borderRadius: 10
                      }}>
                        <span style={{
                          width: 26, height: 26, borderRadius: 7, background: ch.badgeBg, color: ch.badgeFg,
                          display: 'grid', placeItems: 'center', flexShrink: 0
                        }}>{ch.icon}</span>
                        <div className="flex-1">
                          <div className="bold" style={{ fontSize: 12.5 }}>{ch.name}</div>
                          <div className="muted tabular" style={{ fontSize: 10.5 }}>{formatCompact(orders)} orders · ${formatCompact(gmv)} GMV</div>
                        </div>
                        <div className="font-display tabular bold" style={{ fontSize: 18, color: ch.color, letterSpacing: '-0.02em' }}>{mix[ch.id]}%</div>
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })()}

          {/* 7d trend */}
          <div className="card-elevated mt-4">
            <div className="title-md mb-2">GMV · 7-day trend</div>
            <Sparkline data={c.spark} color={TIER[c.tier].border} fillId={'drawer-' + c.id} height={70} />
          </div>

          {c.note && (
            <div style={{ marginTop: 14, padding: 14, borderRadius: 12, background: 'rgba(254,233,96,0.20)', border: '1px solid rgba(242,196,17,0.30)' }}>
              <div className="cap-label" style={{ fontSize: 9, color: '#856200' }}>Manager note</div>
              <div style={{ fontSize: 13, marginTop: 4, fontWeight: 600 }}>{c.note}</div>
            </div>
          )}
        </div>

        <style>{`
          @keyframes slideR { from { transform: translateX(40px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
          @keyframes fade   { from { opacity: 0; } to { opacity: 1; } }
        `}</style>
      </div>
    </>
  );
}

// ── BRAND VIEW ─────────────────────────────────────────────────────
function BrandView({ T, tweaks }) {
  const [period, setPeriod] = useState(T.period.d30);
  const [campaignId, setCampaignId] = useState('CMP-201');
  const [channel, setChannel] = useState(T.filter.all);
  const [tier, setTier] = useState(T.filter.all);
  const [openCreator, setOpenCreator] = useState(null);
  const [salesChannels, setSalesChannels] = useState(SALES_CHANNELS);
  const handleConnect = (id) => setSalesChannels(prev => prev.map(s => s.id === id
    ? { ...s, connected: true, seller: 'aurora_lazada_vn', sync: 'just now', orders: 0, gmv: 0 } : s));

  const sortKey = tweaks.affSort || 'gmv';
  const sorted = useMemo(() => {
    const s = [...AFF_CREATORS];
    s.sort((a, b) => (b[sortKey] || 0) - (a[sortKey] || 0));
    return s;
  }, [sortKey]);

  return (
    <>
      {/* Campaign context + connected sales channels (the new top piece) */}
      <CampaignContextBar
        T={T}
        campaignId={campaignId}
        onChangeCampaign={setCampaignId}
        channels={salesChannels}
        onConnect={handleConnect}
      />

      {/* Secondary filter row */}
      <div className="row items-center gap-8 mb-4" style={{ flexWrap: 'wrap' }}>
        <FilterChip label={T.filter.period} value={period}
          options={[T.period.d7, T.period.d30, T.period.d90, T.period.qtd]} onChange={setPeriod} />
        <FilterChip label={T.filter.channel} value={channel}
          options={[T.filter.all, 'TikTok Shop', 'Shopee', 'Lazada', 'Brand site']} onChange={setChannel} />
        <FilterChip label={T.filter.tier} value={tier}
          options={[T.filter.all, 'A', 'B', 'C', 'D']} onChange={setTier} />
        <button style={{
          background: 'transparent', border: 0, cursor: 'pointer', fontFamily: 'inherit',
          fontSize: 11, fontWeight: 700, color: 'var(--ink-soft)', padding: '8px 4px'
        }}>{T.filter.reset}</button>

        <div style={{ marginLeft: 'auto' }} className="row gap-8">
          <button className="btn btn-ghost btn-sm">{Icon.external} {T.cta.export}</button>
          <button className="btn btn-ghost btn-sm">{Icon.spark} {T.cta.compare}</button>
          <button className="btn btn-primary btn-sm">{Icon.external} {T.cta.share}</button>
        </div>
      </div>

      {/* KPI strip */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 10, marginBottom: 18 }}>
        <KpiCell label={T.kpi.gmv} value={Math.round(TOTALS.gmv / 1000)} prefix="$" suffix="K" delta={14.2}
          color="var(--cyan)" sparkData={[1240,1320,1410,1380,1480,1620,1840]} />
        <KpiCell label={T.kpi.orders} value={TOTALS.orders} delta={11.8}
          color="var(--mint-deep)" sparkData={[820,940,1050,1020,1180,1260,1480]} />
        <KpiCell label={T.kpi.cr} value={4.62} suffix="%" delta={3.4}
          color="var(--indigo)" sparkData={[3.8,4.0,4.2,4.1,4.4,4.5,4.6]} />
        <KpiCell label={T.kpi.roas} value={4.8} suffix="x" delta={8.6}
          color="var(--coral)" sparkData={[3.4,3.6,3.8,4.0,4.2,4.5,4.8]} />
        <KpiCell label={T.kpi.aov} value={134} prefix="$" delta={-1.4}
          color="var(--pink-hot)" sparkData={[140,138,136,135,134,134,134]} />
        <KpiCell label={T.kpi.commission} value={Math.round(TOTALS.commission / 1000)} prefix="$" suffix="K" delta={12.7}
          color="var(--mint-deep)" sparkData={[140,150,160,165,175,190,220]} />
      </div>

      {/* Funnel + Channel split */}
      <div style={{ display: 'grid', gridTemplateColumns: '2.2fr 1fr', gap: 14, marginBottom: 18 }}>
        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="row items-end justify-between mb-3">
            <div>
              <div className="title-md">{T.funnel.title}</div>
              <div className="muted" style={{ fontSize: 12 }}>{T.funnel.subtitle}</div>
            </div>
            <div className="row gap-6">
              <Pill variant="mint" icon={Icon.trend}>+14.2% GMV</Pill>
              <Pill variant="cyan">{TOTALS.active} creators</Pill>
            </div>
          </div>
          {tweaks.affFunnel === 'sankey'
            ? <FunnelSankey T={T} />
            : <FunnelHorizontal T={T} />}
        </div>

        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="row items-center justify-between mb-1">
            <div className="title-md">{T.salesChannels}</div>
            <Pill variant="mint">{salesChannels.filter(s => s.connected).length}/{salesChannels.length} {T.connected.toLowerCase()}</Pill>
          </div>
          <div className="muted mb-3" style={{ fontSize: 11 }}>Orders by sales channel · last 30d</div>
          <div className="col gap-12">
            {CHANNEL_SPLIT.map((c, i) => (
              <div key={c.ch}>
                <div className="row items-center justify-between mb-1">
                  <div className="row items-center gap-8">
                    <span style={{
                      width: 22, height: 22, borderRadius: 6, background: c.color, color: 'white',
                      display: 'grid', placeItems: 'center', flexShrink: 0
                    }}>{c.icon}</span>
                    <span className="bold" style={{ fontSize: 12 }}>{c.name}</span>
                  </div>
                  <span className="font-display tabular bold" style={{ fontSize: 14 }}>{c.pct}%</span>
                </div>
                <div style={{ height: 8, background: 'var(--bg-soft)', borderRadius: 999, overflow: 'hidden' }}>
                  <div style={{ width: c.pct + '%', height: '100%', background: c.color, borderRadius: 999,
                    animation: `growW 1s ${i * 0.1 + 0.4}s backwards cubic-bezier(.4,0,.2,1)`, transformOrigin: 'left' }} />
                </div>
                <div className="muted tabular" style={{ fontSize: 10, marginTop: 3 }}>
                  ${formatCompact(SALES_CHANNELS.find(s => s.id === c.ch).gmv)} GMV · {formatCompact(SALES_CHANNELS.find(s => s.id === c.ch).orders)} orders
                </div>
              </div>
            ))}
          </div>
          <div style={{ marginTop: 16, padding: 12, borderRadius: 10, background: 'rgba(0,156,255,0.06)', border: '1px solid rgba(0,156,255,0.15)' }}>
            <div className="cap-label" style={{ fontSize: 9, color: 'var(--cyan-dark)' }}>Insight</div>
            <div style={{ fontSize: 12.5, marginTop: 4, fontWeight: 600, lineHeight: 1.4 }}>
              <b>TikTok Shop</b> closes <b>62%</b> of orders — highest CR per click.
              {!salesChannels.find(s => s.id === 'LZD').connected
                ? <> Lazada is not yet connected; ~14% of clicks bounce there untracked.</>
                : <> All sales channels are live.</>}
            </div>
          </div>
        </div>
      </div>

      {/* Quadrant + Leaderboard */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.1fr 1.6fr', gap: 14, marginBottom: 18 }}>
        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="row items-end justify-between mb-3">
            <div>
              <div className="title-md">{T.quadrant.title}</div>
              <div className="muted" style={{ fontSize: 12 }}>{T.quadrant.subtitle}</div>
            </div>
            <div className="row gap-6">
              {['A','B','C','D'].map(tk => (
                <span key={tk} className="row items-center gap-4" style={{ fontSize: 11, fontWeight: 700 }}>
                  <span style={{ width: 9, height: 9, borderRadius: 3, background: TIER[tk].border }} />
                  {tk}
                </span>
              ))}
            </div>
          </div>
          <QuadrantChart T={T} creators={AFF_CREATORS} />
          <div className="muted" style={{ fontSize: 11, marginTop: 8 }}>
            Bubble size = GMV · click row in leaderboard for detail
          </div>
        </div>

        <div className="card-elevated" style={{ padding: 22, paddingRight: 12 }}>
          <div className="row items-end justify-between mb-3">
            <div>
              <div className="title-md">{T.table.title}</div>
              <div className="muted" style={{ fontSize: 12 }}>{T.table.subtitle}</div>
            </div>
            <div className="row items-center gap-6" style={{ fontSize: 11, color: 'var(--ink-soft)' }}>
              Sort:&nbsp;
              {['gmv','roas','cr','commission','orders'].map(k => (
                <button key={k} onClick={() => tweaks.set('affSort', k)} style={{
                  background: sortKey === k ? 'var(--ink)' : 'transparent',
                  color: sortKey === k ? 'white' : 'var(--ink)',
                  border: 0, padding: '4px 9px', borderRadius: 999, cursor: 'pointer',
                  fontFamily: 'inherit', fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.04em'
                }}>{k}</button>
              ))}
            </div>
          </div>
          <div style={{ maxHeight: 540, overflowY: 'auto', marginRight: 4 }} className="no-scrollbar">
            <table className="tbl" style={{ fontSize: 12 }}>
              <thead>
                <tr>
                  <th style={{ width: 30 }}>{T.table.headRank}</th>
                  <th>{T.table.headCreator}</th>
                  <th style={{ width: 40 }}>{T.table.headTier}</th>
                  <th className="text-right">{T.table.headGmv}</th>
                  <th className="text-right">{T.table.headOrders}</th>
                  <th className="text-right">{T.table.headCr}</th>
                  <th className="text-right">{T.table.headRoas}</th>
                  <th className="text-right">{T.table.headComm}</th>
                  <th style={{ width: 90 }}>{T.channelMix}</th>
                  <th style={{ width: 80 }}>{T.table.headTrend}</th>
                  <th style={{ width: 32 }}></th>
                </tr>
              </thead>
              <tbody>
                {sorted.map((c, i) => (
                  <tr key={c.id} onClick={() => setOpenCreator(c)} style={{ cursor: 'pointer' }}>
                    <td className="muted tabular" style={{ fontWeight: 700, fontSize: 11 }}>{String(i + 1).padStart(2, '0')}</td>
                    <td>
                      <div className="row items-center gap-8">
                        <Avatar name={c.name} size={28} />
                        <div style={{ minWidth: 0 }}>
                          <div className="bold" style={{ fontSize: 12.5, lineHeight: 1.2 }}>{c.name}</div>
                          <div className="row items-center gap-4" style={{ marginTop: 2 }}>
                            {c.channels.map(ch => <ChannelChip key={ch} ch={ch} />)}
                            <span className="muted" style={{ fontSize: 10 }}>{c.handle}</span>
                          </div>
                        </div>
                      </div>
                    </td>
                    <td><TierBadge tier={c.tier} size="sm" /></td>
                    <td className="text-right">
                      <div className="font-display tabular bold" style={{ fontSize: 13 }}>${formatCompact(c.gmv)}</div>
                      <div style={{ fontSize: 9.5, fontWeight: 700, color: c.delta >= 0 ? '#0a8a72' : '#B12B2B' }}>
                        {c.delta >= 0 ? '+' : ''}{c.delta}%
                      </div>
                    </td>
                    <td className="text-right tabular bold">{formatCompact(c.orders)}</td>
                    <td className="text-right tabular">
                      <span style={{
                        padding: '2px 7px', borderRadius: 6,
                        background: c.cr > 4.5 ? 'rgba(31,214,180,0.15)' : c.cr > 2.5 ? 'rgba(242,196,17,0.15)' : 'rgba(255,68,68,0.10)',
                        color: c.cr > 4.5 ? '#0a8a72' : c.cr > 2.5 ? '#856200' : '#B12B2B',
                        fontWeight: 800, fontSize: 11
                      }}>{c.cr.toFixed(1)}%</span>
                    </td>
                    <td className="text-right tabular bold">{c.roas.toFixed(1)}x</td>
                    <td className="text-right tabular">${formatCompact(c.commission)}</td>
                    <td>
                      <ChannelMix mix={channelMixFor(c)} width={84} height={8} />
                    </td>
                    <td>
                      <div style={{ width: 80 }}>
                        <Sparkline data={c.spark} color={TIER[c.tier].border} fillId={'r-' + c.id} height={26} animate={false} />
                      </div>
                    </td>
                    <td>
                      <span style={{ color: 'var(--ink-soft)' }}>{Icon.arrow}</span>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </div>

      {/* Payout pipeline */}
      <div className="card-elevated" style={{ padding: 22 }}>
        <div className="row items-end justify-between mb-3">
          <div>
            <div className="title-md">{T.pipeline.title}</div>
            <div className="muted" style={{ fontSize: 12 }}>{T.pipeline.subtitle}</div>
          </div>
          <div className="row gap-6">
            <Pill variant="yellow">3 {T.pipeline.ready}</Pill>
            <Pill variant="cyan">4 {T.pipeline.processing.toLowerCase()}</Pill>
            <Pill variant="mint">{T.pipeline.cleared.toLowerCase()}</Pill>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14 }}>
          {PAYOUT_QUEUE.map((lane, li) => {
            const laneTotal = lane.items.reduce((s, x) => s + x.amt, 0);
            const laneColor = lane.lane === 'pendingReview' ? 'var(--yellow-deep)'
              : lane.lane === 'processing' ? 'var(--cyan)' : 'var(--mint-deep)';
            return (
              <div key={lane.lane} style={{
                background: 'var(--bg-soft)', borderRadius: 14, padding: 14,
                borderTop: `3px solid ${laneColor}`,
              }}>
                <div className="row items-end justify-between mb-3">
                  <div>
                    <div className="cap-label" style={{ fontSize: 9.5 }}>{T.pipeline[lane.lane]}</div>
                    <div className="font-display tabular" style={{ fontSize: 22, fontWeight: 700, marginTop: 2 }}>
                      ${formatCompact(laneTotal)}
                    </div>
                  </div>
                  <span className="muted" style={{ fontSize: 11 }}>{lane.items.length} items</span>
                </div>
                <div className="col gap-6">
                  {lane.items.map(item => (
                    <div key={item.id} style={{
                      padding: 10, borderRadius: 10, background: 'white',
                      border: item.risk ? '1px solid rgba(255,68,68,0.30)' : '1px solid var(--line)',
                      boxShadow: '0 1px 3px rgba(0,43,80,0.04)',
                      cursor: 'pointer', transition: 'transform .15s, box-shadow .15s'
                    }}
                      onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-1px)'; e.currentTarget.style.boxShadow = 'var(--shadow-sm)'; }}
                      onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 1px 3px rgba(0,43,80,0.04)'; }}>
                      <div className="row items-center gap-8">
                        <Avatar name={item.name} size={26} />
                        <div className="flex-1" style={{ minWidth: 0 }}>
                          <div className="bold" style={{ fontSize: 12 }}>{item.name}</div>
                          <div className="muted" style={{ fontSize: 10 }}>{item.id} · {item.age}{item.eta ? ` · ETA ${item.eta}` : ''}</div>
                        </div>
                        <div className="font-display tabular bold" style={{ fontSize: 13 }}>${formatCompact(item.amt)}</div>
                      </div>
                      {item.risk && (
                        <div className="row items-center gap-6" style={{
                          marginTop: 6, padding: '4px 8px', borderRadius: 6,
                          background: 'rgba(255,68,68,0.08)', color: '#B12B2B',
                          fontSize: 10.5, fontWeight: 700
                        }}>
                          ⚠ {item.reason}
                        </div>
                      )}
                      {lane.lane === 'pendingReview' && (
                        <div className="row gap-4" style={{ marginTop: 8 }}>
                          <button style={{
                            flex: 1, padding: '5px 0', border: 0, borderRadius: 6,
                            background: 'var(--ink)', color: 'white', cursor: 'pointer',
                            fontFamily: 'inherit', fontSize: 10.5, fontWeight: 700
                          }}>{T.actions.approvePayout}</button>
                          <button style={{
                            padding: '5px 10px', border: '1px solid var(--line)', borderRadius: 6,
                            background: 'white', color: 'var(--ink)', cursor: 'pointer',
                            fontFamily: 'inherit', fontSize: 10.5, fontWeight: 700
                          }}>Hold</button>
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {openCreator && <CreatorDetailDrawer creator={openCreator} T={T} onClose={() => setOpenCreator(null)} />}
    </>
  );
}

// ── CREATOR VIEW (self) ────────────────────────────────────────────
function CreatorView({ T }) {
  // Persona: Linh Châu (top creator) viewing her own AFF.
  const me = AFF_CREATORS[0];
  const myMix = channelMixFor(me);
  const myCampaigns = [
    { id: 'CMP-201', name: 'Vitamin C Skin Glow', brand: 'Aurora Beauty', accent: 'var(--cyan)',         status: 'live',   orders: 2240, gmv: 296800, comm: 35616, cr: 6.81, role: 'D2 published · D3 due Jun 4' },
    { id: 'CMP-198', name: 'SPF Glow Tour',       brand: 'DermaPlus',     accent: 'var(--coral)',        status: 'live',   orders:  680, gmv:  92000, comm: 11040, cr: 5.62, role: 'D1 live · wrap Jun 8' },
    { id: 'CMP-179', name: 'Cafe Affiliate · HN', brand: 'Drip Hanoi',    accent: 'var(--yellow-deep)',  status: 'live',   orders:  200, gmv:  24000, comm:  2880, cr: 4.10, role: 'Always-on · 14% comm.' },
    { id: 'CMP-186', name: 'Coffee morning drop', brand: 'Highland',      accent: 'var(--lavender-deep)',status: 'closed', orders:    0, gmv:      0, comm:     0, cr: 0,    role: 'Wrapped Apr 28' },
  ];
  const myLinks = [
    { id: 'L-201', label: 'Vitamin C ampoule · 30ml', campaign: 'Vitamin C Skin Glow', clicks: 18400, orders: 1240, gmv: 168200, comm: 20184, cr: 6.74, posted: '14 days ago', channel: 'TT' },
    { id: 'L-198', label: 'Niacinamide bundle', campaign: 'Vitamin C Skin Glow', clicks: 14200, orders: 940,  gmv: 124000, comm: 14880, cr: 6.62, posted: '21 days ago', channel: 'IG' },
    { id: 'L-186', label: 'SPF50 daily sun', campaign: 'SPF Glow Tour', clicks: 9800,  orders: 540,  gmv: 76400,  comm: 9168, cr: 5.51, posted: '34 days ago', channel: 'TT' },
    { id: 'L-179', label: 'Retinol night cream', campaign: 'Vitamin C Skin Glow', clicks: 5800,  orders: 400,  gmv: 44200,  comm: 5304, cr: 6.90, posted: '6 weeks ago', channel: 'IG' },
  ];

  return (
    <>
      {/* hero strip */}
      <div className="card-elevated mb-4" style={{
        padding: 22, background: 'linear-gradient(135deg, #002B50 0%, #1C1CC9 100%)',
        color: 'white', position: 'relative', overflow: 'hidden'
      }}>
        <div style={{ position: 'absolute', top: -40, right: -40, width: 220, height: 220, borderRadius: '50%',
          background: 'radial-gradient(circle, rgba(121,254,231,0.40), transparent 60%)', filter: 'blur(20px)' }} />
        <div className="row items-center gap-16" style={{ position: 'relative', flexWrap: 'wrap' }}>
          <Avatar name={me.name} size={64} />
          <div className="flex-1" style={{ minWidth: 240 }}>
            <div className="row items-center gap-8" style={{ flexWrap: 'wrap' }}>
              <div className="font-display" style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>{T.creator.mineTitle}</div>
              <TierBadge tier={me.tier} />
              <Pill variant="dark"><span style={{ color: 'var(--mint)' }}>●</span> {me.status}</Pill>
            </div>
            <div style={{ fontSize: 13, opacity: 0.85, marginTop: 4 }}>{T.creator.mineSub}</div>
          </div>
          <div className="row gap-6">
            <button className="btn btn-ghost btn-sm" style={{ color: 'white', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,0.3)' }}>{T.creator.tax}</button>
            <button className="btn btn-yellow btn-sm">{T.creator.shareKit}</button>
          </div>
        </div>
      </div>

      {/* KPI strip — creator-focused */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 14 }}>
        <KpiCell label="My GMV" value={Math.round(me.gmv / 1000)} prefix="$" suffix="K" delta={me.delta}
          color="var(--cyan)" sparkData={me.spark} />
        <KpiCell label="My orders" value={me.orders} delta={me.delta - 2}
          color="var(--mint-deep)" sparkData={[280,310,350,380,420,460,520]} />
        <KpiCell label="My CR" value={me.cr} suffix="%" delta={4.2}
          color="var(--indigo)" sparkData={[5.4,5.6,5.8,6.0,6.2,6.4,6.5]} />
        <KpiCell label="Commission earned" value={Math.round(me.commission / 1000)} prefix="$" suffix="K" delta={18.4}
          color="var(--coral)" sparkData={[28,32,36,40,44,46,49]} />
      </div>

      {/* My campaigns aggregate + my channel mix */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.7fr 1fr', gap: 14, marginBottom: 14 }}>
        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="row items-end justify-between mb-3">
            <div>
              <div className="title-md">My campaigns</div>
              <div className="muted" style={{ fontSize: 12 }}>{myCampaigns.length} campaigns · aggregated across all sales channels</div>
            </div>
            <Pill variant="mint" icon={Icon.trend}>+24% vs last 30d</Pill>
          </div>
          <table className="tbl" style={{ fontSize: 12 }}>
            <thead>
              <tr>
                <th>Campaign</th>
                <th className="text-right">Orders</th>
                <th className="text-right">GMV</th>
                <th className="text-right">CR</th>
                <th className="text-right">Commission</th>
                <th style={{ width: 80 }}>Status</th>
                <th style={{ width: 24 }}></th>
              </tr>
            </thead>
            <tbody>
              {myCampaigns.map(c => (
                <tr key={c.id} style={{ cursor: 'pointer' }}>
                  <td>
                    <div className="row items-center gap-8">
                      <span style={{ width: 30, height: 30, borderRadius: 8, background: c.accent, color: 'white',
                        display: 'grid', placeItems: 'center', fontFamily: 'Space Grotesk', fontWeight: 800, fontSize: 11, letterSpacing: '-0.02em', flexShrink: 0 }}>
                        {c.name.split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase()}
                      </span>
                      <div>
                        <div className="bold" style={{ fontSize: 12.5, lineHeight: 1.2 }}>{c.name}</div>
                        <div className="muted" style={{ fontSize: 10.5 }}>{c.brand} · {c.role}</div>
                      </div>
                    </div>
                  </td>
                  <td className="text-right tabular bold">{c.orders ? formatCompact(c.orders) : '—'}</td>
                  <td className="text-right tabular bold">{c.gmv ? '$' + formatCompact(c.gmv) : '—'}</td>
                  <td className="text-right tabular">
                    {c.cr > 0 ? (
                      <span style={{
                        padding: '2px 7px', borderRadius: 6,
                        background: c.cr > 5 ? 'rgba(31,214,180,0.15)' : 'rgba(242,196,17,0.15)',
                        color: c.cr > 5 ? '#0a8a72' : '#856200', fontWeight: 800, fontSize: 11
                      }}>{c.cr.toFixed(1)}%</span>
                    ) : <span className="muted">—</span>}
                  </td>
                  <td className="text-right tabular bold" style={{ color: 'var(--coral)' }}>{c.comm ? '$' + formatCompact(c.comm) : '—'}</td>
                  <td>
                    <span style={{ fontSize: 10, fontWeight: 800, padding: '2px 7px', borderRadius: 999,
                      background: c.status === 'live' ? 'rgba(31,214,180,0.18)' : 'rgba(0,43,80,0.08)',
                      color: c.status === 'live' ? '#0a8a72' : 'var(--ink-soft)',
                      letterSpacing: '0.08em', textTransform: 'uppercase' }}>{c.status}</span>
                  </td>
                  <td><span style={{ color: 'var(--ink-soft)' }}>{Icon.arrow}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        {/* My channel mix */}
        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="title-md mb-1">My orders by channel</div>
          <div className="muted mb-3" style={{ fontSize: 11 }}>Where your audience checks out</div>
          <ChannelMix mix={myMix} width={'100%'} height={14} />
          <div className="col gap-6 mt-3">
            {SALES_CHANNELS.filter(s => myMix[s.id] !== undefined && myMix[s.id] > 0).map(ch => {
              const orders = Math.round(me.orders * myMix[ch.id] / 100);
              const gmv = Math.round(me.gmv * myMix[ch.id] / 100);
              return (
                <div key={ch.id} className="row items-center gap-10" style={{ padding: '7px 9px', background: 'var(--bg-soft)', borderRadius: 10 }}>
                  <span style={{ width: 24, height: 24, borderRadius: 6, background: ch.badgeBg, color: ch.badgeFg, display: 'grid', placeItems: 'center', flexShrink: 0 }}>{ch.icon}</span>
                  <div className="flex-1">
                    <div className="bold" style={{ fontSize: 12 }}>{ch.name}</div>
                    <div className="muted tabular" style={{ fontSize: 10 }}>{formatCompact(orders)} orders · ${formatCompact(gmv)}</div>
                  </div>
                  <div className="font-display tabular bold" style={{ fontSize: 16, color: ch.color, letterSpacing: '-0.02em' }}>{myMix[ch.id]}%</div>
                </div>
              );
            })}
          </div>
          <div style={{ marginTop: 14, padding: 10, borderRadius: 10, background: 'rgba(31,214,180,0.10)', border: '1px solid rgba(31,214,180,0.22)' }}>
            <div className="cap-label" style={{ fontSize: 9, color: '#0a8a72' }}>Tip</div>
            <div style={{ fontSize: 11.5, marginTop: 3, fontWeight: 600, lineHeight: 1.4 }}>
              TikTok Shop closes <b>62%</b> of your orders. Pin your TT-Shop link in bio first.
            </div>
          </div>
        </div>
      </div>

      {/* my funnel + my links */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 14, marginBottom: 14 }}>
        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="title-md mb-1">{T.creator.myFunnel}</div>
          <div className="muted mb-3" style={{ fontSize: 11 }}>Of every 1,000 people who see your post — how many convert?</div>

          {(() => {
            const fStages = [
              { l: 'People reached',     v: me.reach * 1000, color: 'var(--lavender-deep)' },
              { l: 'Clicked your link',  v: me.clicks,        color: 'var(--cyan)' },
              { l: 'Added to cart',      v: Math.round(me.clicks * 0.21), color: 'var(--indigo-soft)' },
              { l: 'Placed order',       v: me.orders,        color: 'var(--mint-deep)' },
              { l: 'Commission cleared', v: Math.round(me.commission * 0.78), color: 'var(--coral)', isMoney: true },
            ];
            const max = fStages[0].v;
            return (
              <div className="col gap-12 mt-2">
                {fStages.map((s, i) => {
                  const next = fStages[i + 1];
                  const pct = (s.v / max) * 100;
                  const isUnitBreak = next && (s.isMoney || next.isMoney);
                  const cvr = next && !isUnitBreak ? Math.round((next.v / s.v) * 1000) / 10 : null;
                  const aov = isUnitBreak && i === 3 ? Math.round(me.gmv / me.orders) : null;
                  const commPct = isUnitBreak && i === 3 ? 12 : null;
                  return (
                    <div key={i}>
                      <div className="row items-center justify-between mb-1">
                        <span className="cap-label" style={{ fontSize: 10 }}>{s.l}</span>
                        <span className="font-display tabular bold" style={{ fontSize: 16 }}>
                          {s.isMoney ? '$' + formatCompact(s.v) : formatCompact(s.v)}
                        </span>
                      </div>
                      <div style={{ height: 14, borderRadius: 999, background: 'var(--bg-soft)', overflow: 'hidden' }}>
                        <div style={{
                          height: '100%', width: pct + '%',
                          background: `linear-gradient(90deg, ${s.color}, ${s.color}cc)`,
                          borderRadius: 999,
                          animation: `growW .8s ${i * 0.1}s backwards cubic-bezier(.4,0,.2,1)`, transformOrigin: 'left',
                        }} />
                      </div>
                      {cvr !== null && (
                        <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>
                          ↓ <b style={{ color: 'var(--ink)' }}>{cvr}%</b> convert · <span style={{ color: 'var(--coral)' }}>−{(100 - cvr).toFixed(1)}% drop</span>
                        </div>
                      )}
                      {aov !== null && (
                        <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>
                          ↓ AOV <b style={{ color: 'var(--ink)' }}>${aov}</b> · <span style={{ color: 'var(--mint-deep)' }}>{commPct}% commission</span>
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            );
          })()}
        </div>

        <div className="card-elevated" style={{ padding: 22 }}>
          <div className="row items-end justify-between mb-3">
            <div>
              <div className="title-md">{T.creator.myLinks}</div>
              <div className="muted" style={{ fontSize: 12 }}>Each post is a portfolio piece — share the strong ones.</div>
            </div>
            <button className="btn btn-ghost btn-sm">{Icon.external} See all 14</button>
          </div>
          <div className="col gap-6">
            {myLinks.map(l => (
              <div key={l.id} style={{
                padding: 12, borderRadius: 12, background: 'var(--bg-soft)',
                transition: 'background .15s'
              }}
                onMouseEnter={e => e.currentTarget.style.background = 'white'}
                onMouseLeave={e => e.currentTarget.style.background = 'var(--bg-soft)'}>
                <div className="row items-center gap-12">
                  <ChannelChip ch={l.channel} />
                  <div className="flex-1" style={{ minWidth: 0 }}>
                    <div className="bold" style={{ fontSize: 13 }}>{l.label}</div>
                    <div className="muted" style={{ fontSize: 11 }}>{l.campaign} · {l.posted}</div>
                  </div>
                  <div className="row gap-16">
                    <div className="text-right">
                      <div className="cap-label" style={{ fontSize: 9 }}>Clicks</div>
                      <div className="font-display tabular bold" style={{ fontSize: 14 }}>{formatCompact(l.clicks)}</div>
                    </div>
                    <div className="text-right">
                      <div className="cap-label" style={{ fontSize: 9 }}>Orders</div>
                      <div className="font-display tabular bold" style={{ fontSize: 14 }}>{formatCompact(l.orders)}</div>
                    </div>
                    <div className="text-right">
                      <div className="cap-label" style={{ fontSize: 9 }}>CR</div>
                      <div className="font-display tabular bold" style={{ fontSize: 14, color: '#0a8a72' }}>{l.cr.toFixed(1)}%</div>
                    </div>
                    <div className="text-right">
                      <div className="cap-label" style={{ fontSize: 9 }}>Earned</div>
                      <div className="font-display tabular bold" style={{ fontSize: 14, color: 'var(--coral)' }}>${formatCompact(l.comm)}</div>
                    </div>
                  </div>
                  <button style={{
                    padding: '6px 10px', borderRadius: 8,
                    background: 'white', border: '1px solid var(--line)', cursor: 'pointer',
                    fontFamily: 'inherit', fontSize: 11, fontWeight: 700,
                  }}>{T.creator.copyLink}</button>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* my payout queue */}
      <div className="card-elevated" style={{ padding: 22 }}>
        <div className="row items-end justify-between mb-3">
          <div>
            <div className="title-md">{T.creator.payoutQueue}</div>
            <div className="muted" style={{ fontSize: 12 }}>Money on the way · paid to Vietcombank •• 4821</div>
          </div>
          <div className="row gap-6">
            <Pill variant="yellow">$5,816 {T.pipeline.ready.toLowerCase()}</Pill>
            <Pill variant="cyan">$3,216 {T.pipeline.processing.toLowerCase()}</Pill>
            <Pill variant="mint">$28.4K {T.pipeline.cleared.toLowerCase()} this Q</Pill>
          </div>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr) auto', gap: 8, alignItems: 'center' }}>
          {[
            ['May 14', 'Vitamin C · D2 payout', 5816, 'pending', 'var(--yellow-deep)'],
            ['May 12', 'SPF Glow · D1 payout',  3216, 'processing', 'var(--cyan)'],
            ['May 10', 'Vitamin C · D1 payout', 5240, 'cleared', 'var(--mint-deep)'],
            ['May 06', 'Affiliate · Shopee · April', 2860, 'cleared', 'var(--mint-deep)'],
            ['Apr 30', 'Coffee morning · final', 4720, 'cleared', 'var(--mint-deep)'],
            ['Apr 22', 'Vitamin C · D0 payout',  3640, 'cleared', 'var(--mint-deep)'],
          ].map(([d, label, amt, st, col], i) => (
            <React.Fragment key={i}>
              <div style={{ fontSize: 12, fontWeight: 600, gridColumn: '1 / 2' }}>{d}</div>
              <div style={{ fontSize: 13, fontWeight: 600, gridColumn: '2 / 3' }}>{label}</div>
              <div style={{ gridColumn: '3 / 4' }}>
                <span className="row items-center gap-6" style={{ fontSize: 11, fontWeight: 700 }}>
                  <span style={{ width: 7, height: 7, borderRadius: 999, background: col }} />
                  <span style={{ textTransform: 'capitalize' }}>{st}</span>
                </span>
              </div>
              <div className="font-display tabular bold text-right" style={{ fontSize: 14, gridColumn: '4 / 5' }}>${formatCompact(amt)}</div>
              <div style={{ gridColumn: '5 / 6', color: 'var(--ink-soft)' }}>{Icon.arrow}</div>
              {i < 5 && <div style={{ gridColumn: '1 / -1', height: 1, background: 'var(--line)' }} />}
            </React.Fragment>
          ))}
        </div>
      </div>
    </>
  );
}

// ── MAIN SCREEN ────────────────────────────────────────────────────
function ScreenBrandAFFReport() {
  const T = useAff();
  const tweaksHook = useTweaks ? null : null; // we read via window
  // tweak read pattern: app.jsx owns tweaks; we read via document and rely on app re-render
  const [tab, setTab] = useState('brand');
  // Local sort tweak — kept in component state, can also be wired via tweaks
  const [affSort, setAffSort] = useState('gmv');
  const [affFunnel, setAffFunnel] = useState('horizontal');
  const tweaks = { affSort, affFunnel, set: (k, v) => { if (k === 'affSort') setAffSort(v); if (k === 'affFunnel') setAffFunnel(v); } };

  return (
    <div className="app-shell">
      <AppSidebar portal="brand" active="brand-aff" />
      <main className="main">
        <AppTopbar />

        <div className="row items-end justify-between mb-6">
          <div>
            <Pill variant="cyan"><span style={{ color: 'var(--mint-deep)' }}>●</span> {T.eyebrow}</Pill>
            <h1 className="page-title" style={{ marginTop: 8 }}>{T.title}</h1>
            <div className="page-subtitle">{T.subtitle}</div>
          </div>
          <div className="row items-center gap-12">
            <TabPill
              tabs={[{ id: 'brand', label: T.tabBrand }, { id: 'creator', label: T.tabCreator }]}
              value={tab} onChange={setTab} />
            <div className="row gap-6" style={{ borderLeft: '1px solid var(--line)', paddingLeft: 10 }}>
              <button title="Funnel viz" onClick={() => setAffFunnel(f => f === 'sankey' ? 'horizontal' : 'sankey')} style={{
                width: 32, height: 32, borderRadius: 8,
                background: 'white', border: '1px solid var(--line)', cursor: 'pointer',
                display: 'grid', placeItems: 'center', color: 'var(--ink-soft)'
              }}>{Icon.sliders}</button>
            </div>
          </div>
        </div>

        {tab === 'brand' ? <BrandView T={T} tweaks={tweaks} /> : <CreatorView T={T} />}
      </main>
    </div>
  );
}

Object.assign(window, { ScreenBrandAFFReport });
