/* data.jsx, Yoshi mobile · the whole dummy dataset + formatters.
   Numbers are plausible (net worth ≈ $397k). Tickers are real symbols,
   prices are illustrative. Everything here is static seed data; the app
   layers live state on top. Exported on `window`. */

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------- formatters ----------------------------------------------------- */
// Split a number into grouped whole + decimal so the cents can grey out.
const money = (n) => {
  const neg = n < 0;
  const [w, d] = Math.abs(n).toFixed(2).split(".");
  return { neg, whole: w.replace(/\B(?=(\d{3})+(?!\d))/g, ","), dec: d || "" };
};
// Full string e.g. "$1,234.56"
const usd = (n) => {
  const m = money(n);
  return (m.neg ? "-$" : "$") + m.whole + "." + m.dec;
};
const signed = (n) => { const m = money(n); return (n >= 0 ? "+" : "−") + "$" + m.whole + "." + m.dec; };
// Compact e.g. $397k, $1.2M, $840 — for tight labels.
const compactUsd = (n) => {
  const a = Math.abs(n), s = n < 0 ? "-" : "";
  if (a >= 1e6) return s + "$" + (a / 1e6).toFixed(2) + "M";
  if (a >= 1e3) return s + "$" + (a / 1e3).toFixed(2) + "k";
  return s + "$" + a.toFixed(2);
};
const pct = (n) => (n >= 0 ? "+" : "−") + Math.abs(n).toFixed(2) + "%";
/* combined performance readout — the canonical app-wide format: +$XX.XX (X.XX%) */
const perf = (abs, p) => signed(abs) + " (" + Math.abs(p).toFixed(2) + "%)";

/* ---------- seeded series generator ---------------------------------------
   mulberry32 PRNG → a deterministic walk from start→end so a holding's
   chart always matches its quoted % move. */
const mulberry32 = (a) => () => {
  a |= 0; a = (a + 0x6D2B79F5) | 0;
  let t = Math.imul(a ^ (a >>> 15), 1 | a);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
function series(seed, len, start, end, vol) {
  const rnd = mulberry32(seed);
  const pts = [];
  for (let i = 0; i < len; i++) {
    const t = i / (len - 1);
    const base = start + (end - start) * t;
    const noise = (rnd() - 0.5) * vol * (start || 1) * (1 - Math.abs(t - 0.5)); // taper at ends
    pts.push(i === len - 1 ? end : base + noise);
  }
  return pts;
}

/* ---------- the account model ---------------------------------------------- */
const HOLDINGS = [
  { id: "vti",  ticker: "VTI",  name: "Vanguard Total Market",  kind: "etf",    shares: 420,  avg: 235.10, last: 291.44, dch:  0.74, seed: 11,
    perf: { "1W": 1.2, "1M": 3.4, "1Y": 21.8 }, group: "investments",
    fund: [["Asset class","US Equity ETF"],["Expense ratio","0.03%"],["Yield","1.31%"],["52w range","224.10 – 296.80"]],
    news: [["Reuters","Broad market ETFs see record weekly inflows","2h"],["Bloomberg","Total-market funds outperform sector bets in Q1","Yest"]] },
  { id: "nvda", ticker: "NVDA", name: "NVIDIA Corp",            kind: "stock",  shares: 180,  avg: 88.40,  last: 142.17, dch:  2.31, seed: 22,
    perf: { "1W": 4.1, "1M": 9.7, "1Y": 64.2 }, group: "investments",
    fund: [["Market cap","$3.48T"],["P/E ratio","58.2"],["Day range","138.02 – 143.66"],["52w range","86.62 – 153.13"]],
    news: [["CNBC","NVIDIA extends rally on data-center demand","41m"],["WSJ","Chipmakers lead the tape into the close","3h"]] },
  { id: "aapl", ticker: "AAPL", name: "Apple Inc",              kind: "stock",  shares: 145,  avg: 171.20, last: 214.05, dch: -0.58, seed: 33,
    perf: { "1W": -0.9, "1M": 2.1, "1Y": 14.6 }, group: "investments",
    fund: [["Market cap","$3.27T"],["P/E ratio","33.4"],["Day range","212.88 – 216.40"],["52w range","164.08 – 237.49"]],
    news: [["The Verge","Apple's services revenue hits new high","1h"],["Bloomberg","Hardware guidance trimmed for the quarter","Yest"]] },
  { id: "voo",  ticker: "VOO",  name: "Vanguard S&P 500",       kind: "etf",    shares: 60,   avg: 402.30, last: 548.12, dch:  0.66, seed: 44,
    perf: { "1W": 1.0, "1M": 3.0, "1Y": 19.4 }, group: "investments",
    fund: [["Asset class","US Large-Cap ETF"],["Expense ratio","0.03%"],["Yield","1.27%"],["52w range","468.20 – 552.10"]],
    news: [["Morningstar","S&P 500 index funds extend gains","2h"]] },
  { id: "msft", ticker: "MSFT", name: "Microsoft Corp",         kind: "stock",  shares: 32,   avg: 332.50, last: 468.30, dch:  1.12, seed: 55,
    perf: { "1W": 2.2, "1M": 4.8, "1Y": 27.1 }, group: "investments",
    fund: [["Market cap","$3.48T"],["P/E ratio","36.9"],["Day range","462.10 – 470.55"],["52w range","362.90 – 471.00"]],
    news: [["Reuters","Microsoft cloud bookings beat estimates","4h"]] },

  { id: "btc",  ticker: "BTC",  name: "Bitcoin",                kind: "crypto", shares: 0.52, avg: 41200, last: 96180, dch:  3.42, seed: 66,
    perf: { "1W": 5.6, "1M": 12.4, "1Y": 118.0 }, group: "crypto",
    fund: [["Network","Bitcoin"],["Holdings","0.52000000 BTC"],["Cost basis","$41,200.00"],["24h range","92,400 – 97,010"]],
    news: [["CoinDesk","Bitcoin reclaims $96,000.00 as ETFs absorb supply","18m"],["Bloomberg","Spot BTC ETFs log eighth straight inflow day","2h"]] },
  { id: "eth",  ticker: "ETH",  name: "Ethereum",               kind: "crypto", shares: 4.2,  avg: 2210,  last: 3640, dch: -1.18, seed: 77,
    perf: { "1W": -2.1, "1M": 6.8, "1Y": 41.2 }, group: "crypto",
    fund: [["Network","Ethereum"],["Holdings","4.20000000 ETH"],["Cost basis","$2,210.00"],["24h range","3,580 – 3,712"]],
    news: [["The Block","Staking yields tick higher after upgrade","1h"]] },
  { id: "sol",  ticker: "SOL",  name: "Solana",                 kind: "crypto", shares: 120,  avg: 96.10, last: 188.40, dch:  4.77, seed: 88,
    perf: { "1W": 8.2, "1M": 19.3, "1Y": 96.5 }, group: "crypto",
    fund: [["Network","Solana"],["Holdings","120.000 SOL"],["Cost basis","$96.10"],["24h range","176.20 – 191.00"]],
    news: [["Decrypt","Solana network activity sets monthly record","3h"]] },
];

// Derived per-holding numbers.
HOLDINGS.forEach(h => {
  h.value   = h.shares * h.last;
  h.cost    = h.shares * h.avg;
  h.pl      = h.value - h.cost;
  h.plPct   = (h.pl / h.cost) * 100;
  h.dayAbs  = h.value * (h.dch / 100);
});

const CASH = [
  { id: "chk",  name: "Cash",     sub: "Yoshi ••8841", apr: "3.30% APY", value: 18420.55, color: "var(--ink-3)" },
  { id: "sav",  name: "Reserve",  sub: "Yoshi ••2207", apr: "3.30% APY", value: 64000.00, color: "var(--accent-2)" },
];

const GROUPS = {
  cash:        { label: "Cash",        items: CASH,                                       color: "var(--ink-2)" },
  investments: { label: "Investments", items: HOLDINGS.filter(h => h.group === "investments"), color: "var(--accent-4)" },
  crypto:      { label: "Crypto",      items: HOLDINGS.filter(h => h.group === "crypto"),      color: "var(--accent)" },
};

const sum = (arr) => arr.reduce((s, x) => s + x.value, 0);
const CASH_TOTAL   = sum(CASH);
const INVEST_TOTAL = sum(GROUPS.investments.items);
const CRYPTO_TOTAL = sum(GROUPS.crypto.items);
const NET_WORTH    = CASH_TOTAL + INVEST_TOTAL + CRYPTO_TOTAL;

/* Liabilities, read-only, linked from outside Yoshi via Plaid (like the
   external accounts in the Accounts tab). Net worth nets these against assets. */
const LIABILITIES = [
  { id: "mortgage", name: "Home mortgage", sub: "Wells Fargo ••7704", value: 238400.00, color: "var(--signal-neg)", min: "$2,140.00/mo · 27 yr left", apr: "5.88% APR",
    debt: { outstanding: "$238,400.00", original: "$310,000.00", term: "30 yr fixed", payoff: "Mar 2052", paid: "$146,200.00", nextMin: "$2,140.00 · Jun 1" } },
  { id: "sapphire", name: "Chase Sapphire", sub: "Credit card ••6841", value: 3210.44, color: "var(--signal-neg)", min: "$35.00 min · due Jun 14", apr: "21.99% APR",
    debt: { outstanding: "$3,210.44", original: "$12,000.00 limit", term: "Revolving", payoff: "Revolving", paid: "$8,940.00", nextMin: "$35.00 · Jun 14" } },
  { id: "amex",     name: "Amex Gold",      sub: "Credit card ••2008", value: 1180.62, color: "var(--signal-neg)", min: "$40.00 min · due Jun 9", apr: "24.24% APR",
    debt: { outstanding: "$1,180.62", original: "$10,000.00 limit", term: "Revolving", payoff: "Revolving", paid: "$5,210.00", nextMin: "$40.00 · Jun 9" } },
];
const LIAB_TOTAL   = sum(LIABILITIES);
const ASSET_TOTAL  = NET_WORTH;                 // alias, assets held at Yoshi
const NET_WORTH_TRUE = ASSET_TOTAL - LIAB_TOTAL; // assets minus liabilities
const DAY_ABS      = HOLDINGS.reduce((s, h) => s + h.dayAbs, 0) + 0; // cash doesn't move
const DAY_PCT      = (DAY_ABS / (NET_WORTH - DAY_ABS)) * 100;

/* Net-worth intraday series → ends at NET_WORTH, with two automation markers. */
const NW_SERIES = series(101, 34, NET_WORTH - DAY_ABS - 1800, NET_WORTH, 0.0016);
const NW_MARKERS = [];

/* ---------- agent proposals (inbox) ---------------------------------------- */
const PROPOSALS = [
  { id: "p-transfer-once", agent: "Yoshi agent", channel: "in-app", title: "Move $2,000.00 to Reserve",
    why: "Yoshi will make a one-time instant transfer of $2,000.00 from Chase Total Checking ••3392 to your Yoshi Reserve ••2207. This will not repeat.",
    net: 0.00, settles: "In seconds", kind: "transfer", cat: "cash", amountLabel: "Transfer amount", amount: "$2,000.00",
    legs: [["FROM", "Chase Total Checking ••3392", "Current balance $14,231.42", "-$2,000.00"], ["TO", "Yoshi Reserve ••2207", "Current balance $64,000.00", "+$2,000.00"], ["TIMING", "Instant transfer", "Arrives in seconds", "$0.00 fee"], ["REPEAT", "One-time transfer", "", ""]] },
  { id: "p-trade-once", agent: "Yoshi agent", channel: "in-app", title: "Buy $1,400.00 of VTI at the market",
    why: "Yoshi will place a one-time market buy for $1,400.00 of VTI in your Roth IRA using the live price. Current live price is $291.44, up $2.16 (0.74%) today. Final shares will depend on the execution price.",
    net: -1400.00, settles: "today at market", settlesVerb: "trades", kind: "trade", cat: "investments", amountLabel: "Trade amount", amount: "$1,400.00", cashImpactLabel: "Cash impact", cashImpact: "-$1,400.00", timingLabel: "Trade timing", timing: "Today at market",
    legs: [["BUY", { ticker: "VTI", price: "$291.44", change: "+$2.16 (0.74%) today", changeTone: "pos", name: "Vanguard Total Market", valueLabel: "Order amount $1,400.00" }, "", "$1,400.00"], ["FROM", "Roth IRA cash ••7731", "Current balance $4,291.28", "-$1,400.00"], ["TRADE DATE", "Today at market", "Market order after approval", ""]] },
  { id: "p0", agent: "Yoshi agent", channel: "in-app", title: "Set up recurring deposit",
    why: "Deposit $500.00 from Chase Total Checking ••3392 into Yoshi Cash ••8841 on the first business day of every month.",
    net: 500.00, settles: "Jun 2", settlesVerb: "starts", kind: "automation", cat: "cash", amountLabel: "Transfer amount", amount: "$500.00",
    legs: [["TYPE", "Recurring deposit", "Money movement automation", "Automation"], ["FROM", "Chase Total Checking ••3392", "Current balance $14,231.42", "$500.00"], ["TO", "Yoshi Cash ••8841", "Current balance $82,420.55", ""], ["SCHEDULE", "Monthly", "1st business day", "Recurring"], ["APPROVAL", "Approve once", "Then runs monthly until you pause or edit it", ""], ["END DATE", "Never", "Runs until you pause or edit it", ""], ["FIRST RUN", "Jun 2", "First business day", ""]] },
  { id: "p-cash-threshold-dca", agent: "Yoshi agent", channel: "in-app", title: "DCA cash above $50,000.00",
    why: "When a Yoshi cash account has more than $50,000.00 and the excess is at least $1,000.00, Yoshi will invest only the excess across AAPL, GOOG, and TSLA. Each buy uses live prices when the automation runs.",
    net: 0.00, settles: "When excess is available", settlesVerb: "starts", kind: "automation", cat: "investments", amountLabel: "Minimum trigger", amount: "$1,000.00 excess", cashImpactLabel: "Cash impact", cashImpact: "$0.00",
    legs: [["TYPE", "Cash threshold DCA", "Multi-step investing automation", "Automation"], ["TRIGGER", "Account cash above $50,000.00", "Minimum $1,000.00 excess", ""], ["STEP 1", "Calculate excess cash", "Only dollars above $50,000.00 are eligible", ""], ["STEP 2", "Split excess evenly", "AAPL, GOOG, and TSLA", "33.33% each"], ["STEP 3", "Propose market buys", "Amount depends on excess: $1,000.00, $5,000.00, etc.", ""], ["APPROVAL", "Approve once", "Then runs whenever threshold and minimum are met", ""], ["END DATE", "Until paused", "Runs whenever the threshold and minimum are met", ""]] },
  { id: "p-spy-tax-efficient-sell-down", agent: "Yoshi agent", channel: "in-app", title: "Sell down SPY tax efficiently",
    why: "Over the next 6 months, Yoshi will evenly reduce your SPY position and prioritize long-term lots with the least gains first. Each sell uses the live market price when its monthly run starts.",
    net: 0.00, settles: "Monthly", settlesVerb: "starts", kind: "automation", cat: "investments", amountLabel: "Automation amount", amount: "$18,000.00", cashImpactLabel: "Cash impact", cashImpact: "$0.00",
    legs: [["TYPE", "Tax-efficient sell-down", "Multi-step trading automation", "Automation"], ["ACCOUNT", "Brokerage ••2208", "Current balance $104,500.65 · Yoshi · Individual Taxable", ""], ["SCHEDULE", "Monthly for 6 months", "Evenly sized sell proposals", "Recurring"], ["STEP 1", "Review eligible SPY lots", "Long-term lots only", ""], ["STEP 2", "Prioritize lowest gains", "Long-term lots with the least gains first", "Tax-aware"], ["STEP 3", "Propose each SPY sell", "Uses live market price when each run starts", ""], ["APPROVAL", "Approve once", "Then runs monthly until complete or paused", ""], ["END DATE", "After 6 runs", "Completes in 6 months unless paused", ""]] },
  { id: "p1", agent: "Yoshi agent", channel: "in-app", title: "Rebalance your investments",
    why: "Your Roth IRA equity sleeve is above target after NVDA and AAPL outperformed. Yoshi would rotate $3,350.00 from concentrated single-stock exposure into VOO: sell $2,400.00 of NVDA and $950.00 of AAPL, then buy $3,350.00 of VOO in the same Roth IRA. Orders use live market prices checked again before approval.",
    net: 1153.66, settles: "today at market", settlesVerb: "trades", kind: "trade", cat: "investments", amountLabel: "Trade amount", amount: "$6,700.00", cashImpactLabel: "Cash impact", cashImpact: "$0.00", timingLabel: "Trade timing", timing: "Today at market",
    legs: [["ACCOUNT", "Roth IRA ••7731", "Current balance $314,815.05 · Yoshi · Retirement", ""], ["SELL", { ticker: "NVDA", price: "$142.17", change: "+$3.21 (2.31%) today", changeTone: "pos", name: "NVIDIA Corp", valueLabel: "Available $25,590.60" }, "", "-$2,400.00"], ["SELL", { ticker: "AAPL", price: "$214.05", change: "-$1.25 (0.58%) today", changeTone: "neg", name: "Apple Inc", valueLabel: "Available $31,037.25" }, "", "-$950.00"], ["BUY", { ticker: "VOO", price: "$548.12", change: "+$3.59 (0.66%) today", changeTone: "pos", name: "Vanguard S&P 500 ETF", valueLabel: "Current holding $32,887.20" }, "", "+$3,350.00"], ["TRADE DATE", "Today at market", "Market order after approval", ""]] },
  { id: "p2", agent: "External agent", channel: "whatsapp", title: "Pay Chase Sapphire",
    why: "Your $2,340.18 statement is due in 6 days at 21.99% APR. Paying it in full from Cash now means you owe $0.00 interest and keep the card at a zero balance, and if you miss it the interest starts piling up on the whole balance.",
    net: -2340.18, settles: "Tomorrow", settlesVerb: "closes", kind: "transfer", cat: "debt", amountLabel: "Transfer amount", amount: "$2,340.18",
    legs: [["PAY","Chase Sapphire ••6841","Current balance $3,210.44 · 21.99% APR","$2,340.18"],["FROM","Cash ••8841","Current balance $82,420.55","-$2,340.18"]] },
];

const COMPLETED = [
  { id: "c1", title: "Sweep idle cash", detail: "$12,000.00 · Cash to Reserve", when: "May 29", net: 0, by: "Yoshi agent" },
  { id: "c2", title: "Bought VOO", detail: "8.234 sh @ $548.12", when: "May 28", net: -4513.20, by: "Weekly investing · VTI" },
  { id: "c3", title: "Sold BTC", detail: "0.0421 @ $96,180.00", when: "May 25", net: 4049.18, by: "You" },
  { id: "c4", title: "Paid IRS · Q1 estimated", detail: "$8,432.00 · Cash", when: "Apr 22", net: -8432.00, by: "Yoshi agent" },
];

/* ---------- the stream · all activity, grouped by day -----------------------
   A mix of executions, deposits, a weekly summary digest, and a custom report
   the user asked Yoshi for. Newly-approved proposals get prepended to Today. */
const ACTIVITY = [
  { day: "Today", items: [
    { type: "report", kind: "Weekly summary", title: "Your week with Yoshi", detail: "Net worth +$3,212.00 · 4 automations ran · 1 proposal approved · $237.00 interest earned", when: "9:00" },
    { type: "exec", title: "Sweep idle cash", detail: "Cash to Reserve", when: "11:08", net: 0, amount: 12000, by: "Yoshi agent" },
    { type: "exec", title: "Bought VTI", detail: "2.10 sh @ $291.44 · auto-invest", when: "9:31", net: -612.00, by: "Weekly investing · VTI" },
  ] },
  { day: "Yesterday", items: [
    { type: "exec", title: "Bought VOO", detail: "8.234 sh @ $548.12", when: "15:42", net: -4513.20, by: "Weekly investing · VTI" },
    { type: "report", kind: "Custom report", title: "Dining spend · last 90 days", detail: "$1,840.00 across 38 charges. Trending −12.00% vs prior 90d", when: "14:10" },
    { type: "deposit", title: "Pay day", detail: "Acme Corp · direct deposit", when: "08:02", net: 6240.00 },
  ] },
  { day: "Earlier this week", items: [
    { type: "exec", title: "Sold BTC", detail: "0.0421 @ $96,180.00", when: "Mon", net: 4049.18, by: "You" },
    { type: "exec", title: "Reserved tax", detail: "5.00% of deposit to Tax 2026", when: "Sun", net: -1747.20, by: "Yoshi agent" },
    { type: "exec", title: "Paid Chase card", detail: "Statement balance · Cash", when: "Sun", net: -2340.18, by: "Yoshi agent" },
  ] },
  { day: "Apr 22", items: [
    { type: "exec", title: "Paid IRS · Q1 estimated", detail: "$8,432.00 · Cash", when: "Apr 22", net: -8432.00, by: "Yoshi agent" },
  ] },
];

/* ---------- chat seed ------------------------------------------------------ */
const CHAT_SEED = [
  { from: "agent", t: "Morning. Your accounts are up $4,802.00 today, mostly NVDA and SOL. One thing needs you: your Roth IRA has grown past the mix you wanted, so I'd like to even things out.", time: "9:24" },
  { from: "user",  t: "what would that do", time: "9:25" },
  { from: "agent", t: "Three notional orders inside your Roth IRA: sell $2,400.00 of NVDA, sell $950.00 of AAPL, and buy $3,350.00 of VOO. You'd reduce concentrated single-stock exposure and keep the account near target. Here it is, approve whenever you're ready.", time: "9:25", proposal: "p1" },
  { from: "user", t: "set up a recurring deposit into yoshi from my external cash account", time: "9:28" },
  { from: "agent", t: "I drafted the setup brief. Review and approve it to get started or ask me to change any parameter first.", time: "9:28", proposal: "p0" },
];

const QUICK_REPLIES = ["Set up monthly deposit", "Recurring research report", "How's my cash doing?", "Anything need my approval?"];

/* ---------- chat threads · past conversations with Yoshi -------------------
   The live thread is held in component state (seeded from CHAT_SEED above).
   These are read-only history, newest first. */
const THREADS = [
  { id: "th_tbill", title: "Earning more on idle cash", when: "May 26", preview: "Moved $15,000.00 of idle cash into short-term Treasuries at about 5.10%.",
    msgs: [
      { from: "user",  t: "what should i do with the idle cash in savings", time: "2:14 PM" },
      { from: "agent", t: "$15,000.00 has sat unused for 9 days. I'd move it into short-term Treasuries earning about 5.10%, your money stays available every month. Here's the proposal.", time: "2:14 PM" },
      { from: "user",  t: "looks good", time: "2:15 PM" },
      { from: "agent", t: "It's ready, approve whenever you like.", time: "2:15 PM" },
    ] },
  { id: "th_dca", title: "Pause investing for vacation", when: "May 18", preview: "Paused the weekly VTI buy. Kept the cash sweep running.",
    msgs: [
      { from: "user",  t: "pause my investing while i'm away next week", time: "7:40 AM" },
      { from: "agent", t: "Paused the weekly VTI buy. Nothing runs until you turn it back on. I'll keep moving idle cash to your Reserve unless you'd like that off too.", time: "7:41 AM" },
      { from: "user",  t: "keep the sweep on", time: "7:41 AM" },
      { from: "agent", t: "Will do. Enjoy the trip.", time: "7:41 AM" },
    ] },
  { id: "th_tax", title: "Tax reserve setup", when: "May 2", preview: "New rule: reserve 28.00% of every freelance deposit.",
    msgs: [
      { from: "user",  t: "i keep underpaying my quarterly taxes", time: "11:02 AM" },
      { from: "agent", t: "I can fix that at the source. New rule: reserve 28.00% of every freelance deposit into a Tax 2026 bucket, automatically. You'd never spend it by accident.", time: "11:02 AM" },
      { from: "user",  t: "do it", time: "11:03 AM" },
      { from: "agent", t: "Live. The first reserve runs on your next deposit. I'll log each one to your stream.", time: "11:03 AM" },
    ] },
  { id: "th_nvda", title: "Why NVDA dropped", when: "Apr 28", preview: "Sector pullback, not company-specific. Held on.",
    msgs: [
      { from: "user",  t: "why is nvda down today", time: "3:30 PM" },
      { from: "agent", t: "Sector-wide pullback after a downgrade across chipmakers, not company-specific. You're still up 64.00% on it, so this is just noise and nothing I'd act on.", time: "3:30 PM" },
      { from: "user",  t: "ok, leave it", time: "3:31 PM" },
    ] },
];

/* a Transfer always reads with a direction — "Transfer in" for money arriving,
   "Transfer out" for money leaving. `signed` is the row's net (or signed amount);
   net-zero internal moves (e.g. to Reserve) read as "in" toward the named side. */
const directionalCategory = (category, signed) => category === "Transfer" ? ((signed || 0) < 0 ? "Transfer out" : "Transfer in") : category;

/* ---------- recent activity · a real transaction ledger -------------------
   More than agent moves: card spend, payroll, transfers, dividends, refunds. */
const TRANSACTIONS = [
  { id: "t1", icon: "receipt", title: "Whole Foods Market", detail: "Card ··4417", when: "Today", time: "2:41 PM", net: -142.38, category: "Spending", accountScope: "external" },
  { id: "t2", icon: "down",    title: "Northwind Labs", detail: "Direct deposit", when: "Today", time: "8:02 AM", net: 8200.00, category: "Income", accountScope: "external", acct: "Direct deposit" },
  { id: "t3", icon: "trade",   title: "Bought VTI @ $291.44", detail: "2.10 sh @ $291.44", when: "May 28", net: -612.00, category: "Investment", accountScope: "yoshi", cat: "automations", autoId: "a1" },
  { id: "t4", icon: "swap",    title: "Reserve", detail: "Yoshi ··8841 to Reserve ··2207", when: "May 28", net: 0, amount: 6000.00, type: "Internal transfer", rail: "Instant transfer", category: "Transfer", accountScope: "yoshi", cat: "automations", autoId: "a2" },
  { id: "t5", icon: "swap",    title: "Maya Cohen", detail: "Zelle ··4471", when: "May 28", net: -250.00, type: "Sent to a person", rail: "Zelle", category: "Transfer", accountScope: "external", acct: "Zelle ··4471" },
  { id: "t6", icon: "trade",   title: "Dividend · VTI", detail: "Reinvested", when: "May 27", net: 84.20, category: "Investment", accountScope: "yoshi" },
  { id: "t7", icon: "receipt", title: "Uber", detail: "Card ··4417", when: "May 26", net: -23.90, category: "Travel", accountScope: "external" },
  { id: "t8", icon: "down",    title: "Interest paid", detail: "3.30% APY", when: "May 26", net: 237.00, category: "Reserve", accountScope: "yoshi" },
  { id: "t9", icon: "down",    title: "Refund · Delta Air Lines", detail: "Card ··4417", when: "May 25", net: 312.40, category: "Travel", accountScope: "external" },
  { id: "t10", icon: "receipt", title: "Netflix", detail: "Subscription · Card ··4417", when: "May 25", net: -15.49, category: "Subscriptions", accountScope: "external" },
  { id: "t11", icon: "trade",  title: "Bought AAPL @ $214.05", detail: "Round-ups · 0.066 sh", when: "May 25", net: -14.20, category: "Investment", accountScope: "yoshi", cat: "automations", autoId: "a4" },
  { id: "t12", icon: "trade",  title: "Sold AAPL @ $214.05", detail: "18.9 sh @ $214.05 · You", when: "May 24", net: 4049.18, category: "Investment", accountScope: "yoshi" },
  { id: "t13", icon: "receipt", title: "Con Edison", detail: "Autopay · Card ··4417", when: "May 23", net: -118.04, category: "Bills", accountScope: "external" },
  { id: "t14", icon: "swap",   title: "Chase Sapphire", detail: "Checking to Credit card ··6841", when: "May 23", net: -2340.18, type: "Card payment", rail: "ACH", category: "Transfer", accountScope: "yoshi", cat: "automations", autoId: "a5" },
  { id: "t15", icon: "trade",  title: "Dividend · AAPL", detail: "Reinvested", when: "May 22", net: 6.40, category: "Investment", accountScope: "yoshi" },
  { id: "t16", icon: "swap",   title: "Chase Checking", detail: "Chase to Yoshi ··3392", when: "May 22", net: -2000.00, type: "External transfer", rail: "Standard ACH", category: "Transfer", accountScope: "external", acct: "Chase ··3392" },
];

/* ---------- automations · standing rules the agents run -------------------- */
const AUTOMATIONS = [
  { id: "a1", name: "Weekly investing · VTI", status: "active", cadence: "Every Friday · 11 weeks", measure: "+$184.00", sub: "this month",
    summary: "Buy $500.00 of VTI every Friday at market open.", next: "Next run · Fri May 30",
    perf: [["Invested", "$5,500.00"], ["Current value", "$5,684.00"], ["Total return", "+$184.00 (3.30%)"], ["Runs", "11"]],
    ledger: [["May 30", "Bought $500.00 VTI at open", "$500.00"], ["May 23", "Bought $500.00 VTI at open", "$500.00"], ["May 16", "Bought $500.00 VTI at open", "$500.00"], ["May 9", "Bought $500.00 VTI at open", "$500.00"], ["May 2", "Bought $500.00 VTI at open", "$500.00"]] },
  { id: "a2", name: "Keep a cash buffer", status: "active", cadence: "Standing rule · 3.30% APY", measure: "+$237.00", sub: "interest, 90d",
    summary: "Keeps your spendable Cash near $15,000.00 and moves the excess into your Reserve. Both earn 3.30% APY.", next: "Triggers when Cash > $15,000.00",
    perf: [["Swept, 90d", "$48,000.00"], ["Interest", "+$237.00"], ["Threshold", "> $15,000.00"], ["Last run", "May 28"]],
    ledger: [["May 28", "Moved excess to Reserve", "$6,000.00"], ["May 14", "Moved excess to Reserve", "$8,000.00"], ["Apr 30", "Moved excess to Reserve", "$12,000.00"], ["Apr 16", "Moved excess to Reserve", "$9,000.00"]] },
  { id: "a3", name: "Lower taxes on gains", status: "watching", cadence: "Watching · 2 holdings", measure: "+$420.00", sub: "saved ytd",
    summary: "Watches for investments that have dropped, so selling one can reduce the taxes you owe on your gains.", next: "No action needed today",
    perf: [["Saved YTD", "+$420.00"], ["Watching", "2"], ["Est. tax saved", "$96.00"], ["Safeguards", "On"]],
    ledger: [["May 27", "Flagged AMD lot to harvest", "−$180.00"], ["May 12", "Flagged SOL lot to harvest", "−$240.00"], ["Apr 18", "Harvested loss vs gains", "+$420.00"]] },
  { id: "a4", name: "Round-ups into AAPL", status: "active", cadence: "Per card swipe", measure: "+$62.00", sub: "invested, 30d",
    summary: "Rounds each card purchase to the nearest dollar and buys AAPL weekly.", next: "Next buy · Sun Jun 1",
    perf: [["Rounded, 30d", "$62.00"], ["Into", "AAPL"], ["Avg / swipe", "$0.41"], ["Swipes", "151"]],
    ledger: [["Jun 1", "Bought AAPL from round-ups", "$14.20"], ["May 25", "Bought AAPL from round-ups", "$11.80"], ["May 18", "Bought AAPL from round-ups", "$13.40"], ["May 11", "Bought AAPL from round-ups", "$9.60"]] },
  { id: "a5", name: "Pay card in full", status: "active", cadence: "On statement close", measure: "$0.00", sub: "interest paid",
    summary: "Pays the full statement balance from Cash the day before it's due.", next: "Next · Chase Sapphire, Jun 2",
    perf: [["Paid YTD", "$14,200.00"], ["Interest", "$0.00"], ["On-time", "100.00%"], ["Source", "Cash"]],
    ledger: [["May 2", "Paid Chase Sapphire in full", "$2,480.00"], ["Apr 2", "Paid Chase Sapphire in full", "$1,920.00"], ["Mar 2", "Paid Chase Sapphire in full", "$2,760.00"]] },
  { id: "a6", name: "Monthly spending report", status: "active", cadence: "1st of each month", measure: "May", sub: "last sent",
    summary: "Compiles a categorized breakdown of your spending across every account and card, then delivers it to your inbox on the first of the month. No money moves.", next: "Next report · Jun 1",
    perf: [["Reports sent", "5"], ["Categories", "12"], ["Top category", "Dining"], ["Delivery", "Email + app"]],
    ledger: [["Jun 1", "Spending report delivered", "12 categories"], ["May 1", "Spending report delivered", "12 categories"], ["Apr 1", "Spending report delivered", "11 categories"]] },
];

/* ---------- market universe + explore (trade search) ---------------------- */
const MARKET = [
  ...HOLDINGS.map(h => ({ id: h.id, ticker: h.ticker, name: h.name, last: h.last, dch: h.dch, kind: h.kind, held: true })),
  { id: "tsla",  ticker: "TSLA",  name: "Tesla Inc",            last: 342.18, dch: -1.84, kind: "stock" },
  { id: "googl", ticker: "GOOGL", name: "Alphabet Inc",         last: 178.22, dch: 0.91,  kind: "stock" },
  { id: "amzn",  ticker: "AMZN",  name: "Amazon.com Inc",       last: 201.40, dch: 1.22,  kind: "stock" },
  { id: "spy",   ticker: "SPY",   name: "SPDR S&P 500 ETF",     last: 597.10, dch: 0.64,  kind: "etf" },
  { id: "coin",  ticker: "COIN",  name: "Coinbase Global",      last: 248.77, dch: 3.10,  kind: "stock" },
  { id: "qqq",   ticker: "QQQ",   name: "Invesco QQQ Trust",    last: 512.33, dch: 0.88,  kind: "etf" },
  { id: "meta",  ticker: "META",  name: "Meta Platforms",       last: 612.05, dch: 1.45,  kind: "stock" },
  { id: "amd",   ticker: "AMD",   name: "Advanced Micro Dev",   last: 168.90, dch: 2.07,  kind: "stock" },
  { id: "doge",  ticker: "DOGE",  name: "Dogecoin",             last: 0.42,   dch: 5.60,  kind: "crypto" },
];

const securityHolding = (sec) => {
  const id = typeof sec === "string" ? sec : sec?.id;
  const ticker = typeof sec === "string" ? sec.toUpperCase() : sec?.ticker;
  return HOLDINGS.find((h) => h.id === id || h.ticker === ticker) || null;
};
const securityYearReturn = (sec) => {
  const h = securityHolding(sec);
  if (h?.perf?.["1Y"] != null) return h.perf["1Y"];
  const m = typeof sec === "string" ? MARKET.find((x) => x.id === sec || x.ticker === sec.toUpperCase()) : sec;
  return m?.kind === "crypto" ? 72 : m?.kind === "etf" ? 17 : 31;
};
const securityFundamentals = (sec) => {
  const h = securityHolding(sec);
  const m = h || (typeof sec === "string" ? MARKET.find((x) => x.id === sec || x.ticker === sec.toUpperCase()) : sec);
  const fund = h?.fund || [];
  const get = (label) => fund.find(([k]) => k === label)?.[1];
  const asset = m?.kind === "crypto" ? "Crypto" : m?.kind === "etf" ? "ETF" : "Equity";
  const marketCap = get("Market cap") || (m?.kind === "crypto" ? "$1.90T" : m?.kind === "etf" ? "$1.35T" : "$" + ((m?.last || 100) * 2.4).toFixed(2) + "B");
  const metric = get("Expense ratio") ? ["Expense ratio", get("Expense ratio")] :
    get("P/E ratio") ? ["P/E ratio", get("P/E ratio")] :
    m?.kind === "crypto" ? ["Network", get("Network") || m.name] :
    ["P/E ratio", "31.4"];
  return [["Asset class", get("Asset class") || asset], ["Market cap", marketCap], metric, ["1 year return", pct(securityYearReturn(m))]];
};
const securityTake = (sec) => {
  const h = securityHolding(sec);
  const m = h || (typeof sec === "string" ? MARKET.find((x) => x.id === sec || x.ticker === sec.toUpperCase()) : sec);
  const t = m?.ticker || "this name";
  const held = !!h;
  const named = {
    NVDA: held ? ["Your standout winner — and now your largest single position. I'd consider trimming a slice to lock in some of that gain and keep one name from steering the whole portfolio.", `trim some ${t} to lock gains`] : ["NVIDIA is high-quality, but volatile after a huge run. I'd size any new position carefully instead of chasing a green day.", `size a starter position in ${t}`],
    AAPL: held ? ["Steady ballast that's doing its job. Nothing here needs a decision today — hold and let it compound.", `review my ${t} position`] : ["Apple is a mature compounder. Worth comparing against what you already own before adding another mega-cap position.", `compare ${t} to my portfolio`],
    MSFT: held ? ["Quietly compounding. A reasonable place to add on a dip; otherwise just hold.", `set up a buy-the-dip rule for ${t}`] : ["Microsoft is a durable large-cap name. I'd treat it as a core equity candidate, not a quick trade.", `analyze ${t} as a long-term holding`],
    VOO: held ? ["Your low-cost index core. Keep the auto-invest running — this is the boring engine that does most of the work.", `review my ${t} auto-invest`] : ["VOO is broad, low-cost S&P 500 exposure. It's usually a clean default when you want diversified US equity instead of picking single stocks.", `set up recurring buys for ${t}`],
    VTI: held ? ["Total-market index, and it's in your Roth — exactly where it belongs, since the gains compound tax-free. Let it ride.", `review my Roth allocation`] : ["VTI is broad total-market exposure. Good if you want one fund to cover the US market instead of choosing sectors.", `compare ${t} and VOO`],
    BTC: held ? ["Up strongly from your cost, and your most volatile sleeve. I'd size it deliberately so a rough week doesn't rattle you — trimming toward a target weight is the clean move.", `set a target weight for ${t}`] : ["Bitcoin is volatile, so the main decision is position size. I'd only add it if you're clear on the role it plays in your mix.", `set a target weight for ${t}`],
    ETH: held ? ["Held at a gain but choppier than Bitcoin. Fine as a smaller satellite; I wouldn't chase it higher from here.", `rebalance my crypto`] : ["Ethereum can work as a smaller crypto satellite, but I'd size it below your core holdings.", `compare ETH and BTC`],
    SOL: held ? ["A big run on a high-beta name. Taking a little profit into your cash buffer locks some of it in without trying to call the top.", `take some ${t} profit into cash`] : ["Solana is high beta even by crypto standards. I'd treat it as a small satellite, not a core position.", `size a small ${t} position`]
  };
  if (named[t]) return { take: named[t][0], cue: named[t][1] };
  if (m?.kind === "crypto") return { take: held ? `${t} is a volatile sleeve. Worth sizing on purpose rather than adding on momentum.` : `${t} is volatile, so start with sizing and downside tolerance before buying.`, cue: `review ${t}` };
  if (m?.kind === "etf") return { take: `${t} is diversified index exposure — a sensible core you can add to on a schedule.`, cue: `automate adding to ${t}` };
  return { take: held ? `${t} is working for you. No need to touch it unless it has grown into too large a slice of the portfolio.` : `${t} could be a new single-name position. I'd compare it against your current concentration before buying.`, cue: `check whether ${t} fits my portfolio` };
};
const TRENDING = ["nvda", "btc", "tsla", "sol", "coin", "amd"];
const EXPLORE_NEWS = [
  ["Bloomberg", "Chipmakers lead the tape as AI demand holds", "41m"],
  ["Reuters",   "Fed minutes point to one more cut this year",  "2h"],
  ["CoinDesk",  "Spot BTC ETFs log eighth straight inflow day", "3h"],
  ["WSJ",       "Big tech earnings beat, guidance mixed",        "5h"],
];

/* AI news brief · whole-market synthesis with cited, click-out sources */
const MARKET_NEWS = {
  when: "9:41 AM",
  brief: [
    { t: "Equities opened higher with semiconductors leading the tape as AI demand stays firm", s: 0 },
    { t: "Rate worries eased after Fed minutes pointed to one more cut this year", s: 1 },
    { t: "Crypto held steady — spot Bitcoin ETFs logged an eighth straight day of inflows", s: 2 },
    { t: "Big-tech earnings beat on revenue, though forward guidance came in mixed", s: 3 },
  ],
  sources: [
    { pub: "Bloomberg", head: "Chipmakers lead the tape as AI demand holds", when: "41m", url: "https://www.bloomberg.com/markets" },
    { pub: "Reuters",   head: "Fed minutes point to one more cut this year",  when: "2h",  url: "https://www.reuters.com/markets/us/" },
    { pub: "CoinDesk",  head: "Spot BTC ETFs log eighth straight inflow day", when: "3h",  url: "https://www.coindesk.com/markets" },
    { pub: "WSJ",       head: "Big tech earnings beat, guidance mixed",        when: "5h",  url: "https://www.wsj.com/finance/stocks" },
  ],
};

/* AI news brief · synthesis of stories that touch the user's holdings */
const HOLDINGS_NEWS = {
  when: "9:41 AM",
  brief: [
    { tkr: "NVDA", t: "extended its rally on steady AI demand, lifting your largest position", s: 0 },
    { tkr: "VTI",  t: "rides a record day of broad-market ETF inflows — a quiet tailwind", s: 1 },
    { tkr: "BTC",  t: "held a key level, steadying your crypto sleeve; nothing needs action", s: 2 },
  ],
  sources: [
    { pub: "Bloomberg",   head: "Nvidia extends rally as AI orders stay strong", when: "1h", url: "https://www.bloomberg.com/quote/NVDA:US" },
    { pub: "Morningstar", head: "Broad-market ETF inflows hit a record",         when: "3h", url: "https://www.morningstar.com/etfs/arcx/vti/quote" },
    { pub: "CoinDesk",    head: "Bitcoin holds support as ETF demand steadies",  when: "4h", url: "https://www.coindesk.com/price/bitcoin" },
  ],
};

/* ---------- profile -------------------------------------------------------- */
const PROFILE = {
  name: "Rivka Lipson", handle: "@rivka", member: "Member since 2025",
  channels: [
    ["Push notifications", "On this device", true],
    ["SMS", "+1 ••• ••• 4471", true],
  ],
  limits: [
    ["Per-approval cap", "$25,000.00"],
    ["Daily autonomous cap", "$5,000.00"],
    ["Trades without approval", "Off"],
  ],
};

/* ---------- "For you" · the notification hub, split into folders ----------- */
/* folder: "insights" (recaps, reports, opportunities, nudges, price alerts) or
   "automations" (confirmations a standing rule ran). Operational failures live
   in ERROR_ALERTS inside briefs.jsx. "Needs you" pulls from PROPOSALS. */
const BRIEFS = [
  { id: "b1", folder: "insights", type: "recap", title: "Market recap",
    body: "Markets closed higher. Your portfolio is up " + perf(DAY_ABS, DAY_PCT) + " today, led by NVDA and BTC.",
    value: DAY_ABS, tone: "in", when: "4:05 PM",
    visual: { kind: "spark", title: "Portfolio today", points: [0.00, 0.18, 0.26, 0.32, 0.48, 0.53, 0.71, 0.83, 0.98], metrics: [["Portfolio", "+$4,175.99", "+0.98%"], ["Top driver", "NVDA", "+3.20%"], ["Crypto sleeve", "BTC", "+2.40%"]] },
    ask: ["Give me today's market recap.", "Markets closed higher. Your portfolio finished " + perf(DAY_ABS, DAY_PCT) + ", led by NVDA (+3.20%) and BTC (+2.40%). Cash and bonds were flat. Nothing needs your attention right now, so just say the word if you want a deeper read on any holding."] },
  { id: "b2", folder: "insights", type: "report", title: "Debt payoff report",
    body: "Your scheduled report: card balances are down $1,160.00 this month, and at this pace the Amex Gold clears in about 4 months.",
    value: 1160, tone: "in", when: "Mon",
    visual: { kind: "bars", title: "Card payoff progress", bars: [{ label: "Last month", value: 5551, display: "$5,551.00" }, { label: "Today", value: 4391, display: "$4,391.00" }], metrics: [["Month change", "-$1,160.00", "card debt"], ["Highest APR", "24.24%", "Amex Gold"], ["ETA", "4 months", "$300.00/mo"]] },
    ask: ["Show my debt payoff progress.", "Here's where your payoff plan stands. Total card debt is down to $4,391.00 from $5,551.00, the Amex Gold (24.24% APR) clears in about 4 months at $300.00 a month, and the Chase Sapphire follows after that. Want me to put more toward the higher-rate card so it finishes sooner?"] },
  { id: "b3", folder: "insights", type: "opportunity", title: "Idle cash is sitting still",
    body: "$15,000.00 has sat in your Cash for 9 days at 3.30%. Moved to short-term Treasuries it could earn about 5.10% and stay liquid.",
    when: "11:02 AM",
    visual: { kind: "grid", title: "Idle cash evidence", metrics: [["Amount", "$15,000.00", "Cash"], ["Earning now", "3.30%", "APY"], ["Indicative yield", "5.10%", "26-wk Treasuries"], ["Annual estimate", "$760.00", "before tax"]] },
    ask: ["Should I move my idle cash?", "$15,000.00 has sat in your Cash for 9 days at 3.30%. In 26-week Treasuries near 5.10% that's about $760.00 a year more, and it stays available. Want me to draft the move for your approval?"] },
  { id: "b4", folder: "insights", type: "nudge", title: "NVDA is 18.00% of your book",
    body: "After the run, a single name is a large share of your portfolio. Worth trimming to rebalance?",
    when: "Fri",
    visual: { kind: "bars", title: "Single-stock concentration", bars: [{ label: "NVDA current", value: 18, display: "18.00%" }, { label: "Target max", value: 10, display: "10.00%" }, { label: "Next largest", value: 8.10, display: "8.10%" }], metrics: [["Holding value", "$25,590.60", "Roth IRA"], ["Today", "+$591.00", "+2.31%"], ["Target gap", "+8.00%", "above band"]] },
    ask: ["Is my NVDA position too big?", "NVDA is about 18.00% of your investments after the run, which is a lot riding on one name. If you trim a slice into a broad fund you lower the single-stock risk without changing your direction, so want me to size a rebalance?"] },
  { id: "b5", folder: "insights", type: "alert", title: "Price alert · COIN",
    body: "COIN slipped below $240.00, down 2.10% this week. Not held.",
    value: 240, when: "Thu",
    visual: { kind: "grid", title: "Price alert context", metrics: [["Trigger", "$240.00", "below threshold"], ["Week move", "-2.10%", "COIN"], ["Position", "$0.00", "not held"], ["Risk note", "High", "crypto beta"]] },
    ask: ["Should I buy COIN on the dip?", "COIN is down 2.10% this week, trading just under $240.00. You don't hold it today. It's volatile and moves with crypto flows, so if you want exposure I'd keep it small. Want me to put together a paper trade first?"] },
  { id: "r1", folder: "automations", type: "automation", title: "Sweep idle cash ran", autoId: "a2",
    body: "Moved $4,000.00 from Cash to Reserve to keep earning 3.30% APY.",
    value: 4000, when: "9:30 AM" },
  { id: "r2", folder: "automations", type: "automation", title: "Weekly investing ran", autoId: "a1",
    body: "Bought $500.00 of VTI at the open. 11-week streak, +$184.00 so far.",
    value: 500, when: "Fri" },
  { id: "r3", folder: "automations", type: "automation", title: "Paid Chase Sapphire in full", autoId: "a5",
    body: "Paid the $2,340.00 statement from Cash the day before it was due. No interest owed.",
    value: 2340, when: "Jun 2" },
];

/* insights folder — what Yoshi sees across the accounts */
const BRIEF_INSIGHTS = [
  { label: "Spending", stat: "−12.00%", tone: "pos", read: "You spent 12.00% less this month than last, because dining and travel both dropped.",
    visual: { kind: "bars", title: "Monthly spend by category", bars: [{ label: "Dining", value: 1120, display: "-$420.00" }, { label: "Travel", value: 760, display: "-$510.00" }, { label: "Groceries", value: 690, display: "+$38.00" }], metrics: [["Total change", "-12.00%", "month over month"], ["Largest drop", "Travel", "-$510.00"], ["Watch", "Subscriptions", "$184.00"]] },
    ask: ["Break down my spending.", "You're down 12.00% month over month, mostly less dining and travel. Top categories are groceries, utilities, and subscriptions. Want a full breakdown or a budget?"] },
  { label: "Fees paid", stat: "$0.00", tone: "pos", read: "No account, trading, or transfer fees so far this year.",
    visual: { kind: "grid", title: "Fee check", metrics: [["Account fees", "$0.00", "YTD"], ["Trading fees", "$0.00", "YTD"], ["Transfer fees", "$0.00", "YTD"], ["Likely fee", "$0.00", "standard moves"]] },
    ask: ["What fees am I paying?", "You've paid nothing so far this year, because there are no account, commission, or standard transfer fees. Only expedited wires cost anything, so want the fee schedule?"] },
];

Object.assign(window, {
  useState, useEffect, useRef, useMemo, useCallback,
  money, usd, signed, compactUsd, pct, perf, series, mulberry32,
  HOLDINGS, CASH, GROUPS, CASH_TOTAL, INVEST_TOTAL, CRYPTO_TOTAL, NET_WORTH, DAY_ABS, DAY_PCT,
  LIABILITIES, LIAB_TOTAL, ASSET_TOTAL, NET_WORTH_TRUE,
  NW_SERIES, NW_MARKERS, PROPOSALS, COMPLETED, ACTIVITY, CHAT_SEED, QUICK_REPLIES, THREADS, PROFILE,
  TRANSACTIONS, AUTOMATIONS, MARKET, TRENDING, EXPLORE_NEWS, MARKET_NEWS, HOLDINGS_NEWS, BRIEFS, BRIEF_INSIGHTS,
});
