// home.jsx — Flowboard Home (hybrid command center).
//
// Default landing page on sign-in. Synthesizes everything the user
// might want at a glance — their personal queue + workspace pulse —
// from data we already load at boot, plus three small follow-up
// fetches for bugs / tickets / activity that the bootstrap doesn't
// cover yet. No new backend endpoint needed for v1.
//
// Structure:
//   1. Greeting hero — time-of-day aware "Good morning, Aya"
//   2. Stat chips — Open / Overdue / Mentions / Unread notifications
//   3. Quick actions row — New task · Report bug · Jump to last project
//   4. Two-column body —
//        Left  (your work):  Today's queue + Recent activity
//        Right (workspace):  Active sprints + Open bugs + Support queue + CRM funnel
//   5. Recent projects grid — quick-jump tiles
//
// Keep this view low-stakes: every block degrades gracefully if the
// data isn't loaded yet. Click anywhere takes you to the deep view
// (My Work, the project, the bug page, etc.) for the real work.

// Re-show the avatar prompt this many days after dismissal — keeps it
// gentle but persistent so people without a photo still get nudged.
const AVATAR_PROMPT_REDUNDANCE_DAYS = 3;
const AVATAR_PROMPT_LS_KEY = "fb.avatarPrompt.dismissedAt";

function _avatarPromptDismissed() {
  try {
    const ts = parseInt(localStorage.getItem(AVATAR_PROMPT_LS_KEY) || "0", 10);
    if (!ts) return false;
    const ageMs = Date.now() - ts;
    return ageMs < AVATAR_PROMPT_REDUNDANCE_DAYS * 24 * 60 * 60 * 1000;
  } catch { return false; }
}
function _dismissAvatarPrompt() {
  try { localStorage.setItem(AVATAR_PROMPT_LS_KEY, String(Date.now())); } catch {}
}

// ── Avatar prompt card ───────────────────────────────────────────
// Soft nudge for users who haven't uploaded a profile picture yet.
// Sits at the top of Home; one click opens the existing avatar upload
// modal (we just dispatch the topbar's "changePhoto" event).
function AvatarPromptCard({ user, onDismiss }) {
  if (!user) return null;
  const initials = String(user.name || "?")
    .trim().split(/\s+/).map(s => s[0]).slice(0, 2).join("").toUpperCase();
  const accent = user.color || "#7E3B8A";
  return (
    <div
      className="home-avatar-prompt"
      style={{
        background: "linear-gradient(135deg, #fff 0%, #f7f0fb 100%)",
        border: "1px solid #e6dcf0",
        borderRadius: 14,
        padding: "16px 18px",
        margin: "0 0 18px",
        display: "flex",
        alignItems: "center",
        gap: 16,
        boxShadow: "0 2px 6px rgba(126,59,138,.06)",
      }}
    >
      <span
        aria-hidden="true"
        style={{
          width: 56,
          height: 56,
          borderRadius: "50%",
          flexShrink: 0,
          background: accent,
          color: "#fff",
          fontSize: 22,
          fontWeight: 700,
          display: "inline-flex",
          alignItems: "center",
          justifyContent: "center",
          position: "relative",
          boxShadow: "0 4px 12px rgba(126,59,138,.18)",
        }}
      >
        {initials}
        <span
          style={{
            position: "absolute",
            right: -3,
            bottom: -3,
            width: 22,
            height: 22,
            borderRadius: "50%",
            background: "#fff",
            color: "#7E3B8A",
            display: "inline-flex",
            alignItems: "center",
            justifyContent: "center",
            fontSize: 16,
            fontWeight: 800,
            boxShadow: "0 2px 6px rgba(15,23,41,.15)",
          }}
        >
          +
        </span>
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 15, fontWeight: 700, color: "#0f1729", marginBottom: 2 }}>
          Put a face on your account
        </div>
        <div style={{ fontSize: 13, color: "#5b6175", lineHeight: 1.45 }}>
          Add a profile picture so teammates recognize you in chat, comments,
          and assignee lists. Takes 5 seconds — just pick a photo.
        </div>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6, flexShrink: 0 }}>
        <button
          className="btn btn-primary"
          onClick={() => {
            try { window.dispatchEvent(new CustomEvent("flowboard:user:menu:changePhoto")); }
            catch {}
          }}
        >
          Add photo
        </button>
        <button
          className="btn"
          style={{ fontSize: 12, padding: "4px 10px", color: "#676879" }}
          onClick={onDismiss}
          title="Hide for a few days"
        >
          Maybe later
        </button>
      </div>
    </div>
  );
}

function HomeView({ currentUserId, onNavigate, onOpenTask, onOpenBugReport }) {
  // ── Live state from existing globals ─────────────────────────────
  const me = (currentUserId && (typeof PEOPLE !== "undefined")
    ? PEOPLE.find(p => p.id === currentUserId)
    : null) || (window.api && api.getUser && api.getUser()) || { name: "there" };
  const firstName = (me.name || "there").split(/\s+/)[0];

  // ── Avatar prompt visibility ─────────────────────────────────────
  // Show only when the user has no avatar AND hasn't dismissed the
  // nudge within the last 3 days. Re-evaluates after upload via SSE.
  const [showAvatarPrompt, setShowAvatarPrompt] = React.useState(() =>
    !!(me && !me.avatar && !_avatarPromptDismissed())
  );
  React.useEffect(() => {
    setShowAvatarPrompt(!!(me && !me.avatar && !_avatarPromptDismissed()));
  }, [me && me.id, me && me.avatar]);
  const hour = new Date().getHours();
  const greet = hour < 5  ? "Working late"
              : hour < 12 ? "Good morning"
              : hour < 17 ? "Good afternoon"
              : hour < 21 ? "Good evening"
              : "Burning the midnight oil";

  // ── Notifications (live) ─────────────────────────────────────────
  const [notifUnread, setNotifUnread] = React.useState(
    () => (window.flowboardNotify ? window.flowboardNotify.state().unread : 0)
  );
  React.useEffect(() => {
    if (!window.flowboardNotify) return;
    return window.flowboardNotify.subscribe(s => setNotifUnread(s.unread || 0));
  }, []);

  // ── My tasks slice from ALL_TASKS ────────────────────────────────
  // We re-derive on every render because ALL_TASKS is mutated in place
  // by the rest of the app. The shape on Home is read-only — clicking
  // a row opens the drawer through the parent's onOpenTask callback.
  //
  // Important: skip subtasks. ALL_TASKS contains subtasks once the
  // table view has fetched them with include_subtasks=1, and a parent
  // + its subtask both being assigned to me + both overdue would
  // surface as a "duplicate" pair in the My queue. The drawer's
  // subtask list is the right place to see those — keep Home focused
  // on top-level work. Also de-dup by id as a belt-and-braces guard
  // against any future regression that lets the same row land twice
  // in ALL_TASKS.
  const myTasks = React.useMemo(() => {
    const all = (typeof ALL_TASKS !== "undefined" && Array.isArray(ALL_TASKS)) ? ALL_TASKS : [];
    if (!currentUserId) return [];
    const seen = new Set();
    const out = [];
    for (const t of all) {
      if (!t || !t.id || seen.has(t.id)) continue;
      if (t.parentTaskId) continue;          // skip subtasks
      if (t.status === "done") continue;
      if (!Array.isArray(t.owners) || !t.owners.includes(currentUserId)) continue;
      seen.add(t.id);
      out.push(t);
    }
    return out;
  }, [currentUserId, /* re-eval on any state tick */ Date.now()]);

  // ── Personal todos (private notes-table tasks) ───────────────────
  // The Personal page (notes.jsx) stores personal to-dos as rows in
  // the user_notes table with kind='todo'. We fetch the open ones
  // here so the Home queue / counts include them alongside project
  // tasks — same view, different source. They're tagged _isPersonal
  // so the row renderer can show a "Personal" chip and route the
  // click to the Personal page instead of the project drawer.
  const [personalRaw, setPersonalRaw] = React.useState([]);
  React.useEffect(() => {
    if (!window.api || !api.notes || typeof api.notes.list !== "function") return;
    let cancelled = false;
    api.notes.list("todo")
      .then(rows => { if (!cancelled) setPersonalRaw(Array.isArray(rows) ? rows : []); })
      .catch(() => { if (!cancelled) setPersonalRaw([]); });
    return () => { cancelled = true; };
    // No deps — refetched on each Home mount; SSE-driven live updates
    // for the personal table aren't implemented yet (the Personal page
    // refetches on its own mount), but Home gets a fresh list every
    // time the user navigates back to it.
  }, []);

  // Convert a personal todo's ISO due_at into the "Mon DD" / "Today"
  // label shape that parseDue() / isOverdueNow() expect, so personal
  // tasks flow through the same overdue / due-today machinery.
  function _personalDueLabel(due_at) {
    if (!due_at) return "—";
    const head = String(due_at).split(" @ ")[0].trim();
    const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(head);
    if (!m) return head;
    const months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
    const todayLabel = (typeof todayMonDay === "function") ? todayMonDay() : "";
    const mo = months[Number(m[2]) - 1];
    const day = Number(m[3]);
    const label = mo + " " + String(day).padStart(2, "0");
    if (label === todayLabel) return "Today";
    // Drop leading zero so it matches isOverdueNow's parseDue regex
    // (\d{1,2}) — the function strips the head before matching, so
    // "Apr 24" and "Apr 4" both work; mirror that here.
    return mo + " " + day;
  }

  const personalTasks = React.useMemo(() => {
    const out = [];
    for (const r of personalRaw) {
      if (!r || !r.id) continue;
      const status = r.task_status || (r.done ? "done" : "todo");
      if (status === "done") continue;       // hide completed personal todos from Home
      out.push({
        id: r.id,
        name: r.title || "(untitled)",
        // Mirror the project-task shape so existing renderers + filters
        // (isOverdueNow, todayMonDay match, due chip) just work.
        due: _personalDueLabel(r.due_at),
        status: status === "todo" ? "todo" : status,
        owners: currentUserId ? [currentUserId] : [],
        parentTaskId: null,
        projectName: "Personal",
        projectColor: "#ff5e9c",            // brand coral, matches Personal hero
        epicColor:    "#ff7e5f",
        _isPersonal: true,
        // Keep a pointer to the raw row in case we ever want to open
        // the personal task drawer from Home (not implemented yet).
        _raw: r,
      });
    }
    return out;
  }, [personalRaw, currentUserId]);

  // Combined list — project tasks + personal todos. Stats and
  // today's queue both work off this so personal tasks count toward
  // open / overdue / due-today and show up in the queue alongside
  // project work.
  const allMyTasks = React.useMemo(
    () => [...myTasks, ...personalTasks],
    [myTasks, personalTasks]
  );

  const stats = React.useMemo(() => {
    const overdue = allMyTasks.filter(t => typeof isOverdueNow === "function" && isOverdueNow(t)).length;
    const dueToday = allMyTasks.filter(t => {
      if (!t.due || t.due === "—") return false;
      // Quick: if it's "Today" or matches today's "MMM DD" label.
      if (t.due === "Today") return true;
      const today = typeof todayMonDay === "function" ? todayMonDay() : "";
      return today && t.due.startsWith(today);
    }).length;
    return {
      open: allMyTasks.length,
      overdue,
      dueToday,
      mentions: notifUnread,
    };
  }, [allMyTasks, notifUnread]);

  // Today's queue — overdue first, then due-today, then in-progress.
  // Cap at 7 rows so the column stays glanceable. Personal tasks are
  // included via allMyTasks so they bubble up into the same priority
  // buckets as project tasks.
  const todayQueue = React.useMemo(() => {
    const overdue = allMyTasks.filter(t => typeof isOverdueNow === "function" && isOverdueNow(t));
    const dueToday = allMyTasks.filter(t => t.due === "Today" || (typeof todayMonDay === "function" && t.due === todayMonDay()));
    const inProgress = allMyTasks.filter(t => t.status === "progress" || t.status === "review");
    const seen = new Set();
    const merged = [];
    for (const list of [overdue, dueToday, inProgress, allMyTasks]) {
      for (const t of list) {
        if (seen.has(t.id)) continue;
        seen.add(t.id);
        merged.push(t);
        if (merged.length >= 7) return merged;
      }
    }
    return merged;
  }, [allMyTasks]);

  // ── Recent activity (notifications double as a personal feed) ────
  const [recentActivity, setRecentActivity] = React.useState([]);
  React.useEffect(() => {
    if (!window.flowboardNotify) return;
    const unsub = window.flowboardNotify.subscribe(s => {
      // Most-recent 8, regardless of read state.
      setRecentActivity((s.items || []).slice(0, 8));
    });
    return unsub;
  }, []);

  // ── Active sprints summary ──────────────────────────────────────
  // Same subtask exclusion as myTasks above: a sprint's progress bar
  // should reflect top-level work, not double-count once the table's
  // include_subtasks fetch has loaded children into ALL_TASKS.
  const sprintsSummary = React.useMemo(() => {
    const sprints = typeof SPRINTS !== "undefined" && Array.isArray(SPRINTS) ? SPRINTS : [];
    const all = (typeof ALL_TASKS !== "undefined" && Array.isArray(ALL_TASKS)) ? ALL_TASKS : [];
    return sprints.filter(s => s.active).slice(0, 3).map(s => {
      const tasks = all.filter(t => t.sprint === s.id && !t.parentTaskId);
      const done = tasks.filter(t => t.status === "done").length;
      const project = (typeof PROJECTS !== "undefined")
        ? PROJECTS.find(p => p.id === s.project_id)
        : null;
      return {
        id: s.id, label: s.label, dates: s.dates,
        project_id: s.project_id, projectName: project && project.name,
        projectColor: project && project.color,
        done, total: tasks.length,
        pct: tasks.length ? Math.round((done / tasks.length) * 100) : 0,
      };
    });
  }, [/* same global-mutation note */ Date.now()]);

  // ── Bugs (small fetch — workspace-shared) ───────────────────────
  const [bugs, setBugs] = React.useState([]);
  React.useEffect(() => {
    if (!(window.api && api.bugs && api.bugs.list)) return;
    api.bugs.list({ status: "open" })
      .then(rows => setBugs((rows || []).slice(0, 4)))
      .catch(() => setBugs([]));
  }, []);

  // ── Support tickets — only if user has support access ───────────
  const [tickets, setTickets] = React.useState([]);
  const canSeeSupport = me && (me.wsRole === "owner" || me.wsRole === "admin"
    || (me.moduleAccess && me.moduleAccess.support === true));
  React.useEffect(() => {
    if (!canSeeSupport) return;
    if (!(window.api && api.support && api.support.listTickets)) return;
    api.support.listTickets({ status: "open" })
      .then(rows => setTickets((rows || []).slice(0, 4)))
      .catch(() => setTickets([]));
  }, [canSeeSupport]);

  // ── Recent projects (most-recently-touched) ────────────────────
  // Counts top-level tasks only — subtasks belong to their parent's
  // count and would otherwise inflate the totals as the user navigates
  // around projects (which triggers the include_subtasks fetch).
  const recentProjects = React.useMemo(() => {
    const projects = typeof PROJECTS !== "undefined" && Array.isArray(PROJECTS) ? PROJECTS : [];
    const all = (typeof ALL_TASKS !== "undefined" && Array.isArray(ALL_TASKS)) ? ALL_TASKS : [];
    const scored = projects.map(p => {
      const tasks = all.filter(t =>
        (t.projectId === p.id || t.project_id === p.id) && !t.parentTaskId
      );
      const open = tasks.filter(t => t.status !== "done").length;
      return { ...p, total: tasks.length, open };
    });
    scored.sort((a, b) => b.total - a.total);
    return scored.slice(0, 6);
  }, []);

  // ── Lead funnel snapshot ────────────────────────────────────────
  const leads = typeof LEADS !== "undefined" && Array.isArray(LEADS) ? LEADS : [];
  const leadStages = React.useMemo(() => {
    const stages = {};
    for (const l of leads) {
      const s = l.stage || "new";
      stages[s] = (stages[s] || 0) + 1;
    }
    const order = ["new", "contacted", "qualified", "demo", "won"];
    return order.map(id => ({ id, count: stages[id] || 0 }));
  }, [leads.length]);

  // ── Render helpers ──────────────────────────────────────────────
  const StatChip = ({ label, value, tone = "slate", onClick }) => (
    <button className={`home-stat home-stat-${tone}`} onClick={onClick}>
      <div className="home-stat-num">{value}</div>
      <div className="home-stat-label">{label}</div>
    </button>
  );

  return (
    <div className="home-root">
      {/* Avatar nudge — only when the user has no profile picture
          and hasn't dismissed it in the last 3 days. */}
      {showAvatarPrompt && (
        <AvatarPromptCard
          user={me}
          onDismiss={() => {
            _dismissAvatarPrompt();
            setShowAvatarPrompt(false);
          }}
        />
      )}

      {/* Hero */}
      <div className="home-hero">
        <div>
          <div className="home-greet">{greet}, {firstName}</div>
          <div className="home-sub">
            {stats.open === 0
              ? "Inbox zero — nothing assigned to you."
              : stats.overdue > 0
                ? `${stats.overdue} task${stats.overdue === 1 ? "" : "s"} overdue · let's clear those first.`
                : stats.dueToday > 0
                  ? `${stats.dueToday} due today · solid morning ahead.`
                  : `${stats.open} open task${stats.open === 1 ? "" : "s"} on your plate.`}
          </div>
        </div>
        <div className="home-stats">
          <StatChip label="Open"     value={stats.open}      tone="slate"  onClick={() => onNavigate && onNavigate("myWork")}/>
          <StatChip label="Overdue"  value={stats.overdue}   tone="danger" onClick={() => onNavigate && onNavigate("myWork")}/>
          <StatChip label="Due today" value={stats.dueToday} tone="warn"   onClick={() => onNavigate && onNavigate("myWork")}/>
          <StatChip label="Unread"   value={stats.mentions}  tone="brand"  onClick={() => window.flowboardNotify && (() => {})}/>
        </div>
      </div>

      {/* Quick actions — "New task" removed per user request. Tasks
          should be created from inside their parent project (where the
          project / epic / sprint context is already set), not from a
          context-free Home button that synthesises a Shift+N keystroke. */}
      <div className="home-actions">
        <button className="btn" onClick={() => onOpenBugReport && onOpenBugReport()}>
          🐞 Report bug
        </button>
        <button className="btn" onClick={() => onNavigate && onNavigate("myWork")}>
          <Icons.Inbox size={13}/> My work
        </button>
        {canSeeSupport && (
          <button className="btn" onClick={() => onNavigate && onNavigate("support")}>
            <Icons.Headset size={13}/> Support
          </button>
        )}
      </div>

      {/* Body — two-column on wide screens */}
      <div className="home-body">
        {/* LEFT — your work */}
        <div className="home-col">
          {/* Today's queue */}
          <section className="home-card">
            <header className="home-card-head">
              <h3>Today's queue</h3>
              <button className="home-link" onClick={() => onNavigate && onNavigate("myWork")}>
                Open My Work →
              </button>
            </header>
            {todayQueue.length === 0 ? (
              <div className="home-empty">All clear. Nothing assigned and active.</div>
            ) : (
              <ul className="home-tasklist">
                {todayQueue.map(t => {
                  const overdue = typeof isOverdueNow === "function" && isOverdueNow(t);
                  const isPersonal = !!t._isPersonal;
                  return (
                    <li key={(isPersonal ? "p:" : "t:") + t.id}
                        className={"home-taskrow"
                          + (overdue ? " is-overdue" : "")
                          + (isPersonal ? " is-personal" : "")}
                        onClick={() => {
                          if (isPersonal) {
                            // Personal tasks live in the Personal /
                            // Notes view — there's no project drawer
                            // for them, so we route the user there.
                            if (onNavigate) onNavigate("notes");
                          } else if (onOpenTask) {
                            onOpenTask(t);
                          }
                        }}>
                      <span className="home-taskrow-dot"
                            style={{ background: isPersonal
                              ? "linear-gradient(135deg, #ff7e5f, #ff5e9c)"
                              : (t.epicColor || t.projectColor || "var(--brand)") }}/>
                      <span className="home-taskrow-name" title={t.name}>
                        {t.name}
                        {(t.recurrenceRuleId || t.isRecurringTemplate) && (
                          <span className="recur-glyph" aria-hidden="true"
                                style={{ marginLeft: 6, verticalAlign: "middle" }}
                                title={t.isRecurringTemplate
                                  ? "Series template"
                                  : "Created by a recurring task series"}>↻</span>
                        )}
                      </span>
                      {isPersonal ? (
                        <span className="home-taskrow-project home-taskrow-personal"
                              title="Private to you — only visible on the Personal page">
                          <span className="home-taskrow-personal-glyph" aria-hidden="true">✦</span>
                          Personal
                        </span>
                      ) : t.projectName && (
                        <span className="home-taskrow-project"
                              style={{ "--proj-color": t.projectColor || "#a3a8b6" }}>
                          {t.projectName}
                        </span>
                      )}
                      <span className={`home-taskrow-due ${overdue ? "is-overdue" : ""}`}>
                        {t.due === "—" ? "no date" : t.due}
                      </span>
                    </li>
                  );
                })}
              </ul>
            )}
          </section>

          {/* Recent activity */}
          <section className="home-card">
            <header className="home-card-head">
              <h3>Recent activity</h3>
            </header>
            {recentActivity.length === 0 ? (
              <div className="home-empty">No activity yet.</div>
            ) : (
              <ul className="home-activitylist">
                {recentActivity.map(n => (
                  <li key={n.id}
                      className={`home-activity ${n.unread ? "is-unread" : ""}`}
                      onClick={() => {
                        if (n.link && window) window.dispatchEvent(new CustomEvent("flowboard:nav", { detail: { link: n.link, source: "home" } }));
                        if (window.flowboardNotify) window.flowboardNotify.markRead(n.id);
                      }}>
                    <span className="home-activity-dot" style={{ background: n.actor_color || "var(--brand)" }}/>
                    <div className="home-activity-body">
                      <div className="home-activity-title">{n.title}</div>
                      <div className="home-activity-meta">
                        {(typeof fmtRelative === "function" ? fmtRelative(n.created_at) : n.created_at) || ""}
                      </div>
                    </div>
                  </li>
                ))}
              </ul>
            )}
          </section>
        </div>

        {/* RIGHT — workspace pulse */}
        <div className="home-col">
          {/* Active sprints */}
          {sprintsSummary.length > 0 && (
            <section className="home-card">
              <header className="home-card-head">
                <h3>Active sprints</h3>
              </header>
              <ul className="home-sprintlist">
                {sprintsSummary.map(s => (
                  <li key={s.id} className="home-sprint"
                      onClick={() => {
                        if (s.project_id && onNavigate) onNavigate("project", { projectId: s.project_id });
                      }}>
                    <div className="home-sprint-head">
                      <span className="home-sprint-label">{s.label}</span>
                      {s.projectName && (
                        <span className="home-sprint-project"
                              style={{ "--proj-color": s.projectColor || "#a3a8b6" }}>
                          {s.projectName}
                        </span>
                      )}
                    </div>
                    <div className="home-sprint-bar">
                      <div className="home-sprint-fill" style={{ width: `${s.pct}%` }}/>
                    </div>
                    <div className="home-sprint-meta">
                      {s.done} of {s.total} done · {s.pct}%
                    </div>
                  </li>
                ))}
              </ul>
            </section>
          )}

          {/* Open bugs */}
          <section className="home-card">
            <header className="home-card-head">
              <h3>🐞 Open bugs</h3>
              <button className="home-link" onClick={() => onNavigate && onNavigate("bugs")}>
                All bugs →
              </button>
            </header>
            {bugs.length === 0 ? (
              <div className="home-empty">No open bugs. Quality is winning.</div>
            ) : (
              <ul className="home-buglist">
                {bugs.map(b => {
                  const sevColor = b.severity === "critical" ? "#e2445c"
                                : b.severity === "high"     ? "#fdab3d"
                                : b.severity === "low"      ? "#579bfc"
                                : "#9aa0ae";
                  return (
                    <li key={b.id} className="home-bug"
                        onClick={() => onNavigate && onNavigate("bugs")}>
                      <span className="home-bug-sev" style={{ background: sevColor + "22", color: sevColor }}>
                        {b.severity}
                      </span>
                      <span className="home-bug-title" title={b.title}>{b.title}</span>
                      <span className="home-bug-meta">
                        {(typeof fmtRelative === "function" ? fmtRelative(b.created_at) : "") || ""}
                      </span>
                    </li>
                  );
                })}
              </ul>
            )}
          </section>

          {/* Support queue (only if user has access) */}
          {canSeeSupport && (
            <section className="home-card">
              <header className="home-card-head">
                <h3>🎧 Support queue</h3>
                <button className="home-link" onClick={() => onNavigate && onNavigate("support")}>
                  All tickets →
                </button>
              </header>
              {tickets.length === 0 ? (
                <div className="home-empty">No open tickets.</div>
              ) : (
                <ul className="home-buglist">
                  {tickets.map(t => (
                    <li key={t.id} className="home-bug"
                        onClick={() => onNavigate && onNavigate("support")}>
                      <span className="home-bug-sev" style={{ background: "rgba(87,155,252,.15)", color: "#1f5db8" }}>
                        {t.priority || "normal"}
                      </span>
                      <span className="home-bug-title" title={t.subject}>{t.subject}</span>
                      <span className="home-bug-meta">
                        {t.customer_name ? t.customer_name.split(" ")[0] : ""}
                      </span>
                    </li>
                  ))}
                </ul>
              )}
            </section>
          )}

          {/* Lead funnel */}
          {leads.length > 0 && (
            <section className="home-card">
              <header className="home-card-head">
                <h3>Lead funnel</h3>
                <button className="home-link" onClick={() => onNavigate && onNavigate("crm")}>
                  Open CRM →
                </button>
              </header>
              <ul className="home-funnel">
                {leadStages.map(s => (
                  <li key={s.id} className="home-funnel-stage">
                    <span className="home-funnel-label">{s.id}</span>
                    <span className="home-funnel-count">{s.count}</span>
                  </li>
                ))}
              </ul>
            </section>
          )}
        </div>
      </div>

      {/* Recent projects grid */}
      {recentProjects.length > 0 && (
        <section className="home-projects">
          <div className="home-projects-head">
            <h3>Your projects</h3>
          </div>
          <div className="home-projects-grid">
            {recentProjects.map(p => (
              <button key={p.id} className="home-project-tile"
                      onClick={() => onNavigate && onNavigate("project", { projectId: p.id })}>
                <span className="home-project-stripe" style={{ background: p.color || "var(--brand)" }}/>
                <div className="home-project-body">
                  <div className="home-project-name">{p.name}</div>
                  <div className="home-project-meta">
                    {p.open} open · {p.total} total
                  </div>
                </div>
              </button>
            ))}
          </div>
        </section>
      )}
    </div>
  );
}

Object.assign(window, { HomeView });
