/* Ply — interactive interface walkthrough (v0.6.26-b).
   Faux-desktop window → workspace rail → vertical page list → live page → AI panel.
   Mock data mirrors the shipped app: workspaces, Stuff sections, the three AI modes,
   per-site privacy, LAN sync. All state is local. */

const { useState, useEffect, useRef, useMemo } = React;

/* ————— Icons (single stroke style) ————— */
const Icon = ({ d, size = 14, fill = "none", stroke = "currentColor", sw = 1.5, style }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" style={style}>
    <path d={d} />
  </svg>
);

const icons = {
  search: "m21 21-4.3-4.3M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z",
  plus: "M12 5v14M5 12h14",
  chevronR: "m9 6 6 6-6 6",
  chevronD: "m6 9 6 6 6-6",
  back: "m15 18-6-6 6-6",
  fwd: "m9 6 6 6-6 6",
  refresh: "M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5",
  more: "M5 12h.01M12 12h.01M19 12h.01",
  spark: "M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5 18 18M6 18l2.5-2.5M15.5 8.5 18 6",
  lock: "M5 11h14v10H5zM8 11V7a4 4 0 1 1 8 0v4",
  layers: "m12 2 10 5-10 5-10-5 10-5ZM2 17l10 5 10-5M2 12l10 5 10-5",
  book: "M4 4h10a4 4 0 0 1 4 4v12H8a4 4 0 0 1-4-4V4ZM18 8a4 4 0 0 1 4 4v8H18",
  dl: "M12 4v12m0 0-5-5m5 5 5-5M5 20h14",
  clock: "M12 7v5l3 2M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20Z",
  star: "M12 3l2.6 5.6 6.1.6-4.6 4.2 1.3 6L12 16.8 6.6 19.4l1.3-6L3.3 9.2l6.1-.6L12 3Z",
  note: "M4 4h16v12l-4 4H4zM16 20v-4h4",
  highlight: "M4 20h16M6 16l8-8 4 4-8 8H6z",
  snippet: "M3 7h18M3 12h12M3 17h18",
  link: "M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1",
  puzzle: "M10 4a2 2 0 1 1 4 0v2h2a2 2 0 0 1 2 2v2a2 2 0 1 1 0 4v2a2 2 0 0 1-2 2h-2a2 2 0 1 0-4 0H8a2 2 0 0 1-2-2v-2a2 2 0 1 1 0-4V8a2 2 0 0 1 2-2h2z",
  canvas: "M4 5h16v14H4zM4 9h16M8 9v10",
  globe: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20ZM2 12h20M12 2a14 14 0 0 1 0 20M12 2a14 14 0 0 0 0 20",
  x: "M18 6 6 18M6 6l12 12",
  arrow: "M5 12h14m-6-6 6 6-6 6",
  pin: "M12 17v5M9 3h6l-1 4 3 5H7l3-5-1-4Z",
  shield: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z",
  device: "M4 5h16v10H4zM2 19h20M9 19v-2M15 19v-2",
  reader: "M4 6h16M4 10h16M4 14h10M4 18h10",
  split: "M4 4h16v16H4zM12 4v16",
  cog: "M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8ZM12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M7 17l-2 2",
};

/* ————— Mock data ————— */
const mockWorkspaces = [
  { id: "w1", name: "Browser research", icon: "◆", color: "var(--accent)", count: 14, active: true },
  { id: "w2", name: "Q3 roadmap", icon: "●", color: "var(--blue)", count: 7 },
  { id: "w3", name: "House hunt", icon: "▲", color: "var(--green)", count: 22, container: true },
  { id: "w4", name: "Reading", icon: "■", color: "var(--fg-3)", count: 5 },
];

const mockPages = [
  { id: "p1", title: "The web is a workshop, not a feed", url: "alexanderobenauer.com/labnotes/036", favicon: "A", time: "2h", pinned: true, frozen: false, group: "Pinned" },
  { id: "p2", title: "Designing for many open pages", url: "mattgemmell.com/pages", favicon: "M", time: "1h", pinned: true, frozen: false, group: "Pinned" },
  { id: "p3", title: "Field notes: a month of project-based browsing", url: "research.local/notes/month", favicon: "R", time: "45m", group: "Today" },
  { id: "p4", title: "On-device search, in practice", url: "are.na/channels/local-first", favicon: "a", time: "32m", group: "Today" },
  { id: "p5", title: "Vertical tabs research — Mozilla", url: "research.mozilla.org/vertical-tabs", favicon: "M", time: "28m", group: "Today" },
  { id: "p6", title: "Fingerprinting defenses compared", url: "privacytests.org/fingerprint", favicon: "P", time: "15m", group: "Today", frozen: true },
  { id: "p7", title: "Readability & reader modes", url: "github.com/mozilla/readability", favicon: "G", time: "8m", group: "Today" },
  { id: "p8", title: "Browser memory benchmarks 2026", url: "tomshardware.com/browsers-2026", favicon: "T", time: "3m", group: "Today", frozen: true },
];

/* ————— Window chrome (faux desktop) ————— */
function OSChrome({ children, dim }) {
  return (
    <div style={{
      background: dim ? "var(--app-frame-dim)" : "var(--app-frame)",
      border: "1px solid var(--rule-2)",
      borderRadius: 12,
      padding: 0,
      overflow: "hidden",
      boxShadow: "0 30px 60px -20px rgba(20,19,15,.18), 0 2px 4px rgba(20,19,15,.08)",
    }}>
      {/* Slim window bar — Ply ships with no app title bar, just window controls */}
      <div style={{
        height: 30,
        display: "flex",
        alignItems: "center",
        padding: "0 14px",
        gap: 8,
        background: "linear-gradient(180deg, var(--app-bar-1), var(--app-bar-2))",
        borderBottom: "1px solid var(--rule-2)",
      }}>
        <div style={{ display: "flex", gap: 6 }}>
          <div style={{ width: 11, height: 11, borderRadius: 99, background: "#e96d59" }} />
          <div style={{ width: 11, height: 11, borderRadius: 99, background: "#e6bf3f" }} />
          <div style={{ width: 11, height: 11, borderRadius: 99, background: "#62c454" }} />
        </div>
        <div style={{ flex: 1 }} />
      </div>
      {children}
    </div>
  );
}

/* ————— Sidebar: workspaces ————— */
function WorkspaceRail({ active, setActive, collapsed, setCollapsed }) {
  return (
    <div style={{
      width: collapsed ? 56 : 240,
      transition: "width 220ms ease",
      background: "var(--app-rail)",
      borderRight: "1px solid var(--rule-2)",
      display: "flex",
      flexDirection: "column",
      flexShrink: 0,
    }}>
      {/* Brand + collapse */}
      <div style={{ display: "flex", alignItems: "center", padding: "14px 14px 10px", gap: 10 }}>
        <div style={{
          width: 18, height: 18, background: "var(--accent)", borderRadius: 3,
          transform: "rotate(45deg)", flexShrink: 0,
        }} />
        {!collapsed && (
          <div style={{ fontFamily: "var(--serif)", fontSize: 18, letterSpacing: "-0.02em" }}>Ply</div>
        )}
        <div style={{ flex: 1 }} />
        <button onClick={() => setCollapsed(c => !c)} style={btnIcon}>
          <Icon d={collapsed ? icons.chevronR : icons.chevronD} size={12} />
        </button>
      </div>

      {/* Search / Command */}
      {!collapsed && (
        <div style={{ padding: "8px 12px 14px" }}>
          <div style={{
            display: "flex", alignItems: "center", gap: 8,
            padding: "7px 10px",
            background: "var(--app-active)",
            border: "1px solid var(--rule-2)",
            borderRadius: 7,
            fontSize: 13, color: "var(--fg-3)",
          }}>
            <Icon d={icons.search} size={13} />
            <span style={{ flex: 1 }}>Search or jump…</span>
            <span className="kbd" style={{ fontSize: 10 }}>⌘K</span>
          </div>
        </div>
      )}

      {/* Workspaces */}
      <div style={{ padding: "0 8px", flex: 1, overflow: "auto" }}>
        {!collapsed && <div style={railLabel}>Workspaces</div>}
        {mockWorkspaces.map(w => (
          <button
            key={w.id}
            onClick={() => setActive(w.id)}
            title={w.container ? "Container — isolated cookie jar" : undefined}
            style={{
              ...railItem,
              background: active === w.id ? "var(--app-active)" : "transparent",
              color: active === w.id ? "var(--fg)" : "var(--fg-2)",
              justifyContent: collapsed ? "center" : "flex-start",
              boxShadow: w.container ? "inset 0 0 0 1px " + (w.color === "var(--accent)" ? "var(--accent)" : w.color) : "none",
            }}
          >
            <span style={{ color: w.color, fontSize: 14, lineHeight: 1, width: 16, textAlign: "center" }}>{w.icon}</span>
            {!collapsed && (
              <>
                <span style={{ flex: 1, textAlign: "left", fontSize: 13 }}>{w.name}</span>
                <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)" }}>{w.count}</span>
              </>
            )}
          </button>
        ))}

        {!collapsed && <div style={railLabel}>Library</div>}
        {[
          { icon: icons.star, label: "Stuff", n: 412 },
          { icon: icons.canvas, label: "Canvas", n: null },
          { icon: icons.clock, label: "History", n: null },
          { icon: icons.dl, label: "Downloads", n: 2 },
        ].map(l => (
          <button key={l.label} style={{ ...railItem, color: "var(--fg-2)", justifyContent: collapsed ? "center" : "flex-start" }}>
            <Icon d={l.icon} size={13} />
            {!collapsed && <>
              <span style={{ flex: 1, textAlign: "left", fontSize: 13 }}>{l.label}</span>
              {l.n !== null && <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)" }}>{l.n}</span>}
            </>}
          </button>
        ))}
      </div>

      {/* Footer: Session panel + Devices/Settings */}
      {!collapsed && (
        <div style={{ borderTop: "1px solid var(--rule-2)" }}>
          <div style={{ padding: "10px 14px 8px" }}>
            <div style={{ fontFamily: "var(--mono)", fontSize: 9, color: "var(--fg-3)", letterSpacing: "0.1em", textTransform: "uppercase", marginBottom: 6 }}>Session</div>
            <div style={{ display: "flex", gap: 14, fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-2)" }}>
              <span><span style={{ color: "var(--fg)" }}>312</span> MB</span>
              <span><span style={{ color: "var(--fg)" }}>6</span> awake</span>
              <span><span style={{ color: "var(--fg)" }}>8</span> asleep</span>
            </div>
          </div>
          <button style={{ ...railItem, color: "var(--fg-2)" }}>
            <Icon d={icons.device} size={13} />
            <span style={{ flex: 1, textAlign: "left", fontSize: 13 }}>Devices · sync</span>
          </button>
          <button style={{ ...railItem, color: "var(--fg-2)", marginBottom: 8 }}>
            <Icon d={icons.cog} size={13} />
            <span style={{ flex: 1, textAlign: "left", fontSize: 13 }}>Settings</span>
          </button>
        </div>
      )}
    </div>
  );
}

const railLabel = {
  fontFamily: "var(--mono)",
  fontSize: 10,
  letterSpacing: "0.1em",
  textTransform: "uppercase",
  color: "var(--fg-3)",
  padding: "16px 8px 6px",
};
const railItem = {
  display: "flex", alignItems: "center", gap: 10,
  width: "100%",
  padding: "7px 8px",
  border: "none",
  background: "transparent",
  borderRadius: 6,
  cursor: "pointer",
  fontFamily: "var(--sans)",
  textAlign: "left",
};
const btnIcon = {
  background: "transparent",
  border: "none",
  padding: 4,
  cursor: "pointer",
  color: "var(--fg-3)",
  display: "flex", alignItems: "center", justifyContent: "center",
  borderRadius: 4,
};

/* ————— Page list (middle pane) ————— */
function PageList({ pages, activeId, setActive, onOpenAi }) {
  const grouped = useMemo(() => {
    const g = {};
    pages.forEach(p => { (g[p.group] = g[p.group] || []).push(p); });
    return g;
  }, [pages]);

  return (
    <div style={{
      width: 280,
      background: "var(--app-pane)",
      borderRight: "1px solid var(--rule-2)",
      display: "flex",
      flexDirection: "column",
      flexShrink: 0,
    }}>
      {/* Workspace header */}
      <div style={{ padding: "16px 16px 12px", borderBottom: "1px solid var(--rule-2)" }}>
        <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.1em", textTransform: "uppercase" }}>Workspace</div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4 }}>
          <span style={{ color: "var(--accent)", fontSize: 14 }}>◆</span>
          <div style={{ fontSize: 16, fontWeight: 500, letterSpacing: "-0.01em" }}>Browser research</div>
        </div>
        <div style={{ display: "flex", gap: 4, marginTop: 12 }}>
          <button style={tinyBtn}><Icon d={icons.plus} size={11} /> New page</button>
          <button style={tinyBtn} onClick={onOpenAi}><Icon d={icons.spark} size={11} /> Ask AI</button>
        </div>
      </div>

      {/* Page groups */}
      <div style={{ flex: 1, overflow: "auto", padding: "8px 0" }}>
        {Object.entries(grouped).map(([group, items]) => (
          <div key={group}>
            <div style={{
              fontFamily: "var(--mono)",
              fontSize: 10,
              color: "var(--fg-3)",
              letterSpacing: "0.1em",
              textTransform: "uppercase",
              padding: "10px 16px 4px",
            }}>{group}</div>
            {items.map(p => (
              <PageRow key={p.id} page={p} active={p.id === activeId} onClick={() => setActive(p.id)} />
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}

function PageRow({ page, active, onClick }) {
  return (
    <button onClick={onClick} style={{
      display: "flex", alignItems: "flex-start", gap: 10,
      width: "100%",
      padding: "8px 14px",
      border: "none",
      background: active ? "var(--app-active)" : "transparent",
      borderLeft: active ? "2px solid var(--accent)" : "2px solid transparent",
      cursor: "pointer",
      textAlign: "left",
      fontFamily: "var(--sans)",
      opacity: page.frozen ? 0.6 : 1,
      position: "relative",
    }}>
      <div style={{
        width: 18, height: 18, flexShrink: 0,
        background: "var(--bg-3)",
        border: "1px solid var(--rule-2)",
        borderRadius: 4,
        display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "var(--mono)",
        fontSize: 10,
        color: "var(--fg-2)",
        marginTop: 2,
      }}>{page.favicon}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 13, color: "var(--fg)", lineHeight: 1.3, letterSpacing: "-0.005em",
          textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap",
        }}>
          {page.title}
        </div>
        <div style={{
          fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 2,
          textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap",
        }}>
          {page.url} · {page.time}
        </div>
      </div>
      {page.frozen && (
        <span title="Asleep — reloads on click" style={{
          fontFamily: "var(--mono)", fontSize: 9, color: "var(--fg-3)",
          background: "var(--bg-3)", padding: "1px 5px", borderRadius: 3,
          textTransform: "uppercase", letterSpacing: "0.06em",
        }}>zzz</span>
      )}
      {page.pinned && !page.frozen && (
        <Icon d={icons.pin} size={11} stroke="var(--fg-4)" style={{ marginTop: 3 }} />
      )}
    </button>
  );
}

const tinyBtn = {
  display: "inline-flex", alignItems: "center", gap: 5,
  padding: "5px 9px",
  border: "1px solid var(--rule-2)",
  background: "var(--app-btn)",
  borderRadius: 6,
  fontFamily: "var(--sans)",
  fontSize: 11,
  color: "var(--fg-2)",
  cursor: "pointer",
  whiteSpace: "nowrap",
};

/* ————— Main page area ————— */
function PageView({ onAsk }) {
  return (
    <div style={{ flex: 1, background: "var(--bg)", display: "flex", flexDirection: "column", minWidth: 0 }}>
      {/* Toolbar */}
      <div style={{
        display: "flex", alignItems: "center", gap: 8,
        padding: "10px 14px",
        borderBottom: "1px solid var(--rule)",
        background: "var(--app-toolbar)",
      }}>
        <button style={btnIcon}><Icon d={icons.back} size={14} /></button>
        <button style={btnIcon}><Icon d={icons.fwd} size={14} /></button>
        <button style={btnIcon}><Icon d={icons.refresh} size={13} /></button>

        <div style={{
          flex: 1,
          display: "flex", alignItems: "center", gap: 8,
          margin: "0 6px",
          padding: "6px 12px",
          background: "var(--bg)",
          border: "1px solid var(--rule)",
          borderRadius: 7,
          fontFamily: "var(--mono)",
          fontSize: 12,
          color: "var(--fg-2)",
        }}>
          <button style={{ ...btnIcon, padding: 0 }} title="Site privacy"><Icon d={icons.shield} size={12} stroke="var(--green)" /></button>
          <span style={{ color: "var(--fg-3)" }}>research.local/notes/</span>
          <span style={{ color: "var(--fg)" }}>month</span>
          <div style={{ flex: 1 }} />
          <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)" }}>13 trackers blocked</span>
        </div>

        <button title="Reader mode" style={btnIcon}><Icon d={icons.reader} size={14} /></button>
        <button title="Highlight" style={btnIcon}><Icon d={icons.highlight} size={14} /></button>
        <button title="Split view" style={btnIcon}><Icon d={icons.split} size={14} /></button>

        <button onClick={onAsk} title="AI panel" style={{
          display: "inline-flex", alignItems: "center", gap: 6,
          padding: "6px 12px",
          background: "var(--accent-bg)",
          border: "1px solid oklch(0.78 0.08 60)",
          borderRadius: 7,
          fontFamily: "var(--mono)",
          fontSize: 11,
          color: "var(--accent)",
          letterSpacing: "0.04em",
          textTransform: "uppercase",
          cursor: "pointer",
        }}>
          <Icon d={icons.spark} size={11} /> AI
        </button>
        <button style={btnIcon}><Icon d={icons.more} size={14} /></button>
      </div>

      {/* Sample article */}
      <div style={{ flex: 1, overflow: "auto", padding: "40px 56px 80px", maxWidth: 760, margin: "0 auto" }}>
        <div style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--fg-3)", letterSpacing: "0.06em" }}>
          LAB NOTES · MAY 2026
        </div>
        <h1 style={{
          fontFamily: "var(--serif)", fontWeight: 400,
          fontSize: 42, lineHeight: 1.05, letterSpacing: "-0.02em",
          margin: "16px 0 20px",
        }}>
          Field notes: a month of project-based browsing
        </h1>
        <p style={{ fontFamily: "var(--serif)", fontSize: 20, lineHeight: 1.4, color: "var(--fg-2)", margin: "0 0 24px" }}>
          What changes when the browser is organised around what you're working on, instead of around a row of tabs you're trying not to lose.
        </p>
        <p>The first thing you notice is that closing a page stops feeling risky. When everything you read is captured to a searchable library anyway, a page list can stay short without anxiety — you're not throwing anything away, just clearing your desk.</p>
        <p>The second is that idle pages sleeping in the background is invisible until you want it: the memory comes back, and the page you left reloads in a blink when you click it. The trade is a short reload on return, paid only for pages you'd stopped looking at.</p>
        <p style={{ marginTop: 24, fontFamily: "var(--mono)", fontSize: 12, color: "var(--fg-3)" }}>
          <span className="cursor">▌</span> highlighted by you · 32m ago
        </p>
        <p style={{
          padding: "12px 16px",
          background: "var(--accent-bg)",
          borderLeft: "2px solid var(--accent)",
          margin: "8px 0 24px",
          fontFamily: "var(--serif)",
          fontSize: 18, lineHeight: 1.4,
          color: "var(--fg)",
        }}>
          Closing a page stops feeling risky when everything you read is captured to a searchable library anyway.
        </p>
        <p>Select that line and press ⌘⇧H and it lands in Stuff with a backlink to this exact passage — drag it onto the Canvas later and it arrives as an attributed quote.</p>
      </div>
    </div>
  );
}

/* ————— AI panel (bring-your-own-model) ————— */
const AI_MODES = [
  { id: "tabs", label: "Search tabs" },
  { id: "summary", label: "Summarize" },
  { id: "library", label: "Search library" },
];

function AiPanel({ onClose, initialMode }) {
  const [mode, setMode] = useState(initialMode || "summary");
  const [q, setQ] = useState("");
  const [phase, setPhase] = useState("idle"); // idle | thinking | answer
  const ref = useRef(null);
  useEffect(() => { ref.current?.focus(); }, [mode]);
  useEffect(() => { setPhase("idle"); setQ(""); }, [mode]);

  const run = () => { setPhase("thinking"); setTimeout(() => setPhase("answer"), 850); };

  const sentNote = {
    tabs: "Sends your open tabs' titles, URLs & workspace names",
    summary: "Sends this page's text, title & URL",
    library: "Searched on this device — only the snippets you select are sent",
  }[mode];

  return (
    <div onClick={onClose} style={{
      position: "absolute", inset: 0,
      background: "rgba(20,19,15,.32)",
      display: "flex", alignItems: "flex-start", justifyContent: "center",
      padding: "80px 24px 24px",
      zIndex: 30,
      animation: "fadein 180ms ease",
      backdropFilter: "blur(2px)",
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: "min(620px, 100%)",
        background: "var(--bg)",
        border: "1px solid var(--rule-2)",
        borderRadius: 12,
        boxShadow: "0 30px 80px -20px rgba(20,19,15,.4)",
        overflow: "hidden",
      }}>
        {/* Header */}
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "12px 16px", borderBottom: "1px solid var(--rule)" }}>
          <Icon d={icons.spark} size={14} stroke="var(--accent)" />
          <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.1em", textTransform: "uppercase" }}>AI · your model</span>
          <div style={{ flex: 1 }} />
          <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-2)" }}>Ollama · llama3.1</span>
          <span className="kbd" style={{ fontSize: 9 }}>Esc</span>
        </div>

        {/* Mode tabs */}
        <div style={{ display: "flex", gap: 4, padding: "10px 14px 0" }}>
          {AI_MODES.map(m => (
            <button key={m.id} onClick={() => setMode(m.id)} style={{
              padding: "6px 12px",
              border: "1px solid " + (mode === m.id ? "oklch(0.78 0.08 60)" : "var(--rule)"),
              background: mode === m.id ? "var(--accent-bg)" : "transparent",
              color: mode === m.id ? "var(--accent)" : "var(--fg-2)",
              borderRadius: 7, cursor: "pointer",
              fontFamily: "var(--sans)", fontSize: 12,
            }}>{m.label}</button>
          ))}
        </div>

        {/* Input for tabs / library */}
        {mode !== "summary" && (
          <input
            ref={ref}
            value={q}
            onChange={e => setQ(e.target.value)}
            onKeyDown={e => e.key === "Enter" && run()}
            placeholder={mode === "tabs" ? "Ask across your open pages…" : "Search your library, then ask about the results…"}
            style={{
              width: "100%", padding: "16px", border: "none", outline: "none",
              fontFamily: "var(--serif)", fontSize: 20, background: "transparent",
              color: "var(--fg)", letterSpacing: "-0.01em",
            }}
          />
        )}

        {/* Body */}
        <div style={{ padding: "8px 16px 14px", fontSize: 14, color: "var(--fg-2)", lineHeight: 1.55 }}>
          {mode === "summary" && (
            <div>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.06em", padding: "6px 0 10px" }}>
                SUMMARY OF THIS PAGE
              </div>
              <p style={{ margin: "0 0 10px" }}>Project-based browsing makes closing pages low-stakes because everything read is captured to a searchable library. Background pages sleep to reclaim memory, reloading on click — the only cost a brief reload on return.</p>
              <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
                <button style={{ ...tinyBtn, padding: "4px 9px" }}>Save to Stuff · AI summaries</button>
                <button style={{ ...tinyBtn, padding: "4px 9px", background: "var(--bg)" }}>Copy</button>
              </div>
            </div>
          )}

          {mode === "tabs" && phase === "idle" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 4, paddingTop: 4 }}>
              <Suggestion onClick={run}>Which of my open pages cover fingerprinting?</Suggestion>
              <Suggestion onClick={run}>Group my 14 open pages by theme</Suggestion>
            </div>
          )}

          {mode === "library" && phase === "idle" && (
            <div style={{ paddingTop: 4 }}>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.06em", marginBottom: 8 }}>
                ON-DEVICE RESULTS · SELECT WHAT TO SEND
              </div>
              {[
                "Highlight — “closing a page stops feeling risky…”",
                "Note — reader mode gives tidier quotes",
                "Link — Mozilla vertical-tabs research",
              ].map((t, i) => (
                <label key={i} style={{ display: "flex", gap: 9, alignItems: "center", padding: "6px 0", fontSize: 13, cursor: "pointer" }}>
                  <input type="checkbox" defaultChecked={i < 2} style={{ accentColor: "var(--accent)" }} />
                  <span>{t}</span>
                </label>
              ))}
              <button onClick={run} style={{ ...tinyBtn, marginTop: 8, padding: "5px 10px" }}>Ask model about 2 selected</button>
            </div>
          )}

          {phase === "thinking" && (
            <div style={{ padding: "20px 0", textAlign: "center", color: "var(--fg-3)" }}>
              <div style={{ fontFamily: "var(--mono)", fontSize: 11, letterSpacing: "0.08em" }}>ASKING YOUR MODEL…</div>
              <div style={{ marginTop: 14, height: 2, background: "var(--bg-2)", borderRadius: 99, overflow: "hidden" }}>
                <div style={{ width: "55%", height: "100%", background: "var(--accent)" }} />
              </div>
            </div>
          )}

          {phase === "answer" && mode !== "summary" && (
            <div>
              <p style={{ margin: "0 0 8px" }}>
                {mode === "tabs"
                  ? "Two open pages cover fingerprinting: privacytests.org (defenses compared) and the Mozilla research note. Both argue randomisation beats blocking."
                  : "Across the two snippets: your own read is that capture-by-default is what makes a short page list workable — the library, not the tab strip, is the safety net."}
              </p>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 6 }}>
                {mode === "tabs" ? "from 2 open pages" : "from 2 selected snippets · nothing else sent"}
              </div>
            </div>
          )}
        </div>

        {/* Footer note */}
        <div style={{
          padding: "10px 16px", borderTop: "1px solid var(--rule)", background: "var(--bg-2)",
          fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.04em",
          display: "flex", gap: 10, alignItems: "center",
        }}>
          <Icon d={icons.shield} size={11} stroke="var(--green)" />
          <span>{sentNote}</span>
          <div style={{ flex: 1 }} />
          <span>OFF BY DEFAULT</span>
        </div>
      </div>
    </div>
  );
}

function Suggestion({ children, onClick }) {
  return (
    <button onClick={onClick} style={{
      display: "flex", alignItems: "center", gap: 8,
      padding: "7px 0", border: "none", background: "transparent",
      textAlign: "left", fontFamily: "var(--sans)", fontSize: 13,
      color: "var(--fg-2)", cursor: "pointer",
    }}>
      <Icon d={icons.arrow} size={11} stroke="var(--fg-3)" />
      {children}
    </button>
  );
}

/* ————— Top-level walkthrough ————— */
function PlyPrototype() {
  const [activeWs, setActiveWs] = useState("w1");
  const [activePage, setActivePage] = useState("p3");
  const [collapsed, setCollapsed] = useState(false);
  const [ai, setAi] = useState(null); // null | "tabs" | "summary" | "library"

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && ai) setAi(null); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [ai]);

  return (
    <OSChrome dim={!!ai}>
      <div style={{ position: "relative", height: 620, display: "flex", overflow: "hidden" }}>
        <WorkspaceRail active={activeWs} setActive={setActiveWs} collapsed={collapsed} setCollapsed={setCollapsed} />
        <PageList pages={mockPages} activeId={activePage} setActive={setActivePage} onOpenAi={() => setAi("library")} />
        <PageView onAsk={() => setAi("summary")} />
        {ai && <AiPanel onClose={() => setAi(null)} initialMode={ai} />}
      </div>
    </OSChrome>
  );
}

/* ————— Mini mock: Stuff library ————— */
const STUFF_SECTIONS = [
  { id: "notes", label: "Notes", n: 38, icon: icons.note },
  { id: "ai", label: "AI summaries", n: 12, icon: icons.spark },
  { id: "snips", label: "Snippets", n: 64, icon: icons.snippet },
  { id: "hl", label: "Highlights", n: 211, icon: icons.highlight },
  { id: "links", label: "Links", n: 79, icon: icons.link },
  { id: "ext", label: "Extensions", n: 8, icon: icons.puzzle },
];

function StuffMini() {
  const [sec, setSec] = useState("hl");
  return (
    <div style={{ display: "flex", background: "var(--bg)", fontFamily: "var(--sans)", minHeight: 320 }}>
      {/* TOC sidebar */}
      <div style={{ width: 200, borderRight: "1px solid var(--rule)", padding: "16px 10px", flexShrink: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "0 6px 12px" }}>
          <Icon d={icons.star} size={14} />
          <div style={{ fontSize: 14, fontWeight: 500 }}>Stuff</div>
        </div>
        {STUFF_SECTIONS.map(s => (
          <button key={s.id} onClick={() => setSec(s.id)} style={{
            ...railItem,
            background: sec === s.id ? "var(--app-active)" : "transparent",
            color: sec === s.id ? "var(--fg)" : "var(--fg-2)",
          }}>
            <Icon d={s.icon} size={13} />
            <span style={{ flex: 1, textAlign: "left", fontSize: 13 }}>{s.label}</span>
            <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)" }}>{s.n}</span>
          </button>
        ))}
      </div>

      {/* Section contents */}
      <div style={{ flex: 1, padding: 18, minWidth: 0 }}>
        <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 12 }}>
          {STUFF_SECTIONS.find(s => s.id === sec).label} · {STUFF_SECTIONS.find(s => s.id === sec).n}
        </div>
        {(STUFF_CONTENT[sec] || STUFF_CONTENT.hl).map((r, i) => (
          <div key={i} style={{
            display: "flex", alignItems: "flex-start", gap: 12,
            padding: "10px 0", borderBottom: "1px solid var(--rule)",
          }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, color: "var(--fg)" }}>{r.t}</div>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 3 }}>
                {r.ext && <span style={{ background: "var(--accent-bg)", color: "var(--accent)", padding: "1px 5px", borderRadius: 3, marginRight: 6 }}>ext</span>}
                {r.src}
              </div>
            </div>
            <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", flexShrink: 0 }}>{r.when}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

const STUFF_CONTENT = {
  hl: [
    { t: "“closing a page stops feeling risky when everything is captured…”", src: "research.local · ◆ Browser research", when: "32m" },
    { t: "“randomisation beats blocking for fingerprint defense”", src: "privacytests.org · ◆ Browser research", when: "2h" },
    { t: "“the library, not the tab strip, is the safety net”", src: "alexanderobenauer.com · ◆ Browser research", when: "1d" },
  ],
  notes: [
    { t: "Reader mode gives tidier highlight quotes — use it before clipping", src: "◆ Browser research", when: "12m" },
    { t: "Container workspace idea: separate jar for the two test accounts", src: "● Q3 roadmap", when: "3d" },
  ],
  ai: [
    { t: "Summary — a month of project-based browsing", src: "research.local · ◆ Browser research", when: "30m" },
    { t: "Summary — browser memory benchmarks 2026", src: "tomshardware.com · ◆ Browser research", when: "1d" },
  ],
  links: [
    { t: "Mozilla vertical-tabs research", src: "research.mozilla.org", when: "28m" },
    { t: "Readability source", src: "github.com/mozilla/readability", ext: true, when: "8m" },
  ],
  snips: [
    { t: "Clipped table — memory by browser, 12 tabs", src: "tomshardware.com", when: "1d" },
    { t: "Clipped figure — fingerprint entropy chart", src: "privacytests.org", when: "2h" },
  ],
  ext: [
    { t: "Quick Note", src: "installed · network: none", ext: true, when: "—" },
    { t: "History Search", src: "installed · network: none", ext: true, when: "—" },
  ],
};

/* ————— Mini mock: Command bar ————— */
function CommandMini() {
  return (
    <div style={{ padding: 24, background: "var(--bg-2)", display: "flex", justifyContent: "center" }}>
      <div style={{
        width: 540, background: "var(--bg)", border: "1px solid var(--rule-2)",
        borderRadius: 10, overflow: "hidden", boxShadow: "0 20px 40px -10px rgba(20,19,15,.18)",
      }}>
        <div style={{
          padding: "14px 16px", fontFamily: "var(--serif)", fontSize: 20,
          color: "var(--fg-2)", borderBottom: "1px solid var(--rule)",
        }}>
          fingerprint<span className="cursor">▌</span>
        </div>
        {[
          { icon: icons.globe, kind: "WEB", text: "Search the web: fingerprint defenses", hi: false },
          { icon: icons.highlight, kind: "STUFF", text: "“randomisation beats blocking for fingerprint defense”", hi: true, sub: "highlight · ◆ Browser research" },
          { icon: icons.clock, kind: "HISTORY", text: "Fingerprinting defenses compared", sub: "visited 15m ago" },
          { icon: icons.layers, kind: "PAGE", text: "Open page: privacytests.org/fingerprint", sub: "in this workspace" },
          { icon: icons.canvas, kind: "CANVAS", text: "Canvas mention: “…fingerprint entropy…”", sub: "Browser research · canvas" },
        ].map((r, i) => (
          <div key={i} style={{
            display: "flex", alignItems: "center", gap: 12, padding: "10px 16px",
            background: r.hi ? "var(--app-hover)" : "transparent",
            borderLeft: r.hi ? "2px solid var(--accent)" : "2px solid transparent",
          }}>
            <Icon d={r.icon} size={13} stroke="var(--fg-2)" />
            <span style={{ fontFamily: "var(--mono)", fontSize: 9, color: "var(--fg-3)", letterSpacing: "0.08em", width: 56 }}>{r.kind}</span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, color: "var(--fg)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r.text}</div>
              {r.sub && <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 2 }}>{r.sub}</div>}
            </div>
          </div>
        ))}
        <div style={{
          padding: "8px 16px", borderTop: "1px solid var(--rule)", background: "var(--bg-2)",
          fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.06em", display: "flex", gap: 14,
        }}>
          <span>↑↓ NAVIGATE</span>
          <span>↵ OPEN</span>
          <div style={{ flex: 1 }} />
          <span>⌘K</span>
        </div>
      </div>
    </div>
  );
}

/* ————— Mini mock: per-site privacy shield ————— */
function PrivacyMini() {
  const rows = [
    { l: "Ads & trackers", v: "13 blocked", c: "var(--green)" },
    { l: "Third-party cookies", v: "blocked", c: "var(--green)" },
    { l: "Fingerprinting", v: "randomised", c: "var(--green)" },
    { l: "AMP & link redirectors", v: "skipped", c: "var(--green)" },
    { l: "Manipulation blocker", v: "1 dark pattern defused", c: "var(--accent)" },
  ];
  return (
    <div style={{ padding: 24, background: "var(--bg-2)", display: "flex", justifyContent: "center" }}>
      <div style={{
        width: 420, background: "var(--bg)", border: "1px solid var(--rule-2)", borderRadius: 10,
        overflow: "hidden", boxShadow: "0 20px 40px -10px rgba(20,19,15,.18)",
      }}>
        <div style={{ padding: "14px 16px", borderBottom: "1px solid var(--rule)", display: "flex", alignItems: "center", gap: 10 }}>
          <Icon d={icons.shield} size={15} stroke="var(--green)" />
          <div>
            <div style={{ fontSize: 14, fontWeight: 500 }}>privacytests.org</div>
            <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--green)", marginTop: 1 }}>● Connection encrypted</div>
          </div>
        </div>
        {rows.map((r, i) => (
          <div key={i} style={{
            display: "flex", alignItems: "center", justifyContent: "space-between",
            padding: "11px 16px", borderBottom: i < rows.length - 1 ? "1px solid var(--rule)" : "none", fontSize: 13,
          }}>
            <span style={{ color: "var(--fg-2)" }}>{r.l}</span>
            <span style={{ fontFamily: "var(--mono)", fontSize: 11, color: r.c }}>{r.v}</span>
          </div>
        ))}
        <div style={{ padding: "9px 16px", background: "var(--bg-2)", fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.04em" }}>
          TAP A ROW TO EXPAND · PER-SITE EXCEPTIONS
        </div>
      </div>
    </div>
  );
}

/* ————— Mini mock: device sync ————— */
function SyncMini() {
  return (
    <div style={{ padding: 24, background: "var(--bg-3)", display: "flex", justifyContent: "center", gap: 24, flexWrap: "wrap" }}>
      {[
        { name: "MacBook Pro", role: "This device", state: "Paired", last: "—" },
        { name: "Studio PC", role: "Paired device", state: "Pull ready", last: "2m ago" },
      ].map((d, i) => (
        <div key={i} style={{
          width: 220, background: "var(--bg)", border: "1px solid var(--rule)", borderRadius: 10, padding: 16,
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <Icon d={icons.device} size={14} stroke="var(--fg-2)" />
            <div style={{ fontSize: 14, fontWeight: 500 }}>{d.name}</div>
          </div>
          <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 4, letterSpacing: "0.06em", textTransform: "uppercase" }}>{d.role}</div>
          <div style={{ marginTop: 12, fontSize: 12, color: "var(--green)" }}>● {d.state}</div>
          <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-3)", marginTop: 4 }}>last sync {d.last}</div>
          {i === 1 && <button style={{ ...tinyBtn, marginTop: 12, width: "100%", justifyContent: "center" }}>Pull updates</button>}
        </div>
      ))}
      <div style={{ width: "100%", maxWidth: 480, textAlign: "center", fontFamily: "var(--mono)", fontSize: 10, color: "var(--fg-2)", letterSpacing: "0.04em", marginTop: 4 }}>
        PAIRED WITH A 6-DIGIT CODE · END-TO-END ENCRYPTED · STAYS ON YOUR LOCAL NETWORK · NO ACCOUNT
      </div>
    </div>
  );
}

/* ————— Mount points ————— */
const mounts = [
  ["#hero-mount", PlyPrototype],
  ["#stuff-mount", StuffMini],
  ["#command-mount", CommandMini],
  ["#privacy-mount", PrivacyMini],
  ["#sync-mount", SyncMini],
];

mounts.forEach(([sel, Comp]) => {
  const el = document.querySelector(sel);
  if (el) ReactDOM.createRoot(el).render(<Comp />);
});

/* Expose shared bits for canvas.jsx artboards */
window.PlyIcon = Icon;
window.plyIcons = icons;
window.plyTinyBtn = tinyBtn;
window.StuffMini = StuffMini;
window.PrivacyMini = PrivacyMini;
window.SyncMini = SyncMini;
window.AiPanel = AiPanel;
