/* flow3.jsx — Plaid link sheet · Funding · External accounts · Agent · Off to work. */

/* =============================================================
   Plaid link — the account-linking product experience, reused for
   the funding source (one depository) and read-only externals (many).
   ============================================================= */
const BANKS = [
  { id: "chase",    name: "Chase",            tint: "#1059a8", accts: [["Checking", "Checking", "••8841", 14231], ["Brokerage", "Brokerage", "••2207", 8400]] },
  { id: "bofa",     name: "Bank of America",  tint: "#c4112f", accts: [["Advantage Checking", "Checking", "••3392", 5210], ["Rewards Savings", "Savings", "••7715", 19800]] },
  { id: "wells",    name: "Wells Fargo",      tint: "#b81e26", accts: [["Everyday Checking", "Checking", "••4471", 3120]] },
  { id: "amex",     name: "American Express",  tint: "#1b6fb3", accts: [["Platinum Card", "Card", "••1008", -2104], ["High Yield Savings", "Savings", "••9920", 22500]] },
  { id: "capone",   name: "Capital One",      tint: "#13415f", accts: [["360 Checking", "Checking", "••5567", 2840]] },
  { id: "schwab",   name: "Charles Schwab",   tint: "#00a0df", accts: [["Brokerage", "Brokerage", "••2231", 88402]] },
  { id: "fidelity", name: "Fidelity",         tint: "#3a8c3f", accts: [["Individual", "Brokerage", "••6610", 31980]] },
  { id: "coinbase", name: "Coinbase",         tint: "#1652f0", accts: [["Portfolio", "Crypto", "••4417", 6712]] },
];

/* Plaid link. `requireFunding` (no funding source established yet) forces the
   user to include a checking/savings account in their selection — so every
   exit from Plaid leaves them with a usable funding source. Always
   multi-select: you link a bank and pull along any other accounts at once. */
const PlaidLink = ({ mode, requireFunding = false, onClose, onLinked, initialStep, initialBankId, initialSel }) => {
  // step: "list" | "connecting" | "select"
  const [step, setStep] = useState(initialStep || "list");
  const [bank, setBank] = useState(() => initialBankId ? BANKS.find((b) => b.id === initialBankId) || null : null);
  const [q, setQ] = useState("");
  const [sel, setSel] = useState(() => new Set(initialSel || []));

  // When establishing the funding source, only surface institutions that
  // actually have a depository account to link.
  const pool = requireFunding ? BANKS.filter((b) => b.accts.some((a) => a[1] === "Checking" || a[1] === "Savings")) : BANKS;
  const shown = pool.filter((b) => b.name.toLowerCase().includes(q.trim().toLowerCase()));

  const isDep = (a) => a[1] === "Checking" || a[1] === "Savings";

  const pick = (b) => {
    setBank(b); setStep("connecting");
    // pre-select every account at the institution — the user trims from there
    setSel(new Set(b.accts.map((_, i) => i)));
    setTimeout(() => setStep("select"), 1700);
  };
  const toggle = (i) => setSel((prev) => { const n = new Set(prev); n.has(i) ? n.delete(i) : n.add(i); return n; });

  // the funding source = first selected depository at this institution
  const fundingIdx = bank ? bank.accts.findIndex((a, i) => sel.has(i) && isDep(a)) : -1;
  const needsFunding = requireFunding && fundingIdx < 0;

  const finish = () => {
    const accts = [...sel].map((i) => ({ inst: bank.name, instId: bank.id, tint: bank.tint, name: bank.accts[i][0], type: bank.accts[i][1], mask: bank.accts[i][2], bal: bank.accts[i][3] }));
    onLinked(accts);
  };

  return (
    <div className="yo-enter" style={{ position: "absolute", inset: 0, zIndex: 410, background: "#f6f7f9", display: "flex", flexDirection: "column" }}>
      <div style={{ flex: "none", display: "flex", alignItems: "center", padding: "52px 18px 12px", gap: 10 }}>
        <span style={{ width: 22 }} />
        <div style={{ flex: 1, display: "flex", justifyContent: "center" }}><PlaidMark /></div>
        <span style={{ width: 22 }} />
      </div>

      {step === "list" && (
        <>
          <div style={{ flex: "none", padding: "6px 22px 14px" }}>
            <PHead>{mode === "funding" ? "Select your bank" : "Select an institution"}</PHead>
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "13px 14px", background: "#fff", border: "1.5px solid #d8dadf", borderRadius: 12, marginTop: 16 }}>
              <Icon name="search" size={17} color="#9a9ea6" />
              <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search 12,000+ institutions" autoFocus
                style={{ flex: 1, border: "none", outline: "none", background: "transparent", fontSize: 15, color: "#1a1c1f" }} />
            </div>
          </div>
          <div className="scroll" style={{ flex: 1, minHeight: 0, padding: "0 22px 16px" }}>
            {shown.map((b) => (
              <button key={b.id} className="press" onClick={() => pick(b)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 13, padding: "14px 4px", background: "none", border: "none", borderBottom: "1px solid #eceef1", cursor: "pointer", textAlign: "left" }}>
                <span style={{ width: 38, height: 38, flex: "none", borderRadius: 9, background: b.tint, display: "grid", placeItems: "center", color: "#fff", fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 500 }}>{b.name[0]}</span>
                <span style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 15.5, fontWeight: 500, color: "#1a1c1f" }}>{b.name}</span>
                <Icon name="arrow" size={17} color="#b6b9bf" />
              </button>
            ))}
          </div>
        </>
      )}

      {step === "connecting" && (
        <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "0 30px", textAlign: "center" }}>
          <span style={{ width: 64, height: 64, borderRadius: 14, background: bank.tint, display: "grid", placeItems: "center", color: "#fff", fontFamily: "var(--f-display)", fontSize: 28, fontWeight: 500 }}>{bank.name[0]}</span>
          <div style={{ marginTop: 22, display: "flex", alignItems: "center", gap: 8, color: "#15171a" }}>
            <LiveDot size={6} color="#111" />
            <span style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 500 }}>Connecting to {bank.name}…</span>
          </div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "#6b6f76", marginTop: 10, lineHeight: 1.5, maxWidth: "28ch" }}>
            Plaid signs you in securely. Yoshi never sees your bank password.
          </div>
        </div>
      )}

      {step === "select" && (
        <>
          <div className="scroll" style={{ flex: 1, minHeight: 0, padding: "6px 22px 8px" }}>
            <PHead>Accounts at {bank.name}</PHead>
            <PNote>{requireFunding ? "Pick a checking or savings account to fund Yoshi. Add any others for Yoshi to read." : "Select which accounts Yoshi can see. Add a checking or savings to move money."}</PNote>
            <div style={{ marginTop: 18, display: "grid", gap: 10 }}>
              {bank.accts.map((a, i) => {
                const on = sel.has(i);
                const isFunding = i === fundingIdx;
                return (
                  <button key={i} className="press" onClick={() => toggle(i)} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 13, padding: "14px 15px", background: "#fff", border: `1.5px solid ${on ? "#111" : "#e1e3e8"}`, borderRadius: 12, cursor: "pointer" }}>
                    <span style={{ flex: 1, minWidth: 0 }}>
                      <span style={{ display: "flex", alignItems: "center", gap: 7 }}>
                        <span style={{ fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 500, color: "#1a1c1f" }}>{a[0]}</span>
                      </span>
                      <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 12.5, color: "#8a8e96", marginTop: 2 }}>{a[1]} · {a[2]}</span>
                    </span>
                    <span style={{ fontFamily: "var(--f-mono)", fontSize: 14, fontWeight: 500, color: a[3] < 0 ? "#b03a2e" : "#1a1c1f" }}>{a[3] < 0 ? "−$" : "$"}{Math.abs(a[3]).toLocaleString("en-US")}</span>
                    <span style={{ width: 22, height: 22, flex: "none", borderRadius: 6, border: `1.5px solid ${on ? "#111" : "#cdd0d5"}`, background: on ? "#111" : "transparent", display: "grid", placeItems: "center" }}>
                      {on && <Icon name="check" size={13} stroke={2.4} color="#fff" />}
                    </span>
                  </button>
                );
              })}
            </div>
            {needsFunding && (
              <div style={{ display: "flex", alignItems: "flex-start", gap: 8, marginTop: 14, padding: "11px 13px", background: "#fcf3e6", border: "1px solid #e7c98f", borderRadius: 10 }}>
                <span style={{ flex: "none", marginTop: 1, color: "#9a6a14" }}><Icon name="bank" size={15} color="#9a6a14" /></span>
                <span style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "#7a5410", lineHeight: 1.45 }}>Select a checking or savings account to fund Yoshi.</span>
              </div>
            )}
          </div>
          <div style={{ flex: "none", padding: "12px 22px 26px" }}>
            <PBtn disabled={sel.size === 0} onClick={finish}>{`Link ${sel.size} account${sel.size === 1 ? "" : "s"}`}</PBtn>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 6, marginTop: 14, color: "#9a9ea6" }}>
              <Icon name="shield" size={13} color="#9a9ea6" />
              <span style={{ fontFamily: "var(--f-display)", fontSize: 11, fontWeight: 500 }}>Secured by Plaid</span>
            </div>
          </div>
        </>
      )}
    </div>
  );
};

/* =============================================================
   08 · CONNECT YOUR BANK — link once through Plaid; it pulls every
   account at that institution. Pick the one that funds Yoshi (read/write);
   the rest ride along read-only. The more you connect, the more Yoshi sees.
   ============================================================= */
const FUND_PRESETS = [250, 1000, 5000, 10000];
const FUND_PRESET_RATIOS = [0, 1 / 3, 2 / 3, 1];

const fundingPresetStepFor = (cap) => {
  if (cap <= 500) return 1;
  if (cap <= 1000) return 10;
  if (cap <= 5000) return 50;
  return 100;
};

const fundingPresetsFor = (balance) => {
  const cap = Math.floor(Math.max(0, balance || 0));
  if (!cap) return FUND_PRESETS;
  if (cap >= 5000) return [250, 500, 1000, 5000];
  const maxPreset = Math.min(cap, 5000);
  const floor = Math.min(cap, cap <= 250 ? 100 : 250);
  const span = maxPreset - floor;
  const step = fundingPresetStepFor(maxPreset);
  return FUND_PRESET_RATIOS.map((ratio, i) => {
    if (i === 0) return floor;
    if (i === FUND_PRESET_RATIOS.length - 1) return maxPreset;
    const raw = floor + span * ratio;
    return Math.min(maxPreset, Math.max(floor, Math.round(raw / step) * step));
  });
};

const fundingPresetLabel = (amount) => {
  if (amount >= 1000) {
    const k = amount / 1000;
    return `$${k.toFixed(k >= 10 ? 1 : 1).replace(/\.0$/, "")}k`;
  }
  return `$${amount.toLocaleString("en-US")}`;
};

/* What Yoshi can do once it can SEE a given institution — the concrete
   payoff for connecting more, surfaced live as accounts come in. */
const INSIGHTS = {
  amex:     { tag: "Pay down your card", find: "Your Amex balance is accruing interest at 21.99% APR. Yoshi can clear it from cash before it's due.", value: "Stops interest", w: 95 },
  schwab:   { tag: "Put idle cash to work", find: "Uninvested cash is sitting in your Schwab brokerage. Yoshi can invest it on a schedule.", value: "+$1,240 / yr", w: 82 },
  fidelity: { tag: "Fix portfolio drift", find: "Your Fidelity mix has drifted from target after the run-up. Yoshi can propose a rebalance.", value: "Back on target", w: 78 },
  chase:    { tag: "Sweep idle cash", find: "Cash is sitting in Chase earning almost nothing. Yoshi can sweep it to 4.8% APY.", value: "+$402 / yr", w: 70 },
  bofa:     { tag: "Sweep idle cash", find: "Idle cash in Bank of America could earn 4.8% instead of sitting still.", value: "+$360 / yr", w: 68 },
  coinbase: { tag: "One net worth", find: "Your Coinbase crypto now rolls into a single balance Yoshi watches with everything else.", value: "Tracked", w: 45 },
  wells:    { tag: "Catch recurring fees", find: "With Wells Fargo visible, Yoshi can flag recurring fees and forgotten subscriptions.", value: "Watching", w: 35 },
  capone:   { tag: "Catch recurring fees", find: "Capital One spending is now visible. Yoshi spots fees and duplicate subscriptions.", value: "Watching", w: 34 },
};

const isDepository = (a) => a.type === "Checking" || a.type === "Savings";
const acctLabel = (a) => `${a.inst} ${a.type} · ${a.mask}`;
const sameAcct = (a, b) => !!(a && b && a.instId === b.instId && a.mask === b.mask);

/* ---- Connected account row ---- */
const ConnectedRow = ({ a, selected, onSelect, accent }) => (
  <div className="yo-enter lucid-surface-row" style={{ display: "flex", alignItems: "center", gap: 13, padding: "13px 14px", background: "var(--bg-card)", border: `1px solid ${accent ? "var(--accent)" : "var(--rule-2)"}`, borderRadius: 12 }}>
    <span style={{ width: 34, height: 34, flex: "none", borderRadius: 8, background: a.tint, display: "grid", placeItems: "center", color: "#fff", fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 500 }}>{a.inst[0]}</span>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500 }}>{a.inst} {a.type}</div>
      <div style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.04em", marginTop: 2 }}>{a.mask}</div>
    </div>
    {onSelect && (
      <button onClick={onSelect} style={{ background: "none", border: "none", padding: 4, cursor: "pointer", color: selected ? "var(--accent)" : "var(--ink-3)" }}>
        <Icon name="check" size={16} stroke={selected ? 2.4 : 1.5} color={selected ? "var(--accent)" : "var(--rule-2)"} />
      </button>
    )}
    {!onSelect && a.type !== "Checking" && a.type !== "Savings" && (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
        <Icon name="eye" size={12} color="var(--ink-3)" />
      </span>
    )}
    {!onSelect && (a.type === "Checking" || a.type === "Savings") && (
      <span style={{ fontFamily: "var(--f-mono)", fontSize: 13, fontWeight: 500, color: "var(--ink-2)" }}>${Math.abs(a.bal).toLocaleString("en-US")}</span>
    )}
  </div>
);

const Funding = ({ funding, setFunding, externals, setExternals, onNext, onLinkedNext, onSkipToAgent }) => {
  const [plaid, setPlaid]           = useState(false);
  const [attempts, setAttempts]     = useState(0);   // how many times Plaid was opened
  const [plaidFailed, setPlaidFailed] = useState(false); // last attempt failed/exited

  const depAccts  = externals.filter(isDepository);
  const hasBank   = depAccts.length > 0;
  const hasInvest = externals.some((a) => a.type === "Brokerage" || a.type === "Crypto");
  const hasAny    = externals.length > 0;

  // state 1: bank linked → Next goes to funding page
  // state 2: invest-only → Next goes to funding page (will prompt bank link there)
  // state 3: failed/exited → Next skips to agent (no retry gating)
  const canProceed = hasAny || plaidFailed;
  const skipToAgent = !hasAny && plaidFailed;

  const onLinked = (accts) => {
    const next = [...externals];
    accts.forEach((a) => { if (!next.some((x) => sameAcct(x, a))) next.push(a); });
    setExternals(next);
    if (!funding) { const dep = next.find(isDepository); if (dep) setFunding(dep); }
    setPlaid(false);
    setPlaidFailed(false);
    onLinkedNext && onLinkedNext();
  };

  const onPlaidClose = () => {
    setPlaid(false);
    setPlaidFailed(true);
  };

  const openPlaid = () => {
    setAttempts((n) => n + 1);
    setPlaid(true);
  };

  // idle state: nothing linked yet, no failure
  const showIdle = !hasAny && !plaidFailed;
  // failure state: exited/errored, haven't succeeded
  const showRetry = !hasAny && plaidFailed;

  return (
    <Screen>
      <Body>
        <H>Connect your<Brk /><Accent>accounts.</Accent></H>
        <Sub>Link securely through Plaid to power Yoshi. The more accounts you connect, the more Yoshi can see and do.</Sub>

        {/* ---- IDLE: nothing linked yet ---- */}
        {showIdle && (
          <>
            <button className="press lucid-connect" onClick={openPlaid} style={{ width: "100%", display: "flex", alignItems: "center", gap: 13, marginTop: 18, padding: "16px 15px", background: "var(--bg-card)", border: "1px dashed var(--rule-2)", borderRadius: 12, cursor: "pointer", textAlign: "left" }}>
              <span style={{ flex: "none", color: "var(--accent)" }}><Icon name="bank" size={24} color="var(--accent)" /></span>
              <span style={{ flex: 1 }}>
                <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 500 }}>Link accounts</span>
              </span>
              <Icon name="arrow" size={18} color="var(--ink-3)" />
            </button>
            <Disclosure>Connections run through Plaid. Yoshi never sees your password, and every move still needs your approval.</Disclosure>
          </>
        )}

        {/* ---- RETRY: Plaid failed or exited ---- */}
        {showRetry && (
          <>
            <div style={{ marginTop: 18, padding: "13px 14px", background: "color-mix(in srgb, var(--accent) 14%, var(--bg-card))", border: "1px solid var(--accent)", borderRadius: 12 }}>
              <div style={{ display: "flex", alignItems: "flex-start", gap: 9 }}>
                <span style={{ flex: "none", marginTop: 1, color: "var(--accent)" }}><Icon name="bank" size={16} color="var(--accent)" /></span>
                <div style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 500, color: "var(--ink)", lineHeight: 1.45 }}>Connection didn't complete. That's okay, try again below.</div>
              </div>
            </div>
            <button className="press lucid-connect" onClick={openPlaid} style={{ width: "100%", display: "flex", alignItems: "center", gap: 13, marginTop: 10, padding: "16px 15px", background: "var(--bg-card)", border: "1px dashed var(--rule-2)", borderRadius: 12, cursor: "pointer", textAlign: "left" }}>
              <span style={{ flex: "none", color: "var(--accent)" }}><Icon name="bank" size={24} color="var(--accent)" /></span>
              <span style={{ flex: 1 }}>
                <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 15, fontWeight: 500 }}>Link accounts</span>
              </span>
              <Icon name="arrow" size={18} color="var(--ink-3)" />
            </button>
            <Disclosure>You can always connect accounts later from the Accounts tab.</Disclosure>
          </>
        )}

        {/* ---- STATE 1 + 2: Accounts linked ---- */}
        {hasAny && (
          <>
            {/* All linked accounts — bank, brokerage, crypto, side by side */}
            <SubHead>Connected accounts</SubHead>
            <div style={{ display: "grid", gap: 9 }}>
              {externals.map((a, i) => (
                <ConnectedRow key={i} a={a} accent={isDepository(a) && sameAcct(a, funding)} selected={sameAcct(a, funding)} />
              ))}
            </div>

            {/* No bank — callout */}
            {!hasBank && (
              <div style={{ marginTop: 18, padding: "13px 14px", background: "color-mix(in srgb, var(--accent) 14%, var(--bg-card))", border: "1px solid var(--accent)", borderRadius: 12 }}>
                <div style={{ display: "flex", alignItems: "flex-start", gap: 9 }}>
                  <span style={{ flex: "none", marginTop: 1, color: "var(--accent)" }}><Icon name="bank" size={16} color="var(--accent)" /></span>
                  <div style={{ flex: 1, fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 500, color: "var(--ink)" }}>You'll need to add a checking or savings account to fund Yoshi.</div>
                </div>
              </div>
            )}
          </>
        )}
      </Body>
      <Dock>
        {hasAny ? (
          <Btn full onClick={onNext}>Continue</Btn>
        ) : plaidFailed ? (
          <SkipLink onClick={onSkipToAgent}>Skip for now</SkipLink>
        ) : null}
      </Dock>
      {plaid && <PlaidLink mode="readonly" requireFunding={!funding} onClose={onPlaidClose} onLinked={onLinked} />}
    </Screen>
  );
};

/* =============================================================
   09 · PUT YOSHI TO WORK — fund the account so Yoshi has something
   to work with. Optional; skip and fund later.
   ============================================================= */
const FundingBankIcon = ({ account }) => {
  const src = account.instId === "chase" ? "../assets/lucid-chase.svg" : account.instId === "bofa" ? "../assets/lucid-boa.svg" : null;
  return <span className="lucid-funding-icon" aria-hidden="true">{src ? <img src={src} alt="" /> : <Icon name="bank" size={24} stroke={1.75} />}</span>;
};

const FundDeposit = ({ funding, setFunding, externals = [], setExternals, deposit, setDeposit, onNext, onSkip }) => {
  const [amt, setAmt] = useState(deposit || 0);
  const [other, setOther] = useState(false);
  const [customStr, setCustomStr] = useState("");
  const [confirming, setConfirming] = useState(false);
  const [confirmed, setConfirmed] = useState(false);
  const [pickerOpen, setPickerOpen] = useState(false);
  const [plaid, setPlaid] = useState(false);
  const [fundingMethod, setFundingMethod] = useState(funding ? "bank" : "");
  const web = usePlatform() === "web";

  const banks = externals.filter(isDepository);
  const hasMultipleBanks = banks.length > 1;
  const availableBalance = Math.max(0, funding?.bal || 0);
  const presetAmounts = fundingPresetsFor(fundingMethod === "bank" && funding ? availableBalance : 5000);
  const overAvailable = fundingMethod === "bank" && funding && amt > availableBalance;
  const fundingMethodCta = amt <= 0 && fundingMethod
    ? "Choose an amount"
    : !fundingMethod ? "Choose a funding method"
    : !funding ? "Link bank account"
    : confirmed ? "Confirmed"
    : "Confirm";

  useEffect(() => {
    if (fundingMethod === "bank" && funding && amt > availableBalance) {
      setAmt(0);
      setOther(false);
      setCustomStr("");
    }
  }, [fundingMethod, funding, availableBalance]);

  const onLinked = (accts) => {
    const next = [...externals];
    accts.forEach((a) => { if (!next.some((x) => sameAcct(x, a))) next.push(a); });
    setExternals(next);
    if (!funding) { const dep = next.find(isDepository); if (dep) setFunding(dep); }
    setPlaid(false);
  };

  const completeFunding = () => {
    setDeposit(amt);
    onNext({ skipped: false, amount: amt, method: "bank" });
  };

  const handleNext = () => {
    if (amt <= 0 || overAvailable || !fundingMethod) return;
    if (!funding) { setPlaid(true); return; }
    if (amt > 0 && !confirmed) { setConfirming(true); return; }
    completeFunding();
  };

  const onPasskeyConfirm = () => {
    setConfirming(false);
    setConfirmed(true);
    setTimeout(completeFunding, 400);
  };
  return (
    <Screen>
      <Body>
        <H>Put Yoshi<Brk />to <Accent>work.</Accent></H>
        <Sub>Move money into your Yoshi account so it has something to work with. You can skip and fund anytime later.</Sub>

        <SubHead>Funding method</SubHead>
        <div style={{ display: "grid", gap: 9 }}>
          {funding ? (
            <div className="lucid-connected-funding">
              <button type="button" className="press lucid-funding-tile lucid-connected-account"
                aria-expanded={hasMultipleBanks ? pickerOpen : undefined}
                onClick={() => {
                  setFundingMethod("bank");
                  if (hasMultipleBanks) setPickerOpen((o) => fundingMethod === "bank" ? !o : true);
                }}>
                <FundingBankIcon account={funding} />
                <span className="lucid-funding-copy">
                  <strong>{funding.inst} {funding.type}</strong>
                  <small>{funding.inst} {funding.mask}</small>
                </span>
                <span className="lucid-account-balance" aria-label={`Available balance ${usd(funding.bal)}`}>{usd(funding.bal)}</span>
              </button>
              {pickerOpen && fundingMethod === "bank" && hasMultipleBanks && (
                <div className="lucid-funding-options">
                  {banks.filter((b) => !sameAcct(b, funding)).map((a, i) => (
                    <button key={i} type="button" className="press lucid-funding-tile lucid-connected-account"
                      onClick={() => { setFunding(a); setFundingMethod("bank"); setPickerOpen(false); }}>
                      <FundingBankIcon account={a} />
                      <span className="lucid-funding-copy">
                        <strong>{a.inst} {a.type}</strong>
                        <small>{a.inst} {a.mask}</small>
                      </span>
                      <span className="lucid-account-balance" aria-label={`Available balance ${usd(a.bal)}`}>{usd(a.bal)}</span>
                    </button>
                  ))}
                </div>
              )}
            </div>
          ) : (
            <button type="button" className="press lucid-funding-tile"
              onClick={() => { setFundingMethod("bank"); setPlaid(true); }}>
              <span className="lucid-funding-icon" aria-hidden="true"><Icon name="bank" size={24} stroke={1.75} /></span>
              <span className="lucid-funding-copy">
                <strong>Link bank account</strong>
                <small>Use your primary checking or savings account</small>
              </span>
              <img className="lucid-funding-chevron" src="../assets/lucid-chevron.svg" alt="" />
            </button>
          )}
        </div>

        <SubHead>Amount · optional</SubHead>
        <div className="lucid-funding-amounts">
          {presetAmounts.map((p, i) => {
            const on = !other && amt === p;
            return (
              <button key={`${i}-${p}`} className="press lucid-pill lucid-amount-pill" aria-pressed={on} onClick={() => { setOther(false); setAmt(on ? 0 : p); }} style={{ padding: "13px 2px", cursor: "pointer", borderRadius: 10, background: on ? "color-mix(in srgb, var(--accent) 12%, var(--bg-card))" : "var(--bg-2)", border: `1px solid ${on ? "var(--accent)" : "var(--rule)"}`, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 500, color: "var(--ink)" }}>
                {fundingPresetLabel(p)}
              </button>
            );
          })}
          <button className="press lucid-pill lucid-amount-pill" aria-pressed={other} onClick={() => { setOther(true); setAmt(customStr ? parseInt(customStr, 10) : 0); }} style={{ padding: "13px 2px", cursor: "pointer", borderRadius: 10, background: other ? "color-mix(in srgb, var(--accent) 12%, var(--bg-card))" : "var(--bg-2)", border: `1px solid ${other ? "var(--accent)" : "var(--rule)"}`, fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 500, color: "var(--ink)" }}>
            Other
          </button>
        </div>
        {other && (
          <div className="yo-enter" style={{ marginTop: 9 }}>
            <Field prefix="$" inputMode="numeric" autoFocus placeholder="Enter an amount"
              value={customStr ? parseInt(customStr, 10).toLocaleString("en-US") : ""}
              onChange={(v) => { const d = v.replace(/[^0-9]/g, ""); setCustomStr(d); setAmt(d ? parseInt(d, 10) : 0); }} />
            {overAvailable && (
              <div style={{ marginTop: 7, fontFamily: "var(--f-display)", fontSize: 11.5, color: "var(--signal-neg)" }}>
                Amount can't be more than {usd(availableBalance)}.
              </div>
            )}
          </div>
        )}

        <Disclosure>
          <span style={{ display: "grid", gap: 2 }}>
            <span>Deposits in your Yoshi account are FDIC-insured through Column N.A., Member FDIC.</span>
            <a href="/cash-account-disclosures/" target="_blank" rel="noopener noreferrer" style={{ color: "inherit", textDecoration: "underline", textUnderlineOffset: 2, justifySelf: "start" }}>Authorization terms and conditions</a>
          </span>
        </Disclosure>

      </Body>
      <Dock>
        <Btn full disabled={amt <= 0 || overAvailable || !fundingMethod} onClick={handleNext}>
          {confirmed ? <><Icon name="check" size={18} color="var(--accent-ink)" /> Confirmed</> : <>{fundingMethodCta}</>}
        </Btn>
        <SkipLink onClick={() => onSkip({ skipped: true, amount: 0, method: "none" })}>Skip to enter Yoshi</SkipLink>
      </Dock>

      {/* Passkey confirm — centered modal on web, bottom sheet on mobile */}
      {confirming && (
        <>
          <div onClick={() => setConfirming(false)} style={{ position: "absolute", inset: 0, zIndex: 50, background: "rgba(0,0,0,0.44)", backdropFilter: "blur(4px)", WebkitBackdropFilter: "blur(4px)" }} />
          {web ? (
            <div style={{ position: "absolute", inset: 0, zIndex: 51, display: "flex", alignItems: "center", justifyContent: "center", padding: 28 }}>
              <div className="yo-enter" style={{ width: "100%", maxWidth: 360, background: "var(--bg-card)", border: "1px solid var(--rule-2)", borderRadius: 24, padding: "30px 28px 26px", boxShadow: "var(--shadow-card)" }}>
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 10, marginBottom: 24 }}>
                  <span style={{ width: 52, height: 52, borderRadius: 14, background: "var(--bg-2)", border: "1px solid var(--rule-2)", display: "grid", placeItems: "center" }}>
                    <Icon name="shield" size={26} color="var(--accent)" />
                  </span>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 500, letterSpacing: "-0.02em" }}>Confirm</div>
                    <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-3)", marginTop: 5, lineHeight: 1.45 }}>
                      Authorise a transfer of <strong>${amt.toLocaleString("en-US")}</strong> from your {funding ? `${funding.inst} ${funding.type}` : "funding source"}.
                    </div>
                  </div>
                </div>
                <div style={{ display: "grid", gap: 9 }}>
                  <Btn full onClick={onPasskeyConfirm}>
                    <Icon name="shield" size={16} color="var(--accent-ink)" /> Use passkey
                  </Btn>
                  <button onClick={() => setConfirming(false)} style={{ background: "none", border: "none", fontFamily: "var(--f-display)", fontSize: 14, color: "var(--ink-3)", cursor: "pointer", padding: "8px 0" }}>Cancel</button>
                </div>
              </div>
            </div>
          ) : (
            <div style={{ position: "absolute", bottom: 0, left: 0, right: 0, zIndex: 51, background: "var(--bg-card)", borderRadius: "20px 20px 0 0", padding: "20px 24px 40px", boxShadow: "0 -8px 32px rgba(0,0,0,0.18)" }}>
              <div style={{ width: 36, height: 4, borderRadius: 999, background: "var(--rule-2)", margin: "0 auto 22px" }} />
              <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 10, marginBottom: 24 }}>
                <span style={{ width: 52, height: 52, borderRadius: 14, background: "var(--bg-2)", border: "1px solid var(--rule-2)", display: "grid", placeItems: "center" }}>
                  <Icon name="shield" size={26} color="var(--accent)" />
                </span>
                <div style={{ textAlign: "center" }}>
                  <div style={{ fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 500, letterSpacing: "-0.02em" }}>Confirm</div>
                  <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-3)", marginTop: 5, lineHeight: 1.45 }}>
                    Authorise a transfer of <strong>${amt.toLocaleString("en-US")}</strong> from your {funding ? `${funding.inst} ${funding.type}` : "funding source"}.
                  </div>
                </div>
              </div>
              <div style={{ display: "grid", gap: 9 }}>
                <Btn full onClick={onPasskeyConfirm}>
                  <Icon name="shield" size={16} color="var(--accent-ink)" /> Use passkey
                </Btn>
                <button onClick={() => setConfirming(false)} style={{ background: "none", border: "none", fontFamily: "var(--f-display)", fontSize: 14, color: "var(--ink-3)", cursor: "pointer", padding: "8px 0" }}>Cancel</button>
              </div>
            </div>
          )}
        </>
      )}
      {plaid && <PlaidLink mode="readonly" requireFunding onClose={() => setPlaid(false)} onLinked={onLinked} />}
    </Screen>
  );
};

/* =============================================================
   10 · DISCLOSURES — the last gate before Yoshi gets to work.
   Institutional register: concede the fine print, lay it out plainly.
   Tapping continue is the acknowledgment; the seam draws as you sign.
   ============================================================= */
const AckRow = ({ label, href, children, last }) => (
  <div style={{ padding: "15px 0", borderBottom: last ? "none" : "1px dashed var(--rule)" }}>
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <Eyebrow color="var(--accent)" style={{ fontSize: 9.5 }}>{label}</Eyebrow>
      {href && (
        <a href={href} target="_blank" rel="noopener noreferrer" className="press" aria-label={label + " document"} style={{ marginLeft: "auto", flex: "none", display: "inline-flex", color: "var(--ink-3)" }}>
          <Icon name="external" size={14} color="var(--ink-3)" />
        </a>
      )}
    </div>
    <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 13.5, color: "var(--ink)", lineHeight: 1.48, marginTop: 5, textWrap: "pretty" }}>{children}</span>
  </div>
);

const CheckMark = ({ checked }) => (
  <span style={{
    width: 19, height: 19, flex: "none", borderRadius: 5, display: "grid", placeItems: "center",
    border: `1px solid ${checked ? "var(--accent)" : "var(--rule-2)"}`,
    background: checked ? "var(--accent)" : "transparent",
    color: "var(--accent-ink)",
    transition: "background 160ms ease, border-color 160ms ease"
  }}>
    {checked && <Icon name="check" size={13} color="var(--accent-ink)" />}
  </span>
);

const AgreementCheckRow = ({ checked, onToggle, label, sub, href, onOpen, first, last }) => {
  const openProps = href
    ? { as: "a", href, target: "_blank", rel: "noopener noreferrer" }
    : {};
  const openControl = onOpen
    ? (
      <button type="button" className="press" onClick={(event) => { event.stopPropagation(); onOpen(); }} aria-label={`${label} agreements`} style={{ border: "none", background: "none", padding: 4, margin: -4, display: "inline-flex", color: "var(--ink-3)", cursor: "pointer" }}>
        <Icon name="external" size={14} color="var(--ink-3)" />
      </button>
    )
    : (
      <a {...openProps} className="press" onClick={(event) => event.stopPropagation()} aria-label={`${label} agreements`} style={{ display: "inline-flex", color: "var(--ink-3)" }}>
        <Icon name="external" size={14} color="var(--ink-3)" />
      </a>
    );
  return (
    <div className="lucid-agreement-row">
      <button type="button" className="press lucid-agreement-check" role="checkbox" aria-checked={checked} onClick={onToggle}>
        <CheckMark checked={checked} />
        <span style={{ minWidth: 0 }}>
          <span className="lucid-agreement-title">{label}</span>
          <span className="lucid-agreement-description">{sub}</span>
        </span>
      </button>
      {openControl}
    </div>
  );
};

const PartnerRow = ({ name, role, member, href, onClick, first }) => {
  const common = {
    textDecoration: "none", width: "100%", display: "grid", gridTemplateColumns: "1fr auto", gap: 12, alignItems: "center",
    padding: "13px 0", background: "none", border: "none", borderTop: `1px ${first ? "solid" : "dashed"} var(--rule)`,
    color: "var(--ink)", cursor: "pointer", textAlign: "left" };
  const body = (
    <>
      <span style={{ minWidth: 0 }}>
        <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 14.5, fontWeight: 500, letterSpacing: "-0.015em" }}>{name}</span>
        <span style={{ display: "block", fontFamily: "var(--f-mono)", fontSize: 9, letterSpacing: "0.05em", textTransform: "uppercase", color: "var(--ink-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{role} · {member}</span>
      </span>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 5, flex: "none", fontFamily: "var(--f-display)", fontSize: 11.5, fontWeight: 500, color: "var(--ink-2)" }}>
        Agreements <Icon name="external" size={14} color="var(--ink-3)" />
      </span>
    </>
  );
  return onClick
    ? <button type="button" className="press" onClick={onClick} style={common}>{body}</button>
    : <a href={href} target="_blank" rel="noopener noreferrer" className="press" style={common}>{body}</a>;
};

/* The Apex agreements + disclosures, as an in-app push screen reached from the
   brokerage row. Each document opens its PDF; the disclosures live at the foot. */
const APEX_DOCS = [
  ["Customer Account Agreement", "https://storage.googleapis.com/apexclearing-account-agreements-prd-00/SCAA-OBD-20260318-EN.pdf"],
  ["Customer Information Brochure", "https://library.apexfintechsolutions.com/wp-content/uploads/2024/12/Apex-Direct-Customer-Infromation-Brochure.pdf"],
  ["Privacy Policy", "https://library.apexfintechsolutions.com/wp-content/uploads/2025/04/AFBS-Privacy-Policy.pdf"],
  ["Terms of Service", "https://library.apexfintechsolutions.com/wp-content/uploads/2025/04/AFBS-Terms-of-Service-Template.pdf"],
  ["CIP Notice", "https://library.apexfintechsolutions.com/wp-content/uploads/2025/04/FINRA-CIP-Notice.pdf"],
  ["Business Continuity Plan", "https://library.apexfintechsolutions.com/wp-content/uploads/2024/12/Business-Continuity-Plan-Policy-11-08-2024.pdf"],
  ["Fee Sheet", "https://library.apexfintechsolutions.com/wp-content/uploads/2024/12/Apex-Direct-Misc-Services-Fee-Sheet-11.2024.pdf"],
];

const ApexAgreements = ({ onClose }) => {
  const link = { color: "var(--ink-2)", textDecoration: "underline", textUnderlineOffset: 2 };
  const disc = { fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", lineHeight: 1.58, marginTop: 12, marginBottom: 0, textWrap: "pretty", letterSpacing: "0.003em" };
  return (
    <div style={{ position: "absolute", inset: 0, zIndex: 80, background: "var(--bg)", display: "flex", flexDirection: "column", animation: "sheet-in 320ms cubic-bezier(0.16,1,0.30,1) both" }} data-screen-label="Apex agreements">
      <NavBar title="Apex Clearing Corporation" sub="Brokerage agreements" right={
        <button className="press" onClick={onClose} aria-label="Close" style={{ background: "none", border: "none", padding: 6, margin: "0 -6px", display: "flex", color: "var(--ink)", cursor: "pointer", flex: "none" }}>
          <Icon name="close" size={20} />
        </button>
      } />
      <div className="scroll" style={{ flex: 1, minHeight: 0, padding: "12px 24px 28px" }}>
        <Eyebrow color="var(--ink-2)">Documents</Eyebrow>
        <div style={{ display: "grid", marginTop: 4 }}>
          {APEX_DOCS.map(([name, url], i) => (
            <a key={name} href={url} target="_blank" rel="noopener noreferrer" className="press" style={{
              textDecoration: "none", display: "grid", gridTemplateColumns: "1fr auto", gap: 12, alignItems: "center",
              padding: "14px 0", borderTop: `1px ${i === 0 ? "solid" : "dashed"} var(--rule)`, color: "var(--ink)" }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500, letterSpacing: "-0.01em" }}>{name}</span>
              <Icon name="external" size={15} color="var(--ink-3)" />
            </a>
          ))}
        </div>

        <div style={{ marginTop: 26, paddingTop: 18, borderTop: "1px solid var(--rule-2)" }}>
          <p style={{ ...disc, marginTop: 0 }}>
            Brokerage services are provided by Apex Clearing Corporation, an SEC-registered broker-dealer and member FINRA/SIPC. Learn more about Apex at{" "}
            <a href="https://brokercheck.finra.org/" target="_blank" rel="noopener noreferrer" style={link}>FINRA BrokerCheck</a>.
          </p>
          <p style={disc}>
            Investing in securities involves risks, including the potential loss of principal. Securities investments are not FDIC insured, are not bank guaranteed, and may lose value. Before investing, please carefully review your investment objectives, risk tolerance, charges, and expenses. Yoshi is not owned or operated by Apex Clearing Corporation.
          </p>
          <p style={{ ...disc, display: "flex", alignItems: "center", gap: 7 }}>
            <span>For additional information about SIPC coverage, visit{" "}
              <a href="https://www.sipc.org" target="_blank" rel="noopener noreferrer" style={link}>sipc.org</a>.</span>
          </p>
        </div>
      </div>
    </div>
  );
};

const Disclosures = ({ onNext }) => {
  const [signing, setSigning] = useState(false);
  const [showApex, setShowApex] = useState(false);
  const [checks, setChecks] = useState({ esign: false, column: false, apex: false });
  const toggleCheck = (key) => setChecks((current) => ({ ...current, [key]: !current[key] }));
  const sign = () => { if (signing) return; setSigning(true); setTimeout(() => onNext(), 760); };
  const selectAllAndContinue = () => {
    if (signing) return;
    setChecks({ esign: true, column: true, apex: true });
    sign();
  };
  const link = { color: "var(--ink-2)", textDecoration: "underline", textUnderlineOffset: 2 };

  return (
    <Screen style={{ position: "relative" }}>
      <Body>
        <H>A bit of fine <Accent>print.</Accent></H>
        <Sub style={{ maxWidth: "none" }}>Check the boxes below to confirm you've read and accept the agreements.</Sub>

        {/* Selection and document-opening controls are separate siblings. */}
        <div className="lucid-glass-panel" style={{ position: "relative", marginTop: 20, padding: "4px 20px 6px", overflow: "hidden" }}>
          <AgreementCheckRow first checked={checks.esign} onToggle={() => toggleCheck("esign")} label="E-sign" sub="Electronic delivery and signature of your account documents." href="/esign-consent/" />
          <AgreementCheckRow checked={checks.column} onToggle={() => toggleCheck("column")} label="Column N.A." sub="Banking · Member FDIC" href="https://column.com/legal" />
          <AgreementCheckRow last checked={checks.apex} onToggle={() => toggleCheck("apex")} label="Apex Clearing Corporation" sub="Brokerage · Member FINRA/SIPC" onOpen={() => setShowApex(true)} />
        </div>

        {/* the required fine print, in full */}
        <p style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", lineHeight: 1.55, marginTop: 22, marginBottom: 4, textWrap: "pretty", letterSpacing: "0.004em" }}>
          Yoshi is a fintech company, not a bank. Cash Account and banking services provided by Column N.A., Member FDIC. FDIC insurance covers the failure of an insured depository institution. Brokerage services are provided by Apex Clearing Corporation, an SEC-registered broker-dealer and member FINRA/SIPC. Learn more about Apex at{" "}
          <a href="https://brokercheck.finra.org/" target="_blank" rel="noopener noreferrer" style={link}>FINRA BrokerCheck</a>.
        </p>
      </Body>
      <Dock>
        {/* the seam draws across at the moment of signing — the brand's approval signature */}
        <div style={{ height: 1, background: "var(--accent)", opacity: 0.6, transformOrigin: "left center", transform: `scaleX(${signing ? 1 : 0})`, transition: "transform 700ms linear" }} />
        <Btn full onClick={selectAllAndContinue} disabled={signing}>
          {signing
            ? <><LiveDot size={6} color="var(--accent-ink)" /> Signing…</>
            : <>Select all &amp; continue</>}
        </Btn>
      </Dock>

      {showApex && <ApexAgreements onClose={() => setShowApex(false)} />}
    </Screen>
  );
};

/* =============================================================
   12 · OFF TO WORK — account creation before external linking.
   ============================================================= */
const OffToWork = ({ accent = "#000000", onDone }) => {
  const [status, setStatus] = useState("creating");
  useEffect(() => {
    const live = setTimeout(() => setStatus("live"), 2400);
    const done = setTimeout(() => { onDone && onDone(); }, 3800);
    return () => { clearTimeout(live); clearTimeout(done); };
  }, [onDone]);
  const ink = "var(--ink)";
  const live = status === "live";

  return (
    <Screen style={{ background: "var(--bg)", color: ink }}>
      <div className="scroll" style={{ flex: 1, minHeight: 0, padding: "12px 24px 28px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
        <div style={{ display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center" }}>
          <MotionLogo size={88} />
          <div className="yo-enter" data-delay="1" style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 9, minHeight: 18, marginTop: 24 }}>
            {live ? <Icon name="check" size={15} stroke={2.6} color={accent} /> : <LiveDot size={8} color={accent} />}
            <span style={{ fontFamily: "var(--f-display)", fontSize: 10.5, fontWeight: 500, letterSpacing: "0.16em", textTransform: "uppercase", color: accent }}>{live ? "Your accounts are live!" : "Creating your accounts."}</span>
          </div>
          <div className="yo-enter" data-delay="2" style={{ fontFamily: "var(--f-display)", fontSize: 40, fontWeight: 500, letterSpacing: "-0.035em", lineHeight: 1.0, marginTop: 14, color: ink }}>
            Yoshi is off<br />to <span style={{ color: accent }}>work.</span>
          </div>
        </div>


      </div>
    </Screen>
  );
};

Object.assign(window, { PlaidLink, BANKS, Funding, FundDeposit, Disclosures, OffToWork });
