/* global React, ReactDOM, Icon, Avatar, Rail, RightRail, UpdatesView, CheckInModal, WikiView, PersonView, HistoryView, AdminView, AuthScreen */
/* global TweaksPanel, useTweaks, TweakSection, TweakRadio */
const { useState, useEffect, useMemo, useRef } = React;

// ── Highlight a query term inside a string ────────────────────────────────
function highlightMatch(text, q) {
  if (!text || !q) return text || "";
  const i = text.toLowerCase().indexOf(q.toLowerCase());
  if (i === -1) return text;
  return React.createElement(
    React.Fragment,
    null,
    text.slice(0, i),
    React.createElement(
      "mark",
      {
        key: "h",
        style: {
          background: "var(--accent-soft)",
          color: "var(--accent)",
          borderRadius: 2,
          padding: "0 1px",
        },
      },
      text.slice(i, i + q.length),
    ),
    text.slice(i + q.length),
  );
}

// ── Global search overlay ─────────────────────────────────────────────────
const STATUS_CLS = {
  live: "outcome",
  decided: "outcome",
  complete: "outcome",
  open: "decision",
  running: "decision",
  draft: "ghost",
  abandoned: "ghost",
};

function GlobalSearch({ authToken, onNavigate, focusTick }) {
  const [q, setQ] = useState("");
  const [results, setResults] = useState(null);
  const [open, setOpen] = useState(false);
  const [cursor, setCursor] = useState(-1);
  const inputRef = useRef(null);
  const timerRef = useRef(null);
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";

  // Focus when ⌘K pressed
  useEffect(() => {
    if (focusTick > 0) {
      inputRef.current?.focus();
      inputRef.current?.select();
    }
  }, [focusTick]);

  // Debounced search
  useEffect(() => {
    clearTimeout(timerRef.current);
    if (q.trim().length < 2) {
      setResults(null);
      setOpen(false);
      return;
    }
    timerRef.current = setTimeout(async () => {
      try {
        const r = await fetch(
          `${apiBase}/search?q=${encodeURIComponent(q.trim())}`,
          {
            headers: { Authorization: `Bearer ${authToken}` },
          },
        );
        if (r.ok) {
          setResults(await r.json());
          setOpen(true);
          setCursor(-1);
        }
      } catch {}
    }, 300);
    return () => clearTimeout(timerRef.current);
  }, [q]);

  const close = () => {
    setOpen(false);
    setCursor(-1);
  };

  // Flatten for keyboard nav
  const flat = useMemo(() => {
    if (!results) return [];
    const items = [];
    (results.people || []).forEach((r) =>
      items.push({ ...r, _type: "person" }),
    );
    (results.articles || []).forEach((r) =>
      items.push({ ...r, _type: "article" }),
    );
    (results.decisions || []).forEach((r) =>
      items.push({ ...r, _type: "decision" }),
    );
    (results.experiments || []).forEach((r) =>
      items.push({ ...r, _type: "experiment" }),
    );
    (results.checkins || []).forEach((r) =>
      items.push({ ...r, _type: "checkin" }),
    );
    return items;
  }, [results]);

  const handleKey = (e) => {
    if (!open || !flat.length) {
      if (e.key === "Escape") {
        close();
        setQ("");
      }
      return;
    }
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setCursor((c) => Math.min(c + 1, flat.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setCursor((c) => Math.max(c - 1, 0));
    } else if (e.key === "Escape") {
      close();
      setQ("");
    } else if (e.key === "Enter" && cursor >= 0) {
      e.preventDefault();
      onNavigate(flat[cursor]);
      close();
      setQ("");
    }
  };

  const renderGroup = (label, type, items, startIdx) => {
    if (!items || !items.length) return null;
    return (
      <div key={label}>
        <div
          style={{
            padding: "6px 12px 2px",
            fontSize: 10.5,
            fontWeight: 700,
            color: "var(--ink-4)",
            textTransform: "uppercase",
            letterSpacing: "0.06em",
          }}
        >
          {label}
        </div>
        {items.map((item, i) => {
          const idx = startIdx + i;
          const active = cursor === idx;
          const title = item.name || item.title;
          const sCls = STATUS_CLS[item.status] || "";
          return (
            <div
              key={item.id}
              style={{
                display: "flex",
                alignItems: "flex-start",
                gap: 10,
                padding: "7px 12px",
                cursor: "pointer",
                background: active ? "var(--accent-soft)" : "transparent",
              }}
              onMouseEnter={() => setCursor(idx)}
              onMouseDown={(e) => {
                e.preventDefault();
                onNavigate({ ...item, _type: type });
                close();
                setQ("");
              }}
            >
              <div style={{ flex: 1, minWidth: 0 }}>
                <div
                  style={{
                    fontSize: 13,
                    fontWeight: 500,
                    color: active ? "var(--accent)" : "var(--ink-1)",
                    whiteSpace: "nowrap",
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                  }}
                >
                  {highlightMatch(title, q)}
                </div>
                {item.snippet && (
                  <div
                    style={{
                      fontSize: 11.5,
                      color: "var(--ink-3)",
                      marginTop: 1,
                      whiteSpace: "nowrap",
                      overflow: "hidden",
                      textOverflow: "ellipsis",
                    }}
                  >
                    {highlightMatch(item.snippet, q)}
                  </div>
                )}
                {item.role && (
                  <div
                    style={{
                      fontSize: 11.5,
                      color: "var(--ink-3)",
                      marginTop: 1,
                    }}
                  >
                    {item.role}
                  </div>
                )}
                {!item.role && item.author && (
                  <div
                    style={{
                      fontSize: 11,
                      color: "var(--ink-4)",
                      marginTop: 1,
                    }}
                  >
                    {item.author}
                  </div>
                )}
              </div>
              {sCls && (
                <span
                  className={`tag ${sCls}`}
                  style={{ fontSize: 10, flexShrink: 0, marginTop: 2 }}
                >
                  {item.status}
                </span>
              )}
            </div>
          );
        })}
      </div>
    );
  };

  const pLen = results?.people?.length || 0;
  const aLen = results?.articles?.length || 0;
  const dLen = results?.decisions?.length || 0;
  const eLen = results?.experiments?.length || 0;
  const hasAny = flat.length > 0;

  return (
    <div style={{ position: "relative", flex: 1, maxWidth: 520 }}>
      <div
        className="search"
        style={{ width: "100%", boxSizing: "border-box" }}
      >
        <Icon.Search style={{ width: 14, height: 14 }} />
        <input
          ref={inputRef}
          placeholder="Search check-ins, decisions, people…"
          value={q}
          onChange={(e) => setQ(e.target.value)}
          onFocus={() => {
            if (results && q.trim().length >= 2) setOpen(true);
          }}
          onKeyDown={handleKey}
        />
        {q ? (
          <button
            style={{
              border: 0,
              background: "transparent",
              color: "var(--ink-3)",
              cursor: "pointer",
              lineHeight: 1,
              fontSize: 15,
            }}
            onMouseDown={(e) => {
              e.preventDefault();
              setQ("");
              setResults(null);
              setOpen(false);
            }}
          >
            ×
          </button>
        ) : (
          <>
            <span className="kbd">⌘</span>
            <span className="kbd">K</span>
          </>
        )}
      </div>
      {open && results && (
        <>
          <div
            style={{ position: "fixed", inset: 0, zIndex: 98 }}
            onClick={close}
          />
          <div
            style={{
              position: "absolute",
              top: "calc(100% + 6px)",
              left: 0,
              right: 0,
              background: "var(--bg)",
              border: "1px solid var(--line)",
              borderRadius: 10,
              boxShadow: "0 8px 32px rgba(0,0,0,0.28)",
              zIndex: 99,
              maxHeight: 440,
              overflowY: "auto",
            }}
          >
            {!hasAny && (
              <div
                style={{
                  padding: "20px 16px",
                  fontSize: 13,
                  color: "var(--ink-3)",
                  textAlign: "center",
                }}
              >
                No results for "{q}"
              </div>
            )}
            {renderGroup("People", "person", results.people, 0)}
            {renderGroup(
              "Knowledge articles",
              "article",
              results.articles,
              pLen,
            )}
            {renderGroup(
              "Decisions",
              "decision",
              results.decisions,
              pLen + aLen,
            )}
            {renderGroup(
              "Experiments",
              "experiment",
              results.experiments,
              pLen + aLen + dLen,
            )}
            {renderGroup(
              "Check-ins",
              "checkin",
              results.checkins,
              pLen + aLen + dLen + eLen,
            )}
            {hasAny && (
              <div
                style={{
                  padding: "5px 12px 8px",
                  fontSize: 11,
                  color: "var(--ink-4)",
                  borderTop: "1px solid var(--line)",
                  marginTop: 4,
                }}
              >
                ↑↓ navigate · ↵ select · Esc close
              </div>
            )}
          </div>
        </>
      )}
    </div>
  );
}

// ── Drafts review modal ─────────────────────────────────────────────────────
function DraftsModal({ authToken, onClose, onPublished, onDeleted }) {
  const [drafts, setDrafts] = useState([]);
  const [loading, setLoading] = useState(true);
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
  const headers = {
    Authorization: `Bearer ${authToken}`,
    "Content-Type": "application/json",
  };

  useEffect(() => {
    fetch(`${apiBase}/me/drafts`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => (r.ok ? r.json() : []))
      .then((d) => setDrafts(d))
      .finally(() => setLoading(false));
  }, []);

  const publish = async (id) => {
    const r = await fetch(`${apiBase}/check-ins/${id}/publish`, {
      method: "POST",
      headers,
    });
    if (r.ok) {
      setDrafts((ds) => ds.filter((d) => d.id !== id));
      onPublished();
    }
  };

  const remove = async (id) => {
    const r = await fetch(`${apiBase}/check-ins/${id}`, {
      method: "DELETE",
      headers,
    });
    if (r.ok) {
      setDrafts((ds) => ds.filter((d) => d.id !== id));
      onDeleted();
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div
        className="suggested-todos-modal"
        onClick={(e) => e.stopPropagation()}
        style={{ maxWidth: 520, width: "90vw" }}
      >
        <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>
          Draft check-ins for review
        </div>
        <div
          style={{ fontSize: 12.5, color: "var(--ink-3)", marginBottom: 12 }}
        >
          These were created from a meeting transcript. Publish to make them
          visible in the feed, or delete to discard.
        </div>

        {loading && (
          <div
            style={{
              padding: 20,
              textAlign: "center",
              color: "var(--ink-3)",
              fontSize: 13,
            }}
          >
            Loading…
          </div>
        )}

        {!loading && drafts.length === 0 && (
          <div
            style={{
              padding: 20,
              textAlign: "center",
              color: "var(--ink-3)",
              fontSize: 13,
            }}
          >
            No drafts remaining.
          </div>
        )}

        {drafts.map((d) => (
          <div
            key={d.id}
            style={{
              border: "1px solid var(--line)",
              borderRadius: 8,
              padding: "10px 12px",
              marginBottom: 8,
            }}
          >
            <div
              style={{ fontSize: 13, color: "var(--ink-1)", marginBottom: 6 }}
            >
              {d.transcript}
            </div>
            {d.signals && d.signals.length > 0 && (
              <div
                style={{
                  display: "flex",
                  gap: 4,
                  flexWrap: "wrap",
                  marginBottom: 6,
                }}
              >
                {d.signals.map((s, i) => (
                  <span
                    key={i}
                    style={{
                      fontSize: 11,
                      padding: "2px 6px",
                      borderRadius: 4,
                      background: "var(--accent-soft)",
                      color: "var(--accent)",
                    }}
                  >
                    {s.kind}
                  </span>
                ))}
              </div>
            )}
            {d.created_by_name && (
              <div
                style={{ fontSize: 11, color: "var(--ink-3)", marginBottom: 6 }}
              >
                Created by {d.created_by_name}
              </div>
            )}
            <div
              style={{ display: "flex", gap: 6, justifyContent: "flex-end" }}
            >
              <button
                onClick={() => remove(d.id)}
                style={{
                  fontSize: 12,
                  padding: "4px 10px",
                  borderRadius: 5,
                  border: "1px solid var(--line)",
                  background: "var(--bg)",
                  color: "var(--ink-2)",
                  cursor: "pointer",
                }}
              >
                Delete
              </button>
              <button
                onClick={() => publish(d.id)}
                style={{
                  fontSize: 12,
                  padding: "4px 10px",
                  borderRadius: 5,
                  border: 0,
                  background: "var(--accent)",
                  color: "#fff",
                  cursor: "pointer",
                  fontWeight: 500,
                }}
              >
                Publish
              </button>
            </div>
          </div>
        ))}

        <div
          style={{ display: "flex", justifyContent: "flex-end", marginTop: 10 }}
        >
          <button
            onClick={onClose}
            style={{
              fontSize: 12.5,
              padding: "6px 14px",
              borderRadius: 6,
              border: "1px solid var(--line)",
              background: "var(--bg)",
              color: "var(--ink-2)",
              cursor: "pointer",
            }}
          >
            Close
          </button>
        </div>
      </div>
    </div>
  );
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/ {
  density: "comfortable",
}; /*EDITMODE-END*/

function App() {
  const { SEED } = window;
  const [tweaks, setTweaks] = useTweaks(TWEAK_DEFAULTS);

  // ── Auth state ──────────────────────────────────────────────
  const [authToken, setAuthToken] = useState(
    () => localStorage.getItem("pulse_token") || null,
  );
  const [authUser, setAuthUser] = useState(() => {
    try {
      return JSON.parse(localStorage.getItem("pulse_user"));
    } catch {
      return null;
    }
  });

  const handleAuth = (token, user) => {
    setAuthToken(token);
    setAuthUser(user);
  };
  const handleSignOut = () => {
    localStorage.removeItem("pulse_token");
    localStorage.removeItem("pulse_user");
    setAuthToken(null);
    setAuthUser(null);
    // Clear Cognito SSO session in background (no visible redirect)
    const cfg = window.PULSE_CONFIG?.cognito;
    if (cfg?.clientId) {
      const logoutUrl = `https://${cfg.domain}/logout?client_id=${cfg.clientId}&logout_uri=${encodeURIComponent(cfg.redirectUri.replace("/auth/callback", ""))}`;
      const iframe = document.createElement("iframe");
      iframe.style.display = "none";
      iframe.src = logoutUrl;
      document.body.appendChild(iframe);
      setTimeout(() => iframe.remove(), 3000);
    }
  };

  // Check token expiry client-side (avoids showing blank app on expired token)
  if (authToken) {
    try {
      const payload = JSON.parse(atob(authToken.split(".")[1]));
      if (payload.exp && payload.exp * 1000 < Date.now()) {
        localStorage.removeItem("pulse_token");
        localStorage.removeItem("pulse_user");
        return <AuthScreen onAuth={handleAuth} />;
      }
    } catch {
      /* malformed token — fall through to auth check */
    }
  }

  // Show auth screen if not logged in or if we're handling an SSO callback
  const hasSSOCode = new URLSearchParams(window.location.search).has("code");
  if (!authToken || !authUser || hasSSOCode) {
    return <AuthScreen onAuth={handleAuth} />;
  }

  return (
    <AppShell
      tweaks={tweaks}
      setTweaks={setTweaks}
      authToken={authToken}
      authUser={authUser}
      onSignOut={handleSignOut}
    />
  );
}

function AppShell({ tweaks, setTweaks, authToken, authUser, onSignOut }) {
  const { SEED } = window;

  // ── Timezone-aware time formatting ──────────────────────────
  const userTz =
    authUser?.timezone ||
    Intl.DateTimeFormat().resolvedOptions().timeZone ||
    "Europe/London";
  window._pulseTz = userTz;
  const fmtTime = (date, opts = {}) =>
    date.toLocaleTimeString("en-GB", { timeZone: userTz, ...opts });
  const fmtDate = (date, opts = {}) =>
    date.toLocaleDateString("en-GB", { timeZone: userTz, ...opts });

  const [scope, setScope] = useState("squad");
  const [view, setView] = useState("updates"); // updates | wiki | person | history
  const [personId, setPersonId] = useState(null);
  const [modalOpen, setModalOpen] = useState(false);
  const [filter, setFilter] = useState("all");
  const [roleFilter, setRoleFilter] = useState("all"); // 'all' | a ROLE_TAGS value
  const [periodType, setPeriodType] = useState("week"); // day | week | month | quarter
  const [periodOffset, setPeriodOffset] = useState(0); // 0 = current, -1 = previous …
  const period = useMemo(
    () => window.computePeriod(periodType, periodOffset),
    [periodType, periodOffset],
  );

  const [updates, setUpdates] = useState([]);
  const [wiki, setWiki] = useState(SEED.INITIAL_WIKI);
  const [todos, setTodos] = useState(SEED.INITIAL_TODOS);
  const [squad, setSquad] = useState([]);
  const [highlightIds, setHighlightIds] = useState([]);

  const [scopeCounts, setScopeCounts] = useState({});
  const [dataVersion, setDataVersion] = useState(0);

  const [toast, setToast] = useState(null);
  const [wikiTarget, setWikiTarget] = useState(null);
  const [searchFocusTick, setSearchFocusTick] = useState(0);
  const [myCheckedIn, setMyCheckedIn] = useState({ done: false, time: null });
  const [suggestedTodos, setSuggestedTodos] = useState(null); // array of { text, selected } or null
  const [suggestedCompletions, setSuggestedCompletions] = useState(null); // array of { id, text, selected } or null

  // ── Multi-squad: active squad switcher ──────────────────────
  const [activeSquadId, setActiveSquadId] = useState(authUser?.squad_id || "");
  const [userSquads, setUserSquads] = useState([]); // [{id, name}]
  const [orgs, setOrgs] = useState([]); // full org hierarchy [{id, name, type, parent_id}]
  const [userPermissions, setUserPermissions] = useState(null);
  const [verified, setVerified] = useState(false);
  const [draftCount, setDraftCount] = useState(0);
  const [showDrafts, setShowDrafts] = useState(false);

  const refreshUserSquads = () => {
    const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
    fetch(`${apiBase}/me`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        if (!data) return;
        if (data.squad_ids?.length) {
          fetch(`${apiBase}/orgs`)
            .then((r) => r.json())
            .then((orgs) => {
              setOrgs(orgs);
              const mySquads = orgs.filter((o) =>
                data.squad_ids.includes(o.id),
              );
              setUserSquads(mySquads);
              if (!activeSquadId && mySquads.length)
                setActiveSquadId(mySquads[0].id);
            })
            .catch(() => {});
        }
      })
      .catch(() => {});
  };

  useEffect(() => {
    if (!authToken) return;
    const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
    fetch(`${apiBase}/me`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => {
        if (r.status === 401 || r.status === 403) {
          onSignOut();
          return null;
        }
        return r.ok ? r.json() : null;
      })
      .then((data) => {
        if (!data) return;
        setVerified(true);
        if (data.permissions) setUserPermissions(data.permissions);
        if (data.draft_count) setDraftCount(data.draft_count);
        if (data.squad_ids?.length) {
          fetch(`${apiBase}/orgs`)
            .then((r) => r.json())
            .then((orgs) => {
              setOrgs(orgs);
              const mySquads = orgs.filter((o) =>
                data.squad_ids.includes(o.id),
              );
              setUserSquads(mySquads);
              if (!activeSquadId && mySquads.length)
                setActiveSquadId(mySquads[0].id);
            })
            .catch(() => {});
        }
      })
      .catch(() => {
        setVerified(true);
      });
  }, [authToken]);

  // ── Load scoped check-ins from API whenever scope changes ─────
  useEffect(() => {
    if (!authToken || scope === "checkins") return;
    const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
    const headers = { Authorization: `Bearer ${authToken}` };

    // Clear feed immediately so stale data doesn't flash
    setUpdates([]);

    const squadParam = activeSquadId
      ? `&squad_id=${encodeURIComponent(activeSquadId)}`
      : "";
    const roleParam =
      roleFilter && roleFilter !== "all"
        ? `&role_tag=${encodeURIComponent(roleFilter)}`
        : "";
    const periodParam = `&start=${encodeURIComponent(period.start)}&end=${encodeURIComponent(period.end)}`;
    fetch(
      `${apiBase}/squad/check-ins?scope=${encodeURIComponent(scope)}${squadParam}${roleParam}${periodParam}`,
      { headers },
    )
      .then((r) => {
        if (r.status === 401) {
          onSignOut();
          return [];
        }
        return r.ok ? r.json() : [];
      })
      .then(async (checkins) => {
        if (!checkins.length) return;

        // Fetch pre-signed audio URLs in parallel for every check-in with S3
        // audio — teammates can play each other's voice notes, not just their own.
        const audioUrls = {};
        await Promise.all(
          checkins
            .filter((c) => c.s3_key)
            .map((c) =>
              fetch(`${apiBase}/check-ins/${c.id}/audio-url`, { headers })
                .then((r) => (r.ok ? r.json() : null))
                .then((data) => {
                  if (data?.url) audioUrls[c.id] = data.url;
                })
                .catch(() => {}),
            ),
        );

        const canWriteWiki = userPermissions?.wiki_write !== false;
        const mapped = checkins.map((c) => {
          const kinds = (c.signals || []).map((s) => s.kind);
          const tags = [];
          if (canWriteWiki && kinds.includes("decision")) tags.push("Decision");
          if (kinds.includes("blocker")) tags.push("Blocker");
          if (
            canWriteWiki &&
            (kinds.includes("knowledge") || kinds.includes("wiki"))
          )
            tags.push("Knowledge");
          if (canWriteWiki && kinds.includes("experiment"))
            tags.push("Experiment");
          if (kinds.includes("idea")) tags.push("Idea");
          if (kinds.includes("outcome")) tags.push("Outcome");
          const hasAudio = !!(c.s3_key || c.duration_s);
          const isMeeting = c.source_type === "meeting";
          if (hasAudio) tags.push("Voice");
          if (isMeeting) tags.push("Meeting");

          const wikiSignal = (c.signals || []).find(
            (s) => s.kind === "knowledge" || s.kind === "wiki",
          );
          const decisionSignal = (c.signals || []).find(
            (s) => s.kind === "decision",
          );
          const blockerSignal = (c.signals || []).find(
            (s) => s.kind === "blocker",
          );
          const isVoiceOnly = hasAudio && tags.length === 1;

          // Title: use the primary signal body as a headline, or fall back to timestamped label
          const primarySignal =
            decisionSignal || blockerSignal || (c.signals || [])[0];
          const dt = new Date(c.created_at);
          const timeStr = fmtTime(dt, { hour: "2-digit", minute: "2-digit" });
          const title = isVoiceOnly
            ? `Voice check-in · ${timeStr}`
            : isMeeting
              ? `${primarySignal?.body || (c.transcript || "").slice(0, 60).trim() || "Meeting"} (from Teams transcript)`
              : primarySignal?.body || `Check-in · ${timeStr}`;

          // Body: transcript shown for text check-ins; voice cards use the player
          const body = hasAudio ? null : c.transcript || null;

          return {
            id: c.id,
            who: c.author_name,
            role: c.author_role || "",
            you: !!c.you,
            title,
            body,
            fullTranscript: c.full_transcript || null,
            voice: hasAudio
              ? {
                  url: audioUrls[c.id] || null,
                  duration: c.duration_s || null,
                  transcript: c.transcript,
                }
              : null,
            tags,
            time: fmtDate(dt, { day: "numeric", month: "short" }),
            createdAt: dt.toISOString(),
            wiki: wikiSignal ? wikiSignal.body : null,
            aiRows: (c.signals || []).map((s) => ({
              kind: s.kind,
              text: s.body,
              quote: s.quote || null,
              assignee: s.assignee || null,
              importance: s.importance || 3,
            })),
          };
        });

        setUpdates((prev) => {
          const existingIds = new Set(prev.map((u) => u.id));
          const fresh = mapped.filter((m) => !existingIds.has(m.id));
          return fresh.length ? [...fresh, ...prev] : prev;
        });

        // Mark self as checked in this period (based on rhythm)
        const rhythm = authUser?.rhythm || "daily";
        const isCheckedInForPeriod = (checkins) => {
          const now = new Date();
          const today = now.getDay(); // 0=Sun, 1=Mon, ...
          let windowStart;
          if (rhythm === "weekly") {
            // Window starts on Monday
            const daysSinceMon = (today + 6) % 7;
            windowStart = new Date(now);
            windowStart.setDate(windowStart.getDate() - daysSinceMon);
            windowStart.setHours(0, 0, 0, 0);
          } else if (rhythm === "3x") {
            // Mon/Wed/Fri — window starts at the most recent of those
            const mwf = [1, 3, 5];
            let daysSinceLast = 0;
            for (let i = 0; i <= 6; i++) {
              if (mwf.includes((today - i + 7) % 7)) {
                daysSinceLast = i;
                break;
              }
            }
            windowStart = new Date(now);
            windowStart.setDate(windowStart.getDate() - daysSinceLast);
            windowStart.setHours(0, 0, 0, 0);
          } else {
            // daily
            windowStart = new Date(now);
            windowStart.setHours(0, 0, 0, 0);
          }
          return checkins.some((c) => {
            if (!c.you) return false;
            const d = new Date(c.created_at);
            return d >= windowStart;
          });
        };
        // Self check-in inference only when unfiltered AND viewing the current
        // period — a role filter or a past period may exclude my own check-ins.
        if (
          !roleParam &&
          periodOffset === 0 &&
          isCheckedInForPeriod(checkins)
        ) {
          setSquad((sq) =>
            sq.map((s) => (s.you ? { ...s, checkedIn: true } : s)),
          );
          setMyCheckedIn((prev) =>
            prev.done ? prev : { done: true, time: prev.time },
          );
        }
      })
      .catch(() => {});
  }, [authToken, scope, activeSquadId, dataVersion, roleFilter, period]);

  // ── Load scope members (re-fetches when scope changes) ───────────────────
  const refreshScopeMembers = (activeScope, role = roleFilter) => {
    const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
    const squadParam = activeSquadId
      ? `&squad_id=${encodeURIComponent(activeSquadId)}`
      : "";
    const roleParam =
      role && role !== "all" ? `&role_tag=${encodeURIComponent(role)}` : "";
    fetch(
      `${apiBase}/scope/members?scope=${encodeURIComponent(activeScope)}${squadParam}${roleParam}`,
      {
        headers: { Authorization: `Bearer ${authToken}` },
      },
    )
      .then((r) => (r.ok ? r.json() : []))
      .then((members) => {
        const formatted = members.map((m) => {
          if (m.checked_in_at && !m.time) {
            const dt = new Date(m.checked_in_at);
            m.time = fmtTime(dt, {
              hour: "numeric",
              minute: "2-digit",
              hour12: true,
            }).toLowerCase();
          }
          return m;
        });
        setSquad(formatted);
        // Only derive my check-in status from an unfiltered list — a role
        // filter may exclude me, which must not flip my Check In button.
        if (!roleParam) {
          const me = formatted.find((m) => m.you);
          if (me && me.checkedIn) setMyCheckedIn({ done: true, time: me.time });
          else setMyCheckedIn({ done: false, time: null });
        }
      })
      .catch(() => {});
  };
  useEffect(() => {
    if (!authToken) return;
    refreshScopeMembers(scope, roleFilter);
  }, [authToken, scope, activeSquadId, dataVersion, roleFilter]);

  // ── Load scope counts for the rail ───────────────────────────
  const refreshScopeCounts = () => {
    const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
    fetch(`${apiBase}/me/scope-counts`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => (r.ok ? r.json() : {}))
      .then((counts) => {
        if (Object.keys(counts).length) setScopeCounts(counts);
      })
      .catch(() => {});
  };
  useEffect(() => {
    if (authToken) refreshScopeCounts();
  }, [authToken]);

  useEffect(() => {
    document.documentElement.setAttribute(
      "data-density",
      tweaks.density || "comfortable",
    );
  }, [tweaks.density]);

  // When scope switches away from checkins, sync view
  useEffect(() => {
    if (scope === "checkins") setView("history");
    else if (view === "history" || view === "person") setView("updates");
  }, [scope]);

  const todaysCheckedIn = squad.filter((s) => s.checkedIn).length;

  // Keyboard shortcut: Cmd/Ctrl+K to open check-in
  useEffect(() => {
    const h = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setSearchFocusTick((n) => n + 1);
      } else if (e.key === "Escape" && modalOpen) {
        setModalOpen(false);
      }
    };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [modalOpen]);

  if (!verified) {
    return (
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          height: "100vh",
        }}
      >
        <span className="sp" style={{ width: 24, height: 24 }} />
      </div>
    );
  }

  const openPerson = (id) => {
    setPersonId(id);
    setView("person");
  };

  const handleSearchNavigate = (result) => {
    const t = result._type;
    if (t === "person") {
      openPerson(result.id);
    } else if (t === "article") {
      setView("wiki");
      setWikiTarget({
        section: "knowledge",
        id: result.id,
        category: result.category,
      });
    } else if (t === "decision") {
      setView("wiki");
      setWikiTarget({ section: "decisions", id: result.id });
    } else if (t === "experiment") {
      setView("wiki");
      setWikiTarget({ section: "experiments", id: result.id });
    } else if (t === "checkin") {
      if (scope === "checkins") setView("history");
      else setView("updates");
      setHighlightIds([result.id]);
      setTimeout(() => setHighlightIds([]), 3000);
    }
  };

  const handlePost = (payload) => {
    const myId = payload.id || `u-me-${Date.now()}`;
    const canWrite = userPermissions?.wiki_write !== false;
    const tags = [];
    if (canWrite && payload.aiRows?.some((r) => r.kind === "decision"))
      tags.push("Decision");
    if (payload.aiRows?.some((r) => r.kind === "blocker")) tags.push("Blocker");
    if (
      canWrite &&
      payload.aiRows?.some((r) => ["knowledge", "wiki"].includes(r.kind))
    )
      tags.push("Knowledge");
    if (canWrite && payload.aiRows?.some((r) => r.kind === "experiment"))
      tags.push("Experiment");
    if (payload.aiRows?.some((r) => r.kind === "idea")) tags.push("Idea");
    if (payload.aiRows?.some((r) => r.kind === "outcome")) tags.push("Outcome");
    if (payload.voice) tags.push("Voice");
    if (payload.meeting) tags.push("Meeting");

    const newUpdate = {
      id: myId,
      who: authUser ? authUser.name : SEED.ME.name,
      role: authUser ? authUser.role : SEED.ME.role,
      you: true,
      title: payload.voice
        ? `Voice check-in · ${fmtTime(new Date(), { hour: "2-digit", minute: "2-digit" })}`
        : payload.meeting
          ? `${(payload.aiRows || [])[0]?.text || (payload.text || "").slice(0, 60).trim() || "Meeting"} (from Teams transcript)`
          : `Check-in · ${fmtTime(new Date(), { hour: "2-digit", minute: "2-digit" })}`,
      body: payload.text || null,
      fullTranscript: payload.fullTranscript || null,
      voice: payload.voice || null,
      tags,
      aiRows: payload.aiRows || [],
      time: "just now",
      wiki:
        canWrite &&
        payload.aiRows?.some((r) => ["kb", "knowledge"].includes(r.kind))
          ? payload.aiRows.find((r) => ["kb", "knowledge"].includes(r.kind))
              ?.text || null
          : null,
    };

    // New delegated to-do for Marco (demoed)
    const taskSignals = (payload.aiRows || []).filter(
      (r) => r.kind === "task" || r.kind === "delegation",
    );

    // Mark me as checked in — only if current scope was included in posted scopes
    const nowTime = fmtTime(new Date(), { hour: "2-digit", minute: "2-digit" });
    const postedScopes = payload.scopes || [];
    const postedToCurrentScope =
      postedScopes.includes(scope) ||
      (scope === "squad" && postedScopes.includes("squad")) ||
      (scope === "team" && postedScopes.includes("team")) ||
      (scope === "function" && postedScopes.includes("function")) ||
      (scope === "business" && postedScopes.includes("business"));
    if (postedToCurrentScope) {
      setMyCheckedIn({ done: true, time: nowTime });
      setSquad((sq) =>
        sq.map((s) => (s.you ? { ...s, checkedIn: true, time: nowTime } : s)),
      );
    }
    refreshScopeCounts();
    setTimeout(() => refreshScopeMembers(scope), 1500); // let the server save before re-fetch
    setUpdates((us) => [newUpdate, ...us]);

    if (taskSignals.length && userPermissions?.todos !== false) {
      const existing = todos.map((t) => t.text.toLowerCase());
      const items = taskSignals.map((s) => ({
        text: s.text,
        selected: !existing.some((e) =>
          e.includes(s.text.toLowerCase().slice(0, 20)),
        ),
        assignee: s.assignee || null,
      }));
      if (items.length) {
        setSuggestedTodos(items);
      }
    }

    // Suggest to-dos that sound completed based on the check-in transcript.
    if (
      payload.completedTodoSuggestions &&
      payload.completedTodoSuggestions.length
    ) {
      const matchedTodos = todos
        .filter(
          (t) => !t.done && payload.completedTodoSuggestions.includes(t.id),
        )
        .map((t) => ({ id: t.id, text: t.text, selected: true }));
      if (matchedTodos.length) {
        // Show after a brief delay so it doesn't compete with the new-todos popup.
        setTimeout(
          () => setSuggestedCompletions(matchedTodos),
          suggestedTodos ? 800 : 0,
        );
      }
    }

    // Highlight new update briefly
    setHighlightIds([myId]);
    setTimeout(() => setHighlightIds([]), 2500);

    setModalOpen(false);

    // Toast
    const fanoutCount = (payload.aiRows || []).length;
    const wikiPromoted = tags.some((t) =>
      ["Knowledge", "Decision", "Experiment"].includes(t),
    );
    setToast({
      msg: payload.voice
        ? `Voice check-in posted · ${fanoutCount} signals routed`
        : "Check-in posted",
      action: wikiPromoted
        ? {
            label: "See in wiki",
            onClick: () => {
              setView("wiki");
              setToast(null);
            },
          }
        : null,
    });
    setTimeout(() => setToast(null), 5500);
  };

  const mainContent = () => {
    if (view === "admin")
      return (
        <AdminView
          authToken={authToken}
          onDataChange={() => setDataVersion((v) => v + 1)}
        />
      );
    if (view === "wiki")
      return (
        <WikiView
          authToken={authToken}
          authUser={authUser}
          highlightIds={highlightIds}
          wikiTarget={wikiTarget}
          activeSquadId={activeSquadId}
          userSquads={userSquads}
          setActiveSquadId={setActiveSquadId}
          canWrite={userPermissions?.wiki_write !== false}
          canRead={userPermissions?.wiki_read !== false}
        />
      );
    if (view === "person")
      return (
        <PersonView
          personId={personId}
          squad={squad}
          authToken={authToken}
          onBack={() => setView("updates")}
        />
      );
    if (view === "history" || scope === "checkins")
      return <HistoryView authToken={authToken} />;
    return (
      <>
        {draftCount > 0 && (
          <div
            style={{
              background: "var(--accent-soft)",
              border: "1px solid var(--accent)",
              borderRadius: 10,
              padding: "10px 16px",
              marginBottom: 12,
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              fontSize: 13,
            }}
          >
            <span>
              <strong>{draftCount}</strong> check-in
              {draftCount !== 1 ? "s" : ""} from a meeting transcript{" "}
              {draftCount !== 1 ? "are" : "is"} awaiting your review
            </span>
            <button
              className="btn accent"
              style={{ fontSize: 12, padding: "5px 12px" }}
              onClick={() => setShowDrafts(true)}
            >
              Review
            </button>
          </div>
        )}
        <UpdatesView
          updates={updates}
          setUpdates={setUpdates}
          scope={scope}
          squad={squad}
          todaysCheckedIn={todaysCheckedIn}
          filter={filter}
          setFilter={setFilter}
          roleFilter={roleFilter}
          setRoleFilter={setRoleFilter}
          highlightIds={highlightIds}
          authToken={authToken}
          activeSquadId={activeSquadId}
          orgs={orgs}
          userSquads={userSquads}
          periodType={periodType}
          setPeriodType={setPeriodType}
          periodOffset={periodOffset}
          setPeriodOffset={setPeriodOffset}
          period={period}
        />
      </>
    );
  };

  return (
    <div className="app">
      <header className="topbar">
        <div className="brand">
          <div className="brand-mark">
            <Icon.Logo />
          </div>
          <div>
            <div className="brand-name">Centrica Pulse</div>
            <div className="brand-sub">Operating console</div>
          </div>
        </div>

        <div className="tabs">
          <button
            className="tab"
            aria-current={
              view === "updates" || view === "person" || view === "history"
            }
            onClick={() => {
              setView(scope === "checkins" ? "history" : "updates");
            }}
          >
            <Icon.List /> Updates
          </button>
          <button
            className="tab"
            aria-current={view === "wiki"}
            onClick={() => setView("wiki")}
          >
            <Icon.Wiki /> Wiki
          </button>
          {[
            "john.harper1@centrica.com",
            "ambrose.choy@centrica.com",
            "will.fox@centrica.com",
          ].includes(authUser?.email) && (
            <button
              className="tab"
              aria-current={view === "admin"}
              onClick={() => setView("admin")}
            >
              <Icon.Settings /> Admin
            </button>
          )}
        </div>

        <GlobalSearch
          authToken={authToken}
          onNavigate={handleSearchNavigate}
          focusTick={searchFocusTick}
        />

        {(() => {
          const checkedInToday = myCheckedIn.done;
          const myTime = myCheckedIn.time;
          const rhythm = authUser?.rhythm || "daily";
          const rhythmLabel =
            rhythm === "weekly"
              ? "Weekly"
              : rhythm === "3x"
                ? "3× weekly"
                : "Daily";
          const periodLabel =
            rhythm === "weekly"
              ? "this week"
              : rhythm === "3x"
                ? "this period"
                : "today";
          return (
            <>
              <div className="reminder">
                {checkedInToday ? (
                  <Icon.Check
                    style={{ width: 14, height: 14, color: "var(--ink-3)" }}
                  />
                ) : (
                  <Icon.Spark
                    style={{ width: 14, height: 14, color: "var(--ok)" }}
                  />
                )}
                <div>
                  {checkedInToday ? (
                    <>
                      <b style={{ color: "var(--ink-3)", fontWeight: 500 }}>
                        {rhythmLabel} check-in done
                      </b>
                      <br />
                      <span>
                        Checked in {periodLabel}
                        {myTime ? ` · ${myTime}` : ""}
                      </span>
                    </>
                  ) : (
                    <>
                      <b>{rhythmLabel} squad check-in</b>
                      <br />
                      <span>Haven't checked in {periodLabel}</span>
                    </>
                  )}
                </div>
              </div>
              <button
                className={`checkin-btn${checkedInToday ? " done" : ""}`}
                onClick={() => setModalOpen(true)}
              >
                {checkedInToday ? (
                  <>
                    <Icon.Check style={{ width: 13, height: 13 }} />
                    Checked In
                  </>
                ) : (
                  <>
                    <span className="pulse" />
                    Check In
                  </>
                )}
              </button>
            </>
          );
        })()}
      </header>

      <Rail
        scope={scope}
        setScope={(s) => {
          setScope(s);
          setView(s === "checkins" ? "history" : "updates");
        }}
        squad={squad}
        authUser={authUser}
        onSignOut={onSignOut}
        scopeCounts={scopeCounts}
        userSquads={userSquads}
        activeSquadId={activeSquadId}
        setActiveSquadId={setActiveSquadId}
        view={view}
        onProfileSave={refreshUserSquads}
      />
      <main className="main">{mainContent()}</main>
      <RightRail
        todos={todos}
        setTodos={setTodos}
        scope={scope}
        authToken={authToken}
        showTodos={userPermissions?.todos !== false}
      />

      <CheckInModal
        open={modalOpen}
        onClose={() => setModalOpen(false)}
        onPost={handlePost}
        currentScope={scope}
        activeSquadId={activeSquadId}
        userSquads={userSquads}
        setActiveSquadId={setActiveSquadId}
        checkinScope={userPermissions?.checkin_scope || "business"}
      />

      {/* Suggested todos modal */}
      {suggestedTodos && (
        <div className="modal-backdrop" onClick={() => setSuggestedTodos(null)}>
          <div
            className="suggested-todos-modal"
            onClick={(e) => e.stopPropagation()}
          >
            <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>
              {suggestedTodos.length} potential to-do
              {suggestedTodos.length !== 1 ? "s" : ""} identified
            </div>
            <div
              style={{
                fontSize: 12.5,
                color: "var(--ink-3)",
                marginBottom: 12,
              }}
            >
              From your check-in. Select which to add:
            </div>
            {suggestedTodos.map((s, i) => (
              <div
                key={i}
                style={{
                  padding: "8px 0",
                  borderBottom: "1px solid var(--line)",
                }}
              >
                <label
                  style={{
                    display: "flex",
                    alignItems: "flex-start",
                    gap: 8,
                    fontSize: 13,
                    cursor: "pointer",
                    color: "var(--ink-1)",
                  }}
                >
                  <input
                    type="checkbox"
                    checked={s.selected}
                    onChange={() =>
                      setSuggestedTodos((ts) =>
                        ts.map((t, j) =>
                          j === i ? { ...t, selected: !t.selected } : t,
                        ),
                      )
                    }
                    style={{ marginTop: 2, accentColor: "var(--accent)" }}
                  />
                  {s.text}
                </label>
                {s.selected && (
                  <div
                    style={{
                      display: "grid",
                      gridTemplateColumns: "1fr 1fr 1fr",
                      gap: 6,
                      marginTop: 6,
                      marginLeft: 24,
                    }}
                  >
                    <div>
                      <label
                        style={{
                          fontSize: 10,
                          color: "var(--ink-4)",
                          display: "block",
                          marginBottom: 2,
                        }}
                      >
                        Priority
                      </label>
                      <select
                        value={s.priority || "medium"}
                        onChange={(e) =>
                          setSuggestedTodos((ts) =>
                            ts.map((t, j) =>
                              j === i ? { ...t, priority: e.target.value } : t,
                            ),
                          )
                        }
                        style={{
                          width: "100%",
                          fontSize: 11,
                          padding: "3px 6px",
                          border: "1px solid var(--line)",
                          borderRadius: 5,
                          background: "var(--surface)",
                        }}
                      >
                        <option value="high">High</option>
                        <option value="medium">Medium</option>
                        <option value="low">Low</option>
                      </select>
                    </div>
                    <div>
                      <label
                        style={{
                          fontSize: 10,
                          color: "var(--ink-4)",
                          display: "block",
                          marginBottom: 2,
                        }}
                      >
                        To do by
                      </label>
                      <input
                        type="date"
                        value={s.due_date || ""}
                        onChange={(e) =>
                          setSuggestedTodos((ts) =>
                            ts.map((t, j) =>
                              j === i ? { ...t, due_date: e.target.value } : t,
                            ),
                          )
                        }
                        style={{
                          width: "100%",
                          fontSize: 11,
                          padding: "3px 6px",
                          border: "1px solid var(--line)",
                          borderRadius: 5,
                          background: "var(--surface)",
                        }}
                      />
                    </div>
                    <div>
                      <label
                        style={{
                          fontSize: 10,
                          color: "var(--ink-4)",
                          display: "block",
                          marginBottom: 2,
                        }}
                      >
                        Assign to
                      </label>
                      <select
                        value={s.assignee || ""}
                        onChange={(e) =>
                          setSuggestedTodos((ts) =>
                            ts.map((t, j) =>
                              j === i
                                ? { ...t, assignee: e.target.value || null }
                                : t,
                            ),
                          )
                        }
                        style={{
                          width: "100%",
                          fontSize: 11,
                          padding: "3px 6px",
                          border: "1px solid var(--line)",
                          borderRadius: 5,
                          background: s.assignee
                            ? "var(--accent-soft)"
                            : "var(--surface)",
                        }}
                      >
                        <option value="">Me</option>
                        {squad
                          .filter((m) => !m.you && m.name)
                          .map((m) => (
                            <option key={m.id || m.name} value={m.name}>
                              {m.name}
                            </option>
                          ))}
                      </select>
                    </div>
                  </div>
                )}
              </div>
            ))}
            <div
              style={{
                display: "flex",
                gap: 8,
                marginTop: 14,
                justifyContent: "flex-end",
              }}
            >
              <button
                onClick={() => setSuggestedTodos(null)}
                style={{
                  fontSize: 12.5,
                  padding: "6px 14px",
                  borderRadius: 6,
                  border: "1px solid var(--line)",
                  background: "var(--bg)",
                  color: "var(--ink-2)",
                  cursor: "pointer",
                }}
              >
                Ignore all
              </button>
              <button
                onClick={() => {
                  const selected = suggestedTodos.filter((s) => s.selected);
                  const apiBase =
                    window.PULSE_CONFIG?.apiBase || "http://localhost:8000";
                  selected.forEach((s) => {
                    const isAssigned = !!s.assignee;
                    const tempId = `td-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
                    if (!isAssigned) {
                      setTodos((ts) => [
                        {
                          id: tempId,
                          text: s.text,
                          done: false,
                          source: "your check-in",
                          priority: s.priority || "medium",
                          due_date: s.due_date || null,
                        },
                        ...ts,
                      ]);
                    }
                    fetch(`${apiBase}/todos`, {
                      method: "POST",
                      headers: {
                        "Content-Type": "application/json",
                        Authorization: `Bearer ${authToken}`,
                      },
                      body: JSON.stringify({
                        text: s.text,
                        source: isAssigned ? null : "your check-in",
                        priority: s.priority || "medium",
                        due_date: s.due_date || null,
                        assign_to_name: s.assignee || null,
                      }),
                    })
                      .then((r) => (r.ok ? r.json() : null))
                      .then((data) => {
                        if (data && !isAssigned)
                          setTodos((ts) =>
                            ts.map((t) =>
                              t.id === tempId ? { ...t, id: data.id } : t,
                            ),
                          );
                      })
                      .catch(() => {});
                  });
                  setSuggestedTodos(null);
                }}
                style={{
                  fontSize: 12.5,
                  padding: "6px 14px",
                  borderRadius: 6,
                  border: 0,
                  background: "var(--accent)",
                  color: "#fff",
                  cursor: "pointer",
                  fontWeight: 500,
                }}
              >
                Add selected
              </button>
            </div>
          </div>
        </div>
      )}

      {suggestedCompletions && (
        <div
          className="modal-backdrop"
          onClick={() => setSuggestedCompletions(null)}
        >
          <div
            className="suggested-todos-modal"
            onClick={(e) => e.stopPropagation()}
          >
            <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>
              {suggestedCompletions.length} to-do
              {suggestedCompletions.length !== 1 ? "s" : ""} you may have
              completed
            </div>
            <div
              style={{
                fontSize: 12.5,
                color: "var(--ink-3)",
                marginBottom: 12,
              }}
            >
              Based on your check-in. Tick off the ones you've done:
            </div>
            {suggestedCompletions.map((s, i) => (
              <label
                key={s.id}
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 8,
                  padding: "6px 0",
                  fontSize: 13,
                  cursor: "pointer",
                  color: "var(--ink-1)",
                }}
              >
                <input
                  type="checkbox"
                  checked={s.selected}
                  onChange={() =>
                    setSuggestedCompletions((ts) =>
                      ts.map((t, j) =>
                        j === i ? { ...t, selected: !t.selected } : t,
                      ),
                    )
                  }
                  style={{ accentColor: "var(--ok, #22c55e)" }}
                />
                <span
                  style={{
                    textDecoration: s.selected ? "line-through" : "none",
                    opacity: s.selected ? 0.7 : 1,
                  }}
                >
                  {s.text}
                </span>
              </label>
            ))}
            <div
              style={{
                display: "flex",
                gap: 8,
                marginTop: 14,
                justifyContent: "flex-end",
              }}
            >
              <button
                onClick={() => setSuggestedCompletions(null)}
                style={{
                  fontSize: 12.5,
                  padding: "6px 14px",
                  borderRadius: 6,
                  border: "1px solid var(--line)",
                  background: "var(--bg)",
                  color: "var(--ink-2)",
                  cursor: "pointer",
                }}
              >
                Skip
              </button>
              <button
                onClick={() => {
                  const selected = suggestedCompletions.filter(
                    (s) => s.selected,
                  );
                  selected.forEach((s) => {
                    setTodos((ts) =>
                      ts.map((t) => (t.id === s.id ? { ...t, done: true } : t)),
                    );
                    fetch(
                      `${window.PULSE_CONFIG?.apiBase || "http://localhost:8000"}/todos/${s.id}`,
                      {
                        method: "PATCH",
                        headers: {
                          "Content-Type": "application/json",
                          Authorization: `Bearer ${authToken}`,
                        },
                        body: JSON.stringify({ done: true }),
                      },
                    ).catch(() => {});
                  });
                  setSuggestedCompletions(null);
                }}
                style={{
                  fontSize: 12.5,
                  padding: "6px 14px",
                  borderRadius: 6,
                  border: 0,
                  background: "var(--ok, #22c55e)",
                  color: "#fff",
                  cursor: "pointer",
                  fontWeight: 500,
                }}
              >
                Mark done
              </button>
            </div>
          </div>
        </div>
      )}

      {showDrafts && (
        <DraftsModal
          authToken={authToken}
          onClose={() => setShowDrafts(false)}
          onPublished={() => {
            setDraftCount((c) => Math.max(0, c - 1));
            setDataVersion((v) => v + 1);
          }}
          onDeleted={() => setDraftCount((c) => Math.max(0, c - 1))}
        />
      )}

      {toast && (
        <div className="toast-wrap">
          <div className="toast">
            <span className="dot" />
            <span>{toast.msg}</span>
            {toast.action && (
              <span className="lk" onClick={toast.action.onClick}>
                {toast.action.label}
              </span>
            )}
          </div>
        </div>
      )}

      <TweaksPanel title="Tweaks">
        <TweakSection label="Density">
          <TweakRadio
            value={tweaks.density || "comfortable"}
            onChange={(v) => setTweaks("density", v)}
            options={[
              { value: "comfortable", label: "Comfortable" },
              { value: "compact", label: "Compact" },
              { value: "terminal", label: "Terminal" },
            ]}
          />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
