// Featureban.jsx — Run the board.
// A simple deploy kanban: tap a strategy to move it forward through the
// lifecycle (Backlog → Dry-run → Live → Closed). Open the performance
// panel any time to see how live strategies are doing. End the day when
// you're ready to review.
// Stages: 'intro' → 'play'  (end-of-day hands off to the review)

const { useState: useStateFB, useMemo: useMemoFB, useRef: useRefFB } = React;

// ─────────────────────────────────────────────────────────────
// Provisional P&L for a strategy once it's live. Deterministic from
// the strategy id so the number is stable across re-renders, weighted
// slightly positive and scaled by the risk units (R) at stake.
// ─────────────────────────────────────────────────────────────
function fbSeededPnl(story) {
  let h = 0;
  const key = String(story.id || story.ref || "x");
  for (let i = 0; i < key.length; i++) h = (h * 31 + key.charCodeAt(i)) % 100000;
  const r = (h % 1000) / 1000;            // 0..1
  const sign = r < 0.62 ? 1 : -1;         // ~62% winners
  const mag = 40 + (h % 220) + (story.points || 3) * 18;
  return sign * Math.round(mag);
}

// Paper-trade P&L — same deterministic engine, salted so a strategy's paper
// run reads differently from its eventual live run. Lets the strategy review
// score a strategy that's still paper-trading, before any capital is at risk.
function fbPaperPnl(story) {
  return fbSeededPnl({ ...story, id: String(story.id || story.ref || "x") + ":paper" });
}

function fbStatusLabel(col) {
  return { todo: "Queued", doing: "Paper trade", review: "Live run", done: "Closed" }[col] || col;
}

// ─────────────────────────────────────────────────────────────
// Intro
// ─────────────────────────────────────────────────────────────
function FBIntro({ storyCount, onStart, onBack }) {
  return (
    <div style={{
      display: "flex",
      flexDirection: "column",
      height: "100%",
      padding: "0 20px 24px",
      gap: 14,
      boxSizing: "border-box",
    }}>
      <button
        onClick={onBack}
        style={{
          alignSelf: "flex-start",
          background: "none",
          border: "none",
          padding: 0,
          color: "var(--color-text-link)",
          fontFamily: "var(--font-family-sans)",
          fontSize: 14,
          fontWeight: 500,
          cursor: "pointer",
          display: "inline-flex",
          alignItems: "center",
          gap: 4,
          marginTop: 6,
        }}
      >
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
          <polyline points="15 18 9 12 15 6" />
        </svg>
        Back
      </button>

      <div className="ds-overline" style={{ color: "var(--color-brand-primary)", marginTop: 4 }}>
        Run the board
      </div>
      <h1 style={{
        margin: 0,
        fontFamily: "var(--font-family-sans)",
        fontWeight: 600,
        fontSize: 26,
        lineHeight: "32px",
        letterSpacing: "-0.01em",
        color: "var(--color-text-primary)",
        textWrap: "balance",
      }}>
        Deploy your strategies.<br />Watch them run.
      </h1>
      <p className="ds-body-sm" style={{ margin: 0, color: "var(--color-text-secondary)" }}>
        {storyCount} {storyCount === 1 ? "strategy is" : "strategies are"} queued.
        Move each one forward when you're ready: paper-trade it, take it live,
        then close it out.
      </p>

      {/* Steps */}
      <div style={{
        display: "flex",
        flexDirection: "column",
        gap: 0,
        background: "var(--color-border-subtle)",
        border: "1px solid var(--color-border-subtle)",
        borderRadius: "var(--radius-md)",
        overflow: "hidden",
        marginTop: 2,
      }}>
        {[
          ["01", "Move it forward.", "Tap a strategy to advance it: Backlog → Paper trade → Live run → Closed."],
          ["02", "Check performance.", "Open the performance panel any time to see live P&L."],
          ["03", "End the day.", "When you're done, close the book and review the session."],
        ].map(([n, t, d]) => (
          <div key={n} style={{
            background: "var(--color-surface-default)",
            padding: "12px 14px",
            display: "flex",
            gap: 12,
            alignItems: "flex-start",
          }}>
            <span style={{
              fontFamily: "var(--font-family-sans)",
              fontWeight: 700,
              fontSize: 16,
              color: "var(--color-brand-primary)",
              fontVariantNumeric: "tabular-nums",
              minWidth: 22,
              paddingTop: 2,
            }}>{n}</span>
            <div>
              <div style={{ fontWeight: 600, fontSize: 14, color: "var(--color-text-primary)" }}>{t}</div>
              <div className="ds-body-sm" style={{ fontSize: 13, lineHeight: "18px", color: "var(--color-text-secondary)" }}>{d}</div>
            </div>
          </div>
        ))}
      </div>

      <button
        onClick={onStart}
        style={{
          marginTop: "auto",
          height: 52,
          background: "var(--color-brand-primary)",
          color: "var(--color-text-on-brand)",
          border: "none",
          borderRadius: "var(--radius-sm)",
          fontFamily: "var(--font-family-sans)",
          fontWeight: 600,
          fontSize: 16,
          cursor: "pointer",
        }}
      >
        Open the board →
      </button>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Strategy tile
// ─────────────────────────────────────────────────────────────
function FBStrategyTile({ story, canAdvance, onOpen }) {
  const done = story.column === "done";
  const live = story.column === "review";
  const pnl = (live || done) ? story.pnl : null;
  return (
    <button
      onClick={() => onOpen?.(story.id)}
      style={{
        position: "relative",
        background: "var(--color-surface-default)",
        border: `1px solid ${live ? "var(--color-brand-primary)" : "var(--color-border-subtle)"}`,
        borderRadius: 6,
        padding: "7px 8px 7px",
        display: "flex",
        flexDirection: "column",
        gap: 3,
        textAlign: "left",
        cursor: "pointer",
        boxShadow: live ? "var(--shadow-1)" : "none",
        width: "100%",
        boxSizing: "border-box",
        font: "inherit",
        color: "inherit",
        transition: "border-color var(--motion-base) var(--ease-standard)",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 4 }}>
        <span style={{
          fontFamily: "var(--font-family-sans)",
          fontSize: 9,
          fontWeight: 600,
          color: "var(--color-text-muted)",
          letterSpacing: "0.04em",
          fontVariantNumeric: "tabular-nums",
        }}>{story.ref}</span>
        <span style={{
          fontSize: 8.5,
          fontWeight: 700,
          padding: "0 5px",
          minWidth: 16,
          height: 14,
          background: "var(--color-surface-subtle)",
          color: "var(--color-text-primary)",
          borderRadius: "var(--radius-pill)",
          border: "1px solid var(--color-border-subtle)",
          fontVariantNumeric: "tabular-nums",
          display: "inline-flex",
          alignItems: "center",
          justifyContent: "center",
        }}>{story.points}R</span>
      </div>
      <div style={{
        fontFamily: "var(--font-family-sans)",
        fontSize: 11,
        fontWeight: 600,
        lineHeight: "14px",
        color: "var(--color-text-primary)",
        letterSpacing: "-0.002em",
      }}>
        {story.want}
      </div>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 4, marginTop: 1 }}>
        <span style={{
          fontSize: 8,
          letterSpacing: "0.1em",
          textTransform: "uppercase",
          color: "var(--color-text-muted)",
          fontWeight: 600,
        }}>{story.tag}</span>
        {pnl != null ? (
          <span style={{
            fontSize: 10,
            fontWeight: 700,
            fontVariantNumeric: "tabular-nums",
            color: pnl >= 0 ? "var(--color-success)" : "var(--color-danger)",
          }}>{pnl >= 0 ? "+" : "−"}${Math.abs(pnl)}</span>
        ) : canAdvance ? (
          <span style={{ display: "inline-flex", alignItems: "center", color: "var(--color-brand-primary)" }}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <line x1="5" y1="12" x2="19" y2="12" />
              <polyline points="13 6 19 12 13 18" />
            </svg>
          </span>
        ) : null}
      </div>
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Board column / swimlane
// ─────────────────────────────────────────────────────────────
// Column header row — shown once above the swimlanes.
function FBColumnHeaders({ stories }) {
  return (
    <div style={{ display: "flex", gap: 5, padding: "0 2px 4px" }}>
      {window.FB_COLUMNS.map((col) => {
        const n = stories.filter((s) => s.column === col.id).length;
        return (
          <div key={col.id} style={{
            flex: 1, minWidth: 0,
            padding: "5px 6px",
            background: "var(--color-surface-subtle)",
            border: "1px solid var(--color-border-subtle)",
            borderRadius: 5,
            display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 4,
          }}>
            <span style={{ fontSize: 9, letterSpacing: "0.08em", textTransform: "uppercase", fontWeight: 700, color: "var(--color-text-secondary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{col.label}</span>
            <span style={{ fontSize: 11, fontWeight: 700, color: "var(--color-text-muted)", fontVariantNumeric: "tabular-nums" }}>{n}</span>
          </div>
        );
      })}
    </div>
  );
}

// One cell = a single column's tiles within a swimlane.
function FBLaneCell({ col, stories, onOpen }) {
  const inCol = stories.filter((s) => s.column === col.id);
  const isClosed = col.id === "done";
  return (
    <div style={{
      flex: 1, minWidth: 0,
      display: "flex", flexDirection: "column", gap: 4,
      padding: "4px",
      background: "var(--color-surface-subtle)",
      borderRadius: 4,
      minHeight: 56,
    }}>
      {inCol.map((s) => (
        <FBStrategyTile key={s.id} story={s} canAdvance={!isClosed} onOpen={onOpen} />
      ))}
    </div>
  );
}

// A swimlane = one trading goal, with all four columns.
function FBLane({ label, stories, onOpen }) {
  const live = stories.filter((s) => s.column === "review").length;
  const pnl = stories.filter((s) => s.column === "review" || s.column === "done").reduce((a, s) => a + (s.pnl || 0), 0);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, padding: "2px 2px 0" }}>
        <span style={{
          fontSize: 10.5, fontWeight: 700, letterSpacing: "-0.002em",
          color: "var(--color-text-primary)",
          overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
        }}>{label}</span>
        <span style={{ fontSize: 9.5, fontWeight: 600, color: "var(--color-text-muted)", fontVariantNumeric: "tabular-nums", flexShrink: 0 }}>
          {live} live · {pnl >= 0 ? "+" : "−"}${Math.abs(pnl)}
        </span>
      </div>
      <div style={{ display: "flex", gap: 5 }}>
        {window.FB_COLUMNS.map((col) => (
          <FBLaneCell key={col.id} col={col} stories={stories} onOpen={onOpen} />
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Performance panel (slide-up)
// ─────────────────────────────────────────────────────────────
function FBPerformancePanel({ stories, onClose }) {
  const running = stories.filter((s) => s.column === "review" || s.column === "done");
  const total = running.reduce((sum, s) => sum + (s.pnl || 0), 0);
  const winners = running.filter((s) => (s.pnl || 0) >= 0).length;
  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute", inset: 0,
        background: "rgba(0,0,0,0.45)",
        zIndex: 40,
        display: "flex",
        alignItems: "flex-end",
        animation: "fbFadeIn 160ms var(--ease-standard)",
      }}
    >
      <style>{`
        @keyframes fbFadeIn { from { opacity: 0 } to { opacity: 1 } }
        @keyframes fbSheetIn { from { transform: translateY(40px); opacity: 0 } to { transform: translateY(0); opacity: 1 } }
      `}</style>
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: "var(--color-surface-default)",
          borderTopLeftRadius: "var(--radius-lg)",
          borderTopRightRadius: "var(--radius-lg)",
          padding: "14px 18px 18px",
          boxShadow: "var(--shadow-4)",
          display: "flex",
          flexDirection: "column",
          gap: 12,
          animation: "fbSheetIn 220ms var(--ease-standard)",
          maxHeight: "82%",
          overflowY: "auto",
        }}
      >
        <div aria-hidden style={{
          alignSelf: "center", width: 36, height: 4,
          background: "var(--color-border-subtle)", borderRadius: 2, marginTop: -2,
        }} />

        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <span style={{
            fontFamily: "var(--font-family-sans)", fontWeight: 700, fontSize: 11,
            letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--color-brand-primary)",
          }}>Live performance</span>
          <button onClick={onClose} aria-label="Close" style={{
            background: "none", border: "none", padding: 4, cursor: "pointer",
            color: "var(--color-text-muted)", display: "flex",
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <line x1="18" y1="6" x2="6" y2="18" />
              <line x1="6" y1="6" x2="18" y2="18" />
            </svg>
          </button>
        </div>

        {/* Session total */}
        <div style={{
          background: "var(--color-surface-promo)",
          borderRadius: "var(--radius-md)",
          padding: "14px 16px",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
        }}>
          <div>
            <div className="ds-overline" style={{ fontSize: 10, color: "var(--color-brand-mark)" }}>
              Open + booked P&L
            </div>
            <div style={{
              fontFamily: "var(--font-family-sans)",
              fontWeight: 700,
              fontSize: 30,
              lineHeight: 1,
              letterSpacing: "-0.02em",
              color: total >= 0 ? "var(--color-success)" : "var(--color-danger)",
              fontVariantNumeric: "tabular-nums",
            }}>{total >= 0 ? "+" : "−"}${Math.abs(total).toLocaleString()}</div>
          </div>
          <div style={{ textAlign: "right" }}>
            <div style={{
              fontFamily: "var(--font-family-sans)", fontWeight: 700, fontSize: 16,
              color: "var(--color-text-primary)", fontVariantNumeric: "tabular-nums", lineHeight: 1.1,
            }}>{winners}/{running.length}</div>
            <div style={{
              fontSize: 9, letterSpacing: "0.14em", textTransform: "uppercase",
              color: "var(--color-text-muted)", fontWeight: 600,
            }}>in the green</div>
          </div>
        </div>

        {/* Per-strategy rows */}
        {running.length === 0 ? (
          <div style={{
            padding: "14px 12px", textAlign: "center", fontSize: 12, lineHeight: "17px",
            color: "var(--color-text-secondary)",
          }}>
            Nothing live yet. Move a strategy to <strong>Live</strong> to start tracking P&L.
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {running.map((s) => (
              <div key={s.id} style={{
                display: "flex", alignItems: "center", gap: 10,
                padding: "8px 10px",
                background: "var(--color-surface-subtle)",
                borderRadius: "var(--radius-sm)",
                border: "1px solid var(--color-border-subtle)",
              }}>
                <span style={{
                  width: 8, height: 8, borderRadius: "50%", flexShrink: 0,
                  background: s.column === "done" ? "var(--color-text-muted)" : "var(--color-success)",
                }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{
                    fontSize: 12, fontWeight: 600, color: "var(--color-text-primary)",
                    overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                  }}>{s.want}</div>
                  <div style={{ fontSize: 10, color: "var(--color-text-muted)", letterSpacing: "0.04em" }}>
                    {s.ref} · {fbStatusLabel(s.column)} · {s.points}R
                  </div>
                </div>
                <span style={{
                  fontSize: 13, fontWeight: 700, fontVariantNumeric: "tabular-nums",
                  color: (s.pnl || 0) >= 0 ? "var(--color-success)" : "var(--color-danger)",
                }}>{(s.pnl || 0) >= 0 ? "+" : "−"}${Math.abs(s.pnl || 0)}</span>
              </div>
            ))}
          </div>
        )}

        <button onClick={onClose} style={{
          height: 44,
          background: "var(--color-brand-primary)",
          color: "var(--color-text-on-brand)",
          border: "none", borderRadius: "var(--radius-sm)",
          fontFamily: "var(--font-family-sans)", fontWeight: 600, fontSize: 15, cursor: "pointer",
        }}>
          Back to the board
        </button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Board (play)
// ─────────────────────────────────────────────────────────────
function FBPlay({ sg, stories, setStories, onFinish, onExit }) {
  const [showPerf, setShowPerf] = useStateFB(false);
  const [confirmLive, setConfirmLive] = useStateFB(null);
  const [detailStoryId, setDetailStoryId] = useStateFB(null);
  const [toast, setToast] = useStateFB(null);
  const toastTimer = useRefFB(null);

  const flash = (text) => {
    setToast(text);
    if (toastTimer.current) clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 1500);
  };

  const doAdvance = (storyId) => {
    setStories((curr) => curr.map((s) => {
      if (s.id !== storyId) return s;
      const next = window.fbNextColumn(s.column);
      if (!next) return s;
      const updated = { ...s, column: next };
      if (next === "review" && updated.pnl == null) updated.pnl = fbSeededPnl(s);
      if (next === "doing" && updated.paperPnl == null) updated.paperPnl = fbPaperPnl(s);
      return updated;
    }));
    const s = stories.find((x) => x.id === storyId);
    const next = s && window.fbNextColumn(s.column);
    if (next) flash(`→ ${fbStatusLabel(next)}`);
  };

  // Every move asks for confirmation before it happens.
  const advance = (storyId) => {
    const s = stories.find((x) => x.id === storyId);
    if (!s) return;
    if (!window.fbNextColumn(s.column)) return;
    setConfirmLive(s);
  };

  const liveCount = stories.filter((s) => s.column === "review").length;
  const closedCount = stories.filter((s) => s.column === "done").length;
  const runningPnl = stories
    .filter((s) => s.column === "review" || s.column === "done")
    .reduce((sum, s) => sum + (s.pnl || 0), 0);

  // Group strategies into swimlanes by their trading goal, preserving order.
  const lanes = (() => {
    const order = [];
    const map = {};
    stories.forEach((s) => {
      const key = s.goalLabel || "Unassigned";
      if (!map[key]) { map[key] = []; order.push(key); }
      map[key].push(s);
    });
    return order.map((key) => ({ key, label: key, stories: map[key] }));
  })();

  const endDay = () => {
    // Close the book: anything live books its P&L and moves to Closed.
    // Paper-trade strategies are left running — but still handed to the
    // review so they can be scored on their paper results.
    const closed = stories.map((s) =>
      s.column === "review" ? { ...s, column: "done" } : s
    );
    setStories(closed);
    const shipped = closed.filter((s) => s.column === "done");
    const paper = closed.filter((s) => s.column === "doing");
    onFinish({ shipped, paper, totalStories: stories.length });
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box", position: "relative" }}>
      {/* Header */}
      <div style={{
        padding: "8px 16px 10px",
        borderBottom: "1px solid var(--color-border-subtle)",
        background: "var(--color-surface-default)",
        display: "flex",
        flexDirection: "column",
        gap: 6,
      }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
          <button onClick={onExit} style={{
            background: "none", border: "none", padding: 0, color: "var(--color-text-link)",
            fontFamily: "var(--font-family-sans)", fontSize: 12, fontWeight: 500, cursor: "pointer",
            display: "inline-flex", alignItems: "center", gap: 3,
          }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="15 18 9 12 15 6" />
            </svg>
            Home
          </button>
          <span style={{
            fontSize: 11, color: "var(--color-text-secondary)",
            overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 200,
          }}>{sg.goal}</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
          <div style={{ display: "flex", alignItems: "baseline", gap: 10 }}>
            <span style={{
              fontFamily: "var(--font-family-sans)", fontWeight: 700, fontSize: 18,
              color: "var(--color-text-primary)", letterSpacing: "-0.01em",
            }}>Trading desk</span>
            <span style={{ fontSize: 11, color: "var(--color-text-muted)", fontVariantNumeric: "tabular-nums" }}>
              {liveCount} live · {closedCount} closed
            </span>
          </div>
          <button onClick={() => setShowPerf(true)} style={{
            height: 30, padding: "0 12px 0 10px",
            background: "var(--color-surface-promo)",
            border: "1px solid rgba(196,31,62,0.20)",
            borderRadius: "var(--radius-pill)",
            cursor: "pointer",
            display: "inline-flex", alignItems: "center", gap: 6,
            fontFamily: "var(--font-family-sans)", fontWeight: 700, fontSize: 11,
            color: "var(--color-brand-mark)",
          }}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <line x1="18" y1="20" x2="18" y2="10" />
              <line x1="12" y1="20" x2="12" y2="4" />
              <line x1="6" y1="20" x2="6" y2="14" />
            </svg>
            <span style={{ fontVariantNumeric: "tabular-nums" }}>
              {runningPnl >= 0 ? "+" : "−"}${Math.abs(runningPnl)}
            </span>
          </button>
        </div>
      </div>

      {/* Board — column headers + a swimlane per trading goal */}
      <div style={{
        flex: 1, minHeight: 0,
        padding: "8px 12px 8px",
        background: "var(--color-surface-default)",
        display: "flex", flexDirection: "column", gap: 10, overflowY: "auto",
      }}>
        <FBColumnHeaders stories={stories} />
        {lanes.map((lane) => (
          <FBLane key={lane.key} label={lane.label} stories={lane.stories} onOpen={setDetailStoryId} />
        ))}
      </div>

      {/* Footer */}
      <div style={{
        borderTop: "1px solid var(--color-border-subtle)",
        background: "var(--color-surface-default)",
        padding: "10px 16px 14px",
        display: "flex", flexDirection: "column", gap: 6,
      }}>
        <div style={{
          minHeight: 16, fontSize: 11, textAlign: "center",
          color: "var(--color-text-muted)", letterSpacing: "0.01em",
        }}>
          {toast || "Tap a strategy to move it forward · open performance any time"}
        </div>
        <button onClick={endDay} style={{
          height: 46,
          background: "var(--color-brand-primary)",
          color: "var(--color-text-on-brand)",
          border: "none", borderRadius: "var(--radius-sm)",
          fontFamily: "var(--font-family-sans)", fontWeight: 600, fontSize: 15, cursor: "pointer",
          display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8,
        }}>
          Strategy review
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="9 18 15 12 9 6" />
          </svg>
        </button>
      </div>

      {showPerf && <FBPerformancePanel stories={stories} onClose={() => setShowPerf(false)} />}
      {confirmLive && (
        <FBConfirmLive
          story={confirmLive}
          onCancel={() => setConfirmLive(null)}
          onConfirm={() => { doAdvance(confirmLive.id); setConfirmLive(null); }}
        />
      )}
      {detailStoryId && window.CardDetail && (() => {
        const story = stories.find((s) => s.id === detailStoryId);
        if (!story) return null;
        const canAdvance = !!window.fbNextColumn(story.column);
        return (
          <window.CardDetail
            story={story}
            canAdvance={canAdvance}
            onClose={() => setDetailStoryId(null)}
            onAdvance={(id) => {
              doAdvance(id);
              setDetailStoryId(null);
            }}
          />
        );
      })()}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Confirm a board move — wording adapts to the transition.
// ─────────────────────────────────────────────────────────────
function FBConfirmLive({ story, onCancel, onConfirm }) {
  const p = story.params || {};
  const next = window.fbNextColumn(story.column);
  var COPY = {
    doing:  { eyebrow: "Start paper trading", title: "Move {x} into paper trade?", note: "Simulated run — no real capital at risk.", confirm: "Start paper", danger: false },
    review: { eyebrow: "Go live — real risk", title: "Take {x} to a live run?",     note: "This puts real capital on the line.",     confirm: "Go live",     danger: true },
    done:   { eyebrow: "Close position",      title: "Close {x} and book it?",       note: "Books the P&L and closes the strategy out.", confirm: "Close it", danger: false },
  };
  var c = COPY[next] || COPY.review;
  const accent = c.danger ? "var(--color-danger)" : "var(--color-brand-primary)";
  const pnl = story.pnl;
  return (
    <div onClick={onCancel} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)", zIndex: 50, display: "flex", alignItems: "center", justifyContent: "center", padding: 18, animation: "fbFadeIn 160ms var(--ease-standard)" }}>
      <div onClick={(e) => e.stopPropagation()} style={{ width: "100%", maxWidth: 320, background: "var(--color-surface-default)", borderRadius: "var(--radius-lg)", padding: "18px 18px 16px", boxShadow: "var(--shadow-4)", display: "flex", flexDirection: "column", gap: 12, animation: "fbSheetIn 220ms var(--ease-standard)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ width: 32, height: 32, borderRadius: "50%", background: `${accent}1a`, color: accent, display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
            {next === "review" ? (
              <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 9v4" /><path d="M12 17h.01" /><path d="M10.3 3.6 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.6a2 2 0 0 0-3.4 0z" /></svg>
            ) : next === "done" ? (
              <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
            ) : (
              <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12" /><polyline points="13 6 19 12 13 18" /></svg>
            )}
          </span>
          <span style={{ fontFamily: "var(--font-family-sans)", fontWeight: 700, fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: accent }}>{c.eyebrow}</span>
        </div>
        <div style={{ fontFamily: "var(--font-family-sans)", fontWeight: 600, fontSize: 15, lineHeight: "20px", color: "var(--color-text-primary)", letterSpacing: "-0.004em" }}>
          {c.title.split("{x}")[0]}<strong>{story.want}</strong>{c.title.split("{x}")[1]}
        </div>
        <div style={{ background: "var(--color-surface-subtle)", borderRadius: "var(--radius-sm)", padding: "10px 12px", fontSize: 12, lineHeight: "17px", color: "var(--color-text-secondary)" }}>
          {c.note}
          <div style={{ marginTop: 4, color: "var(--color-text-muted)" }}>
            {story.ref} · {story.tag}
            {p.riskR ? ` · ${p.riskR}R · ${p.stopPct}% kill · ${p.leverage}× lev` : ""}
            {next === "done" && pnl != null ? ` · P&L ${pnl >= 0 ? "+" : "−"}$${Math.abs(pnl)}` : ""}
          </div>
        </div>
        <div style={{ display: "flex", gap: 8, marginTop: 2 }}>
          <button onClick={onCancel} style={{ flex: 1, height: 44, background: "var(--color-surface-default)", color: "var(--color-text-primary)", border: "1px solid var(--color-border-subtle)", borderRadius: "var(--radius-sm)", fontFamily: "var(--font-family-sans)", fontWeight: 600, fontSize: 14, cursor: "pointer" }}>Not yet</button>
          <button onClick={onConfirm} style={{ flex: 1.3, height: 44, background: accent, color: "#fff", border: "none", borderRadius: "var(--radius-sm)", fontFamily: "var(--font-family-sans)", fontWeight: 600, fontSize: 14, cursor: "pointer" }}>{c.confirm}</button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Container
// ─────────────────────────────────────────────────────────────
function Featureban({ sg, board, setBoard, onExit, onReview }) {
  return (
    <FBPlay
      sg={sg}
      stories={board}
      setStories={setBoard}
      onExit={onExit}
      onFinish={({ shipped, paper, totalStories }) => onReview?.({ shipped, paper, totalStories })}
    />
  );
}

Object.assign(window, { Featureban, fbSeededPnl, fbPaperPnl });
