/* inbox.jsx, agent inbox (proposals + activity) and the approval flow.
   ApprovalSheet runs the moment the brand is built around:
   review → confirm (Face ID) → the seam draws → executed. Plus
   Decline (with a reason) and Modify (bounce back to the agent in chat). */

const Inbox = ({ nav, proposals, completed, onApprove, initialTab = "needs" }) => {
  const [tab, setTab] = useState(initialTab);
  const [open, setOpen] = useState(null);
  const activityCount = ACTIVITY.reduce((s, g) => s + g.items.length, 0) + completed.filter((c) => String(c.id).startsWith("ex_")).length;
  const TABS = [["needs", "Needs you"], ["briefs", "Briefs"], ["autos", "Automations"], ["activity", "All activity"]];
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{ flex: "none", padding: "6px 18px 10px", borderBottom: "1px solid var(--rule)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontFamily: "var(--f-display)", fontSize: 22, fontWeight: 700, letterSpacing: "-0.025em" }}>Stream</span>
        </div>
        <div className="hcar" style={{ marginTop: 10, display: "flex", justifyContent: "space-between", overflowX: "auto", borderBottom: "1px solid var(--rule)" }}>
          {TABS.map(([k, l], i) => {
            const on = tab === k;
            return <button key={k} className="press" onClick={() => setTab(k)} style={{ flex: "none", position: "relative", textAlign: "center", padding: "6px 0 10px", background: "none", border: "none", color: on ? "var(--ink)" : "var(--ink-3)", fontFamily: "var(--f-display)", fontSize: 13, fontWeight: on ? 700 : 500, cursor: "pointer", whiteSpace: "nowrap" }}>
              {l}
              {on && <span style={{ position: "absolute", left: 0, right: 0, bottom: -1, height: 2, background: "var(--accent)" }} />}
            </button>;
          })}
        </div>
      </div>

      <div className="scroll">
        {tab === "needs" ?
        proposals.length ? proposals.map((p, i) =>
        <ProposalCard key={p.id} p={p} delay={i} onReview={() => onApprove(p.id)} />
        ) :
        <div style={{ padding: "60px 24px", textAlign: "center" }}>
              <div style={{ width: 40, height: 40, border: "1.5px solid var(--accent)", borderRadius: 999, display: "grid", placeItems: "center", margin: "0 auto 14px" }}><Icon name="check" size={20} stroke={2} color="var(--accent)" /></div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 16, fontWeight: 600 }}>You're all caught up.</div>
              <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-3)", marginTop: 5, lineHeight: 1.5 }}>Your agents will surface the next thing that needs you here.</div>
            </div> :

        tab === "briefs" ?
        <window.BriefsBoard nav={nav} onOpen={setOpen} /> :
        tab === "activity" ?
        <Activity completed={completed} nav={nav} /> :

        <AutomationsTab nav={nav} />
        }
        <div style={{ height: 16 }} />
      </div>

      {open && <window.BriefDetail b={open} onBack={() => setOpen(null)} onClose={() => setOpen(null)} nav={nav} />}
    </div>);

};

/* ---- automations · the standing-rules summary tab ------------------------- */
const AUTO_STATUS = {
  active: ["●", "Active", "var(--accent)"],
  watching: ["○", "Watching", "var(--ink-3)"],
  paused: ["○", "Paused", "var(--ink-3)"]
};
const AutoStat = ({ status }) => {
  return null;
  const [dot, label, color] = AUTO_STATUS[status] || AUTO_STATUS.active;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "1px 6px", borderRadius: 999, border: "1px solid var(--rule-2)", fontFamily: "var(--f-display)", fontSize: 8, fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase", color, flex: "none" }}>
      <span style={{ fontSize: 6, lineHeight: 1 }}>{dot}</span>{label}
    </span>);

};

const AutomationsTab = ({ nav }) => {
  const active = AUTOMATIONS.filter((a) => a.status === "active").length;
  const watching = AUTOMATIONS.filter((a) => a.status === "watching").length;
  const buildWithYoshi = () => nav.ask(
    "Build a new automation",
    "Sure. Tell me the rule in plain words, something like \"move anything over $20k in Checking to Savings\" or \"buy $200 of VTI every payday.\" I'll set it up within your limits and show you the first run before it executes."
  );
  return (
    <div>
      <div style={{ padding: "16px 18px 18px", borderBottom: "1px solid var(--rule)" }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 19, fontWeight: 600, letterSpacing: "-0.02em", color: "var(--ink)" }}>Your active automations</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)", marginTop: 6, lineHeight: 1.5 }}>Rules you approved that Yoshi continues to run in the background, within your limits. Update them any time.

        </div>
        <Btn full onClick={buildWithYoshi} style={{ marginTop: 13 }}>Build with Yoshi <Icon name="plus" size={17} color="var(--accent-ink)" /></Btn>
      </div>
      {AUTOMATIONS.map((a, i) =>
      <AutoRow key={a.id} a={a} last={i === AUTOMATIONS.length - 1} onOpen={() => nav.sheet({ type: "automation", id: a.id })} />
      )}
    </div>);

};

const AutoRow = ({ a, onOpen, last }) =>
<button className="press" onClick={onOpen} style={{
  width: "100%", textAlign: "left", background: "none", border: "none", borderBottom: last ? "none" : "1px solid var(--rule)",
  display: "grid", gridTemplateColumns: "1fr auto auto", gap: 10, alignItems: "center", padding: "13px 18px", cursor: "pointer"
}}>
    <div style={{ minWidth: 0 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
        <span style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, letterSpacing: "-0.01em", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.name}</span>
        <AutoStat status={a.status} />
      </div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.cadence}</div>
    </div>
    <div style={{ textAlign: "right" }}>
      <div style={{ fontFamily: "var(--f-mono)", fontSize: 13.5, color: a.measure.startsWith("+") ? "var(--accent-pos)" : "var(--ink-2)", fontVariantNumeric: "tabular-nums" }}>{a.measure}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 9.5, color: "var(--ink-3)", marginTop: 3 }}>{a.sub}</div>
    </div>
    <Icon name="back" size={15} color="var(--ink-3)" style={{ transform: "scaleX(-1)" }} />
  </button>;


const ProposalCard = ({ p, onReview, delay = 0 }) =>
<div className="yo-enter" data-delay={Math.min(delay + 1, 4)} style={{ margin: "12px 18px 0", border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden", background: "var(--bg-card)", position: "relative" }}>
    <div style={{ padding: "13px 14px 14px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
        <span style={{ width: 6, height: 6, borderRadius: 999, flex: "none", background: /^yoshi/i.test(p.agent) ? "var(--accent)" : "transparent", border: /^yoshi/i.test(p.agent) ? "none" : "1.5px solid var(--ink-3)" }} />
        <span style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, color: "var(--ink-3)", letterSpacing: "0.04em" }}>{p.agent}</span>
      </div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 600, letterSpacing: "-0.02em", marginTop: 8 }}>{p.title}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)", marginTop: 5, lineHeight: 1.5 }}>{p.why}</div>

      {/* legs preview */}
      <div style={{ marginTop: 11, border: "1px solid var(--rule)" }}>
        {p.legs.map((leg, i) => <Leg key={i} leg={leg} last={i === p.legs.length - 1} />)}
      </div>

      <div style={{ display: "flex", alignItems: "baseline", gap: 8, marginTop: 11 }}>
        <span style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ink-3)" }}>Net</span>
        <Money value={p.net} size={14} sign color={p.net >= 0 ? "var(--accent-pos)" : "var(--ink)"} dim="var(--ink-3)" />
      </div>

      <Btn full onClick={onReview} style={{ marginTop: 12 }}>Review <Icon name="arrow" size={17} color="var(--accent-ink)" /></Btn>
    </div>
  </div>;


const Leg = ({ leg, last }) => {
  const [tag, label, detail, amount] = leg;
  const tagColor = tag === "SELL" ? "var(--signal-neg)" : tag === "BUY" ? "var(--accent-pos)" : "var(--ink-2)";
  return (
    <div style={{ display: "grid", gridTemplateColumns: "44px 1fr auto", gap: 8, alignItems: "center", padding: "9px 11px", borderBottom: last ? "none" : "1px dashed var(--rule)" }}>
      <span style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.08em", color: tagColor }}>{tag}</span>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 500 }}>{label}</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 10.5, color: "var(--ink-3)" }}>{detail}</div>
      </div>
      <span style={{ fontFamily: "var(--f-mono)", fontSize: 12, color: "var(--ink)", whiteSpace: "nowrap" }}>{amount}</span>
    </div>);

};

/* ---- activity · the full stream, grouped by day --------------------------- */
const Activity = ({ completed }) => {
  // proposals approved this session get prepended into Today
  const fresh = completed.
  filter((c) => String(c.id).startsWith("ex_")).
  map((c) => ({ type: "exec", title: c.title, detail: c.detail, when: c.when, net: c.net, by: c.by }));
  const groups = ACTIVITY.map((g, i) => i === 0 ? { ...g, items: [...fresh, ...g.items] } : g);

  return (
    <div>
      {groups.map((g) =>
      <section key={g.day}>
          <div style={{ padding: "9px 18px 8px", background: "var(--bg-2)", display: "flex", alignItems: "baseline" }}>
            <Eyebrow color="var(--ink-2)">{g.day}</Eyebrow>
            <span style={{ marginLeft: "auto", fontFamily: "var(--f-display)", fontSize: 9.5, color: "var(--ink-3)", letterSpacing: "0.06em", textTransform: "uppercase" }}>{g.items.length} {g.items.length === 1 ? "event" : "events"}</span>
          </div>
          {g.items.map((it, j) => <ActivityItem key={j} it={it} />)}
        </section>
      )}
    </div>);

};

const ActivityItem = ({ it }) => {
  if (it.type === "report") {
    return (
      <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 10, padding: "12px 18px", borderBottom: "1px solid var(--rule)", alignItems: "center" }}>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--accent-pos)" }}>◆ {it.kind}</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500, marginTop: 3 }}>{it.title}</div>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-2)", marginTop: 3 }}>{it.detail}</div>
        </div>
        <button className="press" style={{ background: "none", border: "none", color: "var(--accent)", fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 4, cursor: "pointer", whiteSpace: "nowrap" }}>View <Icon name="arrow" size={14} color="var(--accent)" /></button>
      </div>);

  }
  const isDeposit = it.type === "deposit";
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 10, padding: "12px 18px", borderBottom: "1px solid var(--rule)", alignItems: "center" }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", color: isDeposit ? "var(--accent-pos)" : "var(--accent)" }}>● {isDeposit ? "Deposit" : "Executed"}</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 500, marginTop: 3 }}>{it.title}</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-2)", marginTop: 3 }}>{it.detail}</div>
      </div>
      {it.net !== 0 ?
      <span style={{ whiteSpace: "nowrap", textAlign: "right" }}><Money value={it.net} size={13} sign color={it.net > 0 ? "var(--accent-pos)" : "var(--ink)"} dim="var(--ink-3)" /></span> :
      it.amount ?
      <span style={{ whiteSpace: "nowrap", textAlign: "right" }}><Money value={it.amount} size={13} color="var(--ink)" dim="var(--ink-3)" /></span> :
      <span style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)" }}>Done</span>}
    </div>);

};

/* ============================================================
   Approval flow · the moment.
   phases: review → confirm → success | decline | modify
   ============================================================ */
const DECLINE_REASONS = ["Not now", "Too large", "I'll do it manually", "Don't trust the timing"];
const MODIFY_CHIPS = ["Make it smaller", "Wait until Friday", "Only the safest leg", "Explain the risk first"];

const ApprovalSheet = ({ proposal, onClose, onApproved, onDeclined, onModified, onOpenThread, hasThread }) => {
  const [phase, setPhase] = useState("review");
  const [authing, setAuthing] = useState(false);
  const [note, setNote] = useState("");
  const p = proposal;

  const doConfirm = () => {
    setAuthing(true);
    setTimeout(() => {setAuthing(false);setPhase("success");}, 950);
  };

  return (
    <div className="push-enter" data-screen-label="Approval" style={{ position: "absolute", inset: 0, zIndex: 320, background: "var(--bg)", display: "flex", flexDirection: "column" }}>
        {window.StatusBar && <window.StatusBar />}
        {phase !== "success" &&
      <div style={{ display: "flex", justifyContent: "flex-end", padding: "4px 20px 0", flex: "none" }}>
          <button className="press" onClick={onClose} aria-label="Close" style={{ background: "none", border: "none", padding: 0, color: "var(--ink-3)", display: "flex", cursor: "pointer" }}><Icon name="close" size={19} /></button>
        </div>}

        {phase === "review" && <ReviewPhase p={p} onClose={onClose} onApprove={() => setPhase("confirm")} onDecline={() => setPhase("decline")} onAsk={(t) => onOpenThread(p.id, t)} hasThread={hasThread} onThread={() => onOpenThread(p.id)} />}
        {phase === "confirm" && <ConfirmPhase p={p} authing={authing} onBack={() => setPhase("review")} onConfirm={doConfirm} />}
        {phase === "success" && <SuccessPhase p={p} onDone={() => {onApproved(p.id);}} />}
        {phase === "decline" && <DeclinePhase p={p} onBack={() => setPhase("review")} onDeclined={(r) => onDeclined(p.id, r)} />}
        {phase === "modify" && <ModifyPhase p={p} note={note} setNote={setNote} onBack={() => setPhase("review")} onSend={() => onModified(p.id, note)} />}
    </div>);

};

const SheetHead = ({ p, label }) => {
  const isYoshi = /^yoshi/i.test(p.agent);
  return (
    <div style={{ padding: "8px 20px 0", flex: "none" }}>
    <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
      <span style={{ width: 7, height: 7, borderRadius: 999, flex: "none",
          background: isYoshi ? "var(--accent)" : "transparent",
          border: isYoshi ? "none" : "1.5px solid var(--ink-3)" }} />
      <span style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.06em", textTransform: "uppercase", color: isYoshi ? "var(--accent)" : "var(--ink-3)" }}>{p.agent}</span>
    </div>
    {label && <Eyebrow color="var(--accent)" style={{ marginTop: 10 }}>{label}</Eyebrow>}
  </div>);

};

const MiniToggle = ({ 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: "#fff", transition: "left 180ms var(--ease)", boxShadow: "0 1px 3px rgba(0,0,0,0.3)" }} />
  </button>;


const ReviewPhase = ({ p, onClose, onApprove, onDecline, onAsk, hasThread, onThread }) => {
  const [autoOn, setAutoOn] = useState(false);
  const [cap, setCap] = useState(5000);
  const [msg, setMsg] = useState("");
  const ask = () => {const t = msg.trim();if (!t) return;setMsg("");onAsk(t);};
  return (
    <>
    <SheetHead p={p} />
    <div className="scroll" style={{ padding: "0 20px" }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 22, fontWeight: 600, letterSpacing: "-0.025em", marginTop: 8 }}>{p.title}</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, color: "var(--ink-2)", marginTop: 7, lineHeight: 1.55 }}>{p.why}</div>

      <Eyebrow style={{ margin: "16px 0 7px" }}>Proposal</Eyebrow>
      <div style={{ border: "1px solid var(--rule-2)", borderRadius: 12, overflow: "hidden" }}>{p.legs.map((leg, i) => <Leg key={i} leg={leg} last={i === p.legs.length - 1} />)}</div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 0, marginTop: 14, border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden" }}>
        <SummaryCell label="Net effect" value={signed(p.net)} color={p.net >= 0 ? "var(--accent-pos)" : "var(--ink)"} />
        <SummaryCell label={p.settlesVerb || "Settles"} value={p.settles} border />
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 12, padding: "10px 12px", background: "var(--bg-2)" }}>
        <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 }}>Yoshi makes the move, only after you approve.</span>
      </div>

      {/* per-automation autonomy — the rule's own limits, set here on the proposal */}
      <div style={{ marginTop: 12, marginBottom: 4, padding: "12px 0" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 13.5, fontWeight: 600 }}>Do this automatically next time</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 2, lineHeight: 1.4 }}>Yoshi will handle a move like this on its own, up to the limit you set.</div>
          </div>
          <MiniToggle on={autoOn} onChange={setAutoOn} />
        </div>
        {autoOn &&
          <div style={{ marginTop: 13 }}>
            <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
              <span style={{ fontFamily: "var(--f-display)", fontSize: 12, color: "var(--ink-2)" }}>Do it without asking up to</span>
              <span style={{ marginLeft: "auto", fontFamily: "var(--f-mono)", fontSize: 14, fontWeight: 500, color: "var(--accent)", fontVariantNumeric: "tabular-nums" }}>{usd(cap, 0)}</span>
            </div>
            <input className="yo-range" type="range" min={500} max={50000} step={500} value={cap} onChange={(e) => setCap(parseInt(e.target.value, 10))} style={{ marginTop: 10 }} />
            <div style={{ fontFamily: "var(--f-display)", fontSize: 10.5, color: "var(--ink-3)", marginTop: 7, lineHeight: 1.4 }}>Any move above this will still ask for your approval.</div>
          </div>
          }
      </div>
    </div>

    {/* the seam, between the proposal and the approve */}
    <div style={{ flex: "none", padding: "0 20px" }}><Seam style={{ margin: "12px 0 0", background: "var(--rule-2)", opacity: 1 }} /></div>
    <div style={{ flex: "none", padding: "12px 20px 20px" }}>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
        <Btn kind="danger" onClick={onDecline}>Decline</Btn>
        <Btn onClick={onApprove}>Approve</Btn>
      </div>
      {/* free-form question — opens (or continues) this proposal's forked thread.
                     When a thread already exists, the chat icon jumps straight into it. */}
      <div style={{ marginTop: 10 }}>
        <YoshiComposer value={msg} onChange={setMsg} onSend={ask} placeholder={hasThread ? "Reply in the thread…" : "Ask Yoshi about this…"}
          onAttach={(doc) => onAsk(`I attached ${doc.name} — use it as context for this proposal.`)}
          onThreadJump={hasThread ? onThread : null} />
      </div>
    </div>
  </>);

};

const SummaryCell = ({ label, value, color = "var(--ink)", border }) =>
<div style={{ padding: "11px 13px", borderLeft: border ? "1px solid var(--rule)" : "none" }}>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ink-3)" }}>{label}</div>
    <div style={{ fontFamily: "var(--f-mono)", fontSize: 15, fontWeight: 500, color, marginTop: 3, fontVariantNumeric: "tabular-nums" }}>{value}</div>
  </div>;


const ConfirmPhase = ({ p, authing, onBack, onConfirm }) =>
<>
    <SheetHead p={p} label="Confirm" />
    <div style={{ padding: "8px 20px 0", flex: 1, display: "flex", flexDirection: "column" }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 20, fontWeight: 600, letterSpacing: "-0.02em" }}>{p.title}</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 8, marginTop: 12, paddingBottom: 14, borderBottom: "1px solid var(--rule)" }}>
        <Eyebrow>Net effect</Eyebrow>
        <Money value={p.net} size={20} sign color={p.net >= 0 ? "var(--accent-pos)" : "var(--ink)"} style={{ marginLeft: "auto" }} />
      </div>

      <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 16, padding: "24px 0" }}>
        <div style={{ position: "relative", width: 72, height: 72, display: "grid", placeItems: "center" }}>
          {authing && <span style={{ position: "absolute", inset: 0, border: "1.5px solid var(--accent)", borderRadius: 16, animation: "ring-out 950ms ease-out infinite" }} />}
          <div style={{ width: 64, height: 64, border: `1.5px solid ${authing ? "var(--accent)" : "var(--rule-2)"}`, borderRadius: 16, display: "grid", placeItems: "center", transition: "border-color 200ms ease" }}>
            <Icon name="shield" size={30} stroke={1.4} color={authing ? "var(--accent)" : "var(--ink-2)"} />
          </div>
        </div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-2)", textAlign: "center" }}>
          {authing ? "Authenticating…" : "Confirm with your passkey to authorize.\nYoshi will execute immediately."}
        </div>
      </div>
    </div>
    <div style={{ flex: "none", padding: "0 20px 20px" }}>
      <Btn full onClick={onConfirm} disabled={authing}>{authing ? "Confirming…" : "Confirm with passkey"}</Btn>
      <Btn kind="ghost" full onClick={onBack} style={{ marginTop: 8 }} disabled={authing}>Back</Btn>
    </div>
  </>;


const SuccessPhase = ({ p, onDone }) =>
<div style={{ padding: "8px 20px 22px", display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center" }}>
    <div style={{ width: "100%", margin: "6px 0 22px" }}><Seam draw /></div>
    <div style={{ width: 66, height: 66, borderRadius: 999, border: "1.5px solid var(--accent)", display: "grid", placeItems: "center", marginBottom: 18 }}>
      <svg width="34" height="34" 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)">Executed</Eyebrow>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 21, fontWeight: 600, letterSpacing: "-0.02em", marginTop: 6 }}>{p.title}</div>
    <div style={{ fontFamily: "var(--f-display)", fontSize: 13, color: "var(--ink-2)", marginTop: 7, lineHeight: 1.5, maxWidth: 280 }}>
      Yoshi handled the move. Net {signed(p.net)} · {p.settlesVerb || "settles"} {p.settles}. You'll see it in your stream.
    </div>
    <div style={{ width: "100%", marginTop: 22 }}><Btn full onClick={onDone}>Done</Btn></div>
  </div>;


const DeclinePhase = ({ p, onBack, onDeclined }) => {
  const [r, setR] = useState(null);
  const [note, setNote] = useState("");
  return (
    <>
      <SheetHead p={p} label="Decline" />
      <div style={{ padding: "8px 20px 0", flex: 1 }}>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 18, fontWeight: 600, letterSpacing: "-0.018em" }}>Why decline?</div>
        <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)", marginTop: 5, lineHeight: 1.5 }}>The agent learns from this. It won't run.</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 16 }}>
          {DECLINE_REASONS.map((reason) =>
          <button key={reason} className="press" onClick={() => setR(reason)} style={{ padding: "9px 13px", borderRadius: 999, background: r === reason ? "var(--ink)" : "transparent", color: r === reason ? "var(--bg)" : "var(--ink)", border: "1px solid var(--rule-2)", fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 500, cursor: "pointer" }}>{reason}</button>
          )}
        </div>
        <textarea value={note} onChange={(e) => setNote(e.target.value)} placeholder="Or tell Yoshi why, in your own words…" rows={3}
        style={{ width: "100%", boxSizing: "border-box", marginTop: 14, padding: "12px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", borderRadius: 12, color: "var(--ink)", fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.5, outline: "none", resize: "none" }} />
      </div>
      <div style={{ flex: "none", padding: "16px 20px 20px" }}>
        <Btn kind="danger" full onClick={() => onDeclined(note.trim() || r || "Not now")}>Decline proposal</Btn>
        <Btn kind="ghost" full onClick={onBack} style={{ marginTop: 8 }}>Back</Btn>
      </div>
    </>);

};

const ModifyPhase = ({ p, note, setNote, onBack, onSend }) =>
<>
    <SheetHead p={p} />
    <div style={{ padding: "8px 20px 0", flex: 1 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 18, fontWeight: 600, letterSpacing: "-0.018em" }}>What should change?</div>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 12.5, color: "var(--ink-2)", marginTop: 5, lineHeight: 1.5 }}>Yoshi will revise and re-propose in chat.</div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 14 }}>
        {MODIFY_CHIPS.map((c) =>
      <button key={c} className="press" onClick={() => setNote(c)} style={{ padding: "8px 12px", borderRadius: 999, background: note === c ? "var(--accent)" : "transparent", color: note === c ? "var(--accent-ink)" : "var(--ink)", border: `1px solid ${note === c ? "var(--accent)" : "var(--rule-2)"}`, fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 500, cursor: "pointer" }}>{c}</button>
      )}
      </div>
      <input value={note} onChange={(e) => setNote(e.target.value)} placeholder="Or type a change…" style={{ width: "100%", marginTop: 14, padding: "12px 13px", background: "var(--bg-2)", border: "1px solid var(--rule-2)", color: "var(--ink)", fontFamily: "var(--f-display)", fontSize: 13.5, outline: "none" }} />
    </div>
    <div style={{ flex: "none", padding: "16px 20px 20px" }}>
      <Btn full onClick={onSend} disabled={!note.trim()}>Send change <Icon name="send" size={16} color="var(--accent-ink)" /></Btn>
      <Btn kind="ghost" full onClick={onBack} style={{ marginTop: 8 }}>Back</Btn>
    </div>
  </>;


Object.assign(window, { Inbox, ApprovalSheet, ProposalCard, AutomationsTab, AutoRow, AutoStat });