/* profile.jsx — the "You" hamburger hub. A clean menu: identity, open-a-new
   account (accordion), and entries into Settings / Documents / Help. Settings
   is its own screen with collapsible sections. */

const Toggle = ({ on, onChange }) =>
<button className="press" role="switch" aria-checked={on} onClick={() => onChange(!on)} style={{ width: 40, height: 23, padding: 0, position: "relative", background: on ? "var(--accent)" : "var(--rule-2)", border: "none", borderRadius: 999, cursor: "pointer", flex: "none", transition: "background 180ms ease" }}>
    <span style={{ position: "absolute", top: 2.5, left: on ? 20 : 2.5, width: 18, height: 18, borderRadius: "50%", background: "var(--ld-white)", transition: "left 180ms var(--ease)", boxShadow: "0 1px 3px rgba(0,0,0,0.3)" }} />
  </button>;


const SettingRow = ({ label, sub, right, last, onClick }) => {
  return (
    <div className={onClick ? "press" : undefined} role={onClick ? "button" : undefined} tabIndex={onClick ? 0 : undefined}
    onClick={onClick} onKeyDown={onClick ? (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onClick(e); } } : undefined}
    style={{ width: "100%", textAlign: "left", background: "none", border: "none", color: "var(--ink)", display: "flex", alignItems: "center", gap: 12, padding: "13px 16px", borderBottom: last ? "none" : "1px solid var(--rule)", cursor: onClick ? "pointer" : "default" }}>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-body)", fontWeight: 500 }}>{label}</div>
      {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-small)", color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>}
    </div>
    {right}
  </div>
  );
};


/* hold-to-confirm — press and hold 3s to commit a sensitive change */
const HoldButton = ({ label, onConfirm }) => {
  const [progress, setProgress] = useState(0);
  const raf = useRef(null);
  const startT = useRef(0);
  const DURATION = 3000;
  const stop = (done) => {
    if (raf.current) cancelAnimationFrame(raf.current);
    raf.current = null;startT.current = 0;
    setProgress(0);
    if (done) onConfirm();
  };
  const frame = (t) => {
    if (!startT.current) startT.current = t;
    const p = Math.min(1, (t - startT.current) / DURATION);
    setProgress(p);
    if (p >= 1) {stop(true);return;}
    raf.current = requestAnimationFrame(frame);
  };
  const begin = (e) => {e.preventDefault();startT.current = 0;raf.current = requestAnimationFrame(frame);};
  const holding = progress > 0 && progress < 1;
  return (
    <button className="press"
    onPointerDown={begin} onPointerUp={() => stop(false)} onPointerLeave={() => stop(false)} onPointerCancel={() => stop(false)}
    style={{ position: "relative", overflow: "hidden", width: "100%", padding: "12px 16px", border: "1px solid var(--hold-accent)", background: "transparent", color: "var(--hold-accent)", fontFamily: "var(--f-display)", fontSize: typeSize(13), fontWeight: 500, cursor: "pointer", borderRadius: 10, touchAction: "none", WebkitUserSelect: "none", userSelect: "none" }}>
      <span style={{ position: "absolute", top: 0, left: 0, bottom: 0, width: `${progress * 100}%`, background: "var(--hold-accent)", opacity: 0.32, transition: holding ? "none" : "width 180ms ease" }} />
      <span style={{ position: "relative" }}>{holding ? "Keep holding…" : label}</span>
    </button>);

};

const TILE = { width: 34, height: 34, flex: "none", border: "1px solid var(--rule-2)", borderRadius: 999, display: "grid", placeItems: "center" };

/* whole-Yoshi deletion — no individual account closure exists in Product. */
const DeleteYoshiAccount = () => {
  const reviewView = new URLSearchParams(window.location.search).get("view");
  const readyExample = reviewView === "delete-yoshi-ready" || reviewView === "delete-yoshi-requested";
  const [requested, setRequested] = useState(reviewView === "delete-yoshi-requested");
  const blockers = readyExample ? [] : [
    "Withdraw the remaining cash from Yoshi Cash",
    "Sell or transfer all investments",
    "Wait for every in-motion transaction to finish",
  ];

  return (
    <div style={{ padding: "4px 16px 18px" }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), fontWeight: 500, color: "var(--signal-danger)", letterSpacing: "normal" }}>Delete your Yoshi account</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11.5), color: "var(--ink-3)", lineHeight: 1.55, marginTop: 5 }}>
        This permanently closes Yoshi Cash and Brokerage, removes your profile, and ends your access to Yoshi. It cannot be undone.
      </div>

      {blockers.length > 0 ?
      <div style={{ marginTop: 14, border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden" }}>
          <div style={{ padding: "11px 12px", background: "color-mix(in srgb, var(--signal-danger) 7%, transparent)", borderBottom: "1px solid var(--rule)" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(12.5), fontWeight: 500, color: "var(--ink)" }}>Not ready to delete</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", lineHeight: 1.45, marginTop: 3 }}>Complete every step before deleting Yoshi.</div>
          </div>
          {blockers.map((blocker, index) =>
          <div key={blocker} style={{ display: "flex", alignItems: "flex-start", gap: 9, padding: "10px 12px", borderBottom: index === blockers.length - 1 ? "none" : "1px solid var(--rule)" }}>
              <Icon name="clock" size={14} color="var(--signal-neg)" stroke={1.8} />
              <span style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11.5), lineHeight: 1.45, color: "var(--ink-2)" }}>{blocker}</span>
            </div>)}
        </div> :
      requested ?
      <div style={{ display: "flex", alignItems: "flex-start", gap: 8, padding: "11px 12px", marginTop: 14, border: "1px solid color-mix(in srgb, var(--signal-danger) 40%, var(--rule-2))", background: "color-mix(in srgb, var(--signal-danger) 8%, transparent)", borderRadius: 10 }}>
          <Icon name="check" size={15} color="var(--signal-danger)" stroke={2.2} />
          <div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(12.5), fontWeight: 500, color: "var(--ink)" }}>Deletion requested</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), lineHeight: 1.45, color: "var(--ink-3)", marginTop: 3 }}>We'll email you to confirm. Nothing is deleted until you complete that confirmation in Yoshi.</div>
          </div>
        </div> :
      <>
          <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "10px 12px", marginTop: 14, border: "1px solid color-mix(in srgb, var(--accent) 35%, var(--rule-2))", background: "color-mix(in srgb, var(--accent) 8%, transparent)", borderRadius: 10 }}>
            <Icon name="check" size={15} color="var(--accent)" stroke={2.2} />
            <span style={{ fontFamily: "var(--f-display)", fontSize: typeSize(12.5), fontWeight: 500, color: "var(--ink)" }}>Ready to delete</span>
          </div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", lineHeight: 1.5, marginTop: 11 }}>
            Download any documents you want to keep before confirming deletion.
          </div>
          <div style={{ marginTop: 12, "--hold-accent": "var(--signal-danger)" }}>
            <HoldButton label="Hold to delete your Yoshi account" onConfirm={() => setRequested(true)} />
          </div>
        </>}
    </div>);

};


/* a tappable hub row with a leading icon tile */
const MenuRow = ({ icon, label, sub, onClick, last }) =>
<button className="press" onClick={onClick} style={{ width: "100%", background: "none", border: "none", borderBottom: last ? "none" : "1px solid var(--rule)", textAlign: "left", cursor: "pointer", display: "flex", alignItems: "center", gap: 12, padding: "14px 16px" }}>
    <Icon name={icon} size={22} stroke={1.5} color="var(--ink)" />
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-body)", fontWeight: 500 }}>{label}</div>
      {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-small)", color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>}
    </div>
    <Icon name="back" size={15} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
  </button>;


/* a collapsible group — tap the header to expand */
const Accordion = ({ icon, label, sub, children, defaultOpen, last, tag }) => {
  const [open, setOpen] = useState(!!defaultOpen);
  return (
    <div style={{ borderBottom: last ? "none" : "1px solid var(--rule)" }}>
      <button className="press" onClick={() => setOpen((o) => !o)} style={{ width: "100%", background: "none", border: "none", textAlign: "left", cursor: "pointer", display: "flex", alignItems: "center", gap: 12, padding: "14px 16px" }}>
        {icon && <Icon name={icon} size={22} stroke={1.5} color="var(--ink)" />}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-body)", fontWeight: 500 }}>{label}</span>
            {tag && <span style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-caption)", fontWeight: 500, letterSpacing: "normal", textTransform: "uppercase", color: "var(--ink-3)", border: "1px solid var(--rule-2)", padding: "2px 6px" }}>{tag}</span>}
          </div>
          {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: "var(--ld-type-small)", color: "var(--ink-3)", marginTop: 3 }}>{sub}</div>}
        </div>
        <Icon name="down" size={16} color="var(--ink-3)" style={{ transform: open ? "rotate(180deg)" : "none", transition: "transform 180ms ease" }} />
      </button>
      {open && <div>{children}</div>}
    </div>);

};

const COMING_SOON_ACCOUNTS = [
["Crypto", "A dedicated spot wallet"],
["Retirement", "Roth & Traditional IRA"],
["Joint", "Shared with another person"]];


/* ---- profile form fields · Yoshi-styled (sharp, hairline) ----------------- */
const PInput = ({ label, value, onChange, placeholder, mono }) =>
<div style={{ marginBottom: 12 }}>
    {label && <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), fontWeight: 500, color: "var(--ink-2)", marginBottom: 6 }}>{label}</div>}
    <input value={value || ""} onChange={(e) => onChange && onChange(e.target.value)} placeholder={placeholder}
  style={{ width: "100%", padding: "11px 12px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", outline: "none", color: "var(--ink)", fontFamily: mono ? "var(--f-mono)" : "var(--f-display)", fontSize: typeSize(14) }} />
  </div>;

const PSelect = ({ label, value, onChange, options }) =>
<div style={{ marginBottom: 12 }}>
    {label && <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), fontWeight: 500, color: "var(--ink-2)", marginBottom: 6 }}>{label}</div>}
    <div style={{ position: "relative" }}>
      <select value={value} onChange={(e) => onChange && onChange(e.target.value)}
    style={{ width: "100%", padding: "11px 30px 11px 12px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", outline: "none", color: value && value !== "Select" ? "var(--ink)" : "var(--ink-3)", fontFamily: "var(--f-display)", fontSize: typeSize(14), appearance: "none", WebkitAppearance: "none", borderRadius: 0, cursor: "pointer" }}>
        {options.map((o) => <option key={o} value={o}>{o}</option>)}
      </select>
      <Icon name="down" size={15} color="var(--ink-3)" style={{ position: "absolute", right: 10, top: "50%", marginTop: -7, pointerEvents: "none" }} />
    </div>
  </div>;

const PTwo = ({ children }) => <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>{children}</div>;
const PDivider = () => <div style={{ height: 1, background: "var(--rule)", margin: "6px 0 14px" }} />;

const PersonalInfoForm = () => {
  const [f, setF] = useState({ preferred: "Rivka", first: "Rivka", last: "Lipson", tcFirst: "", tcLast: "", tcEmail: "" });
  const set = (k) => (v) => setF((s) => ({ ...s, [k]: v }));
  return (
    <div style={{ padding: "4px 16px 16px" }}>
      <PInput label="Preferred name" value={f.preferred} onChange={set("preferred")} />
      <PTwo>
        <PInput label="First name" value={f.first} onChange={set("first")} />
        <PInput label="Last name" value={f.last} onChange={set("last")} />
      </PTwo>
      <PDivider />
      <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), fontWeight: 500, marginBottom: 10 }}>Trusted contact</div>
      <PTwo>
        <PInput label="First name" value={f.tcFirst} onChange={set("tcFirst")} placeholder="First name" />
        <PInput label="Last name" value={f.tcLast} onChange={set("tcLast")} placeholder="Last name" />
      </PTwo>
      <PInput label="Email" value={f.tcEmail} onChange={set("tcEmail")} placeholder="name@email.com" />
      <PDivider />
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13.5), fontWeight: 500 }}>Address</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", marginTop: 3 }}>148 Mercer St, New York, NY</div>
        </div>
        <Btn kind="ghost" onClick={() => {}} style={{ padding: "8px 13px", fontSize: typeSize(12) }}>Edit address</Btn>
      </div>
    </div>);

};

const INVESTOR_PROFILE = {
  version: 3,
  source: "User attested",
  status: "Complete",
  attested: "Jun 24, 2026",
  risk: "Moderate",
  horizon: "10 years",
  objectives: ["Growth", "Balanced"],
  liquidity: "Moderate",
  income: "$100k–$249k",
  liquid: "$250k–$999k",
  netWorth: "$1M–$4.99M",
  tax: "High",
  experience: "Good",
  employment: "Employed",
  dependents: "2",
  expenses: [{ description: "Home down payment", timeframe: "3 years", amount: "$100,000.00" }],
  constraints: ["Avoid single-stock concentration"],
  considerations: "Prefers ESG-aligned holdings.",
  facts: [
    "Would stay invested or rebalance rather than sell during a 20.00% market decline.",
    "No material external concentrated stock, crypto, options, margin, or private investment exposure disclosed."
  ]
};

const ReadOnlyPill = ({ children, tone }) =>
<span style={{ display: "inline-flex", alignItems: "center", height: 22, padding: "0 8px", border: "1px solid " + (tone === "accent" ? "color-mix(in srgb, var(--accent) 45%, var(--rule-2))" : "var(--rule-2)"), background: tone === "accent" ? "color-mix(in srgb, var(--accent) 10%, transparent)" : "transparent", color: tone === "accent" ? "var(--accent)" : "var(--ink-3)", fontFamily: "var(--f-mono)", fontSize: typeSize(10), fontWeight: 500, letterSpacing: "normal", textTransform: "uppercase", whiteSpace: "nowrap" }}>{children}</span>;

const ReadOnlyField = ({ label, value, children }) =>
<div style={{ minWidth: 0, marginBottom: 12 }}>
    <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(10.5), fontWeight: 500, letterSpacing: "normal", textTransform: "uppercase", color: "var(--ink-3)", marginBottom: 6 }}>{label}</div>
    <div style={{ minHeight: 40, display: "flex", alignItems: "center", gap: 7, flexWrap: "wrap", padding: "10px 11px", background: "color-mix(in srgb, var(--ink) 3%, var(--bg-2))", border: "1px solid var(--rule-2)", borderRadius: 10, color: "var(--ink)", fontFamily: "var(--f-display)", fontSize: typeSize(13.5), lineHeight: 1.35 }}>
      {children || value}
    </div>
  </div>;

const ReadOnlySection = ({ title, children }) =>
<div style={{ marginTop: 16 }}>
    <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(12), fontWeight: 500, letterSpacing: "normal", textTransform: "uppercase", color: "var(--ink-3)", marginBottom: 8 }}>{title}</div>
    {children}
  </div>;

const InvestorProfileForm = ({ nav }) => {
  const p = INVESTOR_PROFILE;
  const chatUpdate = () => {
    if (!nav) return;
    nav.ask("Update my investor profile.", "Of course. Tell me what changed about your goals, risk comfort, time horizon, liquidity needs, income, net worth, tax picture, investing experience, constraints, or special considerations. I'll update the profile from the conversation and ask you to confirm anything material.");
  };
  return (
    <div data-investor-profile-readonly="true" style={{ padding: "4px 16px 18px" }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginBottom: 14 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(15), fontWeight: 500, letterSpacing: "normal" }}>Yoshi's view of your investor profile</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11.5), color: "var(--ink-3)", marginTop: 4, lineHeight: 1.45 }}>Built from conversations with Yoshi. Changes happen through chat, not this settings form.</div>
        </div>
        <ReadOnlyPill tone="accent">{p.status}</ReadOnlyPill>
      </div>

      <div style={{ border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden", background: "var(--bg-card)" }}>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", borderBottom: "1px solid var(--rule)" }}>
          {[
            ["Source", p.source],
            ["Profile version", p.version],
            ["Attested", p.attested]
          ].map(([label, value], i) => (
            <div key={label} style={{ padding: "11px 12px", borderLeft: i === 0 ? "none" : "1px solid var(--rule)" }}>
              <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(10), fontWeight: 500, letterSpacing: "normal", textTransform: "uppercase", color: "var(--ink-3)" }}>{label}</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), fontWeight: 500, color: "var(--ink)", marginTop: 4 }}>{value}</div>
            </div>
          ))}
        </div>
        <div style={{ padding: "12px", display: "flex", alignItems: "center", gap: 10 }}>
          <Icon name="shield" size={18} color="var(--accent)" stroke={1.6} />
          <div style={{ flex: 1, minWidth: 0, fontFamily: "var(--f-display)", fontSize: typeSize(12.5), color: "var(--ink-2)", lineHeight: 1.45 }}>
            This is the profile Yoshi uses for suitability and advice context.
          </div>
        </div>
      </div>

      <ReadOnlySection title="Core profile">
      <PTwo>
          <ReadOnlyField label="Risk tolerance" value={p.risk} />
          <ReadOnlyField label="Time horizon" value={p.horizon} />
      </PTwo>
      <PTwo>
          <ReadOnlyField label="Objectives">
            {p.objectives.map((x) => <ReadOnlyPill key={x}>{x}</ReadOnlyPill>)}
          </ReadOnlyField>
          <ReadOnlyField label="Liquidity needs" value={p.liquidity} />
      </PTwo>
      </ReadOnlySection>

      <ReadOnlySection title="Financial picture">
      <PTwo>
          <ReadOnlyField label="Annual income band" value={p.income} />
          <ReadOnlyField label="Liquid net worth" value={p.liquid} />
      </PTwo>
      <PTwo>
          <ReadOnlyField label="Total net worth" value={p.netWorth} />
          <ReadOnlyField label="Tax status" value={p.tax} />
      </PTwo>
      <PTwo>
          <ReadOnlyField label="Investment experience" value={p.experience} />
          <ReadOnlyField label="Employment" value={p.employment} />
      </PTwo>
      </ReadOnlySection>

      <ReadOnlySection title="Facts Yoshi confirmed">
        <div style={{ border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden" }}>
          {p.facts.map((fact, i) => (
            <div key={fact} style={{ display: "grid", gridTemplateColumns: "18px minmax(0, 1fr)", gap: 9, padding: "12px 13px", borderBottom: i === p.facts.length - 1 ? "none" : "1px solid var(--rule)" }}>
              <Icon name="check" size={15} color="var(--accent)" stroke={2.1} />
              <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(12.5), color: "var(--ink-2)", lineHeight: 1.5 }}>{fact}</div>
            </div>
          ))}
        </div>
      </ReadOnlySection>

      <ReadOnlySection title="Constraints and considerations">
        <div style={{ border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden" }}>
          <div style={{ padding: "12px 13px", borderBottom: "1px solid var(--rule)" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", marginBottom: 5 }}>Large planned expense</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), color: "var(--ink)", lineHeight: 1.45 }}>{p.expenses[0].description} · {p.expenses[0].amount} in {p.expenses[0].timeframe}</div>
          </div>
          <div style={{ padding: "12px 13px", borderBottom: "1px solid var(--rule)" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", marginBottom: 5 }}>Investment constraints</div>
            <div style={{ display: "flex", gap: 7, flexWrap: "wrap" }}>{p.constraints.map((x) => <ReadOnlyPill key={x}>{x}</ReadOnlyPill>)}</div>
          </div>
          <div style={{ padding: "12px 13px" }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", marginBottom: 5 }}>Special considerations</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), color: "var(--ink-2)", lineHeight: 1.45 }}>{p.considerations}</div>
          </div>
        </div>
      </ReadOnlySection>

      <div data-investor-profile-chat-cta="text-width" style={{ marginTop: 14, display: "flex", justifyContent: "center" }}>
        <Btn onClick={chatUpdate}>Chat with Yoshi to update</Btn>
      </div>
    </div>);

};

/* ============ SETTINGS — its own screen, collapsible sections. On web it
   renders as a page beside the menu drawer; on mobile it pushes over the You
   hub. ============ */
/* ---- settings section bodies, each self-contained so it can render either as
   an accordion (mobile) or as a focused pane beside the drawer (web) ---- */
const NotificationsSettings = () => {
  const [channels, setChannels] = useState(PROFILE.channels.map((c) => c[2]));
  const [emailNotif, setEmailNotif] = useState(true);
  return (
    <>
      {PROFILE.channels.map(([name, detail], i) => {
      const web = window.__YOSHI_WEB && i === 0;
      return <SettingRow key={name} label={web ? "Browser notifications" : name} sub={web ? "This browser" : detail}
      right={<Toggle on={channels[i]} onChange={(v) => setChannels((c) => c.map((x, j) => j === i ? v : x))} />} />;
      })}
      <SettingRow label="Email" sub={PROFILE.email} last right={<Toggle on={emailNotif} onChange={setEmailNotif} />} />
    </>
  );
};

const PasskeyRecoveryPanel = ({ step, onCancel, onPlaidSuccess, onGenerated, onDone }) => {
  const [busy, setBusy] = useState(false);
  const run = (next) => {
    if (busy) return;
    setBusy(true);
    setTimeout(() => { setBusy(false); next(); }, 900);
  };
  const plaid = step === "plaid";
  const done = step === "done";
  return (
    <div className="push-enter" style={{ padding: "16px", minHeight: 360 }}>
      <div style={{ border: "1px solid var(--rule-2)", background: "var(--bg-card)", borderRadius: 12, padding: 18 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 16 }}>
          <div style={{ width: 40, height: 40, border: `1px solid ${plaid ? "#12a87c" : "var(--rule-2)"}`, borderRadius: 12, display: "grid", placeItems: "center", color: plaid ? "#12a87c" : "var(--accent)" }}>
            <Icon name={plaid ? "eye" : done ? "check" : "key"} size={22} stroke={1.6} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <Eyebrow color={plaid ? "#12a87c" : "var(--accent)"}>{plaid ? "Plaid identity" : done ? "Recovered" : "Yoshi passkey"}</Eyebrow>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(20), fontWeight: 500, letterSpacing: "normal", marginTop: 3 }}>
              {plaid ? "Liveness check" : done ? "New passkey ready" : "Generate new passkey"}
            </div>
          </div>
          {!done && <StatusTag tone="neutral">Required</StatusTag>}
        </div>

        <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(13), color: "var(--ink-2)", lineHeight: 1.55 }}>
          {plaid
            ? "Verify it's you with Plaid, then you'll return to Yoshi to create a new passkey."
            : done
              ? "This device now has a new passkey. Your previous device passkeys stay active unless you remove them."
              : "Plaid confirmed it's you. Create a new passkey in Yoshi."}
        </div>

        <div style={{ display: "grid", gap: 9, marginTop: 18 }}>
          {plaid && <Btn full onClick={() => run(onPlaidSuccess)} disabled={busy}>{busy ? "Checking…" : "Complete liveness check"}</Btn>}
          {step === "generate" && <Btn full onClick={() => run(onGenerated)} disabled={busy}>{busy ? "Generating…" : "Generate new passkey"}</Btn>}
          {done && <Btn full onClick={onDone}>Done</Btn>}
          {!done && <Btn kind="ghost" full onClick={onCancel} disabled={busy}>Back to security</Btn>}
        </div>
      </div>
    </div>
  );
};

const SecuritySettings = () => {
  const [recoveryStep, setRecoveryStep] = useState(null);
  if (recoveryStep) {
    return (
      <PasskeyRecoveryPanel
        step={recoveryStep}
        onCancel={() => setRecoveryStep(null)}
        onPlaidSuccess={() => setRecoveryStep("generate")}
        onGenerated={() => setRecoveryStep("done")}
        onDone={() => setRecoveryStep(null)}
      />
    );
  }
  return (
    <>
      <SettingRow label="Passkeys" sub="2 devices enrolled"
      right={<Btn kind="ghost" onClick={() => setRecoveryStep("plaid")} style={{ padding: "8px 13px", fontSize: typeSize(12), whiteSpace: "nowrap" }}>Recover passkey</Btn>} />
      <SettingRow label="Google sign-in" sub="Manage the Google account and email used to sign in to Yoshi" last
      right={<Btn kind="ghost" onClick={() => {}} style={{ padding: "8px 13px", fontSize: typeSize(12), whiteSpace: "nowrap" }}>Change</Btn>} />
    </>
  );
};

const AppearanceSettings = ({ palette, setPalette }) => (
  <div style={{ padding: "4px 16px 16px" }}>
    <div style={{ display: "flex", alignItems: "center", marginBottom: 11 }}>
      <span style={{ fontFamily: "var(--f-display)", fontSize: typeSize(14), fontWeight: 500 }}>Theme</span>
      <span style={{ marginLeft: "auto", fontFamily: "var(--f-display)", fontSize: typeSize(11.5), color: "var(--ink-3)" }}>Light</span>
    </div>
    <div style={{ color: "var(--ink-3)", fontSize: 14 }}>Lucid Dreaming</div>
  </div>
);

const AutomationsSettings = () => {
  const [dailyCap, setDailyCap] = useState(5000);
  const [pendingCap, setPendingCap] = useState(5000);
  const [autoOn, setAutoOn] = useState(true);
  return (
    <>
      <SettingRow label="Automations active" sub={autoOn ? "Standing rules run inside your limits" : "All standing rules are paused"} right={<Toggle on={autoOn} onChange={setAutoOn} />} />
      <div style={{ padding: "2px 16px 16px", opacity: autoOn ? 1 : 0.45, pointerEvents: autoOn ? "auto" : "none", transition: "opacity .15s" }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
          <span style={{ fontFamily: "var(--f-display)", fontSize: typeSize(14), fontWeight: 500 }}>Daily autonomous cap</span>
          <span style={{ marginLeft: "auto", fontFamily: "var(--f-mono)", fontSize: typeSize(15), fontWeight: 500, color: "var(--accent)", fontVariantNumeric: "proportional-nums" }}>{usd(pendingCap, 0)}</span>
        </div>
        <input className="yo-range" type="range" min={0} max={25000} step={500} value={pendingCap}
        onChange={(e) => setPendingCap(parseInt(e.target.value, 10))} style={{ marginTop: 11 }} />
        <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(11), color: "var(--ink-3)", marginTop: 7, lineHeight: 1.45 }}>
          The most your agents can move in a day without asking. Per-automation limits are set on each proposal.
        </div>
        {pendingCap !== dailyCap &&
        <div style={{ marginTop: 13 }}><HoldButton label="Tap & hold to confirm" onConfirm={() => setDailyCap(pendingCap)} /></div>
        }
      </div>
    </>
  );
};

/* the section catalog — order matters; shared by the mobile screen, the web
   drawer list, and the web focused pane */
const settingsSections = (palette, setPalette, nav) => [
  { id: "personal", icon: "profile", label: "Personal information", sub: "Contact details and trusted contact", body: <PersonalInfoForm /> },
  { id: "investor", icon: "doc", label: "Investor profile", sub: "Suitability and advisory state", body: <InvestorProfileForm nav={nav} /> },
  { id: "notifications", icon: "bell", label: "Notifications", sub: "How Yoshi reaches you", body: <NotificationsSettings /> },
  { id: "security", icon: "shield", label: "Security", sub: "Passkeys and sign-in", body: <SecuritySettings /> },
  { id: "appearance", icon: "display", label: "Appearance", sub: "Theme and palette", body: <AppearanceSettings palette={palette} setPalette={setPalette} /> },
  { id: "automations", icon: "gear", label: "Automations", sub: "Daily autonomous cap", tag: "Soon", body: <AutomationsSettings /> },
  { id: "delete", icon: "shield", label: "Delete your Yoshi account", sub: "Permanently close Yoshi", body: <DeleteYoshiAccount /> },
];

/* mobile: the full settings screen, sections as accordions */
const SettingsScreen = ({ palette, setPalette, nav, onClose }) => (
  <div className="push-enter" style={{ position: "absolute", inset: 0, zIndex: 40, background: "var(--bg)", display: "flex", flexDirection: "column" }} data-screen-label="Settings">
    <NavBar title="Settings" onBack={onClose} />
    <div className="scroll" style={{ paddingBottom: 24 }}>
      <div style={{ borderTop: "1px solid var(--rule)" }}>
        {settingsSections(palette, setPalette, nav).map((s, i, arr) => (
          <Accordion key={s.id} icon={s.icon} label={s.label} sub={s.sub} tag={s.tag} last={i === arr.length - 1}>{s.body}</Accordion>
        ))}
      </div>
    </div>
  </div>
);
window.SettingsScreen = SettingsScreen;

/* web: the drawer's settings list — replaces the menu contents; each row opens
   its section as a focused pane beside the drawer */
const SettingsList = ({ palette, setPalette, nav, onBack, onOpen }) => (
  <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
    <div style={{ flex: "none", height: 58, display: "flex", alignItems: "center", gap: 4, padding: "0 22px 0 10px", borderBottom: "1px solid var(--rule)" }}>
      <button className="press" aria-label="Back" title="Back" onClick={onBack} style={{ width: 38, height: 38, flex: "none", borderRadius: 10, display: "grid", placeItems: "center", background: "none", border: "none", color: "var(--ink)", cursor: "pointer" }}>
        <Icon name="back" size={22} />
      </button>
      <span style={{ fontFamily: "var(--f-display)", fontSize: typeSize(20), fontWeight: 500, letterSpacing: "normal" }}>Settings</span>
    </div>
    <div className="scroll" style={{ paddingBottom: 24 }}>
      <div style={{ borderTop: "1px solid var(--rule)" }}>
        {settingsSections(palette, setPalette, nav).map((s, i, arr) => (
          <MenuRow key={s.id} icon={s.icon} label={s.label} sub={s.sub} onClick={() => onOpen(s.id)} last={i === arr.length - 1} />
        ))}
      </div>
    </div>
  </div>
);
window.SettingsList = SettingsList;

/* web: a single settings section, rendered as a focused pane beside the drawer */
const SettingsSectionPane = ({ id, palette, setPalette, nav, onClose }) => {
  const sec = settingsSections(palette, setPalette, nav).find((s) => s.id === id);
  if (!sec) return null;
  return (
    <div className="push-enter" style={{ position: "absolute", inset: 0, background: "var(--bg)", display: "flex", flexDirection: "column" }} data-screen-label="Settings section">
      <NavBar title={sec.label} />
      <div className="scroll" style={{ paddingBottom: 24 }}>
        <div style={{ borderTop: "1px solid var(--rule)" }}>{sec.body}</div>
      </div>
    </div>
  );
};
window.SettingsSectionPane = SettingsSectionPane;

const Profile = ({ palette, setPalette, nav, onClose }) => {
  const [view, setView] = useState("menu");
  const openBrokerage = () => nav.openAccount("brokerage");
  if (view === "settings") {
    return window.__YOSHI_WEB
      ? <SettingsList palette={palette} setPalette={setPalette} nav={nav} onBack={() => { setView("menu"); nav.menuPage(null); }} onOpen={(id) => nav.menuPage("settings:" + id)} />
      : <SettingsScreen palette={palette} setPalette={setPalette} nav={nav} onClose={() => setView("menu")} />;
  }
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      {window.__YOSHI_WEB ? (
        /* drawer header: an X aligned to the top-left hamburger it pulled out from */
        <div style={{ flex: "none", height: 58, display: "flex", alignItems: "center", padding: "0 22px 0 14px" }}>
          <button className="press" aria-label="Close menu" title="Close" onClick={() => (onClose ? onClose() : nav.tab("home"))} style={{ width: 38, height: 38, flex: "none", borderRadius: 10, display: "grid", placeItems: "center", background: "none", border: "none", color: "var(--ink)", cursor: "pointer" }}>
            <Icon name="close" size={22} />
          </button>
        </div>
      ) : (
        <NavBar title="You" border={false} onBack={() => nav.tab("home")} />
      )}
      <div className="scroll" style={{ paddingBottom: 24 }}>
        {/* identity */}
        <div style={{ padding: "0 16px 16px", display: "flex", alignItems: "center", gap: 14 }}>
          <div style={{ width: 56, height: 56, borderRadius: 999, background: "var(--accent)", color: "var(--accent-ink)", display: "grid", placeItems: "center", fontFamily: "var(--f-display)", fontSize: typeSize(22), fontWeight: 500 }}>RL</div>
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: typeSize(20), fontWeight: 500, letterSpacing: "normal" }}>{PROFILE.name}</div>
          </div>
        </div>

        <div style={{ borderTop: "1px solid var(--rule)" }}>
          {/* open a new account — surfaced directly in the menu */}
          <MenuRow icon="plus" label="Open a Brokerage account" sub="Taxable investing across stocks and ETFs" onClick={openBrokerage} />
          <MenuRow icon="gear" label="Settings" sub="Automations, channels, security, appearance" onClick={() => setView("settings")} />
          <MenuRow icon="doc" label="Documents" sub="Statements, tax forms, agreements" onClick={() => (window.__YOSHI_WEB ? nav.menuPage("documents") : nav.sheet({ type: "documents" }))} />
          <MenuRow icon="lifebuoy" label="Support" sub="Chat with Fin, our support assistant" onClick={() => nav.sheet({ type: "support" })} last />
        </div>

        <div style={{ padding: "8px 16px 0" }}>
          <Btn kind="ghost" full onClick={() => nav.signOut()}>Sign out</Btn>
        </div>
      </div>
    </div>);

};

window.Profile = Profile;
