// ==========================================
// Dashboard (real-time summary) — modern
// ==========================================

function DashboardPage({ state, setState, onNav }) {
  const stock = useMemo(() => computeStock(state), [state]);
  const [now, setNow] = useState(Date.now());
  const [projFilter, setProjFilter] = useState("all"); // "all" or projectId
  const [showAddProj, setShowAddProj] = useState(false);
  const toast = useToast();

  useEffect(() => {
    const t = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(t);
  }, []);

  // qty per material respecting the project filter
  const qtyOf = (mId) =>
    projFilter === "all"
      ? materialTotal(stock, mId)
      : (stock[mId]?.[projFilter] || 0);

  // Filter transactions according to project filter
  const txnsAll = state.transactions;
  const txns = projFilter === "all" ? txnsAll : txnsAll.filter((t) =>
    t.type === "transfer"
      ? t.fromProjectId === projFilter || t.toProjectId === projFilter
      : t.projectId === projFilter
  );

  // Totals per category (respecting filter)
  const catTotals = state.categories.map((c) => {
    const items = state.materials.filter((m) => m.category === c.id);
    const total = items.reduce((acc, m) => acc + qtyOf(m.id), 0);
    const low = items.filter((m) => qtyOf(m.id) < m.min).length;
    return { ...c, total, low, count: items.length };
  });

  // Low stock items (respecting filter)
  const lowStock = state.materials
    .map((m) => ({ m, qty: qtyOf(m.id) }))
    .filter((x) => x.qty < x.m.min)
    .sort((a, b) => a.qty / Math.max(a.m.min, 1) - b.qty / Math.max(b.m.min, 1));

  // Transactions today / week
  const startToday = new Date(); startToday.setHours(0, 0, 0, 0);
  const sevenAgo = Date.now() - 7 * 86400000;
  const fourteenAgo = Date.now() - 14 * 86400000;
  const todayTxn = txns.filter((t) => new Date(t.date) >= startToday);
  const weekTxn = txns.filter((t) => new Date(t.date).getTime() >= sevenAgo);
  const prevWeekTxn = txns.filter((t) => {
    const tt = new Date(t.date).getTime();
    return tt >= fourteenAgo && tt < sevenAgo;
  });

  const counts = {
    receive: weekTxn.filter((t) => t.type === "receive").length,
    issue: weekTxn.filter((t) => t.type === "issue").length,
    transfer: weekTxn.filter((t) => t.type === "transfer").length,
  };

  function trendPct(curr, prev) {
    if (prev === 0) return curr === 0 ? 0 : 100;
    return Math.round(((curr - prev) / prev) * 100);
  }
  const txnTrend = trendPct(weekTxn.length, prevWeekTxn.length);

  // Last 14 days movement data for area chart + sparkline
  const buildDays = (n) => {
    const arr = [];
    for (let i = n - 1; i >= 0; i--) {
      const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - i);
      const end = d.getTime() + 86400000;
      const slice = txns.filter((t) => {
        const tt = new Date(t.date).getTime();
        return tt >= d.getTime() && tt < end;
      });
      arr.push({
        date: d,
        label: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส"][d.getDay()],
        receive: slice.filter((t) => t.type === "receive").length,
        issue: slice.filter((t) => t.type === "issue").length,
        transfer: slice.filter((t) => t.type === "transfer").length,
        total: slice.length,
      });
    }
    return arr;
  };
  const days14 = buildDays(14);
  const days7 = days14.slice(-7);

  // Recent activity
  const recent = [...txns].sort((a, b) => new Date(b.date) - new Date(a.date)).slice(0, 8);
  const matMap = Object.fromEntries(state.materials.map((m) => [m.id, m]));
  const projMap = Object.fromEntries(state.projects.map((p) => [p.id, p]));
  const catMap = Object.fromEntries(state.categories.map((c) => [c.id, c]));

  const liveClock = new Date(now);
  const tStr = liveClock.toLocaleTimeString("th-TH", { hour: "2-digit", minute: "2-digit", second: "2-digit" });
  const dStr = liveClock.toLocaleDateString("th-TH", { weekday: "long", day: "numeric", month: "long", year: "numeric" });

  // Stock total (respecting filter)
  const totalStock = state.materials.reduce((a, m) => a + qtyOf(m.id), 0);

  const selectedProject = projFilter === "all" ? null : state.projects.find((p) => p.id === projFilter);

  function addProject(form) {
    const id = genId("P");
    setState({ ...state, projects: [...state.projects, { ...form, id }] });
    setProjFilter(id);
    setShowAddProj(false);
    toast("เพิ่มโครงการเรียบร้อย");
  }

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1>Dashboard {selectedProject && <span style={{ color: "var(--accent)" }}>· {selectedProject.code}</span>}</h1>
          <p className="muted">{dStr} · เวลา {tStr}{selectedProject && <> · กำลังดู <b>{selectedProject.name}</b></>}</p>
        </div>
        <div className="live-pill"><span className="live-dot" /> REAL-TIME</div>
      </div>

      {/* ===== Project Selector ===== */}
      <ProjectSelector
        projects={state.projects}
        stock={stock}
        materials={state.materials}
        value={projFilter}
        onChange={setProjFilter}
        onAdd={() => setShowAddProj(true)}
      />

      <div className="stat-grid">
        <StatCardModern
          label="โครงการที่ใช้งาน"
          value={fmtNum(state.projects.filter((p) => p.status === "active").length)}
          sub={`ทั้งหมด ${state.projects.length} โครงการ`}
          accent="#3b82f6"
          icon="🏢"
          spark={state.projects.map((_, i) => 3 + (i % 4))}
        />
        <StatCardModern
          label="วัสดุในระบบ"
          value={fmtNum(state.materials.length)}
          sub={`${state.categories.length} หมวดงาน · รวม ${fmtNum(totalStock)} หน่วย`}
          accent="#0f1e36"
          icon="📦"
          spark={state.categories.map((c) => state.materials.filter((m) => m.category === c.id).length)}
        />
        <StatCardModern
          label="ธุรกรรมสัปดาห์นี้"
          value={fmtNum(weekTxn.length)}
          sub={`วันนี้ ${todayTxn.length} รายการ`}
          accent="#8b5cf6"
          icon="⚡"
          spark={days14.map((d) => d.total)}
          trend={txnTrend}
        />
        <StatCardModern
          label="วัสดุต่ำกว่ากำหนด"
          value={fmtNum(lowStock.length)}
          sub={lowStock.length > 0 ? "ควรจัดซื้อเพิ่ม" : "อยู่ในเกณฑ์ดี ✓"}
          accent={lowStock.length > 0 ? "#ef4444" : "#10b981"}
          icon={lowStock.length > 0 ? "⚠️" : "✓"}
          spark={state.materials.slice(0, 14).map((m) => Math.max(0, m.min - materialTotal(stock, m.id)))}
        />
      </div>

      {/* ROW: chart + donut */}
      <div className="grid-3">
        <div className="card">
          <div className="card-head">
            <div>
              <h3>การเคลื่อนไหววัสดุ</h3>
              <div className="muted small" style={{ marginTop: 2 }}>14 วันล่าสุด · จำนวนธุรกรรมต่อวัน</div>
            </div>
            <div className="legend">
              <span><i style={{ background: "#10b981" }} />รับเข้า</span>
              <span><i style={{ background: "#ef4444" }} />เบิกจ่าย</span>
              <span><i style={{ background: "#8b5cf6" }} />โอนย้าย</span>
            </div>
          </div>
          <AreaChart days={days14} />
          <div className="kpi-row">
            <div className="kpi"><div className="kpi-label">รับเข้า · 7 วัน</div><div className="kpi-val" style={{ color: "#10b981" }}>{counts.receive}</div></div>
            <div className="kpi"><div className="kpi-label">เบิกจ่าย · 7 วัน</div><div className="kpi-val" style={{ color: "#ef4444" }}>{counts.issue}</div></div>
            <div className="kpi"><div className="kpi-label">โอนย้าย · 7 วัน</div><div className="kpi-val" style={{ color: "#8b5cf6" }}>{counts.transfer}</div></div>
          </div>
        </div>

        <div className="card">
          <div className="card-head">
            <h3>สัดส่วนตามหมวด</h3>
          </div>
          <DonutModern slices={catTotals.map((c) => ({ v: c.total, color: c.color, label: c.name }))} centerLabel="คงเหลือ" />
          <div style={{ marginTop: 14 }}>
            {catTotals.map((c) => (
              <div key={c.id} className="legend-row">
                <span className="legend-dot" style={{ background: c.color }} />
                <span style={{ flex: 1 }}>{c.name}</span>
                <b>{fmtNum(c.total)}</b>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card-head">
            <h3>{selectedProject ? "วัสดุแยกหมวด · " + selectedProject.code : "ภาพรวมหน่วยงาน"}</h3>
          </div>
          {selectedProject
            ? <CategoryBars catTotals={catTotals} />
            : <ProjectBars state={state} stock={stock} selectedId={projFilter} onSelect={setProjFilter} />
          }
        </div>
      </div>

      {/* ROW: category tiles */}
      <div className="card">
        <div className="card-head">
          <h3>สรุปตามหมวดงาน</h3>
          <button className="link" onClick={() => onNav("stock")}>ดูคลังทั้งหมด →</button>
        </div>
        <div className="cat-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))" }}>
          {catTotals.map((c) => (
            <div key={c.id} className="cat-tile" style={{ "--cat-color": c.color }}>
              <div className="cat-tile-head">
                <div className="cat-tile-icon" style={{ background: c.color + "1f", color: c.color }}>{c.icon}</div>
                <div>
                  <div className="cat-tile-name">{c.name}</div>
                  <div className="cat-tile-sub">{c.count} รายการวัสดุ</div>
                </div>
              </div>
              <div className="cat-tile-num" style={{ color: c.color }}>{fmtNum(c.total)}</div>
              <div className="cat-tile-unit">หน่วยรวมในคลัง</div>
              {c.low > 0 && <div className="warn-pill">⚠ ต่ำกว่ากำหนด {c.low} รายการ</div>}
            </div>
          ))}
        </div>
      </div>

      {/* ROW: low stock + activity */}
      <div className="grid-2">
        <div className="card">
          <div className="card-head">
            <h3>⚠ วัสดุที่ต้องเติม</h3>
            <span className="muted small">{lowStock.length} รายการ</span>
          </div>
          {lowStock.length === 0 ? <Empty text="ทุกรายการมีสต๊อกเพียงพอ ✓" /> : (
            <div className="lowstock-list">
              {lowStock.slice(0, 6).map(({ m, qty }) => {
                const c = catMap[m.category];
                const pct = Math.max(2, Math.min(100, (qty / m.min) * 100));
                return (
                  <div key={m.id} className="lowstock-row">
                    <div className="lowstock-info">
                      <CatBadge cat={c} />
                      <div className="lowstock-name">{m.name}</div>
                    </div>
                    <div className="lowstock-bar">
                      <div className="lowstock-bar-fill" style={{ width: pct + "%", background: pct < 50 ? "linear-gradient(90deg, #ef4444, #f87171)" : "linear-gradient(90deg, #f59e0b, #fbbf24)" }} />
                    </div>
                    <div className="lowstock-num">
                      <b style={{ color: pct < 50 ? "#ef4444" : "#92400e" }}>{fmtNum(qty)}</b>
                      <span className="muted"> / {fmtNum(m.min)} {m.unit}</span>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        <div className="card">
          <div className="card-head">
            <h3>ความเคลื่อนไหวล่าสุด</h3>
            <button className="link" onClick={() => onNav("reports")}>รายงานทั้งหมด →</button>
          </div>
          <div className="activity-list">
            {recent.map((t) => {
              const m = matMap[t.materialId];
              const cat = m ? catMap[m.category] : null;
              const kind = t.type === "receive" ? { label: "รับเข้า", color: "#10b981", bg: "#d1fae5", sign: "+" }
                : t.type === "issue" ? { label: "เบิกจ่าย", color: "#ef4444", bg: "#fee2e2", sign: "−" }
                : { label: "โอนย้าย", color: "#8b5cf6", bg: "#ede9fe", sign: "↔" };
              return (
                <div key={t.id} className="activity-row">
                  <div className="activity-kind" style={{ background: kind.bg, color: kind.color }}>{kind.sign}</div>
                  <div className="activity-mid">
                    <div className="activity-title">
                      <span>{m?.name || "—"}</span>
                      {cat && <CatBadge cat={cat} />}
                    </div>
                    <div className="activity-sub">
                      {kind.label}{" "}
                      {t.type === "transfer"
                        ? <>· {projMap[t.fromProjectId]?.code} → {projMap[t.toProjectId]?.code}</>
                        : <>· {projMap[t.projectId]?.name}</>
                      }
                    </div>
                  </div>
                  <div className="activity-right">
                    <div style={{ fontWeight: 700, color: kind.color }}>{kind.sign}{fmtNum(t.qty)} <span className="muted" style={{ fontWeight: 400, fontSize: 11 }}>{m?.unit}</span></div>
                    <div className="muted small">{fmtDate(t.date)}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      <Modal open={showAddProj} onClose={() => setShowAddProj(false)} title="เพิ่มโครงการใหม่" width={520}>
        <ProjectForm initial={null} onCancel={() => setShowAddProj(false)} onSubmit={addProject} />
      </Modal>
    </div>
  );
}

// =========== Project Selector ===========
function ProjectSelector({ projects, stock, materials, value, onChange, onAdd }) {
  const scrollRef = useRef(null);
  const [canL, setCanL] = useState(false);
  const [canR, setCanR] = useState(false);

  const updateScrollState = () => {
    const el = scrollRef.current;
    if (!el) return;
    setCanL(el.scrollLeft > 4);
    setCanR(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
  };

  useEffect(() => {
    updateScrollState();
    const el = scrollRef.current;
    if (!el) return;
    el.addEventListener("scroll", updateScrollState);
    window.addEventListener("resize", updateScrollState);
    return () => {
      el.removeEventListener("scroll", updateScrollState);
      window.removeEventListener("resize", updateScrollState);
    };
  }, [projects.length]);

  const scrollBy = (dir) => {
    const el = scrollRef.current;
    if (!el) return;
    el.scrollBy({ left: dir * (el.clientWidth * 0.7), behavior: "smooth" });
  };

  return (
    <div className="proj-selector">
      <div className="proj-selector-head">
        <div className="proj-selector-label">หน่วยงาน / โครงการ</div>
        <div className="proj-selector-controls">
          <button className="proj-scroll-btn" onClick={() => scrollBy(-1)} disabled={!canL} aria-label="เลื่อนซ้าย">‹</button>
          <button className="proj-scroll-btn" onClick={() => scrollBy(1)} disabled={!canR} aria-label="เลื่อนขวา">›</button>
        </div>
      </div>
      <div className="proj-selector-wrap">
        {canL && <div className="proj-fade proj-fade-l" />}
        {canR && <div className="proj-fade proj-fade-r" />}
        <div className="proj-selector-list" ref={scrollRef}>
          <button
            className={`proj-chip ${value === "all" ? "active" : ""}`}
            onClick={() => onChange("all")}
          >
            <span className="proj-chip-icon">🌐</span>
            <span className="proj-chip-body">
              <span className="proj-chip-code">ทั้งหมด</span>
              <span className="proj-chip-name">ทุกโครงการ</span>
            </span>
          </button>
          {projects.map((p) => {
            const total = materials.reduce((a, m) => a + (stock[m.id]?.[p.id] || 0), 0);
            const items = materials.filter((m) => (stock[m.id]?.[p.id] || 0) > 0).length;
            return (
              <button
                key={p.id}
                className={`proj-chip ${value === p.id ? "active" : ""}`}
                onClick={() => onChange(p.id)}
                title={p.name}
              >
                <span className="proj-chip-icon" style={{ background: p.status === "active" ? "#10b98122" : "#88888822", color: p.status === "active" ? "#10b981" : "#888" }}>
                  {p.code.slice(0, 2)}
                </span>
                <span className="proj-chip-body">
                  <span className="proj-chip-code">{p.code}</span>
                  <span className="proj-chip-name">{p.name}</span>
                  <span className="proj-chip-stat">{fmtNum(items)} รายการ · {fmtNum(total)} หน่วย</span>
                </span>
              </button>
            );
          })}
          {onAdd && (
            <button className="proj-chip proj-chip-add" onClick={onAdd}>
              <span className="proj-chip-icon" style={{ background: "var(--accent)22", color: "var(--accent-2)" }}>+</span>
              <span className="proj-chip-body">
                <span className="proj-chip-code">เพิ่มใหม่</span>
                <span className="proj-chip-name">เพิ่มโครงการ</span>
              </span>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

// =========== Modern stat card with sparkline ===========
function StatCardModern({ label, value, sub, accent, icon, spark, trend }) {
  return (
    <div className="stat-card">
      <div className="stat-head">
        <div className="stat-label">{label}</div>
        <div className="stat-icon" style={{ background: accent + "1a", color: accent }}>{icon}</div>
      </div>
      <div className="stat-value" style={{ color: accent }}>{value}</div>
      <div className="stat-sub">
        {trend !== undefined && (
          <span className={`stat-trend ${trend > 0 ? "up" : trend < 0 ? "down" : "flat"}`}>
            {trend > 0 ? "↑" : trend < 0 ? "↓" : "→"} {Math.abs(trend)}%
          </span>
        )}
        <span>{sub}</span>
      </div>
      {spark && spark.length > 1 && <Sparkline data={spark} color={accent} />}
    </div>
  );
}

function Sparkline({ data, color }) {
  const w = 280, h = 60;
  const max = Math.max(1, ...data);
  const min = 0;
  const step = w / (data.length - 1);
  const pts = data.map((d, i) => {
    const x = i * step;
    const y = h - ((d - min) / (max - min || 1)) * h;
    return [x, y];
  });
  const line = pts.map((p, i) => (i === 0 ? `M ${p[0]} ${p[1]}` : `L ${p[0]} ${p[1]}`)).join(" ");
  const area = line + ` L ${w} ${h} L 0 ${h} Z`;
  const gid = "sp-" + color.replace("#", "");
  return (
    <svg viewBox={`0 0 ${w} ${h}`} className="stat-spark" preserveAspectRatio="none">
      <defs>
        <linearGradient id={gid} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.5" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#${gid})`} />
      <path d={line} fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// =========== Area chart for movement ===========
function AreaChart({ days }) {
  const W = 560, H = 220, padL = 32, padR = 12, padT = 14, padB = 28;
  const iw = W - padL - padR;
  const ih = H - padT - padB;
  const max = Math.max(3, ...days.flatMap((d) => [d.receive, d.issue, d.transfer]));
  const step = iw / Math.max(1, days.length - 1);

  const series = [
    { key: "receive", color: "#10b981", id: "g-rc" },
    { key: "issue", color: "#ef4444", id: "g-is" },
    { key: "transfer", color: "#8b5cf6", id: "g-tr" },
  ];

  function pathFor(key) {
    const pts = days.map((d, i) => [padL + i * step, padT + ih - (d[key] / max) * ih]);
    const line = pts.map((p, i) => (i === 0 ? `M ${p[0]} ${p[1]}` : `L ${p[0]} ${p[1]}`)).join(" ");
    const area = line + ` L ${padL + iw} ${padT + ih} L ${padL} ${padT + ih} Z`;
    return { line, area };
  }

  return (
    <svg viewBox={`0 0 ${W} ${H}`} className="chart-area">
      <defs>
        {series.map((s) => (
          <linearGradient key={s.id} id={s.id} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor={s.color} stopOpacity="0.32" />
            <stop offset="100%" stopColor={s.color} stopOpacity="0" />
          </linearGradient>
        ))}
      </defs>
      {/* Grid */}
      {[0.25, 0.5, 0.75, 1].map((g, i) => (
        <g key={i}>
          <line x1={padL} x2={W - padR} y1={padT + ih * (1 - g)} y2={padT + ih * (1 - g)} stroke="#eef0f6" />
          <text x={padL - 6} y={padT + ih * (1 - g) + 3} textAnchor="end" fontSize="9" fill="#8e96a8">{Math.round(max * g)}</text>
        </g>
      ))}
      {/* Areas */}
      {series.map((s) => {
        const { line, area } = pathFor(s.key);
        return (
          <g key={s.id}>
            <path d={area} fill={`url(#${s.id})`} />
            <path d={line} fill="none" stroke={s.color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
            {days.map((d, i) => (
              <circle key={i} cx={padL + i * step} cy={padT + ih - (d[s.key] / max) * ih} r="2.5" fill="#fff" stroke={s.color} strokeWidth="1.5" />
            ))}
          </g>
        );
      })}
      {/* X axis labels */}
      {days.map((d, i) => {
        if (i % 2 === 0 || i === days.length - 1) {
          return <text key={i} x={padL + i * step} y={H - 8} textAnchor="middle" fontSize="9" fill="#8e96a8">{d.date.getDate()}/{d.date.getMonth() + 1}</text>;
        }
        return null;
      })}
    </svg>
  );
}

// =========== Modern Donut ===========
function DonutModern({ slices, size = 200, thickness = 26, centerLabel }) {
  const total = slices.reduce((a, b) => a + b.v, 0) || 1;
  let acc = 0;
  const r = (size - thickness) / 2;
  const c = 2 * Math.PI * r;
  return (
    <div style={{ display: "grid", placeItems: "center" }}>
      <svg viewBox={`0 0 ${size} ${size}`} style={{ width: size, height: size }}>
        <g transform={`translate(${size / 2} ${size / 2}) rotate(-90)`}>
          <circle r={r} fill="none" stroke="#f5f6fa" strokeWidth={thickness} />
          {slices.map((s, i) => {
            const len = (s.v / total) * c;
            const dash = `${len} ${c - len}`;
            const offset = -acc;
            acc += len;
            return <circle key={i} r={r} fill="none" stroke={s.color} strokeWidth={thickness} strokeDasharray={dash} strokeDashoffset={offset} strokeLinecap="butt" />;
          })}
        </g>
        <text x={size / 2} y={size / 2 - 4} textAnchor="middle" fontSize="28" fontWeight="800" fill="#0f1729" letterSpacing="-1">{fmtNum(total)}</text>
        <text x={size / 2} y={size / 2 + 16} textAnchor="middle" fontSize="11" fill="#8e96a8">{centerLabel}</text>
      </svg>
    </div>
  );
}

// =========== Project horizontal bars ===========
function ProjectBars({ state, stock, selectedId, onSelect }) {
  const data = state.projects.map((p) => {
    const total = state.materials.reduce((a, m) => a + (stock[m.id]?.[p.id] || 0), 0);
    return { p, total };
  });
  const max = Math.max(1, ...data.map((d) => d.total));
  const colors = ["#3b82f6", "#10b981", "#f59e0b", "#8b5cf6", "#ef4444", "#06b6d4"];
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      {data.map(({ p, total }, i) => {
        const pct = (total / max) * 100;
        const color = colors[i % colors.length];
        const isSel = selectedId === p.id;
        return (
          <button
            key={p.id}
            onClick={() => onSelect && onSelect(isSel ? "all" : p.id)}
            style={{
              background: isSel ? "var(--bg-2)" : "transparent",
              border: "none", padding: "8px 10px", borderRadius: 10,
              cursor: onSelect ? "pointer" : "default", textAlign: "left",
              boxShadow: isSel ? "inset 0 0 0 1px " + color + "66" : "none",
              transition: "background 0.15s",
            }}
          >
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 5 }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>{p.name}</div>
              <div style={{ fontSize: 13, fontWeight: 700, color }}>{fmtNum(total)}</div>
            </div>
            <div style={{ height: 8, background: "var(--bg-2)", borderRadius: 4, overflow: "hidden" }}>
              <div style={{ width: pct + "%", height: "100%", background: `linear-gradient(90deg, ${color}, ${color}cc)`, borderRadius: 4, transition: "width 0.6s" }} />
            </div>
            <div className="muted small" style={{ marginTop: 4 }}>{p.code} · {p.manager || "—"}</div>
          </button>
        );
      })}
    </div>
  );
}

// =========== Category horizontal bars (used when filtering a single project) ===========
function CategoryBars({ catTotals }) {
  const max = Math.max(1, ...catTotals.map((c) => c.total));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      {catTotals.map((c) => {
        const pct = (c.total / max) * 100;
        return (
          <div key={c.id}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 5 }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>{c.icon} {c.name}</div>
              <div style={{ fontSize: 13, fontWeight: 700, color: c.color }}>{fmtNum(c.total)}</div>
            </div>
            <div style={{ height: 8, background: "var(--bg-2)", borderRadius: 4, overflow: "hidden" }}>
              <div style={{ width: pct + "%", height: "100%", background: `linear-gradient(90deg, ${c.color}, ${c.color}cc)`, borderRadius: 4, transition: "width 0.6s" }} />
            </div>
            <div className="muted small" style={{ marginTop: 4 }}>{c.count} รายการ {c.low > 0 && <span style={{ color: "#ef4444" }}>· ⚠ ต่ำ {c.low}</span>}</div>
          </div>
        );
      })}
    </div>
  );
}

window.DashboardPage = DashboardPage;
window.ProjectSelector = ProjectSelector;
