/* move.jsx, "Move money": the full money-movement hub and every rail Yoshi
   offers, replacing the old peer-to-peer transfer flow.

   Hub lists the rails; each opens a self-contained sub-flow:
     · between        Yoshi ↔ Yoshi book transfer (instant, free)
     · bank           ACH in/out of a linked external bank (push & pull)
     · wire           same-day domestic wire
     · check          mobile check deposit
     · instant        cash out to a debit card in seconds
     · directdeposit  account + routing numbers, pre-filled form
     · recurring      schedule a repeating move
     · billpay        pay a card, rent, or utility

   Exported as TransferFlow (overrides the stub in transfer.jsx). */

/* ---------- data ----------------------------------------------------------- */
const YOSHI_ACCTS = [
  { id: "cash",   name: "Cash",      sub: "Yoshi ••8841 · 4.80% APY", bal: 82420.55 },
  { id: "broker", name: "Brokerage", sub: "Yoshi ••3392 · Individual", bal: 5120.00 },
];
const EXT_ACCTS = [
  { id: "chase", bank: "Chase",           sub: "Checking ••4471", glyph: "C", bal: 7682.97, synced: "1 hour ago" },
  { id: "boa",   bank: "Bank of America", sub: "Savings ••8830",  glyph: "B", bal: 14920.40, synced: "Today" },
];
const DEBIT_CARDS = [
  { id: "visa", bank: "Visa debit", sub: "Chase ••2291", glyph: "VISA" },
];
const WIRE_RECIPIENTS = [
  { id: "title", name: "Bay Area Title Co.", sub: "Wells Fargo · ••5567" },
  { id: "landlord", name: "Ridgeline Property Mgmt", sub: "Chase · ••1180" },
];
const PAYEES = [
  { id: "sapphire", name: "Chase Sapphire", sub: "Credit card ••6841", amt: 3210.44, debt: true, min: 64.00 },
  { id: "rent",     name: "Oakwood Property", sub: "Rent · ACH ••2031", amt: 2450.00 },
  { id: "pge",      name: "Pacific Gas & Electric", sub: "Utility ••5520", amt: 142.18 },
];
/* deterministic "last pulled" time per payee — biller balances are fetched
   on different schedules, so the label varies by payee but stays stable. */
const PULL_TIMES = ["6 hours ago", "2 hours ago", "40 minutes ago", "3 hours ago", "yesterday", "1 hour ago", "9 hours ago"];
const pulledAgo = (id) => { let h = 0; for (const c of String(id)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return PULL_TIMES[h % PULL_TIMES.length]; };

const QUICK_ACTIONS = [
  { id: "bank",  icon: "swap",  name: "Transfer cash" },
];
/* The rail list below the primary Transfer tile. ACATS ("Transfer account")
   now lives here, in the same format as the other rails. */
const RAILS_MORE = [
  { id: "directdeposit", icon: "download", name: "Direct deposit",     sub: "Land your paycheck here" },
  { id: "acats",         icon: "trade",    name: "Transfer account",   sub: "Move a brokerage account" },
  { id: "billpay",       icon: "doc",      name: "Pay a bill",         sub: "Cards, rent, utilities" },
  { id: "check",         icon: "receipt",  name: "Deposit a check",    sub: "Take a picture of your paper check" },
  { id: "recurring",     icon: "clock",    name: "Recurring transfer", sub: "On a set schedule" },
];

/* ---------- shared bits ---------------------------------------------------- */

/* masked account number with tap-to-reveal toggle */
const MaskedAccount = ({ full, masked }) => {
  const [revealed, setRevealed] = useState(false);
  return (
    <span onClick={() => setRevealed(!revealed)} style={{ cursor: "pointer", fontFamily: "var(--f-mono)", letterSpacing: "0.02em", userSelect: "none" }}>
      {revealed ? full : masked}
    </span>
  );
};

const fmtAmt = (amt) => amt === "" ? "0" : amt;

/* format a raw amount string ("1234.5") with thousands separators for display,
   preserving a trailing "." and any in-progress decimals the user is typing */
const commaAmt = (raw) => {
  if (raw === "" || raw == null) return "";
  const neg = raw[0] === "-" ? "-" : "";
  const [intPart, ...rest] = raw.replace(/^-/, "").split(".");
  const grouped = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return neg + (rest.length ? grouped + "." + rest.join("") : grouped);
};

const useAmount = (initial = "") => {
  const [amt, setAmt] = useState(initial);
  const onKey = (k) => setAmt(p => {
    if (k === "⌫") return p.slice(0, -1);
    if (k === "." && p.includes(".")) return p;
    if (p.includes(".") && p.split(".")[1].length >= 2) return p;
    if (p === "" && k === ".") return "0.";
    if (p === "0" && k !== ".") return k;
    return p + k;
  });
  return [amt, setAmt, onKey, parseFloat(amt || "0")];
};

const MvKeypad = ({ onKey }) => (
  <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 1, background: "var(--rule)" }}>
    {["1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "⌫"].map(k => (
      <button key={k} className="press" onClick={() => onKey(k)} style={{ padding: "15px 0", background: "var(--bg)", border: "none", fontFamily: "var(--f-display)", fontSize: 22, fontWeight: 500, color: "var(--ink)", cursor: "pointer" }}>{k}</button>
    ))}
  </div>
);

/* slide-up number-pad sheet · mirrors a native mobile numeric keyboard.
   Opens when an inline amount field is tapped; the field stays read-only so
   the device keyboard never appears. */
const KeypadSheet = ({ open, onClose, amt, amtNum, onKey, label, sub, onMax, error, ctaLabel = "Done" }) => {
  if (!open) return null;
  return (
    <>
      <div onClick={onClose} 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", display: "flex", flexDirection: "column", animation: "sheet-in 300ms cubic-bezier(0.16,1,0.30,1) both", boxShadow: "0 -16px 40px -20px rgba(0,0,0,0.4)" }}>
        <div style={{ display: "flex", justifyContent: "center", paddingTop: 8, flex: "none" }}><span style={{ width: 36, height: 4, background: "var(--rule-2)", borderRadius: 999 }} /></div>

        <div style={{ flex: "none", padding: "14px 20px 8px", display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 12 }}>
          <div style={{ minWidth: 0 }}>
            {label && <Eyebrow style={{ marginBottom: 6 }}>{label}</Eyebrow>}
            <div style={{ display: "flex", alignItems: "baseline" }}>
              <span style={{ fontFamily: "var(--f-mono)", fontSize: 28, fontWeight: 500, color: amtNum ? "var(--ink-2)" : "var(--rule-2)", lineHeight: 1 }}>$</span>
              <span style={{ fontFamily: "var(--f-mono)", fontSize: 40, fontWeight: 500, letterSpacing: "-0.02em", color: amtNum ? "var(--ink)" : "var(--rule-2)", fontVariantNumeric: "tabular-nums", lineHeight: 1, marginLeft: 2 }}>{amt === "" ? "0" : commaAmt(amt)}</span>
            </div>
            {(error || sub) && <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: error ? "var(--signal-neg)" : "var(--ink-3)", marginTop: 7 }}>{error || sub}</div>}
          </div>
          {onMax && <button className="press" onClick={onMax} style={{ flex: "none", padding: "7px 14px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600, color: "var(--ink)", cursor: "pointer" }}>Max</button>}
        </div>

        <MvKeypad onKey={onKey} />
        <div style={{ padding: "12px 18px", paddingBottom: "max(18px, env(safe-area-inset-bottom))", flex: "none" }}>
          <Btn full disabled={!!error} onClick={onClose}>{ctaLabel}</Btn>
        </div>
      </div>
    </>
  );
};

const MoveSuccess = ({ title, sub, onDone }) => (
  <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "0 28px", textAlign: "center" }}>
    <div style={{ width: 200, margin: "0 0 26px" }}><Seam draw /></div>
    <div style={{ width: 70, height: 70, borderRadius: 999, border: "1.5px solid var(--accent)", display: "grid", placeItems: "center", marginBottom: 20 }}>
      <svg width="36" height="36" viewBox="0 0 24 24" style={{ display: "block" }}>
        <path d="M5 12.5 L10 17.5 L19 6.5" fill="none" stroke="var(--accent)" strokeWidth="2.2" strokeLinecap="square" />
      </svg>
    </div>
    <Eyebrow color="var(--accent)">Done</Eyebrow>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 24, fontWeight: 600, letterSpacing: "-0.025em", marginTop: 7 }}>{title}</div>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, color: "var(--ink-2)", marginTop: 8, lineHeight: 1.5, maxWidth: 290 }}>{sub}</div>
    <div style={{ width: "100%", maxWidth: 320, marginTop: 26 }}><Btn full onClick={onDone}>Back to home</Btn></div>
  </div>
);

// amount-entry screen body: big number + context + keypad + CTA
const AmountBody = ({ context, amt, amtNum, onKey, info, error, ctaLabel, onCta, ctaDisabled, note }) => (
  <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
    <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "12px 24px" }}>
      {context}
      <div style={{ display: "flex", alignItems: "baseline", marginTop: 12 }}>
        <span style={{ fontFamily: "var(--f-mono)", fontSize: 30, fontWeight: 500, color: amtNum ? "var(--ink-3)" : "var(--rule-2)" }}>$</span>
        <span style={{ fontFamily: "var(--f-mono)", fontSize: 52, fontWeight: 500, color: amtNum ? "var(--ink)" : "var(--rule-2)", letterSpacing: "-0.02em", fontVariantNumeric: "tabular-nums" }}>{fmtAmt(amt)}</span>
      </div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: error ? "var(--signal-neg)" : "var(--ink-3)", marginTop: 12, textAlign: "center", lineHeight: 1.45, minHeight: 16 }}>
        {error || info}
      </div>
    </div>
    <div style={{ flex: "none" }}>
      <MvKeypad onKey={onKey} />
      <div style={{ padding: "12px 18px 28px" }}>
        <Btn full disabled={ctaDisabled} onClick={onCta}>{ctaLabel} <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn>
        {note && <div style={{ fontFamily: "var(--f-display)", fontSize: 9.5, color: "color-mix(in srgb, var(--ink-3) 62%, transparent)", textAlign: "center", marginTop: 9, lineHeight: 1.4 }}>{note}</div>}
      </div>
    </div>
  </div>
);

const ReviewRow = ({ label, value, sub, accent, last }) => (
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 12, padding: "12px 14px", borderBottom: last ? "none" : "1px dashed var(--rule)" }}>
    <span style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)", flex: "none" }}>{label}</span>
    <div style={{ textAlign: "right", minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 500, color: accent || "var(--ink)" }}>{value}</div>
      {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>}
    </div>
  </div>
);

const ReviewScreen = ({ eyebrow, amt, rows, cta, onCta, footerNote }) => {
  const [gate, setGate] = useState(false);
  return (
  <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
    <div className="scroll" style={{ padding: "10px 20px" }}>
      <Eyebrow>{eyebrow}</Eyebrow>
      {amt != null && <div style={{ marginTop: 6 }}><Money value={amt} size={40} weight={500} /></div>}
      <div style={{ marginTop: amt != null ? 18 : 12, border: "1px solid var(--rule)" }}>{rows}</div>
      {footerNote && (
        <div style={{ display: "flex", gap: 8, marginTop: 12, padding: "10px 12px", background: "var(--bg-2)", alignItems: "center" }}>
          <Icon name="shield" size={16} color="var(--ink-3)" stroke={1.5} />
          <span style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", lineHeight: 1.45 }}>{footerNote}</span>
        </div>
      )}
    </div>
    <div style={{ flex: "none", padding: "0 20px" }}><Seam style={{ marginBottom: 12 }} /></div>
    <div style={{ flex: "none", padding: "0 20px 30px" }}><Btn full onClick={() => setGate(true)}>{cta}</Btn></div>
    {gate && <PasskeyGate title={eyebrow} amount={amt} detail="Use your passkey to authorize this transfer. Yoshi moves it immediately after." cta="Authorize with passkey" onSuccess={() => { setGate(false); onCta(); }} onCancel={() => setGate(false)} />}
  </div>
  );
};

// a selectable account / option row used across flows
const PickRow = ({ glyph, glyphColor, accent, name, sub, right, selected, onClick, last }) => (
  <button className="press" onClick={onClick} style={{
    width: "100%", display: "grid", gridTemplateColumns: glyph ? "38px 1fr auto" : "1fr auto", gap: 12, alignItems: "center",
    padding: "12px 16px", background: selected ? "var(--bg-2)" : "var(--bg-card)", border: "none",
    borderBottom: last ? "none" : "1px solid var(--rule)", textAlign: "left", cursor: "pointer",
    boxShadow: selected ? "inset 2px 0 0 var(--accent)" : "none",
  }}>
    {glyph && (
      <span style={{ width: 38, height: 38, display: "grid", placeItems: "center", background: accent ? "var(--accent)" : "var(--ink)", color: accent ? "var(--accent-ink)" : "var(--bg-card)", fontFamily: "var(--f-display)", fontSize: glyph.length > 2 ? 9 : 15, fontWeight: 700, letterSpacing: glyph.length > 2 ? "0.04em" : 0 }}>{glyph}</span>
    )}
    <div style={{ minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{name}</div>
      {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{sub}</div>}
    </div>
    {right !== undefined ? right : <Icon name={selected ? "check" : "back"} size={16} stroke={selected ? 2.2 : 1.5} color={selected ? "var(--accent)" : "var(--ink-3)"} style={selected ? {} : { transform: "scaleX(-1)" }} />}
  </button>
);

const SectionLabel = ({ children, style }) => (
  <div style={{ padding: "16px 18px 7px", ...style }}><Eyebrow>{children}</Eyebrow></div>
);

// shared chrome for a rail screen
const RailScreen = ({ title, sub, onBack, onClose, children, left, padX }) => (
  <div className="push-enter" style={{ position: "absolute", inset: 0, background: "var(--bg)", display: "flex", flexDirection: "column", zIndex: 2 }}>
    {window.StatusBar && <window.StatusBar />}
    {window.__YOSHI_WEB && <div style={{ height: 16, flex: "none" }} />}
    <NavBar padX={padX} title={window.__YOSHI_WEB ? <span style={{ fontFamily: "var(--f-display)", fontSize: 21, fontWeight: 700, letterSpacing: "-0.025em" }}>{title}</span> : title} sub={sub} onBack={onBack} left={left} border={!window.__YOSHI_WEB}
      right={<button className="press" onClick={onClose} style={{ background: "none", border: "none", color: "var(--ink-3)", display: "flex" }}><Icon name="close" size={20} /></button>} />
    {children}
  </div>
);

/* ========================================================================== *
   The hub + router
 * ========================================================================== */
const TransferFlow = ({ onClose, preset, nav, flash, intent, initialRail }) => {
  const [rail, setRail] = useState(initialRail || null);
  const back = () => setRail(null);
  const f = flash || (() => {});

  const askAuto = () => {
    onClose();
    nav.ask("Help me set up an automation.",
      "Love it. Tell me the rule in plain words, like “sweep anything over $20k in Checking into Savings” or “buy $500 of VTI every payday”, and I’ll set it up as a standing automation, inside the caps you’ve set. You approve it once, then it runs on its own and you can pause it anytime.");
  };
  const askRecurring = () => {
    onClose();
    nav.ask("Set up a recurring transfer.",
      "Happy to. Tell me the move in plain words, like “transfer $500 from Chase to Cash every payday” or “send $1,000 to Savings on the 1st”, and I’ll set it up as a standing automation you approve once. It runs on its own inside your caps, and you can pause it anytime.");
  };
  const open = (id) => {
    if (id === "automation") return askAuto();
    if (id === "recurring") return askRecurring();
    setRail(id);
  };

  const railProps = { onBack: back, onClose, nav, flash: f, preset, switchRail: open };

  return (
    <div style={{ position: "absolute", inset: 0, zIndex: 320, background: "var(--bg)" }} data-screen-label="Transfer">
      {/* the cash-transfer screen is the landing page; the other rails sit below Confirm */}
      <BankFlow root onClose={onClose} nav={nav} flash={f} preset={preset}
        initialDir={intent === "withdraw" ? "out" : "in"}
        railsFooter={RAILS_MORE.map((r, i) => <RailRow key={r.id} r={r} onClick={() => open(r.id)} last={i === RAILS_MORE.length - 1} />)} />

      {rail === "wire" && <WireFlow {...railProps} />}
      {rail === "check" && <CheckFlow {...railProps} />}
      {rail === "sendcheck" && <CheckPayFlow {...railProps} />}
      {rail === "instant" && <InstantFlow {...railProps} />}
      {rail === "acats" && <AccountTransferFlow {...railProps} />}
      {rail === "directdeposit" && <DirectDepositFlow {...railProps} />}
      {rail === "recurring" && <RecurringFlow {...railProps} />}
      {rail === "billpay" && <BillPayFlow {...railProps} />}
    </div>
  );
};

const RailRow = ({ r, onClick, last }) => (
  <button className="press" onClick={onClick} style={{
    width: "100%", display: "grid", gridTemplateColumns: "26px 1fr auto", gap: 15, alignItems: "center",
    padding: "15px 18px", background: "none", border: "none", borderBottom: last ? "none" : "1px solid var(--rule)", textAlign: "left", cursor: "pointer",
  }}>
    <Icon name={r.icon} size={22} stroke={1.5} color="var(--ink)" />
    <div style={{ minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 14.5, fontWeight: 500 }}>{r.name}</div>
      {r.promo && <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, fontWeight: 600, color: "var(--accent-pos)", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.promo}</div>}
      {r.sub && <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.sub}</div>}
    </div>
    <Icon name="back" size={15} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
  </button>
);

/* ---------- an inline account selector (collapsed row → expandable list) --- */
const InlineSelect = ({ label, options, value, onChange, balances }) => {
  const [open, setOpen] = useState(false);
  const sel = options.find(o => o.id === value) || options[0];
  return (
    <div style={{ border: "1px solid var(--rule)" }}>
      <button className="press" onClick={() => setOpen(o => !o)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "12px 14px", background: "var(--bg-card)", border: "none", cursor: "pointer", textAlign: "left" }}>
        <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)", width: 38, flex: "none" }}>{label}</span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600 }}>{sel.name}</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>{sel.sub}</div>
        </div>
        {balances && <Money value={sel.bal} size={11.5} color="var(--ink-3)" />}
        <Icon name={open ? "up" : "down"} size={15} color="var(--ink-3)" />
      </button>
      {open && (
        <div style={{ borderTop: "1px solid var(--rule)" }}>
          {options.map(o => (
            <PickRow key={o.id} name={o.name} sub={o.sub} selected={o.id === value}
              right={balances ? <Money value={o.bal} size={11} color="var(--ink-3)" /> : undefined}
              onClick={() => { onChange(o.id); setOpen(false); }} last />
          ))}
        </div>
      )}
    </div>
  );
};

/* ========================================================================== *
   1 · Between your accounts, instant book transfer
 * ========================================================================== */
const BetweenFlow = ({ onBack, onClose, preset }) => {
  const [step, setStep] = useState("setup");
  const [fromId, setFromId] = useState(YOSHI_ACCTS.find(a => a.id === preset) ? preset : "cash");
  const [toId, setToId] = useState("broker");
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const from = YOSHI_ACCTS.find(a => a.id === fromId);
  const to = YOSHI_ACCTS.find(a => a.id === toId);
  const over = amtNum > from.bal;

  // keep from/to distinct
  const setFrom = (id) => { setFromId(id); if (id === toId) setToId(YOSHI_ACCTS.find(a => a.id !== id).id); };
  const setTo = (id) => { setToId(id); if (id === fromId) setFromId(YOSHI_ACCTS.find(a => a.id !== id).id); };
  const swap = () => { setFromId(toId); setToId(fromId); };

  return (
    <RailScreen title="Between accounts" onBack={step === "setup" ? onBack : () => setStep(step === "review" ? "amount" : "setup")} onClose={onClose}>
      {step === "setup" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <div className="scroll" style={{ padding: "14px 18px" }}>
            <InlineSelect label="From" options={YOSHI_ACCTS} value={fromId} onChange={setFrom} balances />
            <div style={{ display: "flex", justifyContent: "center", margin: "-1px 0" }}>
              <button className="press" onClick={swap} style={{ width: 34, height: 34, borderRadius: 999, background: "var(--bg-2)", border: "1px solid var(--rule-2)", display: "grid", placeItems: "center", cursor: "pointer", zIndex: 1 }}>
                <Icon name="swap" size={16} color="var(--ink)" />
              </button>
            </div>
            <InlineSelect label="To" options={YOSHI_ACCTS} value={toId} onChange={setTo} balances />
            <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 14, padding: "10px 12px", background: "var(--bg-2)" }}>
              <Icon name="bolt" size={15} color="var(--accent)" />
              <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-2)" }}>Instant and free between your Yoshi accounts.</span>
            </div>
          </div>
          <div style={{ flex: "none", padding: "0 18px 30px" }}><Btn full onClick={() => setStep("amount")}>Enter amount <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn></div>
        </div>
      )}
      {step === "amount" && (
        <AmountBody amt={amt} amtNum={amtNum} onKey={onKey}
          context={<div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>{from.name} → <span style={{ color: "var(--ink)", fontWeight: 600 }}>{to.name}</span></div>}
          info={`${usd(from.bal)} available in ${from.name}`} error={over ? "Exceeds available balance" : null}
          ctaLabel="Review" ctaDisabled={!amtNum || over} onCta={() => setStep("review")} />
      )}
      {step === "review" && (
        <ReviewScreen eyebrow="You're moving" amt={amtNum} cta="Confirm · Passkey" onCta={() => setStep("done")}
          footerNote="Authorized by you. Yoshi moves it instantly between your accounts."
          rows={<>
            <ReviewRow label="From" value={from.name} sub={from.sub} />
            <ReviewRow label="To" value={to.name} sub={to.sub} />
            <ReviewRow label="Arrives" value="Instantly" accent="var(--accent-pos)" />
            <ReviewRow label="Fee" value="$0.00" last />
          </>} />
      )}
      {step === "done" && <MoveSuccess title={`${usd(amtNum)} moved`} sub={`From ${from.name} to ${to.name}, instantly. It's in your stream.`} onDone={onClose} />}
    </RailScreen>
  );
};

/* ========================================================================== *
   2 · Bank transfer · single-screen From → To, like a wire form
 * ========================================================================== */
const BankFlow = ({ onBack, onClose, preset, initialDir, root, railsFooter, nav }) => {
  // two-column form + "more ways" rail on wide web windows only
  const web = window.__YOSHI_WEB && window.innerWidth >= 1100;
  const [dir, setDir] = useState(initialDir || "in");
  const [extId, setExtId] = useState(EXT_ACCTS[0].id);
  const [gate, setGate] = useState(false);
  const [pickExt, setPickExt] = useState(false);
  const [linking, setLinking] = useState(false);
  const [speed, setSpeed] = useState("standard");
  const [pickSpeed, setPickSpeed] = useState(false);
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const [padOpen, setPadOpen] = useState(false);
  const [done, setDone] = useState(false);

  const ext = EXT_ACCTS.find(a => a.id === extId);
  const yo = YOSHI_ACCTS.find(a => a.id === "cash");
  const into = dir === "in";                     // deposit: external → Yoshi Cash
  const fromBal = into ? ext.bal : yo.bal;
  const over = amtNum > fromBal;
  const fee = speed === "wire" ? 15 : speed === "instant" && !into ? Math.max(0.25, amtNum * 0.015) : 0;
  const arrival = speed === "wire" ? "Same-day · by 2pm PT" : speed === "instant" ? "In seconds" : "1–3 business days";
  const arrivalPlain = speed === "wire" ? "the same day if sent by 2pm PT" : speed === "instant" ? "in seconds" : "in 1–3 business days";
  const extLabel = `${ext.bank} ${ext.sub}`;
  const yoLabel = `Yoshi ${yo.name} ${yo.sub.split(" ")[1] || ""}`;
  const speedLabel = speed === "wire" ? "Wire" : speed === "instant" ? "Instant" : "Standard";

  if (linking) return <AddExternal onBack={() => setLinking(false)} onClose={onClose} onSaved={() => setLinking(false)} />;
  if (done) return (
    <RailScreen padX={web ? 64 : 16} title={root ? "Transfer" : into ? "Deposit" : "Withdraw"} onBack={root ? undefined : onBack} onClose={onClose} left={root && !window.__YOSHI_WEB ? <YouButton nav={nav} /> : undefined}>
      <MoveSuccess title={`${usd(amtNum)} ${into ? "on the way in" : "sent"}`} sub={`${into ? ext.bank : yo.name} → ${into ? yo.name : ext.bank}. ${arrival}. We'll post it to your stream when it settles.`} onDone={onClose} />
    </RailScreen>
  );

  // one account slot · Yoshi Cash is fixed; the external account is a dropdown
  const AccountCard = ({ yoshi }) => (
    <div style={{ position: "relative", zIndex: pickExt && !yoshi ? 6 : 1 }}>
      <button className="press" onClick={yoshi ? undefined : () => setPickExt(o => !o)} style={{
        width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 14px",
        background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, cursor: yoshi ? "default" : "pointer", textAlign: "left"
      }}>
        <span style={{ width: 36, height: 36, flex: "none", display: "grid", placeItems: "center",
          background: "var(--bg-2)", color: "var(--ink)", fontFamily: "var(--f-display)", fontWeight: 700, fontSize: 15 }}>
          {yoshi ? <Logo size={20} /> : ext.glyph}
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{yoshi ? "Cash" : ext.bank}</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{yoshi ? "Yoshi · 4.80% APY" : ext.sub}</div>
        </div>
        <div style={{ textAlign: "right", flex: "none" }}>
          <div style={{ fontFamily: "var(--f-mono)", fontSize: 13.5, fontVariantNumeric: "tabular-nums" }}>{usd(yoshi ? yo.bal : ext.bal)}</div>
          {!yoshi && <div style={{ fontFamily: "var(--f-display)", fontSize: 10.5, color: "var(--ink-3)", marginTop: 3 }}>{ext.synced}</div>}
        </div>
        {!yoshi && <Icon name="down" size={16} color="var(--ink-3)" style={{ flex: "none" }} />}
      </button>
      {!yoshi && pickExt && (
        <div style={{ position: "absolute", left: 0, right: 0, top: "calc(100% + 4px)", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, boxShadow: "0 14px 30px -14px rgba(0,0,0,0.35)", overflow: "hidden" }}>
          {EXT_ACCTS.map((a, i) => (
            <button key={a.id} className="press" onClick={() => { setExtId(a.id); setPickExt(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: a.id === extId ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
              <span style={{ width: 30, height: 30, flex: "none", border: "1px solid var(--rule-2)", color: "var(--ink)", display: "grid", placeItems: "center", fontFamily: "var(--f-display)", fontWeight: 700, fontSize: 13 }}>{a.glyph}</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{a.bank}</div>
                <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>{a.sub}</div>
              </div>
              <span style={{ fontFamily: "var(--f-mono)", fontSize: 12, color: "var(--ink-3)" }}>{usd(a.bal)}</span>
            </button>
          ))}
          <button className="press" onClick={() => { setPickExt(false); setLinking(true); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
            <span style={{ width: 30, height: 30, flex: "none", border: "1px dashed var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="plus" size={15} color="var(--ink-2)" /></span>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 500 }}>Link a new bank</span>
          </button>
        </div>
      )}
    </div>
  );

  return (
    <RailScreen padX={web ? 64 : 16} title={root ? "Transfer" : into ? "Deposit" : "Withdraw"} onBack={root ? undefined : onBack} onClose={onClose} left={root && !window.__YOSHI_WEB ? <YouButton nav={nav} /> : undefined}>
      <div className="scroll" style={{ padding: web ? "20px 64px 28px" : "16px 18px 28px" }}>
        <div style={web ? { display: "grid", gridTemplateColumns: "repeat(2, minmax(280px, 1fr))", gap: 40, alignItems: "start" } : undefined}>
        <div>
        <Eyebrow style={{ marginBottom: 7 }}>From</Eyebrow>
        <AccountCard yoshi={!into} />

        <div style={{ position: "relative", height: 22, margin: "12px 0 7px" }}>
          <Eyebrow style={{ position: "absolute", left: 0, top: 4 }}>To</Eyebrow>
          <button className="press" onClick={() => { setDir(into ? "out" : "in"); setPickExt(false); }} aria-label="Switch direction" style={{ position: "absolute", left: "50%", top: -3, transform: "translateX(-50%)", background: "none", border: "none", padding: 6, display: "grid", placeItems: "center", cursor: "pointer" }}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
              <path d="M8.5 4 V19 M8.5 19 L5.5 16 M8.5 19 L11.5 16" />
              <path d="M15.5 20 V5 M15.5 5 L12.5 8 M15.5 5 L18.5 8" />
            </svg>
          </button>
        </div>
        <AccountCard yoshi={into} />

        <Eyebrow style={{ margin: "18px 0 7px" }}>Amount <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--ink-3)", fontWeight: 500 }}>({usd(fromBal)} available)</span></Eyebrow>
        <div onClick={() => setPadOpen(true)} style={{ display: "flex", alignItems: "center", gap: 9, minHeight: 50, padding: "0 14px", background: "var(--bg-card)", border: `1px solid ${over ? "var(--signal-neg)" : "var(--rule-2)"}`, borderRadius: 12, cursor: "pointer" }}>
          <span style={{ fontFamily: "var(--f-mono)", fontSize: 18, color: amtNum ? "var(--ink-3)" : "var(--rule-2)" }}>$</span>
          <input readOnly inputMode="none" value={amt === "" ? "" : commaAmt(amt)} onFocus={() => setPadOpen(true)} placeholder="Enter amount"
            style={{ flex: 1, minWidth: 0, border: "none", background: "transparent", outline: "none", color: "var(--ink)", fontFamily: "var(--f-mono)", fontSize: 18, fontVariantNumeric: "tabular-nums", cursor: "pointer" }} />
          <button className="press" onClick={(e) => { e.stopPropagation(); setAmt(String(fromBal)); }} style={{ flex: "none", padding: "6px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600, color: "var(--ink)", cursor: "pointer" }}>Max</button>
        </div>
        {over && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--signal-neg)", marginTop: 6 }}>Exceeds available balance</div>}

        <Eyebrow style={{ margin: "18px 0 7px" }}>Delivery</Eyebrow>
        <div style={{ border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden", background: "var(--bg-card)" }}>
          <button className="press" onClick={() => setPickSpeed(o => !o)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, minHeight: 50, padding: "0 14px", background: "var(--bg-card)", border: "none", cursor: "pointer", textAlign: "left" }}>
            <div style={{ flex: 1 }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600 }}>{speedLabel}</span>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 12, color: "var(--ink-3)", marginLeft: 7 }}>{speed === "wire" ? "Same-day" : speed === "instant" ? "In seconds" : "1–3 days"}</span>
            </div>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 12.5, color: fee ? "var(--ink-2)" : "var(--accent-pos)" }}>{fee ? usd(fee) : "Free"}</span>
            <Icon name={pickSpeed ? "up" : "down"} size={15} color="var(--ink-3)" style={{ flex: "none" }} />
          </button>
          {pickSpeed && (
            <div style={{ borderTop: "1px solid var(--rule)" }}>
              <SpeedCard on={speed === "standard"} onClick={() => { setSpeed("standard"); setPickSpeed(false); }} title="Standard" sub="1–3 business days" fee="Free" />
              <SpeedCard on={speed === "instant"} onClick={() => { setSpeed("instant"); setPickSpeed(false); }} title="Instant" sub="Arrives in seconds" fee={into ? "Free" : "1.5% fee"} />
              <SpeedCard on={speed === "wire"} onClick={() => { setSpeed("wire"); setPickSpeed(false); }} title="Wire" sub="Same-day domestic" fee="$15" last />
            </div>
          )}
        </div>

        <div style={{ marginTop: 22 }}>
          <Seam style={{ marginBottom: 16 }} />
          <Btn full disabled={!amtNum || over} onClick={() => setGate(true)}>Continue</Btn>
        </div>
        {gate && <PasskeyGate title={into ? "Deposit" : "Withdraw"} amount={amtNum} detail={into ? "Funds leave your bank account within the next 1–5 business days." : "Funds arrive in your bank account within the next 1–5 business days."} cta="Authorize with passkey" onSuccess={() => { setGate(false); setDone(true); }} onCancel={() => setGate(false)} />}

        </div>

        {/* other ways to move money — stacked on phone, a right rail on web */}
        {railsFooter && (web ? (
          <div style={{ borderLeft: "1px solid var(--rule)", paddingLeft: 28, alignSelf: "stretch", display: "flex", flexDirection: "column" }}>
            <div style={{ padding: "2px 0 10px" }}><Eyebrow>More ways to move money</Eyebrow></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>{railsFooter}</div>
          </div>
        ) : (
          <div style={{ margin: "26px -18px 0", borderTop: "1px solid var(--rule)" }}>
            <div style={{ padding: "16px 18px 4px" }}><Eyebrow>More ways to move money</Eyebrow></div>
            {railsFooter}
          </div>
        ))}
        </div>
      </div>
      <KeypadSheet open={padOpen} onClose={() => setPadOpen(false)} amt={amt} amtNum={amtNum} onKey={onKey}
        label="Amount" sub={over ? null : `${usd(fromBal)} available`} error={over ? "Exceeds available balance" : null}
        onMax={() => setAmt(String(fromBal))} ctaLabel="Done" />
    </RailScreen>
  );
};

const TapCard = ({ icon, title, sub, onClick }) => (
  <button className="press" onClick={onClick} style={{ display: "flex", alignItems: "center", gap: 13, padding: "15px 15px", background: "var(--bg-card)", border: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
    <span style={{ width: 36, height: 36, flex: "none", borderRadius: 999, background: "var(--bg-2)", display: "grid", placeItems: "center" }}><Icon name={icon} size={18} color="var(--ink)" /></span>
    <div style={{ flex: 1 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 600 }}>{title}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>
    </div>
    <Icon name="back" size={16} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
  </button>
);

const SpeedCard = ({ on, onClick, title, sub, fee, last }) => (
  <button className="press" onClick={onClick} style={{ width: "100%", display: "flex", alignItems: "center", gap: 13, padding: "12px 15px", background: on ? "color-mix(in srgb, var(--accent) 10%, var(--bg-card))" : "var(--bg-card)", border: "none", borderBottom: last ? "none" : "1px solid var(--rule)", boxShadow: on ? "inset 2px 0 0 var(--accent)" : "none", cursor: "pointer", textAlign: "left" }}>
    <div style={{ flex: 1 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 14.5, fontWeight: 600 }}>{title}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>
    </div>
    <span style={{ fontFamily: "var(--f-mono)", fontSize: 12.5, fontWeight: 500, color: fee === "Free" ? "var(--accent-pos)" : "var(--ink-2)" }}>{fee}</span>
  </button>
);

/* ---- add an external account manually (account # + routing) --------------- */
const AddExternal = ({ onBack, onClose, onSaved }) => {
  const [name, setName] = useState("");
  const [acct, setAcct] = useState("");
  const [routing, setRouting] = useState("");
  const valid = name.trim() && acct.trim().length >= 4 && routing.length === 9;
  return (
    <RailScreen title="Link a bank" onBack={onBack} onClose={onClose}>
      <div className="scroll" style={{ padding: "14px 18px" }}>
        <button className="press" onClick={onSaved} style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center", gap: 8, padding: "13px", background: "var(--accent)", border: "none", borderRadius: 10, cursor: "pointer" }}>
          <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, color: "var(--accent-ink)" }}>Connect instantly with Plaid</span>
        </button>
        <div style={{ display: "flex", alignItems: "center", gap: 10, margin: "16px 0" }}>
          <div style={{ flex: 1, height: 1, background: "var(--rule)" }} />
          <span style={{ fontFamily: "var(--f-display)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.06em", textTransform: "uppercase" }}>or enter details</span>
          <div style={{ flex: 1, height: 1, background: "var(--rule)" }} />
        </div>
        <Field label="Account nickname" value={name} onChange={setName} placeholder="e.g. Chase Checking" />
        <Field label="Account number" value={acct} onChange={v => setAcct(v.replace(/\D/g, ""))} placeholder="Account number" mono />
        <Field label="Routing number" value={routing} onChange={v => setRouting(v.replace(/\D/g, "").slice(0, 9))} placeholder="9-digit routing number" mono />
        <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 4, lineHeight: 1.5 }}>We'll send two small deposits to confirm you own this account, usually within one business day.</div>
      </div>
      <div style={{ flex: "none", padding: "0 18px 30px" }}><Btn full disabled={!valid} onClick={onSaved}>Save account</Btn></div>
    </RailScreen>
  );
};

const Field = ({ label, value, onChange, placeholder, mono }) => (
  <div style={{ marginBottom: 13 }}>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 600, color: "var(--ink-2)", marginBottom: 6 }}>{label}</div>
    <input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
      style={{ width: "100%", padding: "12px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", outline: "none", color: "var(--ink)", fontFamily: mono ? "var(--f-mono)" : "var(--f-display)", fontSize: 14 }} />
  </div>
);

/* ========================================================================== *
   3 · Wire transfer
 * ========================================================================== */
const WireFlow = ({ onBack, onClose, preset }) => {
  const [step, setStep] = useState("recipient");
  const [recId, setRecId] = useState(WIRE_RECIPIENTS[0].id);
  const [fromId, setFromId] = useState(preset && YOSHI_ACCTS.find(a => a.id === preset) ? preset : "cash");
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const rec = WIRE_RECIPIENTS.find(r => r.id === recId);
  const from = YOSHI_ACCTS.find(a => a.id === fromId);
  const fee = 15;
  const over = amtNum + fee > from.bal;

  return (
    <RailScreen title="Wire transfer" onBack={step === "recipient" ? onBack : () => setStep(step === "review" ? "amount" : "recipient")} onClose={onClose}>
      {step === "recipient" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <div className="scroll" style={{ padding: "8px 0" }}>
            <SectionLabel style={{ paddingTop: 10 }}>Wire to</SectionLabel>
            <div style={{ borderTop: "1px solid var(--rule)" }}>
              {WIRE_RECIPIENTS.map((r, i) => (
                <PickRow key={r.id} glyph="DOM" name={r.name} sub={r.sub} selected={r.id === recId} onClick={() => setRecId(r.id)} last={i === WIRE_RECIPIENTS.length - 1} />
              ))}
            </div>
            <button className="press" onClick={() => {}} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 18px", background: "none", border: "none", borderBottom: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
              <span style={{ width: 38, height: 38, border: "1px dashed var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="plus" size={18} color="var(--ink-2)" /></span>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>Add a wire recipient</span>
            </button>
            <SectionLabel>Pay from</SectionLabel>
            <div style={{ borderTop: "1px solid var(--rule)" }}>
              {YOSHI_ACCTS.map((a, i) => <PickRow key={a.id} name={a.name} sub={a.sub} right={<Money value={a.bal} size={11} color="var(--ink-3)" />} selected={a.id === fromId} onClick={() => setFromId(a.id)} last={i === YOSHI_ACCTS.length - 1} />)}
            </div>
          </div>
          <div style={{ flex: "none", padding: "12px 18px 30px" }}><Btn full onClick={() => setStep("amount")}>Enter amount <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn></div>
        </div>
      )}
      {step === "amount" && (
        <AmountBody amt={amt} amtNum={amtNum} onKey={onKey}
          context={<div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Wire to <span style={{ color: "var(--ink)", fontWeight: 600 }}>{rec.name}</span></div>}
          info={`Domestic wire · ${usd(fee)} fee · cutoff 2:00pm PT`}
          error={over ? "Amount plus fee exceeds balance" : null}
          ctaLabel="Review" ctaDisabled={!amtNum || over} onCta={() => setStep("review")} />
      )}
      {step === "review" && (
        <ReviewScreen eyebrow="You're wiring" amt={amtNum} cta="Confirm · Passkey" onCta={() => setStep("done")}
          footerNote="Wires are final and can't be reversed once sent. Double-check the recipient details."
          rows={<>
            <ReviewRow label="To" value={rec.name} sub={rec.sub} />
            <ReviewRow label="Type" value="Domestic wire" />
            <ReviewRow label="From" value={from.name} sub={from.sub} />
            <ReviewRow label="Arrives" value="Today, if sent by 2pm PT" accent="var(--accent-pos)" />
            <ReviewRow label="Wire fee" value={usd(fee)} last />
          </>} />
      )}
      {step === "done" && <MoveSuccess title={`${usd(amtNum)} wired`} sub={`To ${rec.name}. Sent same-day on the wire network. The confirmation is in your stream.`} onDone={onClose} />}
    </RailScreen>
  );
};

/* ========================================================================== *
   4 · Deposit a check, mobile capture
 * ========================================================================== */
const CheckFlow = ({ onBack, onClose, nav, switchRail }) => {
  const [step, setStep] = useState("capture");
  const [front, setFront] = useState(false);
  const [bk, setBk] = useState(false);
  const [toId, setToId] = useState("cash");
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const to = YOSHI_ACCTS.find(a => a.id === toId);
  const instant = Math.min(amtNum, 200);

  return (
    <RailScreen title="Deposit a check" onBack={step === "capture" ? onBack : () => setStep(step === "review" ? "amount" : "capture")} onClose={onClose}>
      {step === "capture" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <div className="scroll" style={{ padding: "14px 18px" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)", lineHeight: 1.5, marginBottom: 14 }}>Endorse the back of the check, then capture both sides on a flat, dark surface.</div>
            <CheckCapture label="Front of check" captured={front} onToggle={() => setFront(f => !f)} />
            <div style={{ height: 12 }} />
            <CheckCapture label="Back of check" hint="Sign + “for Yoshi mobile deposit only”" captured={bk} onToggle={() => setBk(b => !b)} />
          </div>
          <div style={{ flex: "none", padding: "0 18px 28px" }}>
            <Btn full disabled={!front || !bk} onClick={() => setStep("amount")}>Enter amount <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn>
            <button className="press" onClick={() => switchRail && switchRail("sendcheck")} style={{ width: "100%", marginTop: 10, padding: "10px 0", background: "none", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 5 }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Want to pay someone with a check?</span>
              <Icon name="back" size={13} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
            </button>
          </div>
        </div>
      )}
      {step === "amount" && (
        <AmountBody amt={amt} amtNum={amtNum} onKey={onKey}
          context={<div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Deposit into <span style={{ color: "var(--ink)", fontWeight: 600 }}>{to.name}</span></div>}
          info="Enter the exact amount written on the check"
          ctaLabel="Review" ctaDisabled={!amtNum} onCta={() => setStep("review")} />
      )}
      {step === "review" && (
        <ReviewScreen eyebrow="You're depositing" amt={amtNum} cta="Submit deposit · Passkey" onCta={() => setStep("done")}
          footerNote="Hold a deposited check until it clears. Funds reverse if the check bounces."
          rows={<>
            <ReviewRow label="Into" value={to.name} sub={to.sub} />
            <ReviewRow label="Front" value="Captured" accent="var(--accent-pos)" />
            <ReviewRow label="Back" value="Captured" accent="var(--accent-pos)" />
            <ReviewRow label="Available now" value={usd(instant)} sub={amtNum > 200 ? `Rest by Jun 2` : "Full amount today"} last />
          </>} />
      )}
      {step === "done" && <MoveSuccess title={`${usd(amtNum)} deposited`} sub={`Into ${to.name}. ${usd(instant)} is available now; the rest clears by Jun 2.`} onDone={onClose} />}
    </RailScreen>
  );
};

const CheckCapture = ({ label, hint, captured, onToggle }) => (
  <button className="press" onClick={onToggle} style={{ width: "100%", border: `1px solid ${captured ? "var(--accent)" : "var(--rule-2)"}`, background: "var(--bg-card)", padding: 0, cursor: "pointer", display: "block", textAlign: "left" }}>
    <div style={{
      height: 120, display: "grid", placeItems: "center",
      background: captured ? "color-mix(in srgb, var(--accent) 9%, var(--bg-2))" : "repeating-linear-gradient(135deg, var(--bg-2) 0 9px, var(--bg-card) 9px 18px)",
    }}>
      {captured
        ? <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }}><span style={{ width: 38, height: 38, borderRadius: 999, border: "1.5px solid var(--accent)", display: "grid", placeItems: "center" }}><Icon name="check" size={20} stroke={2.2} color="var(--accent)" /></span><span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--accent)" }}>captured</span></div>
        : <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 5 }}><Icon name="receipt" size={26} color="var(--ink-3)" /><span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.04em" }}>tap to capture</span></div>}
    </div>
    <div style={{ padding: "9px 12px", borderTop: "1px solid var(--rule)", display: "flex", alignItems: "center", gap: 8 }}>
      <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600 }}>{label}</span>
      {hint && <span style={{ marginLeft: "auto", fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)", textAlign: "right" }}>{hint}</span>}
    </div>
  </button>
);

/* ========================================================================== *
   5 · Instant transfer, cash out to a debit card
 * ========================================================================== */
const InstantFlow = ({ onBack, onClose, preset }) => {
  const [step, setStep] = useState("card");
  const [cardId, setCardId] = useState(DEBIT_CARDS[0].id);
  const [fromId, setFromId] = useState(preset && YOSHI_ACCTS.find(a => a.id === preset) ? preset : "cash");
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const card = DEBIT_CARDS.find(c => c.id === cardId);
  const from = YOSHI_ACCTS.find(a => a.id === fromId);
  const fee = Math.max(0.25, amtNum * 0.015);
  const over = amtNum + fee > from.bal;

  return (
    <RailScreen title="Instant transfer" onBack={step === "card" ? onBack : () => setStep(step === "review" ? "amount" : "card")} onClose={onClose}>
      {step === "card" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <div className="scroll" style={{ padding: "8px 0" }}>
            <SectionLabel style={{ paddingTop: 10 }}>To debit card</SectionLabel>
            <div style={{ borderTop: "1px solid var(--rule)" }}>
              {DEBIT_CARDS.map((c, i) => <PickRow key={c.id} glyph={c.glyph} name={c.bank} sub={c.sub} selected={c.id === cardId} onClick={() => setCardId(c.id)} last={i === DEBIT_CARDS.length - 1} />)}
            </div>
            <button className="press" onClick={() => {}} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 18px", background: "none", border: "none", borderBottom: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
              <span style={{ width: 38, height: 38, border: "1px dashed var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="plus" size={18} color="var(--ink-2)" /></span>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>Add a debit card</span>
            </button>
            <SectionLabel>From</SectionLabel>
            <div style={{ borderTop: "1px solid var(--rule)" }}>
              {YOSHI_ACCTS.map((a, i) => <PickRow key={a.id} name={a.name} sub={a.sub} right={<Money value={a.bal} size={11} color="var(--ink-3)" />} selected={a.id === fromId} onClick={() => setFromId(a.id)} last={i === YOSHI_ACCTS.length - 1} />)}
            </div>
          </div>
          <div style={{ flex: "none", padding: "12px 18px 30px" }}><Btn full onClick={() => setStep("amount")}>Enter amount <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn></div>
        </div>
      )}
      {step === "amount" && (
        <AmountBody amt={amt} amtNum={amtNum} onKey={onKey}
          context={<div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Instant to <span style={{ color: "var(--ink)", fontWeight: 600 }}>{card.bank} {card.sub}</span></div>}
          info={amtNum ? `1.5% fee · ${usd(fee)} · arrives in seconds` : "1.5% fee, $0.25 minimum · arrives in seconds"}
          error={over ? "Amount plus fee exceeds balance" : null}
          ctaLabel="Review" ctaDisabled={!amtNum || over} onCta={() => setStep("review")} />
      )}
      {step === "review" && (
        <ReviewScreen eyebrow="You're sending" amt={amtNum} cta="Confirm · Passkey" onCta={() => setStep("done")}
          footerNote="Instant transfers settle on the card networks and can't be canceled once sent."
          rows={<>
            <ReviewRow label="To" value={`${card.bank} ${card.sub}`} />
            <ReviewRow label="From" value={from.name} sub={from.sub} />
            <ReviewRow label="Arrives" value="In seconds" accent="var(--accent-pos)" />
            <ReviewRow label="Fee" value={`${usd(fee)} · 1.5%`} last />
          </>} />
      )}
      {step === "done" && <MoveSuccess title={`${usd(amtNum)} sent`} sub={`To ${card.bank} ${card.sub}, in seconds. It's in your stream.`} onDone={onClose} />}
    </RailScreen>
  );
};

/* ========================================================================== *
   6 · Direct deposit, account & routing, pre-filled form
 * ========================================================================== */
const DirectDepositFlow = ({ onBack, onClose, flash }) => {
  const ROUTING = "121000358";
  const ACCT = "8841 0023 7790";
  const copy = (label, text) => { try { navigator.clipboard && navigator.clipboard.writeText(text.replace(/\s/g, "")); } catch (e) {} flash(`${label} copied`); };
  return (
    <RailScreen title="Direct deposit" onBack={onBack} onClose={onClose}>
      <div className="scroll" style={{ padding: "14px 18px 24px" }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-2)", lineHeight: 1.5 }}>Send your paycheck, or any direct deposit, straight to your Yoshi Checking. Deposits land up to two days early.</div>

        <Eyebrow style={{ margin: "20px 0 8px" }}>Your account details</Eyebrow>
        <div style={{ border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden" }}>
          <CopyRow label="Account number" value={ACCT} onCopy={() => copy("Account number", ACCT)} />
          <CopyRow label="Routing number" value={ROUTING} onCopy={() => copy("Routing number", ROUTING)} />
          <CopyRow label="Account type" value="Checking" plain last />
        </div>

        <Eyebrow style={{ margin: "20px 0 8px" }}>The easy way</Eyebrow>
        <button className="press" onClick={() => flash("Pre-filled form sent to your email")} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 15px", background: "var(--bg-card)", border: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
          <span style={{ width: 34, height: 34, flex: "none", border: "1px solid var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="doc" size={17} color="var(--ink)" /></span>
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>Email a pre-filled form</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 3 }}>Hand it to payroll, everything's filled in</div>
          </div>
          <Icon name="back" size={15} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
        </button>

        <Eyebrow style={{ margin: "20px 0 8px" }}>Set up with your employer</Eyebrow>
        <div style={{ border: "1px solid var(--rule)" }}>
          {["Gusto", "ADP", "Workday", "Rippling"].map((p, i, arr) => (
            <button key={p} className="press" onClick={() => flash(`Opening ${p} connection`)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "12px 15px", background: "none", border: "none", borderBottom: i === arr.length - 1 ? "none" : "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
              <span style={{ width: 30, height: 30, flex: "none", background: "var(--ink)", color: "var(--bg-card)", display: "grid", placeItems: "center", fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 700 }}>{p[0]}</span>
              <span style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>{p}</span>
              <Icon name="back" size={15} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
            </button>
          ))}
        </div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 36, lineHeight: 1.6 }}>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 bank. Early access to direct deposit depends on when your payer submits it.</div>
      </div>
    </RailScreen>
  );
};

const CopyRow = ({ label, value, onCopy, plain, last }) => {
  const masked = "••" + value.slice(-4);
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderBottom: last ? "none" : "1px dashed var(--rule)" }}>
      <span style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 600, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--ink-3)", flex: 1 }}>{label}</span>
      {plain ? 
        <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>{value}</span> :
        <MaskedAccount full={value} masked={masked} />
      }
      {!plain && <button className="press" onClick={onCopy} aria-label={`Copy ${label}`} style={{ background: "none", border: "none", display: "flex", color: "var(--ink-3)", padding: 2, cursor: "pointer" }}><Icon name="receipt" size={16} /></button>}
    </div>
  );
};

/* ========================================================================== *
   7 · Recurring transfer, schedule a repeating move
 * ========================================================================== */
const RecurringFlow = ({ onBack, onClose, preset, flash }) => {
  const [step, setStep] = useState("setup");
  const [fromId, setFromId] = useState(preset && YOSHI_ACCTS.find(a => a.id === preset) ? preset : "cash");
  const [toId, setToId] = useState("broker");
  const [freq, setFreq] = useState("monthly");
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const from = YOSHI_ACCTS.find(a => a.id === fromId);
  const to = YOSHI_ACCTS.find(a => a.id === toId);
  const FREQ = { weekly: "Every Friday", biweekly: "Every other Friday", monthly: "On the 1st" };
  const setFrom = (id) => { setFromId(id); if (id === toId) setToId(YOSHI_ACCTS.find(a => a.id !== id).id); };
  const setTo = (id) => { setToId(id); if (id === fromId) setFromId(YOSHI_ACCTS.find(a => a.id !== id).id); };

  return (
    <RailScreen title="Recurring transfer" onBack={step === "setup" ? onBack : () => setStep(step === "review" ? "amount" : "setup")} onClose={onClose}>
      {step === "setup" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <div className="scroll" style={{ padding: "14px 18px" }}>
            <div style={{ display: "flex", gap: 9, padding: "11px 13px", marginBottom: 14, background: "color-mix(in srgb, var(--accent) 10%, var(--bg-card))", border: "1px solid var(--accent)", alignItems: "flex-start" }}>
              <Icon name="bolt" size={16} color="var(--accent)" style={{ marginTop: 1 }} />
              <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-2)", lineHeight: 1.5 }}>This creates a <span style={{ fontWeight: 600, color: "var(--ink)" }}>Yoshi automation</span>, a standing rule that runs on its own. You can pause or change it anytime from your automations.</span>
            </div>
            <InlineSelect label="From" options={YOSHI_ACCTS} value={fromId} onChange={setFrom} balances />
            <div style={{ height: 10 }} />
            <InlineSelect label="To" options={YOSHI_ACCTS} value={toId} onChange={setTo} balances />
            <Eyebrow style={{ margin: "18px 0 9px" }}>How often</Eyebrow>
            <Segmented options={[{ value: "weekly", label: "Weekly" }, { value: "biweekly", label: "2 weeks" }, { value: "monthly", label: "Monthly" }]} value={freq} onChange={setFreq} />
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 30 }}>Runs {FREQ[freq].toLowerCase()}, starting next cycle.</div>
          </div>
          <div style={{ flex: "none", padding: "0 18px 30px" }}><Btn full onClick={() => setStep("amount")}>Enter amount <Icon name="arrow" size={18} color="var(--accent-ink)" /></Btn></div>
        </div>
      )}
      {step === "amount" && (
        <AmountBody amt={amt} amtNum={amtNum} onKey={onKey}
          context={<div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>{from.name} → <span style={{ color: "var(--ink)", fontWeight: 600 }}>{to.name}</span>, {FREQ[freq].toLowerCase()}</div>}
          info="The amount to move each time"
          ctaLabel="Review" ctaDisabled={!amtNum} onCta={() => setStep("review")} />
      )}
      {step === "review" && (
        <ReviewScreen eyebrow="Each transfer" amt={amtNum} cta="Schedule it · Passkey" onCta={() => setStep("done")}
          footerNote="A standing schedule. Yoshi shows each run in your stream and skips it if funds are short."
          rows={<>
            <ReviewRow label="From" value={from.name} sub={from.sub} />
            <ReviewRow label="To" value={to.name} sub={to.sub} />
            <ReviewRow label="Frequency" value={{ weekly: "Weekly", biweekly: "Every 2 weeks", monthly: "Monthly" }[freq]} />
            <ReviewRow label="Schedule" value={FREQ[freq]} />
            <ReviewRow label="First run" value="Next cycle" last />
          </>} />
      )}
      {step === "done" && <MoveSuccess title="Transfer scheduled" sub={`${usd(amtNum)} from ${from.name} to ${to.name}, ${FREQ[freq].toLowerCase()}. Manage it in your automations.`} onDone={onClose} />}
    </RailScreen>
  );
};

/* ========================================================================== *
   7b · Send a check (outbound payment)
 * ========================================================================== */
const CheckPayFlow = ({ onBack, onClose, nav }) => {
  const [step, setStep] = useState("setup");
  const [addr, setAddr] = useState({ name: "", line1: "", line2: "", city: "", state: "", zip: "" });
  const [amt, setAmt, onKey, amtNum] = useAmount("");
  const [padOpen, setPadOpen] = useState(false);
  const yo = YOSHI_ACCTS.find(a => a.id === "cash");
  const over = amtNum > yo.bal;
  const addrValid = addr.name.trim() && addr.line1.trim() && addr.city.trim() && addr.state.length === 2 && addr.zip.length === 5;

  if (step === "done") return (
    <RailScreen title="Send a check" onBack={onBack} onClose={onClose}>
      <MoveSuccess title={`${usd(amtNum)} check sent`} sub={`Check mailed to ${addr.name} at ${addr.line1}, ${addr.city} ${addr.state}. Allow 7–10 business days for delivery.`} onDone={onClose} />
    </RailScreen>
  );

  return (
    <RailScreen title="Send a check" onBack={step === "setup" ? onBack : () => setStep("setup")} onClose={onClose}>
      {step === "review" && (
        <ReviewScreen eyebrow="You're sending" amt={amtNum} cta="Confirm with passkey" onCta={() => setStep("done")}
          footerNote="Yoshi prints and mails the check from your Cash account. Allow 7–10 business days for delivery."
          rows={<>
            <ReviewRow label="From" value="Cash" sub="Yoshi" />
            <ReviewRow label="To" value={addr.name} sub={`${addr.line1}${addr.line2 ? ", " + addr.line2 : ""}, ${addr.city} ${addr.state} ${addr.zip}`} />
            <ReviewRow label="Arrives" value="7–10 business days" />
            <ReviewRow label="Fee" value="$0.00" last />
          </>} />
      )}
      {step === "setup" && (
      <div className="scroll" style={{ padding: "16px 18px 28px" }}>
        <Eyebrow style={{ marginBottom: 7 }}>From</Eyebrow>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12 }}>
          <span style={{ width: 36, height: 36, flex: "none", display: "grid", placeItems: "center", border: "1px solid var(--rule-2)", color: "var(--ink)" }}><Logo size={20} /></span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600 }}>Cash</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>Yoshi · 4.80% APY</div>
          </div>
          <div style={{ fontFamily: "var(--f-mono)", fontSize: 13.5, fontVariantNumeric: "tabular-nums", flex: "none" }}>{usd(yo.bal)}</div>
        </div>

        <Eyebrow style={{ margin: "18px 0 10px" }}>To</Eyebrow>
        <Field label="Name" value={addr.name} onChange={v => setAddr(a => ({...a, name: v}))} placeholder="Full name or company" />
        <Field label="Address" value={addr.line1} onChange={v => setAddr(a => ({...a, line1: v}))} placeholder="123 Main St" />
        <Field label="Apt / suite (optional)" value={addr.line2} onChange={v => setAddr(a => ({...a, line2: v}))} placeholder="Suite, unit, etc." />
        <div style={{ display: "grid", gridTemplateColumns: "1fr 56px 88px", gap: 8 }}>
          <Field label="City" value={addr.city} onChange={v => setAddr(a => ({...a, city: v}))} placeholder="City" />
          <Field label="State" value={addr.state} onChange={v => setAddr(a => ({...a, state: v.toUpperCase().slice(0,2)}))} placeholder="CA" />
          <Field label="ZIP" value={addr.zip} onChange={v => setAddr(a => ({...a, zip: v.replace(/\D/g,"").slice(0,5)}))} placeholder="94103" mono />
        </div>

        <Eyebrow style={{ margin: "18px 0 7px" }}>Amount <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--ink-3)", fontWeight: 500 }}>({usd(yo.bal)} available)</span></Eyebrow>
        <div onClick={() => setPadOpen(true)} style={{ display: "flex", alignItems: "center", gap: 9, minHeight: 50, padding: "0 14px", background: "var(--bg-card)", border: `1px solid ${over ? "var(--signal-neg)" : "var(--rule-2)"}`, borderRadius: 12, cursor: "pointer" }}>
          <span style={{ fontFamily: "var(--f-mono)", fontSize: 18, color: amtNum ? "var(--ink-3)" : "var(--rule-2)" }}>$</span>
          <input readOnly inputMode="none" value={amt === "" ? "" : commaAmt(amt)} onFocus={() => setPadOpen(true)} placeholder="Enter amount"
            style={{ flex: 1, minWidth: 0, border: "none", background: "transparent", outline: "none", color: "var(--ink)", fontFamily: "var(--f-mono)", fontSize: 18, fontVariantNumeric: "tabular-nums", cursor: "pointer" }} />
        </div>
        {over && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--signal-neg)", marginTop: 6 }}>Exceeds available balance</div>}

        <div style={{ marginTop: 22 }}>
          <Seam style={{ marginBottom: 16 }} />
          <Btn full disabled={!amtNum || over || !addrValid} onClick={() => setStep("review")}>Review</Btn>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", textAlign: "center", marginTop: 9, lineHeight: 1.4 }}>Mailed from Yoshi · 7–10 business days</div>
        </div>
      </div>
      )}
      <KeypadSheet open={padOpen} onClose={() => setPadOpen(false)} amt={amt} amtNum={amtNum} onKey={onKey}
        label="Amount" sub={over ? null : `${usd(yo.bal)} available`} error={over ? "Exceeds available balance" : null} ctaLabel="Done" />
    </RailScreen>
  );
};

/* ========================================================================== *
   8 · Pay a bill
 * ========================================================================== */
const BillPayFlow = ({ onBack, onClose, nav, switchRail }) => {
  const [payeeId, setPayeeId] = useState(PAYEES[0].id);
  const [gate, setGate] = useState(false);
  const [pickPayee, setPickPayee] = useState(false);
  const [amt, setAmt, onKey, amtNum] = useAmount(String(PAYEES[0].amt));
  const [padOpen, setPadOpen] = useState(false);
  const [done, setDone] = useState(false);
  const payee = PAYEES.find(p => p.id === payeeId);
  const yo = YOSHI_ACCTS.find(a => a.id === "cash");
  const over = amtNum > yo.bal;
  const choosePayee = (id) => { setPayeeId(id); setAmt(String(PAYEES.find(p => p.id === id).amt)); setPickPayee(false); };
  const askAutopay = () => { onClose(); nav && nav.ask("Set up autopay for this bill.", `I can set up a recurring payment to ${payee.name}. Tell me the amount and cadence — monthly, on a specific date, or tied to a statement — and I’ll build the automation. You approve it once and it runs inside your set limits.`); };

  if (done) return (
    <RailScreen title="Pay a bill" onBack={onBack} onClose={onClose}>
      <MoveSuccess title={`${usd(amtNum)} paid`} sub={`ACH initiated to ${payee.name}. The confirmation is in your stream.`} onDone={onClose} />
    </RailScreen>
  );

  return (
    <RailScreen title="Pay a bill" onBack={onBack} onClose={onClose}>
      <div className="scroll" style={{ padding: "16px 18px 28px" }}>
        {/* FROM */}
        <Eyebrow style={{ marginBottom: 7 }}>From</Eyebrow>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12 }}>
          <span style={{ width: 36, height: 36, flex: "none", display: "grid", placeItems: "center", border: "1px solid var(--rule-2)", color: "var(--ink)" }}><Logo size={20} /></span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600 }}>Cash</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>Yoshi · 4.80% APY</div>
          </div>
          <div style={{ fontFamily: "var(--f-mono)", fontSize: 13.5, fontVariantNumeric: "tabular-nums", flex: "none" }}>{usd(yo.bal)}</div>
        </div>

        {/* TO */}
        <Eyebrow style={{ margin: "18px 0 7px" }}>To</Eyebrow>
        <div style={{ position: "relative", zIndex: pickPayee ? 6 : 1 }}>
          <button className="press" onClick={() => setPickPayee(o => !o)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, cursor: "pointer", textAlign: "left" }}>
            <span style={{ width: 36, height: 36, flex: "none", display: "grid", placeItems: "center", border: "1px solid var(--rule-2)", color: "var(--ink)", fontFamily: "var(--f-display)", fontWeight: 700, fontSize: 15 }}>{payee.name[0]}</span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{payee.name}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{payee.sub}</div>
            </div>
            <div style={{ textAlign: "right", flex: "none" }}>
              <div style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontVariantNumeric: "tabular-nums", color: "var(--ink-2)" }}>{usd(payee.amt)}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)", marginTop: 2 }}>{pulledAgo(payee.id)}</div>
            </div>
            <Icon name="down" size={16} color="var(--ink-3)" style={{ flex: "none" }} />
          </button>
          {pickPayee && (
            <div style={{ position: "absolute", left: 0, right: 0, top: "calc(100% + 4px)", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, boxShadow: "0 14px 30px -14px rgba(0,0,0,0.35)", overflow: "hidden" }}>
              {PAYEES.map((p, i) => (
                <button key={p.id} className="press" onClick={() => choosePayee(p.id)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: p.id === payeeId ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
                  <span style={{ width: 30, height: 30, flex: "none", border: "1px solid var(--rule-2)", color: "var(--ink)", display: "grid", placeItems: "center", fontFamily: "var(--f-display)", fontWeight: 700, fontSize: 13 }}>{p.name[0]}</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{p.name}</div>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>{p.sub}</div>
                  </div>
                  <div style={{ textAlign: "right", flex: "none" }}>
                    <div style={{ fontFamily: "var(--f-mono)", fontSize: 12, color: "var(--ink-2)" }}>{usd(p.amt)}</div>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 10, color: "var(--ink-3)", marginTop: 2 }}>{pulledAgo(p.id)}</div>
                  </div>
                </button>
              ))}
              <button className="press" onClick={() => setPickPayee(false)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
                <span style={{ width: 30, height: 30, flex: "none", border: "1px dashed var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="plus" size={15} color="var(--ink-2)" /></span>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 500 }}>Add a payee</span>
              </button>
            </div>
          )}
        </div>

        {/* AMOUNT */}
        <Eyebrow style={{ margin: "18px 0 7px" }}>Amount <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--ink-3)", fontWeight: 500 }}>({usd(yo.bal)} available)</span></Eyebrow>
        <div onClick={() => setPadOpen(true)} style={{ display: "flex", alignItems: "center", gap: 9, minHeight: 50, padding: "0 14px", background: "var(--bg-card)", border: `1px solid ${over ? "var(--signal-neg)" : "var(--rule-2)"}`, borderRadius: 12, cursor: "pointer" }}>
          <span style={{ fontFamily: "var(--f-mono)", fontSize: 18, color: amtNum ? "var(--ink-3)" : "var(--rule-2)" }}>$</span>
          <input readOnly inputMode="none" value={amt === "" ? "" : commaAmt(amt)} onFocus={() => setPadOpen(true)} placeholder="Enter amount"
            style={{ flex: 1, minWidth: 0, border: "none", background: "transparent", outline: "none", color: "var(--ink)", fontFamily: "var(--f-mono)", fontSize: 18, fontVariantNumeric: "tabular-nums", cursor: "pointer" }} />
          <div style={{ display: "flex", gap: 6, flex: "none" }}>
            {payee.debt && <button className="press" onClick={(e) => { e.stopPropagation(); setAmt(String(payee.min ?? Math.max(35, Math.round(payee.amt * 0.02)))); }} style={{ padding: "6px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600, color: "var(--ink)", cursor: "pointer" }}>Min</button>}
            <button className="press" onClick={(e) => { e.stopPropagation(); setAmt(String(payee.amt)); }} style={{ padding: "6px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 600, color: "var(--ink)", cursor: "pointer" }}>Max</button>
          </div>
        </div>
        {over && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--signal-neg)", marginTop: 6 }}>Exceeds available balance</div>}

        <div style={{ marginTop: 22 }}>
          <Seam style={{ marginBottom: 16 }} />
          <Btn full disabled={!amtNum || over} onClick={() => setGate(true)}>Confirm</Btn>
          {gate && <PasskeyGate title={`Pay ${payee.name}`} amount={amtNum} detail={`From ${yo.name} · ACH to ${payee.name}.`} cta="Authorize with passkey" onSuccess={() => { setGate(false); setDone(true); }} onCancel={() => setGate(false)} />}
          <button className="press" onClick={askAutopay} style={{ width: "100%", marginTop: 11, padding: "11px 0", background: "none", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 5 }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Set up autopay for this bill</span>
            <Icon name="back" size={13} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
          </button>
          <button className="press" onClick={() => switchRail && switchRail("sendcheck")} style={{ width: "100%", marginTop: 4, padding: "10px 0", background: "none", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 5 }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-3)" }}>Want to pay with a check?</span>
            <Icon name="back" size={13} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
          </button>
        </div>
      </div>
      <KeypadSheet open={padOpen} onClose={() => setPadOpen(false)} amt={amt} amtNum={amtNum} onKey={onKey}
        label="Amount" sub={over ? null : `${usd(yo.bal)} available`} error={over ? "Exceeds available balance" : null}
        onMax={() => setAmt(String(payee.amt))} ctaLabel="Done" />
    </RailScreen>
  );
};

/* ========================================================================== *
   9 · Account transfer, ACATS in / out (brokerage account portability)
 * ========================================================================== */
const BROKERAGES = [
  { id: "schwab",    bank: "Charles Schwab", sub: "Brokerage · ••4021",  glyph: "S", bal: 148302.41 },
  { id: "fidelity",  bank: "Fidelity",        sub: "Brokerage · ••8830",  glyph: "F", bal: 96540.18 },
  { id: "robinhood", bank: "Robinhood",       sub: "Individual · ••2207", glyph: "R", bal: 23410.55 },
  { id: "vanguard",  bank: "Vanguard",        sub: "Brokerage · ••5567",  glyph: "V", bal: 312900.00 },
];
const YOSHI_BROKERAGES = [
  { id: "existing", name: "Yoshi Brokerage", sub: "Individual · ••3392", glyph: "logo" },
  { id: "new",      name: "New Yoshi brokerage account", sub: "Opened as part of this transfer", glyph: "plus" },
];
const ACAT_DISCLOSURES = [
  ["swap",    "Positions move in-kind", "Holdings transfer over the ACATS network. You stay invested the whole time, nothing is sold."],
  ["clock",   "Takes 5–7 business days", "Once started, the receiving and delivering firms reconcile every position before it lands."],
  ["accounts","Full account only", "Yoshi brings the entire account over. Partial transfers of specific positions aren't supported."],
  ["shield",  "Inbound only", "Yoshi can't initiate ACAT withdrawals. To move a Yoshi account elsewhere, start that request with the other firm."],
];
const AccountTransferFlow = ({ onBack, onClose }) => {
  const [firmId, setFirmId] = useState(BROKERAGES[0].id);
  const [gate, setGate] = useState(false);
  const [pickFirm, setPickFirm] = useState(false);
  const [destId, setDestId] = useState("existing");
  const [pickDest, setPickDest] = useState(false);
  const [done, setDone] = useState(false);
  const firm = BROKERAGES.find(b => b.id === firmId);
  const dest = YOSHI_BROKERAGES.find(d => d.id === destId);

  const GlyphBox = ({ g, size = 36 }) => (
    <span style={{ width: size, height: size, flex: "none", display: "grid", placeItems: "center", border: g === "plus" ? "1px dashed var(--rule-2)" : "none", background: g === "plus" ? "none" : "var(--bg-2)", color: "var(--ink)", fontFamily: "var(--f-display)", fontWeight: 700, fontSize: 15 }}>
      {g === "logo" ? <Logo size={Math.round(size * 0.55)} /> : g === "plus" ? <Icon name="plus" size={Math.round(size * 0.5)} color="var(--ink-2)" /> : g}
    </span>
  );

  if (done) return (
    <RailScreen title="Transfer brokerage account" onBack={onBack} onClose={onClose}>
      <MoveSuccess title="Transfer started" sub={`We've kicked off the ACATS transfer from ${firm.bank} into ${dest.id === "new" ? "your new Yoshi brokerage account" : dest.name}. It settles in about a week and you'll see each position land in your stream.`} onDone={onClose} />
    </RailScreen>
  );

  return (
    <RailScreen title="Transfer brokerage account" onBack={onBack} onClose={onClose}>
      <div className="scroll" style={{ padding: "16px 18px 28px" }}>
        {/* FROM · the external brokerage being brought in */}
        <Eyebrow style={{ marginBottom: 7 }}>From</Eyebrow>
        <div style={{ position: "relative", zIndex: pickFirm ? 6 : 1 }}>
          <button className="press" onClick={() => { setPickFirm(o => !o); setPickDest(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, cursor: "pointer", textAlign: "left" }}>
            <GlyphBox g={firm.glyph} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{firm.bank}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{firm.sub}</div>
            </div>
            <Icon name="down" size={16} color="var(--ink-3)" style={{ flex: "none" }} />
          </button>
          {pickFirm && (
            <div style={{ position: "absolute", left: 0, right: 0, top: "calc(100% + 4px)", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, boxShadow: "0 14px 30px -14px rgba(0,0,0,0.35)", overflow: "hidden" }}>
              {BROKERAGES.map((b, i) => (
                <button key={b.id} className="press" onClick={() => { setFirmId(b.id); setPickFirm(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: b.id === firmId ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
                  <GlyphBox g={b.glyph} size={30} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{b.bank}</div>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>{b.sub}</div>
                  </div>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 12, color: "var(--ink-3)" }}>{usd(b.bal)}</span>
                </button>
              ))}
              <button className="press" onClick={() => setPickFirm(false)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: "none", border: "none", borderTop: "1px solid var(--rule)", cursor: "pointer", textAlign: "left" }}>
                <span style={{ width: 30, height: 30, flex: "none", border: "1px dashed var(--rule-2)", display: "grid", placeItems: "center" }}><Icon name="plus" size={15} color="var(--ink-2)" /></span>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 500 }}>Another brokerage</span>
              </button>
            </div>
          )}
        </div>

        {/* AMOUNT · the whole account value moves; full account only */}
        <Eyebrow style={{ margin: "18px 0 7px" }}>Amount</Eyebrow>
        <div style={{ display: "flex", alignItems: "center", gap: 12, minHeight: 50, padding: "11px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <Money value={firm.bal} size={20} weight={500} />
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>Full account, in-kind · no partials</div>
          </div>
          <span style={{ flex: "none", fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--ink-3)", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 999, padding: "4px 10px" }}>Whole account</span>
        </div>

        {/* TO · pick the existing Yoshi brokerage or open a new one */}
        <Eyebrow style={{ margin: "18px 0 7px" }}>To</Eyebrow>
        <div style={{ position: "relative", zIndex: pickDest ? 6 : 1 }}>
          <button className="press" onClick={() => { setPickDest(o => !o); setPickFirm(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, padding: "13px 14px", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, cursor: "pointer", textAlign: "left" }}>
            <GlyphBox g={dest.glyph} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{dest.name}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{dest.sub}</div>
            </div>
            <Icon name="down" size={16} color="var(--ink-3)" style={{ flex: "none" }} />
          </button>
          {pickDest && (
            <div style={{ position: "absolute", left: 0, right: 0, top: "calc(100% + 4px)", background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 12, boxShadow: "0 14px 30px -14px rgba(0,0,0,0.35)", overflow: "hidden" }}>
              {YOSHI_BROKERAGES.map((d, i) => (
                <button key={d.id} className="press" onClick={() => { setDestId(d.id); setPickDest(false); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", background: d.id === destId ? "var(--bg-2)" : "none", border: "none", borderTop: i ? "1px solid var(--rule)" : "none", cursor: "pointer", textAlign: "left" }}>
                  <GlyphBox g={d.glyph} size={30} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{d.name}</div>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>{d.sub}</div>
                  </div>
                  {d.id === destId && <Icon name="check" size={15} stroke={2} color="var(--accent)" />}
                </button>
              ))}
            </div>
          )}
        </div>

        {/* DISCLOSURES */}
        <Eyebrow style={{ margin: "20px 0 8px" }}>Before you start</Eyebrow>
        <div style={{ border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden" }}>
          {ACAT_DISCLOSURES.map(([ic, t, d], i) => (
            <div key={t} style={{ display: "flex", gap: 11, alignItems: "center", padding: "12px 14px", borderBottom: i === ACAT_DISCLOSURES.length - 1 ? "none" : "1px solid var(--rule)" }}>
              <Icon name={ic} size={16} color="var(--ink-3)" stroke={1.6} style={{ flex: "none" }} />
              <div style={{ minWidth: 0 }}>
                <div style={{ fontFamily: "var(--f-display)", fontSize: 13, fontWeight: 600 }}>{t}</div>
                <div style={{ fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--ink-3)", marginTop: 3, lineHeight: 1.45 }}>{d}</div>
              </div>
            </div>
          ))}
        </div>

        <div style={{ marginTop: 22 }}>
          <Seam style={{ marginBottom: 16 }} />
          <Btn full onClick={() => setGate(true)}>Confirm</Btn>
        </div>
        {gate && <PasskeyGate title="Transfer brokerage account" detail="Yoshi brings the full external account over once you authorize." cta="Authorize with passkey" onSuccess={() => { setGate(false); setDone(true); }} onCancel={() => setGate(false)} />}
      </div>
    </RailScreen>
  );
};

window.TransferFlow = TransferFlow;
