/* accounts.jsx, the unified balance, grouped cash / investments / crypto.
   Tapping an investment or crypto row pushes HoldingDetail (chart + range
   toggle, position, fundamentals, news, transaction history). */

/* ---- hidden-accounts store · lets a user drop a linked account from totals
   & summaries. Persisted to localStorage; broadcasts so the Accounts list and
   the detail screen stay in sync. Keyed by account name. -------------------- */
const HIDDEN_KEY = "yoshi_hidden_accts";
const readHidden = () => {try {return JSON.parse(localStorage.getItem(HIDDEN_KEY) || "[]");} catch (e) {return [];}};
const writeHidden = (arr) => {try {localStorage.setItem(HIDDEN_KEY, JSON.stringify(arr));} catch (e) {}window.dispatchEvent(new CustomEvent("yoshi-hidden"));};
const useHiddenAccts = () => {
  const [hidden, setHidden] = useState(readHidden);
  useEffect(() => {
    const f = () => setHidden(readHidden());
    window.addEventListener("yoshi-hidden", f);
    return () => window.removeEventListener("yoshi-hidden", f);
  }, []);
  const toggle = (name) => {const cur = readHidden();writeHidden(cur.includes(name) ? cur.filter((n) => n !== name) : [...cur, name]);};
  return [hidden, toggle];
};

/* net-worth change · past 30 days · shows both % and $ inline */
const NW_PCT = 3.64;
const NetWorthChange = () => {
  const dollars = Math.round(NET_WORTH_TRUE * NW_PCT / 100);
  const c = NW_PCT >= 0 ? "var(--accent-pos)" : "var(--signal-neg)";
  return (
    <span style={{ display: "inline-flex", alignItems: "baseline", gap: 6, whiteSpace: "nowrap" }}>
      <span style={{ fontFamily: "var(--f-mono)", fontSize: 12.5, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: c, letterSpacing: "-0.005em" }}>{perf(dollars, NW_PCT)}</span>
      <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)" }}>vs 30d ago</span>
    </span>);

};

/* web-only: info "i" disclosures render as a small popover anchored to the
   icon (a tooltip), instead of the phone's slide-up bottom sheet. */
const InfoPop = ({ open, onClose, title, align = "left", width = 266, children }) => {
  if (!open) return null;
  return (
    <>
      <div onClick={(e) => { e.stopPropagation(); onClose(); }} style={{ position: "fixed", inset: 0, zIndex: 48 }} />
      <div onClick={(e) => e.stopPropagation()} style={{ position: "absolute", top: "calc(100% + 9px)", [align]: 0, zIndex: 49, width, background: "var(--ink)", color: "var(--bg)", borderRadius: 12, padding: "12px 14px", boxShadow: "0 16px 40px -14px rgba(0,0,0,0.55)" }}>
        <span style={{ position: "absolute", top: -5, [align]: 13, width: 10, height: 10, background: "var(--ink)", transform: "rotate(45deg)" }} />
        {title && <div style={{ fontFamily: "var(--f-display)", fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", opacity: 0.6, marginBottom: 6 }}>{title}</div>}
        <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, lineHeight: 1.55, position: "relative" }}>{children}</div>
      </div>
    </>
  );
};

/* a small "Hidden" pill for linked accounts dropped from totals */
const HiddenChip = () => <span style={{ fontFamily: "var(--f-display)", fontSize: 8.5, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, padding: "2px 7px", whiteSpace: "nowrap" }}>Hidden</span>;

/* web tier lead-in — big title + muted caps label, with the tier total set
   large so the number hierarchy reads clearly: tier → group → row. */
const TierHead = ({ title, sub, total, totalColor, neg, action }) =>
<div style={{ display: "flex", alignItems: "baseline", gap: 12, padding: "4px 0 14px", borderBottom: "1px solid var(--rule-2)" }}>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 21, fontWeight: 700, letterSpacing: "-0.025em" }}>{title}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)", marginTop: 4, letterSpacing: "0.08em", textTransform: "uppercase" }}>{sub}</div>
    </div>
    <Money value={total} size={21} weight={600} prefix={neg ? "−$" : "$"} color={totalColor || "var(--ink)"} />
    {action && <span style={{ alignSelf: "center", display: "flex", flex: "none" }}>{action}</span>}
  </div>;

/* Yoshi-held account groups: cash (incl. the card), investments, paper trading */
const YoshiGroups = ({ nav, hasCard }) =>
<>
    <Group title="Cash" total={CASH_TOTAL}>
      <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.cash })}
      bar="var(--accent-2)" name="Cash" sub="Yoshi •8841" value={CASH_TOTAL} push />
      <button className="press" onClick={() => nav.push({ type: "card" })} style={{
        width: "100%", textAlign: "left", background: "none", border: "none",
        display: "grid", gridTemplateColumns: window.__YOSHI_WEB ? "1fr auto 16px" : "3px 1fr auto 16px", gap: 12, padding: "15px 18px",
        borderBottom: "1px solid var(--rule)", alignItems: "center"
      }}>
        {!window.__YOSHI_WEB && <div style={{ background: hasCard ? "var(--ink-3)" : "var(--accent)", width: 3, height: 30 }} />}
        <div style={{ minWidth: 0 }}>
          {hasCard ?
          <>
              <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, letterSpacing: "-0.005em" }}>Yoshi Card</span>
              </div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3 }}>Debit •2291</div>
            </> :

          <>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, letterSpacing: "-0.005em" }}>Yoshi Card</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3 }}>Virtual debit · set a PIN to use it</div>
            </>
          }
        </div>
        {hasCard ? <span /> :
        <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, fontWeight: 600, color: "var(--accent)" }}>Activate</span>}
        <Icon name="back" size={16} color="var(--ink-3)" style={{ transform: "scaleX(-1)", justifySelf: "end" }} />
      </button>
    </Group>

    <Group title="Investments" total={INVEST_TOTAL + CRYPTO_TOTAL} delta={<RowDelta pct={DAY_PCT} value={INVEST_TOTAL + CRYPTO_TOTAL} />}>
      <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.brokerage })}
      bar="var(--accent-4)" name="Brokerage" sub="Yoshi · Individual Taxable •2208" value={acctValue(ACCOUNTS.brokerage.ids)}
      chip={<RowDelta pct={DAY_PCT} value={acctValue(ACCOUNTS.brokerage.ids)} />} push />
      <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.roth })}
      bar="var(--accent-4)" name="Roth IRA" sub="Yoshi · Retirement •7731" value={acctValue(ACCOUNTS.roth.ids)}
      chip={<RowDelta pct={DAY_PCT} value={acctValue(ACCOUNTS.roth.ids)} />} push />
      <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.crypto })}
      bar="var(--accent)" name="Crypto" sub="Yoshi · Spot •6614" value={CRYPTO_TOTAL}
      chip={<RowDelta pct={DAY_PCT} value={CRYPTO_TOTAL} />} push />
    </Group>

    <Group title="Paper trading" total={acctValue(ACCOUNTS.paper.ids)} delta={<RowDelta pct={4.25} value={acctValue(ACCOUNTS.paper.ids)} />}>
      <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.paper })}
      bar="var(--rule-2)" name="Test drive 1" sub="Yoshi · Simulated" value={acctValue(ACCOUNTS.paper.ids)} valueColor="var(--ink-2)"
      chip={<RowDelta pct={4.25} value={acctValue(ACCOUNTS.paper.ids)} />} push />
    </Group>
  </>;

/* externally-linked, read-only accounts: cash, investments, debt */
const ExternalGroups = ({ nav }) => {
  const [hidden] = useHiddenAccts();
  const chaseHidden = hidden.includes("Chase");
  const schwabHidden = hidden.includes("Schwab");
  const coinbaseHidden = hidden.includes("Coinbase");
  return (
    <>
      <Group title="Cash" total={chaseHidden ? 0 : 8210.32}>
        <div style={{ opacity: chaseHidden ? 0.5 : 1 }}>
          <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.chase })}
          bar="var(--rule-2)" logo="C" name="Chase" sub="Checking •4417" value={8210.32} valueColor="var(--ink-2)"
          chip={chaseHidden ? <HiddenChip /> : undefined} push />
        </div>
      </Group>

      <Group title="Investments" total={(schwabHidden ? 0 : acctValue(ACCOUNTS.schwab.ids)) + (coinbaseHidden ? 0 : acctValue(ACCOUNTS.coinbase.ids))} delta={<RowDelta pct={0.9} value={(schwabHidden ? 0 : acctValue(ACCOUNTS.schwab.ids)) + (coinbaseHidden ? 0 : acctValue(ACCOUNTS.coinbase.ids))} />}>
        <div style={{ opacity: schwabHidden ? 0.5 : 1 }}>
          <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.schwab })}
          bar="var(--rule-2)" logo="S" name="Schwab" sub="Brokerage •5520" value={acctValue(ACCOUNTS.schwab.ids)} valueColor="var(--ink-2)"
          chip={schwabHidden ? <HiddenChip /> : <RowDelta pct={0.92} value={acctValue(ACCOUNTS.schwab.ids)} />} push />
        </div>
        <div style={{ opacity: coinbaseHidden ? 0.5 : 1 }}>
          <Row onClick={() => nav.push({ type: "account", acct: ACCOUNTS.coinbase })}
          bar="var(--signal-warn)" logo="C" name="Coinbase" sub="Crypto •3097" value={acctValue(ACCOUNTS.coinbase.ids)} valueColor="var(--ink-2)"
          chip={coinbaseHidden ? <HiddenChip /> : undefined}
          reauth={coinbaseHidden ? undefined : () => nav.sheet({ type: "link" })} push />
        </div>
      </Group>

      <Group title="Debt" total={LIAB_TOTAL}>
        {LIABILITIES.map((d) =>
        <Row key={d.id} bar="var(--signal-neg)" logo={d.name[0]} name={d.name} sub={d.sub} value={d.value} valueColor="var(--ink-2)"
        chip={<span style={{ fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-3)" }}>{d.apr}</span>}
        onClick={() => nav.push({ type: "account", acct: { name: d.name, sub: d.sub, cash: true, totalLabel: "Balance", note: d.apr, debt: d.debt, accounts: [{ id: d.id, name: d.name, sub: d.sub, apr: "", value: d.value, bar: "var(--signal-neg)" }], txns: DEBT_TXNS } })} />
        )}
      </Group>
    </>
  );
};

/* web right pillar — the externally-linked accounts, with Link account on top */
const AccountsExternalPanel = ({ nav, inline, onRepin }) => {
  const repinBtn = onRepin ? (
    <button className="press" onClick={onRepin} aria-label="Pin linked accounts to the side" title="Pin to the side"
      style={{ width: 28, height: 28, borderRadius: 999, background: "none", border: "none", display: "grid", placeItems: "center", color: "var(--ink-2)", cursor: "pointer", padding: 0 }}>
      <Icon name="external" size={14} />
    </button>
  ) : null;
  const body = inline ? (
      /* docked: align to the center column (14px / max 660), drop the Link button
         (it moves under the total balance), re-pin sits in line with the title. */
      <section style={{ padding: "12px 14px 0", maxWidth: 660, marginLeft: "auto", marginRight: "auto", boxSizing: "border-box" }}>
        <TierHead title="External" sub="Linked · read-only" total={LIAB_TOTAL} totalColor="var(--ink-2)" neg action={repinBtn} />
        <ExternalGroups nav={nav} />
      </section>
  ) : (
      <section style={{ padding: "16px 18px 0" }}>
        <div style={{ height: 31 }} />
        <Btn kind="primary" full onClick={() => nav.sheet({ type: "link" })} style={{ padding: "11px 0", fontSize: 13 }}>+ Link account</Btn>
        {/* drop "External" down so it lines up with "Yoshi Balance" in the main column */}
        <div style={{ height: 57 }} />
        <TierHead title="External" sub="Linked · read-only" total={LIAB_TOTAL} totalColor="var(--ink-2)" neg />
        <ExternalGroups nav={nav} />
      </section>
  );
  if (inline) return body;
  return (
    <aside className="accounts-ext-col">
      <div className="scroll">{body}</div>
    </aside>
  );
};

const Accounts = ({ nav, hasCard, linkUnderTotal }) => {
  const [fdicOpen, setFdicOpen] = useState(false);
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <NavBar title="Accounts" border left={<YouButton nav={nav} />}
      right={<window.BellButton nav={nav} />} />

      <div className="scroll">
        {/* total */}
        <section style={window.__YOSHI_WEB ? { padding: "14px 14px 12px", maxWidth: 660, marginLeft: "auto", marginRight: "auto", boxSizing: "border-box" } : { padding: "14px 18px 12px" }}>
          <Eyebrow>Total value</Eyebrow>
          <div style={{ marginTop: 5, display: "flex", alignItems: "center", gap: 7 }}>
            <Money value={NET_WORTH_TRUE} size={34} weight={500} />
            <span style={{ position: "relative", display: "inline-grid", alignSelf: "flex-start", marginTop: 2 }}>
              <button className="press" aria-label="About FDIC insurance" onClick={() => setFdicOpen((o) => !o)} style={{ background: "none", border: "none", padding: 4, display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer" }}>
                <Icon name="info" size={16} stroke={1.5} />
              </button>
              {window.__YOSHI_WEB &&
                <InfoPop open={fdicOpen} onClose={() => setFdicOpen(false)} title="FDIC insurance">
                  Yoshi is a fintech company, not an FDIC-insured depository institution. Deposits in Yoshi Cash accounts are FDIC-insured through Column N.A., Member FDIC. Certain conditions must be satisfied for pass-through FDIC insurance to apply.
                </InfoPop>}
            </span>
          </div>
          <div style={{ marginTop: 6 }}><NetWorthChange /></div>

          {/* what net worth is made of — a flat ledger summary (mobile only; on web the Yoshi/External columns carry this) */}
          {!window.__YOSHI_WEB &&
          <div style={{ marginTop: 13 }}>
            <div style={{ display: "flex", alignItems: "center", padding: "12px 0", borderBottom: "1px dashed var(--rule)" }}>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600 }}>Yoshi balance</div>
              </div>
              <span style={{ marginLeft: "auto", display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 2 }}>
                <span style={{ fontFamily: "var(--f-mono)", fontSize: 18, fontWeight: 600, fontVariantNumeric: "tabular-nums", letterSpacing: "-0.01em", color: "var(--ink)" }}>{usd(ASSET_TOTAL, 2)}</span>
              </span>
            </div>
            <div style={{ display: "flex", alignItems: "center", padding: "12px 0" }}>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontFamily: "var(--f-display)", fontWeight: 600, fontSize: 14 }}>External accounts</div>
              </div>
              <span style={{ marginLeft: "auto", display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 2 }}>
                <span style={{ fontFamily: "var(--f-mono)", fontSize: 18, fontWeight: 600, fontVariantNumeric: "tabular-nums", letterSpacing: "-0.01em", color: "var(--ink)" }}>{"−" + usd(LIAB_TOTAL, 2)}</span>
              </span>
            </div>
          </div>}
        </section>

        {/* docked Accounts: the Link button moves up here, under the total balance */}
        {window.__YOSHI_WEB && linkUnderTotal &&
        <section style={{ padding: "0 14px 10px", maxWidth: 660, marginLeft: "auto", marginRight: "auto", boxSizing: "border-box" }}>
          <Btn kind="primary" full onClick={() => nav.sheet({ type: "link" })} style={{ padding: "11px 0", fontSize: 13 }}>+ Link account</Btn>
        </section>}

        {/* actions — mobile only (web puts Transfer in the top nav, Link in the right column) */}
        {!window.__YOSHI_WEB &&
        <section style={{ padding: "0 18px 14px", display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 7 }}>
          <Btn kind="primary" onClick={() => nav.sheet({ type: "transfer" })} style={{ padding: "11px 6px", fontSize: 13 }}>Transfer</Btn>
          <Btn kind="ghost" onClick={() => nav.sheet({ type: "link" })} style={{ padding: "11px 6px", fontSize: 13 }}>+ Link account</Btn>
        </section>}

        {window.__YOSHI_WEB ?
        <section style={{ padding: "12px 14px 0", maxWidth: 660, marginLeft: "auto", marginRight: "auto", boxSizing: "border-box" }}>
          <TierHead title="Yoshi Balance" sub="Held at Yoshi" total={ASSET_TOTAL} />
          <YoshiGroups nav={nav} hasCard={hasCard} />
        </section> :
        <>
          <Tier title="Yoshi" />
          <YoshiGroups nav={nav} hasCard={hasCard} />
          <Tier title="External" />
          <ExternalGroups nav={nav} />
        </>}

        <div style={{ height: 20 }} />
      </div>

      {/* FDIC disclosure · slide-up bottom sheet */}
      {fdicOpen && !window.__YOSHI_WEB &&
      <>
        <div onClick={() => setFdicOpen(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "14px 18px max(26px,env(safe-area-inset-bottom))", display: "flex", gap: 12, alignItems: "flex-start" }}>
            <p style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.6, color: "var(--ink-2)", margin: 0, display: "flex", gap: 9, alignItems: "flex-start" }}>
              <Icon name="shield" size={16} color="var(--ink-3)" stroke={1.5} style={{ flex: "none", marginTop: 2 }} />
              <span>Yoshi is a fintech company, not an FDIC-insured depository institution. Deposits in Yoshi Cash accounts are FDIC-insured through Column N.A., Member FDIC. FDIC deposit insurance covers the failure of an insured depository institution. Certain conditions must be satisfied for pass-through FDIC insurance to apply.</span>
            </p>
            <button className="press" aria-label="Close" onClick={() => setFdicOpen(false)} style={{ flex: "none", background: "none", border: "none", display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer", padding: 2 }}>
              <Icon name="close" size={18} />
            </button>
          </div>
        </div>
      </>}
    </div>);

};

/* a row's daily-change chip · shows both % and $ inline */
const RowDelta = ({ pct: p, value }) => {
  const dollars = Math.round(value * p / 100);
  const c = p >= 0 ? "var(--accent-pos)" : "var(--signal-neg)";
  return (
    <span style={{ fontFamily: "var(--f-mono)", fontSize: 11, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: c, letterSpacing: "-0.005em", whiteSpace: "nowrap" }}>{perf(dollars, p)}</span>);

};

const Group = ({ title, total, live, neg, tag, delta, children }) => {
  const [open, setOpen] = useState(true);
  const showNeg = neg || total < 0;
  return (
    <section style={{ padding: "16px 0 0" }}>
      <button className="press" onClick={() => setOpen((o) => !o)} style={{ width: "100%", background: "none", border: "none", cursor: "pointer", padding: window.__YOSHI_WEB ? "0 18px 9px 0" : "0 18px 8px", display: "flex", alignItems: "center", gap: 8, textAlign: "left" }}>
        <Icon name="down" size={window.__YOSHI_WEB ? 16 : 15} color={window.__YOSHI_WEB ? "var(--ink-2)" : "var(--ink-3)"} style={{ flex: "none", transform: open ? "rotate(180deg)" : "none", transition: "transform 180ms ease" }} />
        <span style={window.__YOSHI_WEB ? { fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--accent)" } : { fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 600, letterSpacing: "-0.015em" }}>{title}</span>
        {live && <span style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--accent)", letterSpacing: "0.02em" }}>● {live}</span>}
        {tag && <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>{tag}</span>}
        <span style={{ marginLeft: "auto", marginRight: window.__YOSHI_WEB ? 28 : 0, display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 2 }}>
          <Money value={Math.abs(total)} size={window.__YOSHI_WEB ? 21 : 16} weight={window.__YOSHI_WEB ? 600 : 500} prefix={showNeg ? "−$" : "$"} color={showNeg ? "var(--signal-neg)" : "var(--ink)"} />
          {delta}
        </span>
      </button>
      {open && <div className="acct-card" style={window.__YOSHI_WEB ? { marginTop: 4, border: "1px solid var(--rule-2)", borderRadius: 12, background: "var(--bg-card)", overflow: "hidden" } : { borderTop: "1px solid var(--rule)" }}>{children}</div>}
    </section>);

};

/* group-level performance line under the headline total — matches RowDelta style */
const GroupFlow = ({ text, pos = true }) =>
<span style={{ fontFamily: "var(--f-mono)", fontSize: 11, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: pos ? "var(--accent-pos)" : "var(--signal-neg)", letterSpacing: "-0.005em", whiteSpace: "nowrap" }}>{text}</span>;

/* top-level tier header — separates Yoshi-held accounts from external/linked ones */
const Tier = ({ title, tag }) =>
<div style={{ padding: "24px 18px 0", display: "flex", alignItems: "baseline", gap: 8 }}>
    <span style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 700, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-2)" }}>{title}</span>
    {tag && <span style={{ marginLeft: "auto", fontFamily: "var(--f-display)", fontSize: 9.5, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>{tag}</span>}
  </div>;


const Row = ({ bar, logo, name, sub, value, valueColor, chip, onClick, push, reauth }) => {
  const web = !!window.__YOSHI_WEB;
  const cols = web ? (logo ? "30px 1fr auto 16px" : "1fr auto 16px") : "3px 1fr auto 16px";
  return (
<button className="press" onClick={onClick} style={{
  width: "100%", textAlign: "left", background: "none", border: "none",
  display: "grid", gridTemplateColumns: cols, gap: 12, padding: "15px 18px",
  borderBottom: "1px solid var(--rule)", alignItems: "center"
}}>
    {web ?
      (logo ? <span style={{ width: 30, height: 30, flex: "none", borderRadius: 999, display: "grid", placeItems: "center", background: "var(--bg-2)", border: "1px solid var(--rule-2)", color: "var(--ink)", fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 700, letterSpacing: "-0.01em" }}>{logo}</span> : null) :
      <div style={{ background: bar, width: 3, height: 30 }} />}
    <div style={{ minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, letterSpacing: "-0.005em" }}>{name}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{sub}</div>
    </div>
    <div style={{ textAlign: "right" }}>
      {reauth ?
    <span role="button" tabIndex={0} className="press" onClick={(e) => {e.stopPropagation();reauth();}}
    style={{ display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--signal-warn)", background: "color-mix(in srgb, var(--signal-warn) 14%, transparent)", border: "1px solid color-mix(in srgb, var(--signal-warn) 38%, transparent)", borderRadius: 999, padding: "5px 11px", cursor: "pointer", whiteSpace: "nowrap" }}>
        <Icon name="connect" size={12.5} color="var(--signal-warn)" /> Re-auth
      </span> :
    <>
        <Money value={value} size={window.__YOSHI_WEB ? 13 : 12} color={valueColor || "var(--ink)"} />
        {chip && <div style={{ marginTop: 2 }}>{chip}</div>}
      </>}
    </div>
    <Icon name="back" size={16} color="var(--ink-3)" style={{ transform: "scaleX(-1)", justifySelf: "end" }} />
  </button>
  );
};


/* ============================================================
   Holding detail
   ============================================================ */
const RANGES = ["1D", "1W", "1M", "1Y"];

const buildSeries = (h, range) => {
  const cfg = { "1D": [30, h.dch, 0.0011], "1W": [40, h.perf["1W"], 0.004], "1M": [44, h.perf["1M"], 0.006], "1Y": [52, h.perf["1Y"], 0.012] }[range];
  const [len, movePct, vol] = cfg;
  const start = h.last / (1 + movePct / 100);
  return { data: series(h.seed + len, len, start, h.last, vol), movePct };
};

const txFor = (h) => {
  if (h.kind === "crypto") return [
  ["BUY", `${(h.shares * 0.3).toFixed(4)} @ $${(h.last * 0.94).toFixed(0)}`, "Apr 19", "var(--ink)"],
  ["BUY", `${(h.shares * 0.4).toFixed(4)} @ $${(h.avg * 1.1).toFixed(0)}`, "Mar 02", "var(--ink)"],
  ["BUY", `${(h.shares * 0.3).toFixed(4)} @ $${h.avg.toFixed(0)}`, "Jan 14", "var(--ink)"]];

  return [
  ["BUY", `${Math.round(h.shares * 0.2)} sh @ $${(h.last * 0.97).toFixed(2)} · auto-invest`, "Fri", "var(--ink)"],
  ["BUY", `${Math.round(h.shares * 0.3)} sh @ $${(h.avg * 1.12).toFixed(2)}`, "Apr 04", "var(--ink)"],
  ["DIV", `$${(h.value * 0.003).toFixed(2)} reinvested`, "Mar 28", "var(--accent-pos)"],
  ["BUY", `${Math.round(h.shares * 0.5)} sh @ $${h.avg.toFixed(2)}`, "Feb 11", "var(--ink)"]];

};

/* Yoshi's bespoke, position-aware take for a holding — shown on its detail
   page, with a one-tap follow-up into chat. Specific by ticker, with sensible
   fallbacks by asset kind + whether the position is at a gain. */
function yoshiTake(h) {
  const t = h.ticker,gain = h.pl >= 0,paper = String(h.id).startsWith("pp-");
  const named = {
    NVDA: ["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`],
    AAPL: ["Steady ballast that's doing its job. Nothing here needs a decision today — hold and let it compound.", `review my ${t} position`],
    MSFT: ["Quietly compounding. A reasonable place to add on a dip; otherwise just hold.", `set up a buy-the-dip rule for ${t}`],
    VOO: ["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`],
    VTI: ["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`],
    BTC: ["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}`],
    ETH: ["Held at a gain but choppier than Bitcoin. Fine as a smaller satellite; I wouldn't chase it higher from here.", `rebalance my crypto`],
    SOL: ["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`]
  };
  if (named[t]) return { take: named[t][0], cue: named[t][1] };
  if (paper) return { take: `This is a paper-trade position — no real money at risk. A good place to test a thesis on ${t} before you put real capital behind it.`, cue: `talk through my ${t} thesis` };
  if (h.kind === "crypto") return gain ?
  { take: `${t} is up from your cost, and it's a volatile sleeve. Worth sizing on purpose rather than adding on momentum — I can set a target weight.`, cue: `set a target weight for ${t}` } :
  { take: `${t} is below your cost. If the thesis still holds, waiting is fine; if not, I can harvest the loss to offset gains.`, cue: `harvest the loss on ${t}` };
  if (h.kind === "etf") return { take: `${t} is a diversified index position — a sensible core you can keep adding to on a schedule.`, cue: `automate adding to ${t}` };
  return gain ?
  { take: `${t} is working for you — up from your cost. No need to touch it unless it's grown into too large a slice of the portfolio.`, cue: `check whether ${t} is overweight` } :
  { take: `${t} is below your cost. If you still believe the story, holding is reasonable; otherwise I can put the loss to work at tax time.`, cue: `weigh holding vs. selling ${t}` };
}

const HoldingDetail = ({ id, nav }) => {
  const h = HOLDINGS.find((x) => x.id === id);
  const [range, setRange] = useState("1D");
  const [scrub, setScrub] = useState(null);
  const { data, movePct } = useMemo(() => buildSeries(h, range), [h, range]);
  const accent = data.length > 1 && data[data.length - 1] >= data[0] ? "var(--accent-pos)" : "var(--signal-neg)";
  const shownPrice = scrub != null ? scrub : h.last;
  const take = yoshiTake(h);

  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <NavBar title={h.ticker} sub={h.name} onBack={() => nav.pop()}
      right={<button className="press" onClick={() => nav.sheet({ type: "trade", id: h.id })} style={{ background: "var(--accent)", border: "none", borderRadius: 8, padding: "7px 13px", fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, color: "var(--accent-ink)" }}>Trade</button>} />

      <div className="scroll">
        {/* price */}
        <section style={{ padding: "14px 18px 8px" }}>
          <Eyebrow>{h.kind === "crypto" ? "Spot price" : "Last price"}</Eyebrow>
          <div style={{ marginTop: 4 }}><Money value={shownPrice} size={32} weight={500} /></div>
          <div style={{ marginTop: 6 }}>
            <Delta abs={h.value * (h.dch / 100)} pct={h.dch} size={12.5} showAbs={false} />
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 12.5, color: h.dch >= 0 ? "var(--accent-pos)" : "var(--signal-neg)", marginLeft: 8 }}>{signed(h.value * h.dch / 100)}</span>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginLeft: 6 }}>today</span>
          </div>
        </section>

        {/* chart */}
        <section style={{ padding: "0 18px" }}>
          <Chart data={data} height={150} accent={accent} fillColor={accent} scrub onScrub={(idx) => setScrub(idx == null ? null : data[idx])} padY={4} />
          <div style={{ marginTop: 10 }}>
            <Segmented options={RANGES} value={range} onChange={(r) => {setRange(r);setScrub(null);}} size="sm" />
          </div>
        </section>

        {/* position */}
        <section style={{ padding: "16px 18px 4px" }}>
          <div style={{ border: "1px solid var(--rule)", background: "var(--bg-card)", position: "relative" }}>
            <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 2, background: "var(--accent-4)" }} />
            <div style={{ padding: "12px 14px 4px" }}><Eyebrow>Your position</Eyebrow></div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 0, padding: "0 14px 12px" }}>
              <Stat label="Market value" value={usd(h.value)} />
              <Stat label="Unrealized P/L" value={perf(h.pl, h.plPct)} color={h.pl >= 0 ? "var(--accent-pos)" : "var(--signal-neg)"} right />
              <Stat label={h.kind === "crypto" ? "Holdings" : "Shares"} value={`${h.shares}`} />
              <Stat label="Avg cost" value={usd(h.avg)} right />
            </div>
          </div>
        </section>

        {/* Yoshi's take — bespoke, position-aware */}
        <section style={{ padding: "16px 18px 4px" }}>
          <div style={{ border: "1px solid var(--accent)", borderRadius: 12, background: "var(--bg-card)", position: "relative", overflow: "hidden" }}>
            <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 2, background: "var(--accent)" }} />
            <div style={{ padding: "13px 14px" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <Logo size={15} />
                <span style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--accent)" }}>Yoshi's take</span>
              </div>
              <p style={{ fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.5, margin: "9px 0 0", color: "var(--ink)" }}>{take.take}</p>
              <button className="press" onClick={() => nav.ask(`What's your take on ${h.ticker}?`, `${take.take} Want me to ${take.cue}?`)} style={{ display: "inline-flex", alignItems: "center", gap: 5, marginTop: 11, background: "none", border: "none", padding: 0, cursor: "pointer", fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600, color: "var(--accent)" }}>
                Ask Yoshi about {h.ticker} <Icon name="back" size={14} color="var(--accent)" style={{ transform: "scaleX(-1)" }} />
              </button>
            </div>
          </div>
        </section>

        {/* fundamentals */}
        <section style={{ padding: "14px 18px 4px" }}>
          <Eyebrow style={{ marginBottom: 6 }}>{h.kind === "crypto" ? "Asset" : "Fundamentals"}</Eyebrow>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0 18px" }}>
            {h.fund.map(([k, v]) =>
            <div key={k} style={{ display: "flex", justifyContent: "space-between", padding: "8px 0", borderBottom: "1px dashed var(--rule)" }}>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)" }}>{k}</span>
                <span style={{ fontFamily: /[0-9]/.test(v) ? "var(--f-mono)" : "var(--f-display)", fontSize: 11.5, fontWeight: 500, color: "var(--ink)" }}>{v}</span>
              </div>
            )}
          </div>
        </section>

        {/* news */}
        <section style={{ padding: "14px 18px 4px" }}>
          <Eyebrow style={{ marginBottom: 4 }}>News</Eyebrow>
          {h.news.map(([src, head, when], i) =>
          <div key={i} style={{ padding: "11px 0", borderBottom: "1px solid var(--rule)" }}>
              <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--accent)" }}>{src}</span>
                <span style={{ marginLeft: "auto", fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-3)" }}>{when}</span>
              </div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 500, marginTop: 3, lineHeight: 1.35 }}>{head}</div>
            </div>
          )}
        </section>

        {/* transactions */}
        <section style={{ padding: "14px 18px 4px" }}>
          <Eyebrow style={{ marginBottom: 4 }}>Transactions</Eyebrow>
          {txFor(h).map(([side, body, when, c], i) =>
          <div key={i} style={{ display: "grid", gridTemplateColumns: "auto 1fr auto", gap: 10, alignItems: "center", padding: "10px 0", borderBottom: "1px solid var(--rule)" }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.1em", color: side === "DIV" ? "var(--accent-pos)" : "var(--ink-2)", width: 30 }}>{side}</span>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink)" }}>{body}</span>
              <span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)" }}>{when}</span>
            </div>
          )}
        </section>
        <div style={{ height: 90 }} />
      </div>

      {/* sticky buy/sell */}
      <div style={{ flex: "none", padding: "12px 18px 14px", borderTop: "1px solid var(--rule)", background: "color-mix(in srgb, var(--bg) 92%, transparent)", backdropFilter: "blur(12px)", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
        <Btn kind="primary" onClick={() => nav.sheet({ type: "trade", id: h.id, side: "BUY" })}>Buy</Btn>
        <Btn kind="ghost" onClick={() => nav.sheet({ type: "trade", id: h.id, side: "SELL" })}>Sell</Btn>
      </div>
    </div>);

};

const Stat = ({ label, value, color = "var(--ink)", right }) =>
<div style={{ padding: "10px 0", borderBottom: "1px dashed var(--rule)", textAlign: right ? "right" : "left" }}>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)" }}>{label}</div>
    <div style={{ fontFamily: "var(--f-mono)", fontSize: 14, fontWeight: 500, color, marginTop: 3, fontVariantNumeric: "tabular-nums" }}>{value}</div>
  </div>;


/* ============================================================
   Account detail · holdings table (h-scroll) + transactions
   ============================================================ */
/* which holdings live in each Yoshi account. Sums stay consistent with the
   group totals shown on the Accounts list. */
const ACCOUNTS = {
  cash: { name: "Cash", sub: "Yoshi ••8841", cash: true, routing: "021000021", account: "1500240048841" },
  brokerage: { name: "Brokerage", sub: "Yoshi · Individual Taxable", ids: ["nvda", "aapl", "msft", "voo"] },
  roth: { name: "Roth IRA", sub: "Yoshi · Retirement", ids: ["vti"] },
  crypto: { name: "Crypto", sub: "Yoshi · Spot ••8841", ids: ["btc", "eth", "sol"] },
  paper: { name: "Test drive 1", sub: "Yoshi · Simulated", ids: ["pp-tsla", "pp-amzn", "pp-spy"] },
  schwab: { name: "Schwab", sub: "Brokerage · Connected", ids: ["sch-spy", "sch-qqq"] },
  coinbase: { name: "Coinbase", sub: "Crypto · Needs re-auth", ids: ["cb-doge"] },
  chase: { name: "Chase", sub: "Checking · Connected", cash: true, totalLabel: "Balance", note: "External",
    accounts: [{ id: "chase-chk", name: "Chase Checking", sub: "••4471", apr: "", value: 8210.32, bar: "var(--rule-2)" }], txns: CHASE_TXNS }
};
const acctValue = (ids) => ids.reduce((s, id) => {const h = HOLDINGS.find((x) => x.id === id);return s + (h ? h.value : 0);}, 0);

/* a combined "All holdings" view across the Yoshi investment accounts — the
   default for the holdings page; filter to a single account via the switcher. */
const ALL_HOLDINGS_ACCT = {
  name: "All holdings",
  sub: "Across your Yoshi accounts",
  ids: [...new Set([...ACCOUNTS.brokerage.ids, ...ACCOUNTS.roth.ids, ...ACCOUNTS.crypto.ids])],
  combined: true
};
/* holdings flagged as recently added (for the "Recently added" filter) */
const RECENT_ADDS = ["nvda", "voo", "sol", "eth"];

/* build a full holding record (so HoldingDetail works) for paper + external accounts */
const mkH = (id, ticker, name, kind, shares, avg, last, dch) => {
  const value = shares * last,cost = shares * avg;
  return { id, ticker, name, kind, shares, avg, last, dch, value, cost, pl: value - cost, plPct: (value - cost) / cost * 100, dayAbs: value * dch / 100,
    perf: { "1W": +(dch * 1.5).toFixed(1), "1M": +(dch * 3).toFixed(1), "1Y": +(dch * 9).toFixed(1) }, seed: Math.round(Math.abs(shares) + last),
    fund: [["Asset class", kind === "crypto" ? "Crypto" : kind === "etf" ? "ETF" : "Equity"], ["Day range", "—"], ["52w range", "—"]],
    news: [["Markets", name + " moved with the broader tape.", "2h"]] };
};
const EXTRA_HOLDINGS = [
mkH("sch-spy", "SPY", "SPDR S&P 500 ETF", "etf", 28, 540.10, 597.10, 0.64),
mkH("sch-qqq", "QQQ", "Invesco QQQ Trust", "etf", 13, 470.00, 512.33, 0.88),
mkH("cb-doge", "DOGE", "Dogecoin", "crypto", 4400, 0.31, 0.42, 5.60),
mkH("pp-tsla", "TSLA", "Tesla Inc", "stock", 120, 360.00, 342.18, -1.84),
mkH("pp-amzn", "AMZN", "Amazon.com Inc", "stock", 50, 180.00, 201.40, 1.22),
mkH("pp-spy", "SPY", "SPDR S&P 500 ETF", "etf", 60, 560.00, 597.10, 0.64)];

EXTRA_HOLDINGS.forEach((h) => {if (!HOLDINGS.find((x) => x.id === h.id)) HOLDINGS.push(h);});

const CHASE_TXNS = [
{ id: "h1", icon: "down", title: "Payroll", detail: "Acme Corp · ACH", amt: 3120.00, when: "Jun 1" },
{ id: "h2", icon: "receipt", title: "Groceries", detail: "Whole Foods", amt: -184.22, when: "May 30" },
{ id: "h3", icon: "swap", title: "Transfer to Yoshi", detail: "External ••8841", rail: "Standard ACH", type: "External transfer", amt: -2000.00, when: "May 28" },
{ id: "h4", icon: "card", title: "Utilities", detail: "ConEd · autopay", amt: -142.05, when: "May 26" }];

const DEBT_TXNS = [
{ id: "d1", icon: "down", title: "Payment received", detail: "From Checking · autopay", amt: 300.00, when: "Jun 1" },
{ id: "d2", icon: "receipt", title: "Purchase", detail: "Travel · airline", amt: -642.18, when: "May 27" },
{ id: "d3", icon: "receipt", title: "Purchase", detail: "Dining", amt: -88.40, when: "May 24" },
{ id: "d4", icon: "bank", title: "Interest charged", detail: "Cycle finance charge", amt: -41.90, when: "May 22" }];


/* synthetic per-account transaction ledger, Stream-style */
const acctTxns = (holdings) => {
  const rows = [];
  holdings.forEach((h) => {
    const cr = h.kind === "crypto";
    const unit = cr ? "" : " sh";
    rows.push({ id: h.id + "-1", side: "BUY", ticker: h.ticker, qty: cr ? (h.shares * 0.3).toFixed(4) : Math.round(h.shares * 0.2), px: h.last * 0.97, when: "Fri", order: 5, note: "auto-invest" });
    rows.push({ id: h.id + "-2", side: "BUY", ticker: h.ticker, qty: cr ? (h.shares * 0.4).toFixed(4) : Math.round(h.shares * 0.3), px: h.avg * 1.08, when: "Apr 04", order: 30 });
    if (!cr) rows.push({ id: h.id + "-d", side: "DIV", ticker: h.ticker, amt: h.value * 0.003, when: "Mar 28", order: 34, note: "reinvested" });
    rows.push({ id: h.id + "-3", side: "BUY", ticker: h.ticker, qty: cr ? (h.shares * 0.3).toFixed(4) : Math.round(h.shares * 0.5), px: h.avg, when: "Feb 11", order: 60 });
  });
  return rows.sort((a, b) => a.order - b.order);
};

/* a compact search bar with an inline filter icon → dropdown of filter options */
const AcctToolbar = ({ q, setQ, placeholder, filters, filter, setFilter }) => {
  const [open, setOpen] = useState(false);
  const active = filter !== "all";
  const activeLabel = (filters.find((f) => f[0] === filter) || [])[1];
  return (
    <div style={{ padding: "10px 18px 4px", position: "relative" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "8px 12px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 10 }}>
        <Icon name="search" size={15} color="var(--ink-3)" stroke={1.5} />
        <input value={q} onChange={(e) => setQ(e.target.value)} placeholder={placeholder}
        style={{ flex: 1, minWidth: 0, border: "none", background: "transparent", outline: "none", color: "var(--ink)", fontFamily: "var(--f-display)", fontSize: 13.5 }} />
        {q && <button className="press" onClick={() => setQ("")} style={{ background: "none", border: "none", display: "flex", color: "var(--ink-3)", padding: 0 }}><Icon name="close" size={15} /></button>}
        <span style={{ width: 1, height: 18, background: "var(--rule-2)", flex: "none" }} />
        <button className="press" onClick={() => setOpen((o) => !o)} aria-label="Filter" style={{ position: "relative", background: "none", border: "none", display: "flex", padding: 1, color: active || open ? "var(--accent)" : "var(--ink-3)", cursor: "pointer" }}>
          <Icon name="filter" size={17} stroke={1.6} />
          {active && <span style={{ position: "absolute", top: -2, right: -2, width: 6, height: 6, borderRadius: 999, background: "var(--accent)", border: "1.5px solid var(--bg-2)" }} />}
        </button>
      </div>

      {active &&
      <div style={{ display: "flex", marginTop: 8 }}>
        <button className="press" onClick={() => setFilter("all")} style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 10px", borderRadius: 999, background: "color-mix(in srgb, var(--accent) 12%, var(--bg-2))", border: "1px solid color-mix(in srgb, var(--accent) 40%, var(--rule-2))", fontFamily: "var(--f-display)", fontSize: 11.5, fontWeight: 600, color: "var(--ink)", cursor: "pointer" }}>
          {activeLabel}<Icon name="close" size={12} color="var(--ink-3)" />
        </button>
      </div>}

      {open &&
      <>
        <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", right: 18, top: "calc(100% - 2px)", zIndex: 31, minWidth: 188, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 12px 28px -14px rgba(0,0,0,0.35)", overflow: "hidden" }}>
          <div style={{ padding: "9px 13px 7px", borderBottom: "1px solid var(--rule)" }}><Eyebrow style={{ fontSize: 9.5 }}>Filter by</Eyebrow></div>
          {filters.map(([k, l], i) =>
          <button key={k} className="press" onClick={() => {setFilter(k);setOpen(false);}} style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, padding: "9px 13px", background: k === filter ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600, color: "var(--ink)" }}>{l}</span>
              {k === filter && <Icon name="check" size={14} stroke={2} color="var(--accent)" style={{ marginLeft: "auto" }} />}
            </button>
          )}
        </div>
      </>}
    </div>);

};

/* horizontally-scrollable holdings table. First column (the holding) is pinned;
   scroll right to reveal % of portfolio, avg cost, and total return. */
const HoldingsTable = ({ holdings, total, nav }) => {
  const NUMCOLS = [
  ["Value", 84, (h) => ({ main: usd(h.value, 2) }), (h) => h.value],
  ["Today", 84, (h) => ({ main: signed(h.dayAbs, 0), sub: pct(h.dch), color: h.dch >= 0 ? "var(--accent-pos)" : "var(--signal-neg)" }), (h) => h.dayAbs],
  ["%Port", 84, (h) => ({ main: (h.value / total * 100).toFixed(1) + "%" }), (h) => h.value],
  ["Cost basis", 92, (h) => ({ main: usd(h.avg, h.kind === "crypto" ? 0 : 2), color: "var(--ink-2)" }), (h) => h.avg],
  ["Return", 84, (h) => ({ main: signed(h.pl, 0), sub: pct(h.plPct), color: h.pl >= 0 ? "var(--accent-pos)" : "var(--signal-neg)" }), (h) => h.pl]];

  // sortable: default Value, highest → lowest. Tapping a header toggles
  // direction; tapping a new column starts it descending (text starts A→Z).
  const [sort, setSort] = useState({ key: "Value", dir: "desc" });
  const onSort = (key) => setSort((s) => s.key === key ? { key, dir: s.dir === "desc" ? "asc" : "desc" } : { key, dir: key === "Holding" ? "asc" : "desc" });
  const sorted = useMemo(() => {
    const acc = sort.key === "Holding" ? null : (NUMCOLS.find((c) => c[0] === sort.key) || [])[3];
    const arr = [...holdings].sort((a, b) =>
    acc ? acc(a) - acc(b) : String(a.ticker).localeCompare(String(b.ticker)));
    return sort.dir === "desc" ? arr.reverse() : arr;
  }, [holdings, sort, total]);

  const web = !!window.__YOSHI_WEB;
  const SEAM = web ? 24 : 20,COLW = web ? 104 : 84,HOLDW = web ? 92 : 72; // edge padding, uniform numeric width, narrower holding column
  const last = NUMCOLS.length - 1;
  const W = SEAM + HOLDW + NUMCOLS.reduce((s, c, i) => s + (i === last ? COLW + SEAM : COLW), 0);
  const stick = { position: "sticky", left: 0, zIndex: 2, background: "var(--bg)", width: SEAM + HOLDW, flex: "none", boxSizing: "border-box", paddingLeft: SEAM };
  const cell = (i) => web
    ? { flex: "1 1 0", minWidth: COLW, boxSizing: "border-box", textAlign: "right", paddingLeft: 8, paddingRight: i === last ? SEAM : 0 }
    : { flex: "none", boxSizing: "border-box", textAlign: "right", width: i === last ? COLW + SEAM : COLW, paddingLeft: 8, paddingRight: i === last ? SEAM : 0 };
  const Caret = ({ k }) => {
    const active = sort.key === k;
    return <span aria-hidden="true" style={{ fontFamily: "var(--f-mono)", fontSize: 8, lineHeight: 1, marginLeft: 3, color: active ? "var(--accent)" : "var(--ink-3)", opacity: active ? 1 : 0.3 }}>{active && sort.dir === "asc" ? "▲" : "▼"}</span>;
  };
  const headBtn = { background: "none", border: "none", padding: 0, margin: 0, cursor: "pointer", display: "inline-flex", alignItems: "center", font: "inherit", color: "inherit", WebkitTapHighlightColor: "transparent" };
  return (
    <div className="hcar" style={{ overflowX: "auto", overflowY: "hidden" }}>
      <div style={web ? { width: "100%", minWidth: W } : { width: W }}>
        {/* header · tap a column to sort high ↔ low */}
        <div style={{ display: "flex", alignItems: "flex-end", padding: "0 0 7px", borderBottom: "1px solid var(--rule)" }}>
          <div style={{ ...stick }}>
            <button className="press" onClick={() => onSort("Holding")} style={headBtn}>
              <Eyebrow color={sort.key === "Holding" ? "var(--accent)" : "var(--ink-3)"} style={{ fontSize: web ? 10.5 : 9.5 }}>Holding</Eyebrow><Caret k="Holding" />
            </button>
          </div>
          {NUMCOLS.map(([label], i) =>
          <div key={label} style={cell(i)}>
            <button className="press" onClick={() => onSort(label)} style={{ ...headBtn, width: "100%", justifyContent: "flex-end" }}>
              <Eyebrow color={sort.key === label ? "var(--accent)" : "var(--ink-3)"} style={{ fontSize: web ? 10.5 : 9.5 }}>{label}</Eyebrow><Caret k={label} />
            </button>
          </div>)}
        </div>
        {sorted.length === 0 ?
        <div style={{ padding: "26px 20px", textAlign: "center", fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>No holdings match.</div> :
        sorted.map((h, ri) =>
        <button key={h.id} className="press" onClick={() => nav.push({ type: "holding", id: h.id })} style={{ width: "100%", display: "flex", alignItems: "center", background: "none", border: "none", borderBottom: ri === sorted.length - 1 ? "none" : "1px solid var(--rule)", padding: "12px 0", cursor: "pointer", textAlign: "left" }}>
              <div style={{ ...stick, display: "flex", flexDirection: "column", justifyContent: "center" }}>
                <span style={{ fontFamily: "var(--f-display)", fontSize: web ? 15 : 13.5, fontWeight: 700, letterSpacing: "-0.01em" }}>{h.ticker}</span>
                <span style={{ fontFamily: "var(--f-mono)", fontSize: web ? 11.5 : 10.5, color: "var(--ink-3)", marginTop: 3 }}>{h.kind === "crypto" ? h.shares : h.shares + " sh"}</span>
              </div>
              {NUMCOLS.map(([label, w, f], i) => {
            const c = f(h);
            return (
              <div key={label} style={cell(i)}>
                    <div style={{ fontFamily: "var(--f-mono)", fontSize: web ? 14 : 12.5, fontWeight: 500, color: c.color || "var(--ink)", fontVariantNumeric: "tabular-nums" }}>{c.main}</div>
                    {c.sub && <div style={{ fontFamily: "var(--f-mono)", fontSize: web ? 11.5 : 10.5, color: c.color || "var(--ink-3)", marginTop: 1, fontVariantNumeric: "tabular-nums" }}>{c.sub}</div>}
                  </div>);

          })}
            </button>
        )}
      </div>
    </div>);

};

const AcctTxnRow = ({ t, last }) => {
  const isDiv = t.side === "DIV";
  const isAuto = t.note === "auto-invest";
  const title = isDiv ? `Dividend · ${t.ticker}` : `${t.side === "BUY" ? "Bought" : "Sold"} ${t.ticker}`;
  const detail = isDiv ? `${usd(t.amt)} ${t.note || ""}`.trim() : `${t.qty}${t.ticker && !String(t.qty).includes(".") ? " sh" : ""} @ ${usd(t.px, 2)}${t.note && !isAuto ? " · " + t.note : ""}`;
  const amt = isDiv ? t.amt : -(Number(t.qty) * t.px);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "auto 1fr auto", gap: 11, alignItems: "center", padding: window.__YOSHI_WEB ? "11px 32px" : "11px 18px", borderBottom: last ? "none" : "1px solid var(--rule)" }}>
      <span style={{ width: 26, height: 26, flex: "none", display: "grid", placeItems: "center", color: "var(--ink-2)" }}>
        {isAuto ? <Logo size={18} /> : <Icon name={isDiv ? "bank" : "trade"} size={19} color="var(--ink-2)" stroke={1.5} />}
      </span>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{title}</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{detail}</div>
      </div>
      <div style={{ textAlign: "right", whiteSpace: "nowrap" }}>
        <Money value={amt} size={12.5} sign color={amt >= 0 ? "var(--accent-pos)" : "var(--ink)"} dim="var(--ink-3)" />
        <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-3)", marginTop: 3 }}>{t.when}</div>
      </div>
    </div>);

};

/* synthetic recent cash activity */
const CASH_TXNS = [
{ id: "k1", icon: "down", title: "Pay day", detail: "Acme Corp · direct deposit", amt: 6240.00, when: "Jun 1" },
{ id: "k2", icon: "receipt", title: "Rent", detail: "Bill pay · Greystar", amt: -2800.00, when: "Jun 1" },
{ id: "k3", icon: "bank", title: "Interest earned", detail: "Savings · 4.80% APY", amt: 256.12, when: "May 31" },
{ id: "k4", icon: "card", title: "Card autopay", detail: "Yoshi Card ••2291", amt: -1240.40, when: "May 28" },
{ id: "k5", icon: "swap", title: "Transfer to Brokerage", detail: "Yoshi · auto-invest", rail: "Instant", type: "Between accounts", amt: -1500.00, when: "May 27" },
{ id: "k6", icon: "down", title: "Zelle from Jordan", detail: "Received ••8841", amt: 320.00, when: "May 24" }];


const CashAccountDetail = ({ acct, nav }) => {
  const accounts = acct.accounts || CASH;
  const txlist = acct.txns || CASH_TXNS;
  const total = accounts.reduce((s, a) => s + a.value, 0);
  const yearly = accounts.reduce((s, a) => s + (/4\.80/.test(a.apr || "") ? a.value * 0.048 : 0), 0);
  const ytd = yearly * (5 / 12);
  const [tab, setTab] = useState("balances");
  const [q, setQ] = useState("");const [f, setF] = useState("all");
  const [confirm, setConfirm] = useState(false);
  const [shown, setShown] = useState(false);
  const [copied, setCopied] = useState("");
  const [nick, setNick] = useState(acct.name);
  const [editingNick, setEditingNick] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [apyInfo, setApyInfo] = useState(false);
  const [fdicOpen, setFdicOpen] = useState(false);
  const [hidden, toggleHidden] = useHiddenAccts();
  const isHidden = hidden.includes(acct.name);
  const external = !!acct.note; // linked / read-only accounts
  const canReveal = !!acct.account;
  const copy = (label, val) => {
    try {navigator.clipboard && navigator.clipboard.writeText(val);} catch (e) {}
    setCopied(label);setTimeout(() => setCopied(""), 1400);
  };
  const shownTx = txlist.filter((t) => {
    if (f === "in" && t.amt < 0) return false;
    if (f === "out" && t.amt >= 0) return false;
    const s = q.trim().toLowerCase();
    return !s || (t.title + " " + t.detail).toLowerCase().includes(s);
  });
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0, position: "relative" }}>
      <NavBar onBack={() => nav.pop()}
      title={nick}
      sub={acct.sub}
      right={
      <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
          {(external || canReveal) &&
          <button className="press" aria-label="Account options" onClick={() => setMenuOpen((o) => !o)} style={{ flex: "none", display: "grid", placeItems: "center", width: 30, height: 30, background: menuOpen ? "var(--bg-2)" : "none", border: "1px solid " + (menuOpen ? "var(--rule-2)" : "transparent"), borderRadius: 8, cursor: "pointer", color: "var(--ink-2)" }}><Icon name="more" size={18} /></button>}
          <button className="press" onClick={() => acct.debt ? nav.sheet({ type: "transfer", rail: "billpay" }) : nav.sheet({ type: "transfer", from: "cash" })} style={{ background: "none", border: "1px solid var(--rule-2)", borderRadius: 8, padding: "6px 12px", fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, color: "var(--ink)" }}>{acct.debt ? "Pay" : "Transfer"}</button>
        </div>} />

      {/* Yoshi cash · reveal numbers, rename, documents */}
      {menuOpen && canReveal &&
      <>
        <div onClick={() => setMenuOpen(false)} style={{ position: "absolute", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", top: 52, right: 14, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 244 }}>
          <button className="press" onClick={() => { setMenuOpen(false); setConfirm(true); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
            <Icon name="eye" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Reveal account & routing number</span>
          </button>
          <button className="press" onClick={() => { setEditingNick(true); setMenuOpen(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <Icon name="doc" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Edit nickname</span>
          </button>
          <button className="press" onClick={() => { setMenuOpen(false); nav.sheet({ type: "documents", acct: "savings" }); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <Icon name="receipt" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Documents</span>
          </button>
        </div>
      </>}

      {/* external-account actions · rename, or drop from totals & summaries */}
      {menuOpen && external &&
      <>
        <div onClick={() => setMenuOpen(false)} style={{ position: "absolute", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", top: 52, right: 14, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 232 }}>
          <button className="press" onClick={() => {setEditingNick(true);setMenuOpen(false);}} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
            <Icon name="doc" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Edit nickname</span>
          </button>
          <button className="press" onClick={() => {toggleHidden(acct.name);setMenuOpen(false);}} style={{ width: "100%", display: "flex", alignItems: "flex-start", gap: 10, padding: "12px 13px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <Icon name="eye" size={17} color="var(--ink-2)" stroke={1.6} style={{ marginTop: 1 }} />
            <span style={{ minWidth: 0 }}>
              <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>{isHidden ? "Show in totals & summary" : "Hide from totals & summary"}</span>
              <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 2, lineHeight: 1.4 }}>{isHidden ? "Count this account again everywhere." : "Remains connected"}</span>
            </span>
          </button>
        </div>
      </>}

      <section style={{ flex: "none", padding: "14px 18px 12px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 5 }}>
          <Eyebrow style={{ margin: 0 }}>{acct.totalLabel || "Total cash"}</Eyebrow>
          {!acct.note && !acct.debt &&
          <span style={{ position: "relative", display: "inline-grid", lineHeight: 0 }}>
            <button className="press" aria-label="About FDIC insurance" onClick={() => setFdicOpen((o) => !o)} style={{ background: "none", border: "none", padding: 0, display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer", lineHeight: 0 }}>
            <Icon name="info" size={12} stroke={1.5} />
          </button>
            {window.__YOSHI_WEB && <InfoPop open={fdicOpen} onClose={() => setFdicOpen(false)} title="FDIC insurance">Yoshi is a fintech company, not an FDIC-insured depository institution. Deposits in Yoshi Cash accounts are FDIC-insured through Column N.A., Member FDIC. Certain conditions must be satisfied for pass-through FDIC insurance to apply.</InfoPop>}
          </span>}
        </div>
        <div style={{ marginTop: 5, display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
          <Money value={total} size={30} weight={500} />
          {isHidden &&
          <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, padding: "3px 9px" }}>Hidden from totals</span>}
        </div>
        <div style={{ marginTop: 6 }}>
          {acct.note ?
          <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.02em" }}>
            <span style={{ width: 5, height: 5, borderRadius: 999, background: "var(--ink-3)", flex: "none" }} />
            Synced {syncedAgo(acct.name)}
          </span> :
          <div style={{ display: "flex", alignItems: "center", gap: 14, marginTop: 4 }}>
            <div>
              <div style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: "var(--accent-pos)" }}>+{usd(ytd, 0)}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)", marginTop: 2 }}>Interest Jan–May</div>
            </div>
            <span style={{ width: 1, alignSelf: "stretch", background: "var(--rule)", flex: "none" }} />
            <div>
              <div style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: "var(--ink)" }}>4.80%</div>
              <div style={{ display: "flex", alignItems: "center", gap: 4, marginTop: 2 }}>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)" }}>Current APY</span>
                <span style={{ position: "relative", display: "inline-grid", lineHeight: 0 }}>
                  <button className="press" aria-label="About your APY" onClick={() => setApyInfo((o) => !o)} style={{ background: "none", border: "none", padding: 0, display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer", lineHeight: 0 }}>
                  <Icon name="info" size={12} stroke={1.5} />
                </button>
                  {window.__YOSHI_WEB && <InfoPop open={apyInfo} onClose={() => setApyInfo(false)} title="About your APY" width={274}>APY is an annual rate. Our current base rate is 4.80% and is subject to change. Interest accrues daily and is paid out monthly.</InfoPop>}
                </span>
              </div>
            </div>
          </div>}
        </div>
      </section>

      {/* APY disclosure · slide-up bottom sheet */}
      {apyInfo && !window.__YOSHI_WEB &&
      <>
        <div onClick={() => setApyInfo(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "16px 18px max(26px,env(safe-area-inset-bottom))" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12 }}>
              <Icon name="info" size={18} color="var(--ink-2)" stroke={1.5} />
              <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600, letterSpacing: "-0.015em" }}>About your APY</div>
              <button className="press" aria-label="Close" onClick={() => setApyInfo(false)} style={{ marginLeft: "auto", background: "none", border: "none", display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer", padding: 2 }}>
                <Icon name="close" size={18} />
              </button>
            </div>
            <p style={{ fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.6, color: "var(--ink-2)", margin: 0 }}>APY is an annual rate. Our current base rate as of today's date is 4.80% and is subject to change. Interest accrues daily and is paid out monthly. Payouts can vary month to month based on the APY account balance and the number of days in the month.</p>
          </div>
        </div>
      </>}

      {/* FDIC disclosure · slide-up bottom sheet */}
      {fdicOpen && !window.__YOSHI_WEB &&
      <>
        <div onClick={() => setFdicOpen(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "14px 18px max(26px,env(safe-area-inset-bottom))", display: "flex", gap: 12, alignItems: "flex-start" }}>
            <p style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.6, color: "var(--ink-2)", margin: 0, display: "flex", gap: 9, alignItems: "flex-start" }}>
              <Icon name="shield" size={16} color="var(--ink-3)" stroke={1.5} style={{ flex: "none", marginTop: 2 }} />
              <span>Yoshi is a fintech company, not an FDIC-insured depository institution. Deposits in Yoshi Cash accounts are FDIC-insured through Column N.A., Member FDIC. FDIC deposit insurance covers the failure of an insured depository institution. Certain conditions must be satisfied for pass-through FDIC insurance to apply.</span>
            </p>
            <button className="press" aria-label="Close" onClick={() => setFdicOpen(false)} style={{ flex: "none", background: "none", border: "none", display: "grid", placeItems: "center", color: "var(--ink-3)", cursor: "pointer", padding: 2 }}>
              <Icon name="close" size={18} />
            </button>
          </div>
        </div>
      </>}

      {/* nickname editor · bottom sheet */}
      {editingNick &&
      <>
        <div onClick={() => setEditingNick(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "14px 18px max(26px,env(safe-area-inset-bottom))" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600, letterSpacing: "-0.015em", marginBottom: 16 }}>Edit nickname</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 600, color: "var(--ink-2)", marginBottom: 6 }}>Account nickname</div>
            <input autoFocus value={nick} onChange={(e) => setNick(e.target.value)} onKeyDown={(e) => {if (e.key === "Enter") setEditingNick(false);}}
              style={{ width: "100%", padding: "12px 13px", background: "var(--bg-2)", border: "1px solid var(--accent)", borderRadius: 10, outline: "none", fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 600, color: "var(--ink)" }} />
            <button className="press" onClick={() => setEditingNick(false)} style={{ width: "100%", marginTop: 14, padding: "12px", background: "var(--accent)", border: "none", borderRadius: 10, fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, cursor: "pointer", color: "var(--accent-ink)" }}>Save</button>
          </div>
        </div>
      </>}

      {/* debt accounts · loan terms as a clean label/value ledger */}
      {acct.debt &&
      <section style={{ flex: "none", padding: "2px 18px 14px" }}>
        <div style={{ border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden" }}>
          {[["Outstanding", acct.debt.outstanding], ["Original loan amount", acct.debt.original], ["Term length", acct.debt.term], ["Expected payoff", acct.debt.payoff], ["Amount paid to date", acct.debt.paid], ["Next payment minimum", acct.debt.nextMin]].map(([label, val], i) =>
          <div key={label} style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 14, padding: "11px 14px", borderTop: i ? "1px solid var(--rule)" : "none" }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)" }}>{label}</span>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: "var(--ink)", letterSpacing: "-0.005em", textAlign: "right" }}>{val}</span>
          </div>
          )}
        </div>
      </section>}

      {/* account numbers · slide-up bottom sheet, revealed after Face ID confirmation */}
      {shown &&
      <>
        <div onClick={() => setShown(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "14px 18px max(26px,env(safe-area-inset-bottom))" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600, letterSpacing: "-0.015em", marginBottom: 16 }}>Account details</div>
            {[["Routing number", acct.routing], ["Account number", acct.account]].map(([label, val]) =>
            <div key={label} role="button" tabIndex={0} className="press" onClick={() => copy(label, val)} style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 10, alignItems: "center", padding: "11px 0", borderBottom: "1px solid var(--rule)", cursor: "pointer" }}>
              <div style={{ minWidth: 0 }}>
                <Eyebrow style={{ fontSize: 9 }}>{label}</Eyebrow>
                <div style={{ fontFamily: "var(--f-mono)", fontSize: 17, letterSpacing: "0.06em", marginTop: 3, color: "var(--ink)" }}>{val}</div>
              </div>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, color: copied === label ? "var(--accent-pos)" : "var(--accent)" }}>
                {copied === label ? "Copied" : "Copy"}
              </span>
            </div>)}
            <button className="press" onClick={() => setShown(false)} style={{ width: "100%", marginTop: 14, padding: "12px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 10, fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>Done</button>
          </div>
        </div>
      </>}

      <div style={{ flex: "none" }}>
        <AcctToolbar q={q} setQ={setQ} placeholder="Search transactions" filter={f} setFilter={setF}
        filters={[["all", "All"], ["in", "Money in"], ["out", "Money out"]]} />
      </div>
      <div className="scroll" style={{ paddingTop: 6 }}>
        {shownTx.length ? shownTx.map((t, i) =>
        <button key={t.id} className="press" onClick={() => nav.sheet({ type: "txn", tx: { ...t, net: t.amt } })} style={{ width: "100%", textAlign: "left", background: "none", border: "none", cursor: "pointer", display: "grid", gridTemplateColumns: "auto 1fr auto", gap: 11, alignItems: "center", padding: "11px 18px" }}>
            <span style={{ width: 26, height: 26, flex: "none", display: "grid", placeItems: "center", color: "var(--ink-2)" }}>
              <Icon name={t.icon} size={19} color="var(--ink-2)" stroke={1.5} />
            </span>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{t.title}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{t.detail}{t.rail ? " · " + t.rail : ""}</div>
            </div>
            <div style={{ textAlign: "right", whiteSpace: "nowrap" }}>
              <Money value={t.amt} size={12.5} sign color={t.amt >= 0 ? "var(--accent-pos)" : "var(--ink)"} dim="var(--ink-3)" />
              <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-3)", marginTop: 3 }}>{t.when}</div>
                </div>
              </button>
        ) : <div style={{ padding: "26px 18px", textAlign: "center", fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>No transactions match.</div>}
        <div style={{ height: 24 }} />
      </div>

      {/* confirmation prompt before revealing sensitive numbers */}
      {confirm &&
      <div style={{ position: "absolute", inset: 0, zIndex: 40, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}>
        <div onClick={() => setConfirm(false)} style={{ position: "absolute", inset: 0, background: "color-mix(in srgb, var(--bg) 55%, transparent)", backdropFilter: "blur(3px)" }} />
        <div style={{ position: "relative", width: "100%", maxWidth: 300, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 16, padding: 20, boxShadow: "0 24px 60px -22px rgba(0,0,0,0.55)" }}>
          <div style={{ width: 38, height: 38, borderRadius: 10, background: "color-mix(in srgb, var(--accent) 14%, transparent)", display: "grid", placeItems: "center", marginBottom: 13 }}>
            <Icon name="shield" size={20} color="var(--accent)" />
          </div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600, letterSpacing: "-0.015em" }}>Reveal account details?</div>
          <p style={{ fontFamily: "var(--f-display)", fontSize: 12.5, lineHeight: 1.5, color: "var(--ink-2)", margin: "7px 0 16px" }}>Confirm it's you to show the full account and routing numbers for {acct.name}.</p>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
            <Btn kind="ghost" onClick={() => setConfirm(false)}>Cancel</Btn>
            <Btn kind="primary" onClick={() => {setShown(true);setConfirm(false);}}>Confirm</Btn>
          </div>
        </div>
      </div>}
    </div>);

};

/* deterministic "last synced" label for a linked account — different accounts
   pull at different times, so the time varies by account name but stays stable. */
const SYNC_TIMES = ["6 hours ago", "2 hours ago", "18 minutes ago", "yesterday", "4 hours ago", "1 hour ago", "11 hours ago", "40 minutes ago"];
const syncedAgo = (name) => { let h = 0; for (const c of String(name)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return SYNC_TIMES[h % SYNC_TIMES.length]; };

const AccountDetail = ({ acct, nav }) => {
  if (acct.cash) return <CashAccountDetail acct={acct} nav={nav} />;
  const YOSHI_INV = [ACCOUNTS.brokerage, ACCOUNTS.roth, ACCOUNTS.crypto].filter(Boolean);
  const isYoshiInv = YOSHI_INV.some((a) => a.name === acct.name) || acct.combined;
  const external = !isYoshiInv && !acct.combined && acct.name !== ALL_HOLDINGS_ACCT.name; // linked / read-only brokerages
  const startAcct = (acct.combined || acct.name === ALL_HOLDINGS_ACCT.name) ? ALL_HOLDINGS_ACCT : acct;
  const [curAcct, setCurAcct] = useState(startAcct);
  const [menuOpen, setMenuOpen] = useState(false);
  const [actionsOpen, setActionsOpen] = useState(false);
  const [nick, setNick] = useState(acct.name);
  const [editingNick, setEditingNick] = useState(false);
  const [hidden, toggleHidden] = useHiddenAccts();
  const isHidden = hidden.includes(acct.name);
  useEffect(() => {setCurAcct(startAcct);setNick(acct.name);}, [acct]);
  const SWITCH = (() => {
    const base = [ALL_HOLDINGS_ACCT, ...YOSHI_INV];
    return base.find((a) => a.name === curAcct.name) ? base : [curAcct, ...base];
  })();
  const holdings = curAcct.ids ? curAcct.ids.map((id) => HOLDINGS.find((h) => h.id === id)).filter(Boolean) : curAcct.holdings || [];
  const total = holdings.reduce((s, h) => s + h.value, 0);
  const dayAbs = holdings.reduce((s, h) => s + h.dayAbs, 0);
  const dayPct = dayAbs / (total - dayAbs) * 100;
  const [tab, setTab] = useState("holdings");
  const [valRange, setValRange] = useState("Today");
  const [valRangeOpen, setValRangeOpen] = useState(false);
  const rangeWord = (r) => r === "Today" ? "today" : `past ${r === "1W" ? "week" : r === "1M" ? "month" : "year"}`;
  const rangeMenuLabel = (r) => r === "Today" ? "Today" : `Past ${r === "1W" ? "week" : r === "1M" ? "month" : "year"}`;
  // account-level change for the selected period: "Today" uses the live day
  // move; longer ranges aggregate each holding's period return into dollars.
  const valChange = useMemo(() => {
    if (valRange === "Today") return { abs: dayAbs, pct: dayPct };
    let abs = 0;
    for (const h of holdings) {
      const p = (h.perf && h.perf[valRange]) || 0;
      abs += h.value - h.value / (1 + p / 100);
    }
    const base = total - abs;
    return { abs, pct: base ? abs / base * 100 : 0 };
  }, [valRange, holdings, total, dayAbs, dayPct]);
  const [hq, setHq] = useState("");const [hf, setHf] = useState("all");
  const [tq, setTq] = useState("");const [tf, setTf] = useState("all");

  const shownHoldings = holdings.filter((h) => {
    if (hf === "gainers" && h.dch < 0) return false;
    if (hf === "losers" && h.dch >= 0) return false;
    if (hf === "stock" && h.kind !== "stock") return false;
    if (hf === "etf" && h.kind !== "etf") return false;
    if (hf === "crypto" && h.kind !== "crypto") return false;
    if (hf === "recent" && !RECENT_ADDS.includes(h.id)) return false;
    const s = hq.trim().toLowerCase();
    return !s || h.ticker.toLowerCase().includes(s) || h.name.toLowerCase().includes(s);
  });
  const kinds = [...new Set(holdings.map((h) => h.kind))];
  const hFilters = [["all", "All"], ["gainers", "Gainers"], ["losers", "Losers"],
  ...(kinds.includes("stock") ? [["stock", "Stocks"]] : []),
  ...(kinds.includes("etf") ? [["etf", "ETFs"]] : []),
  ...(kinds.includes("crypto") ? [["crypto", "Crypto"]] : []),
  ["recent", "Recently added"]];
  const allTxns = useMemo(() => acctTxns(holdings), [curAcct]);
  const shownTxns = allTxns.filter((t) => {
    if (tf === "buys" && t.side !== "BUY") return false;
    if (tf === "sells" && t.side !== "SELL") return false;
    if (tf === "div" && t.side !== "DIV") return false;
    const s = tq.trim().toLowerCase();
    return !s || t.ticker.toLowerCase().includes(s);
  });

  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0, position: "relative" }}>
      <NavBar onBack={() => nav.pop()} sub={curAcct.sub}
      title={external ? nick :
      <button className="press" onClick={() => setMenuOpen((o) => !o)} style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "none", border: "none", padding: 0, cursor: "pointer", maxWidth: "100%" }}>
          <span style={{ fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 600, letterSpacing: "-0.02em", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", color: "var(--ink)" }}>{curAcct.name}</span>
          <Icon name="down" size={16} color="var(--ink-3)" style={{ transform: menuOpen ? "rotate(180deg)" : "none", transition: "transform .15s", flex: "none" }} />
        </button>}
      right={
      <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
          {curAcct.name !== ALL_HOLDINGS_ACCT.name && <button className="press" aria-label="Account options" onClick={() => setActionsOpen((o) => !o)} style={{ flex: "none", display: "grid", placeItems: "center", width: 30, height: 30, background: actionsOpen ? "var(--bg-2)" : "none", border: "1px solid " + (actionsOpen ? "var(--rule-2)" : "transparent"), borderRadius: 8, cursor: "pointer", color: "var(--ink-2)" }}><Icon name="more" size={18} /></button>}
          <button className="press" onClick={() => nav.sheet({ type: "trade" })} style={{ background: "var(--accent)", border: "none", borderRadius: 8, padding: "7px 13px", fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, color: "var(--accent-ink)" }}>Trade</button>
        </div>} />

      {/* account options (kebab) · external = rename / hide; Yoshi = rename / documents */}
      {actionsOpen && external &&
      <>
        <div onClick={() => setActionsOpen(false)} style={{ position: "absolute", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", top: 52, right: 14, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 232 }}>
          <button className="press" onClick={() => { setEditingNick(true); setActionsOpen(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
            <Icon name="doc" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Edit nickname</span>
          </button>
          <button className="press" onClick={() => { toggleHidden(acct.name); setActionsOpen(false); }} style={{ width: "100%", display: "flex", alignItems: "flex-start", gap: 10, padding: "12px 13px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <Icon name="eye" size={17} color="var(--ink-2)" stroke={1.6} style={{ marginTop: 1 }} />
            <span style={{ minWidth: 0 }}>
              <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>{isHidden ? "Show in totals & summary" : "Hide from totals & summary"}</span>
              <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 2, lineHeight: 1.4 }}>{isHidden ? "Count this account again everywhere." : "Remains connected"}</span>
            </span>
          </button>
        </div>
      </>}

      {actionsOpen && !external &&
      <>
        <div onClick={() => setActionsOpen(false)} style={{ position: "absolute", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", top: 52, right: 14, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 224 }}>
          <button className="press" onClick={() => { setEditingNick(true); setActionsOpen(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
            <Icon name="doc" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Edit nickname</span>
          </button>
          <button className="press" onClick={() => { setActionsOpen(false); nav.sheet({ type: "documents", acct: { Brokerage: "brokerage", "Roth IRA": "roth", Crypto: "crypto" }[curAcct.name] }); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 13px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <Icon name="receipt" size={17} color="var(--ink-2)" stroke={1.6} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Documents</span>
          </button>
        </div>
      </>}

      {menuOpen && !external &&
      <>
        <div onClick={() => setMenuOpen(false)} style={{ position: "absolute", inset: 0, zIndex: 30 }} />
        <div style={{ position: "absolute", top: 52, left: 16, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 210 }}>
          {SWITCH.map((a, i) => {
            const on = a.name === curAcct.name;
            return (
              <button key={a.name} className="press" onClick={() => {setCurAcct(a);setMenuOpen(false);setTab("holdings");}} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "11px 13px", background: on ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>{a.name}</div>
                  <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.sub}</div>
                </div>
                {on && <Icon name="check" size={15} color="var(--accent)" style={{ flex: "none" }} />}
              </button>);
          })}
        </div>
      </>}

      {/* value header */}
      <section style={{ flex: "none", padding: "14px 18px 12px" }}>
        <Eyebrow>Account value</Eyebrow>
        <div style={{ marginTop: 5, display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
          <Money value={total} size={30} weight={500} />
          {external && isHidden &&
          <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, padding: "3px 9px" }}>Hidden from totals</span>}
        </div>
        <div style={{ marginTop: 6, display: "flex", alignItems: "baseline", gap: 8, position: "relative" }}>
          <span style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: valChange.pct >= 0 ? "var(--accent-pos)" : "var(--signal-neg)", letterSpacing: "-0.005em" }}>{perf(valChange.abs, valChange.pct)}</span>
          <button className="press" onClick={() => setValRangeOpen((o) => !o)} style={{ display: "inline-flex", alignItems: "center", gap: 4, background: "none", border: "none", padding: 0, cursor: "pointer" }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)" }}>{rangeWord(valRange)}</span>
            <Icon name="down" size={13} color="var(--ink-3)" style={{ transform: valRangeOpen ? "rotate(180deg)" : "none", transition: "transform .15s" }} />
          </button>
          {valRangeOpen &&
          <>
            <div onClick={() => setValRangeOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 30 }} />
            <div style={{ position: "absolute", top: "calc(100% + 6px)", left: 0, zIndex: 31, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 10, boxShadow: "0 14px 30px -16px rgba(0,0,0,0.35)", overflow: "hidden", minWidth: 150 }}>
              {["Today", "1W", "1M", "1Y"].map((r, i) => {
                const on = r === valRange;
                return (
                  <button key={r} className="press" onClick={() => { setValRange(r); setValRangeOpen(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "10px 13px", background: on ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
                    <span style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{rangeMenuLabel(r)}</span>
                    {on && <Icon name="check" size={14} stroke={2} color="var(--accent)" />}
                  </button>);
              })}
            </div>
          </>}
        </div>
        {external &&
        <div style={{ marginTop: 9, display: "flex", alignItems: "center", gap: 6, fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.02em" }}>
          <span style={{ width: 5, height: 5, borderRadius: 999, background: "var(--ink-3)", flex: "none" }} />
          Synced {syncedAgo(acct.name)}
        </div>}
      </section>

      {/* nickname editor · bottom sheet */}
      {editingNick &&
      <>
        <div onClick={() => setEditingNick(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 40, animation: "scrim-in 200ms ease both" }} />
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 41, background: "var(--bg)", borderTop: "1px solid var(--rule-2)", borderRadius: "16px 16px 0 0", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both" }}>
          <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>
          <div style={{ padding: "14px 18px max(26px,env(safe-area-inset-bottom))" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600, letterSpacing: "-0.015em", marginBottom: 16 }}>Edit nickname</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 600, color: "var(--ink-2)", marginBottom: 6 }}>Account nickname</div>
            <input autoFocus value={nick} onChange={(e) => setNick(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") setEditingNick(false); }}
              style={{ width: "100%", padding: "12px 13px", background: "var(--bg-2)", border: "1px solid var(--accent)", borderRadius: 10, outline: "none", fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 600, color: "var(--ink)" }} />
            <button className="press" onClick={() => setEditingNick(false)} style={{ width: "100%", marginTop: 14, padding: "12px", background: "var(--accent)", border: "none", borderRadius: 10, fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, cursor: "pointer", color: "var(--accent-ink)" }}>Save</button>
          </div>
        </div>
      </>}

      {/* tab toggle */}
      <div style={{ flex: "none", padding: "0 18px 4px" }}>
        <Segmented options={[{ value: "holdings", label: "Holdings" }, { value: "transactions", label: "Transactions" }]} value={tab} onChange={setTab} />
      </div>

      {tab === "holdings" ?
      <>
          <div style={{ flex: "none" }}>
            <AcctToolbar q={hq} setQ={setHq} placeholder="Search holdings" filter={hf} setFilter={setHf}
          filters={hFilters} />
          </div>
          <div className="scroll" style={{ paddingTop: 6 }}>
            <HoldingsTable holdings={shownHoldings} total={total} nav={nav} />
            <div style={{ height: 24 }} />
          </div>
        </> :

      <>
          <div style={{ flex: "none" }}>
            <AcctToolbar q={tq} setQ={setTq} placeholder="Search transactions" filter={tf} setFilter={setTf}
          filters={[["all", "All"], ["buys", "Buys"], ["sells", "Sells"], ["div", "Dividends"]]} />
          </div>
          <div className="scroll" style={{ paddingTop: 6 }}>
            {shownTxns.length ? shownTxns.map((t, i) => <AcctTxnRow key={t.id} t={t} last={i === shownTxns.length - 1} />) :
          <div style={{ padding: "26px 18px", textAlign: "center", fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>No transactions match.</div>}
            <div style={{ height: 24 }} />
          </div>
        </>
      }
    </div>);

};


Object.assign(window, { Accounts, AccountsExternalPanel, HoldingDetail, AccountDetail, ACCOUNTS, ALL_HOLDINGS_ACCT });