/* ========================================================================
   pages-1.jsx — Dashboard, SIM Management (index/show/edit), Alerts, CO2
   ======================================================================== */
const { useState: u1, useMemo: m1, useEffect: e1 } = React;
const D = window.MILO_DATA;

/* =====================================================================
   Currency helper
   ===================================================================== */
const gbp = (n) => "£" + Number(n).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");

/* =====================================================================
   Line chart (used on Overview + Environmental Impact)
   - viewBox renders at design resolution (1200×340) and scales uniformly
   - smooth cubic curve, area fill, all month labels, callout on latest value
   ===================================================================== */
const CHART_MONTHS = ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun"];

function LineChart({ data, color = "#256751", ySuffix = "" }) {
  const w = 1200;
  const h = 340;
  const pad = { t: 36, r: 40, b: 40, l: 60 };
  const innerW = w - pad.l - pad.r;
  const innerH = h - pad.t - pad.b;
  const rawMax = Math.max(...data, 1);
  const max = Math.ceil(rawMax * 1.15 / 5) * 5;
  const min = 0;
  const stepX = innerW / (data.length - 1);
  const pts = data.map((v, i) => [
  pad.l + i * stepX,
  pad.t + (1 - (v - min) / (max - min)) * innerH]
  );
  const [hover, setHover] = u1(null);

  const pathFor = (close = false) => {
    let d = `M${pts[0][0].toFixed(1)},${pts[0][1].toFixed(1)}`;
    for (let i = 1; i < pts.length; i++) {
      const cp1x = pts[i - 1][0] + stepX * 0.4;
      const cp1y = pts[i - 1][1];
      const cp2x = pts[i][0] - stepX * 0.4;
      const cp2y = pts[i][1];
      d += ` C${cp1x.toFixed(1)},${cp1y.toFixed(1)} ${cp2x.toFixed(1)},${cp2y.toFixed(1)} ${pts[i][0].toFixed(1)},${pts[i][1].toFixed(1)}`;
    }
    if (close) {
      d += ` L${pts[pts.length - 1][0].toFixed(1)},${(h - pad.b).toFixed(1)} L${pts[0][0].toFixed(1)},${(h - pad.b).toFixed(1)} Z`;
    }
    return d;
  };
  const linePath = pathFor(false);
  const areaPath = pathFor(true);

  const yTicks = [0, 0.25, 0.5, 0.75, 1].map((t) => ({
    y: pad.t + t * innerH,
    v: Math.round((max - min) * (1 - t) + min)
  }));
  const labels = CHART_MONTHS;
  const lastIdx = pts.length - 1;
  const activeIdx = hover !== null ? hover : lastIdx;
  const activePt = pts[activeIdx];
  const activeVal = data[activeIdx];
  const calloutY = Math.max(activePt[1] - 56, 26);
  const calloutText = activeVal.toFixed(1) + ySuffix;
  const calloutW = Math.max(76, calloutText.length * 8 + 24);

  return (
    <div className="mp-chart">
      <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="xMidYMid meet" style={{ width: "100%", height: "auto", display: "block" }}
        onMouseLeave={() => setHover(null)}>
        <defs>
          <linearGradient id="lc-grad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.22" />
            <stop offset="100%" stopColor={color} stopOpacity="0" />
          </linearGradient>
        </defs>

        {yTicks.map((t, i) =>
        <g key={i}>
            <line className="mp-chart-grid" x1={pad.l} x2={w - pad.r} y1={t.y} y2={t.y} />
            <text className="mp-chart-y-label" x={pad.l - 14} y={t.y + 5} textAnchor="end">
              {t.v}{ySuffix}
            </text>
          </g>
        )}

        <path d={areaPath} fill="url(#lc-grad)" />
        <path d={linePath} fill="none" stroke={color} strokeWidth="3" strokeLinejoin="round" strokeLinecap="round" />

        {/* Hover vertical guide line */}
        {hover !== null ? <line x1={activePt[0]} x2={activePt[0]} y1={pad.t} y2={h - pad.b}
          stroke={color} strokeWidth="1.5" strokeDasharray="4,4" opacity="0.4" /> : null}

        {/* Dots */}
        {pts.map((p, i) =>
        i !== activeIdx ?
        <circle key={i} cx={p[0]} cy={p[1]} r="5" fill="#fff" stroke={color} strokeWidth="2.5"
          style={{ opacity: hover !== null ? 0.5 : 1, transition: "opacity 150ms" }} /> :
        null
        )}

        {/* Active point highlight */}
        <circle cx={activePt[0]} cy={activePt[1]} r="16" fill={color} fillOpacity="0.16" />
        <circle cx={activePt[0]} cy={activePt[1]} r="7" fill={color} stroke="#fff" strokeWidth="3" />

        {/* Callout pill */}
        <g transform={`translate(${activePt[0]}, ${calloutY})`}>
          <rect x={-calloutW / 2} y="-16" width={calloutW} height="32" rx="8" fill="#1e4136" />
          <polygon points={`-6,16 6,16 0,24`} fill="#1e4136" />
          <text x="0" y="5" textAnchor="middle" style={{ fontSize: 14, fill: "#fff", fontWeight: 700, fontFamily: "var(--font-sans)" }}>
            {calloutText}
          </text>
        </g>

        {/* X labels */}
        {pts.map((p, i) =>
        <text key={"x" + i} className="mp-chart-x-label" x={p[0]} y={h - 14} textAnchor="middle"
          style={{ fontWeight: i === activeIdx ? 700 : 500 }}>
            {labels[i]}
          </text>
        )}

        {/* Invisible hit areas for hover */}
        {pts.map((p, i) =>
        <rect key={"hit" + i} x={p[0] - stepX / 2} y={pad.t} width={stepX} height={innerH + pad.b}
          fill="transparent" style={{ cursor: "pointer" }}
          onMouseEnter={() => setHover(i)} />
        )}
      </svg>
    </div>);

}

/* =====================================================================
   Donut chart (CO2 breakdown)
   ===================================================================== */
function DonutChart({ data, total }) {
  const size = 220,r = 90,sr = 60,cx = size / 2,cy = size / 2;
  const sum = data.reduce((a, b) => a + b.value, 0);
  const [hover, setHover] = u1(null);
  let angle = -Math.PI / 2;
  const arcs = data.map((d, idx) => {
    const a = d.value / sum * Math.PI * 2;
    const x1 = cx + Math.cos(angle) * r,y1 = cy + Math.sin(angle) * r;
    const x2 = cx + Math.cos(angle + a) * r,y2 = cy + Math.sin(angle + a) * r;
    const xi1 = cx + Math.cos(angle + a) * sr,yi1 = cy + Math.sin(angle + a) * sr;
    const xi2 = cx + Math.cos(angle) * sr,yi2 = cy + Math.sin(angle) * sr;
    const large = a > Math.PI ? 1 : 0;
    const mid = angle + a / 2;
    const path = `M${x1},${y1} A${r},${r} 0 ${large},1 ${x2},${y2} L${xi1},${yi1} A${sr},${sr} 0 ${large},0 ${xi2},${yi2} Z`;
    angle += a;
    return { d, path, mid, idx };
  });
  const hd = hover !== null ? data[hover] : null;
  return (
    <div style={{ display: "flex", gap: 24, alignItems: "center", flexWrap: "wrap" }}>
      <svg viewBox={`0 0 ${size} ${size}`} style={{ width: size, height: size }}>
        {arcs.map((a) => <path key={a.idx} d={a.path} fill={a.d.color}
          style={{ opacity: hover !== null && hover !== a.idx ? 0.35 : 1, transition: "opacity 150ms", cursor: "pointer" }}
          onMouseEnter={() => setHover(a.idx)} onMouseLeave={() => setHover(null)} />)}
        {hover === null ? <>
          <text x={cx} y={cy - 6} textAnchor="middle" style={{ fontSize: 13, fill: "var(--fg-3)", fontWeight: 600, pointerEvents: "none" }}>Total</text>
          <text x={cx} y={cy + 16} textAnchor="middle" style={{ fontSize: 22, fill: "var(--fg-1)", fontWeight: 800, letterSpacing: "-0.01em", pointerEvents: "none" }}>{total.toFixed(1)}</text>
          <text x={cx} y={cy + 32} textAnchor="middle" style={{ fontSize: 12, fill: "var(--fg-3)", fontWeight: 600, pointerEvents: "none" }}>kg CO₂e</text>
        </> : <>
          <text x={cx} y={cy - 4} textAnchor="middle" style={{ fontSize: 11, fill: "var(--fg-3)", fontWeight: 600, pointerEvents: "none" }}>{hd.label}</text>
          <text x={cx} y={cy + 16} textAnchor="middle" style={{ fontSize: 20, fill: "var(--fg-1)", fontWeight: 800, pointerEvents: "none" }}>{hd.value.toFixed(2)}</text>
          <text x={cx} y={cy + 30} textAnchor="middle" style={{ fontSize: 11, fill: "var(--fg-3)", fontWeight: 600, pointerEvents: "none" }}>{(hd.value / sum * 100).toFixed(0)}% · kg CO₂e</text>
        </>}
      </svg>
      <div className="mp-legend" style={{ flexDirection: "column", gap: 10 }}>
        {data.map((d, i) =>
        <div key={d.label} className="mp-legend-item" style={{ opacity: hover !== null && hover !== i ? 0.4 : 1, transition: "opacity 150ms", cursor: "pointer" }}
          onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}>
            <span className="mp-legend-dot" style={{ background: d.color }}></span>
            <span style={{ flex: 1 }}>{d.label}</span>
            <span style={{ fontWeight: 700, marginLeft: 16 }}>{d.value.toFixed(2)} kg</span>
          </div>
        )}
      </div>
    </div>);

}

/* =====================================================================
   Stat card variants — picked via the "Stat card style" Tweak.
   Used on the Overview page to compare visual treatments.
   ===================================================================== */

/* SUBTLE: flat inline icon next to label, no fill, lighter touch */
function StatCardSubtle({ label, value, valueSuffix, hint, icon }) {
  const isZero = window.isZeroValue && window.isZeroValue(value);
  return (
    <div className="mp-stat mp-stat--subtle" style={{ fontWeight: "500" }}>
      <div className="mp-stat-sub-head">
        {icon ? <Icon name={icon} size={14} /> : null}
        <span>{label}</span>
      </div>
      <div className={"mp-stat-value" + (isZero ? " mp-stat-value--zero" : "")} style={{ fontWeight: "500" }}>
        {value}{valueSuffix ? <span className="mp-stat-suffix">{valueSuffix}</span> : null}
      </div>
      {hint ? <div className="mp-stat-hint">{hint}</div> : null}
    </div>);

}

/* BOLD: large pine-tinted icon at top, accent left edge, gradient corner */
function StatCardBold({ label, value, valueSuffix, hint, icon }) {
  const isZero = window.isZeroValue && window.isZeroValue(value);
  return (
    <div className="mp-stat mp-stat--bold">
      <div className="mp-stat-bold-accent"></div>
      {icon ?
      <div className="mp-stat-bold-icon"><Icon name={icon} size={26} /></div> :
      null}
      <div className={"mp-stat-bold-value" + (isZero ? " mp-stat-value--zero" : "")}>
        {value}{valueSuffix ? <span>{valueSuffix}</span> : null}
      </div>
      <div className="mp-stat-bold-label">{label}</div>
      {hint ? <div className="mp-stat-hint" style={{ marginTop: 6 }}>{hint}</div> : null}
    </div>);

}

/* SAAS: Linear / Stripe inspired — minimal card, label top, value, delta pill */
function StatCardSaas({ label, value, valueSuffix, hint, deltaPct, deltaDir }) {
  const isZero = window.isZeroValue && window.isZeroValue(value);
  return (
    <div className="mp-stat mp-stat--saas">
      <div className="mp-stat-saas-label">{label}</div>
      <div className={"mp-stat-value mp-stat-value--tabular" + (isZero ? " mp-stat-value--zero" : "")}>
        {value}{valueSuffix ? <span className="mp-stat-suffix">{valueSuffix}</span> : null}
      </div>
      {deltaPct !== undefined ?
      <div className={"mp-stat-saas-delta mp-stat-saas-delta--" + (deltaDir || "flat")}>
          <Icon name={deltaDir === "up" ? "trending-up" : deltaDir === "down" ? "trending-down" : "minus"} size={12} />
          <span>{deltaPct >= 0 ? "+" : ""}{deltaPct}%</span>
          <span className="mp-stat-saas-delta-cmp">vs last month</span>
        </div> :
      hint ?
      <div className="mp-stat-hint">{hint}</div> :
      null}
    </div>);

}

/* =====================================================================
   DASHBOARD
   ===================================================================== */
function DashboardPage({ tweaks }) {
  const activeSims = D.SIMS.filter((s) => s.status === "Active" || s.status === "Activated").length;
  const suspendedSims = D.SIMS.filter((s) => s.status === "Suspended" && window.simGroup && window.simGroup(s) === "individual").length;
  const monthlyCost = billedMonthly(D.SIMS);
  const recentAlerts = D.ALERTS.slice(0, 5);
  const style = tweaks && tweaks.stat_card_style || "current";
  const [panelOpen, setPanelOpen] = u1(() => {
    try { return localStorage.getItem("mp-emissions-panel") !== "closed"; } catch (e) { return true; }
  });
  const togglePanel = () => setPanelOpen((o) => {
    try { localStorage.setItem("mp-emissions-panel", o ? "closed" : "open"); } catch (e) {}
    return !o;
  });
  const [emissionsOpen, setEmissionsOpen] = u1(false);
  const emissionRows = D.CO2.trend.map((value, i) => ({
    month: CHART_MONTHS[i],
    value,
    change: i === 0 ? null : (value - D.CO2.trend[i - 1]) / D.CO2.trend[i - 1] * 100
  })).reverse();

  const renderAlert = (a) => {
    const k = D.ALERT_KINDS[a.kind] || { icon: "circle-check", tone: "mist" };
    return (
      <div key={a.id} className={"mp-act mp-act--" + k.tone}>
        <div className="mp-act-ic"><Icon name={k.icon} size={16} /></div>
        <div className="mp-act-body">
          <div className="mp-act-title">{a.title}</div>
          <div className="mp-act-desc">{a.description}</div>
        </div>
        <div className="mp-act-time">{fmtAgo(a.time_ago)}</div>
      </div>);

  };

  // 4 cards — shape varies per style
  const cards = [
  { label: "Total Active SIMs", value: activeSims, icon: "smartphone", iconTone: "mist", deltaPct: 0, deltaDir: "flat", hint: <><span className="up">+0%</span><span>vs last month</span></> },
  { label: "Suspended SIMs", value: suspendedSims, icon: "triangle-alert", iconTone: "clay", hint: suspendedSims > 0 ? <a href="#/sims?status=Suspended" style={{ color: "var(--mp-pine)", fontWeight: 700, textDecoration: "underline" }}>Review suspended SIMs</a> : null },
  { label: "Monthly Spend", value: gbp(monthlyCost), icon: "credit-card", valueSuffix: "/month", deltaPct: 0, deltaDir: "flat", hint: <><span className="up">+0%</span><span>vs last month</span></> }];


  const Card4 = (c) => {
    if (style === "subtle") return <StatCardSubtle key={c.label} {...c} />;
    if (style === "bold") return <StatCardBold key={c.label} {...c} />;
    if (style === "saas") return <StatCardSaas key={c.label} {...c} />;
    return (
      <StatCard key={c.label} label={c.label} icon={c.icon} iconTone={c.iconTone} value={c.value} valueSuffix={c.valueSuffix} hint={c.hint}
      valueColor={c.label === "Monthly Spend" ? "var(--mp-deep-forest)" : undefined} />);

  };

  return (
    <>
      <PageHead title="Overview" />

      <div className="mp-grid-stats-3">
        {cards.map(Card4)}
      </div>

      {window.PoolStatusBanner ?
      <window.PoolStatusBanner tweaks={tweaks} context="dashboard" /> :
      null}

      <Card>
        <div className="mp-card-head">
          <h3>Recent Alerts</h3>
          <Button variant="secondary" size="sm" icon="bell" href="#/alerts">View All</Button>
        </div>
        {recentAlerts.length ?
        <div className="mp-activity">
            {recentAlerts.map(renderAlert)}
          </div> :

        <Empty icon="bell" title="No recent alerts" message="When there are new alerts, they will appear here." />
        }
      </Card>

      <Card style={{ overflow: "hidden" }}>
        <div className="mp-card-head">
          <h3>SIM Fleet Emissions</h3>
          <button type="button" className={"mp-panel-toggle" + (panelOpen ? " is-open" : "")}
            onClick={togglePanel} aria-expanded={panelOpen}>
            <Icon name="chevron-down" size={15} />
            <span>{panelOpen ? "Hide" : "Show"}</span>
          </button>
        </div>
        {panelOpen ?
        <>
        <div className="mp-card-body">
          <LineChart data={D.CO2.trend} ySuffix=" kg" />
          <p style={{ fontSize: 13, color: "var(--fg-3)", marginTop: 14 }}>
            Carbon emissions calculated using verified emission factors based on actual usage.
          </p>
        </div>

        <button type="button" className={"mp-sim-disclosure" + (emissionsOpen ? " is-open" : "")}
          onClick={() => setEmissionsOpen((o) => !o)} aria-expanded={emissionsOpen}>
          <Icon name="chevron-down" size={16} />
          <span>{emissionsOpen ? "Hide" : "Show"} monthly figures</span>
        </button>

        {emissionsOpen ?
        <TableScroll>
          <table className="mp-table">
            <thead>
              <tr><th>Month</th><th>Emissions</th><th>Change</th></tr>
            </thead>
            <tbody>
              {emissionRows.map((r) =>
                <tr key={r.month}>
                  <td>{r.month}</td>
                  <td style={{ fontWeight: 700 }}>{r.value.toFixed(2)} kg CO₂e</td>
                  <td>{r.change === null ?
                    <span style={{ color: "var(--fg-3)" }}>—</span> :
                    <span style={{ color: r.change <= 0 ? "var(--mp-pine)" : "var(--mp-clay-ink)", fontWeight: 600 }}>
                      {r.change > 0 ? "+" : ""}{r.change.toFixed(1)}%
                    </span>}</td>
                </tr>)}
            </tbody>
          </table>
        </TableScroll> : null}
        </> : null}
      </Card>

      <div className="mp-commit">
        <div className="mp-commit-icon"><Icon name="leaf" size={40} /></div>
        <div>
          <h2 className="mp-commit-title">Our Commitment to Sustainability</h2>
          <p className="mp-commit-body">At Meaningful Planet, we're committed to ethical and sustainable approaches, using renewable energy, efficient infrastructure, offsetting all emissions, and actively supporting nature restoration projects across the UK. 


          </p>
        </div>
      </div>
    </>);

}

/* ---------- Type-ahead user picker (assign / reassign a SIM) ---------- */
function UserSearchPicker({ candidates, value, onChange, placeholder = "Search by name or email..." }) {
  const picked = candidates.find((u) => String(u.id) === String(value)) || null;
  const [q, setQ] = u1("");
  const [open, setOpen] = u1(false);
  const [active, setActive] = u1(0);
  const wrap = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); };
    window.addEventListener("click", onDoc);
    return () => window.removeEventListener("click", onDoc);
  }, [open]);

  const matches = React.useMemo(() => {
    const term = q.trim().toLowerCase();
    if (!term) return candidates.slice(0, 8);
    return candidates.filter((u) =>
      u.full_name.toLowerCase().includes(term) || u.email.toLowerCase().includes(term)
    ).slice(0, 8);
  }, [candidates, q]);

  const choose = (u) => { onChange(String(u.id)); setQ(""); setOpen(false); };

  if (picked) {
    return (
      <div className="mp-userpick-chosen">
        <span className="mp-assigned"><Avatar initials={picked.initials} size={30} tone="mist" /><span>{picked.full_name}</span></span>
        <span className="mp-userpick-email">{picked.email}</span>
        <button type="button" className="mp-userpick-clear" onClick={() => onChange("")} aria-label="Choose someone else">
          <Icon name="x" size={15} />
        </button>
      </div>
    );
  }

  return (
    <div className="mp-userpick" ref={wrap}>
      <div className="mp-userpick-field">
        <Icon name="search" size={16} className="mp-userpick-ic" />
        <input
          className="mp-field-input"
          type="search"
          value={q}
          placeholder={placeholder}
          onFocus={() => setOpen(true)}
          onChange={(e) => { setQ(e.target.value); setOpen(true); setActive(0); }}
          onKeyDown={(e) => {
            if (e.key === "ArrowDown") { e.preventDefault(); setOpen(true); setActive((i) => Math.min(i + 1, matches.length - 1)); }
            else if (e.key === "ArrowUp") { e.preventDefault(); setActive((i) => Math.max(i - 1, 0)); }
            else if (e.key === "Enter" && open && matches[active]) { e.preventDefault(); choose(matches[active]); }
            else if (e.key === "Escape") setOpen(false);
          }} />
      </div>
      {open ? (
        <div className="mp-userpick-list" role="listbox">
          {matches.length ? matches.map((u, i) => (
            <button key={u.id} type="button" role="option" aria-selected={i === active}
              className={"mp-userpick-opt" + (i === active ? " is-active" : "")}
              onMouseEnter={() => setActive(i)} onClick={() => choose(u)}>
              <Avatar initials={u.initials} size={28} tone="mist" />
              <span className="mp-userpick-opt-text">
                <span className="mp-userpick-opt-name">{u.full_name}</span>
                <span className="mp-userpick-opt-email">{u.email}</span>
              </span>
            </button>
          )) : (
            <div className="mp-userpick-empty">No one matches "{q.trim()}".</div>
          )}
        </div>
      ) : null}
    </div>
  );
}

/* =====================================================================
   SIM MANAGEMENT — index
   ===================================================================== */
function SimsIndexPage() {
  /* Pick up ?status= from the URL for filtered navigation (e.g. from dashboard) */
  const initStatus = React.useMemo(() => {
    const p = new URLSearchParams(window.location.hash.split("?")[1] || "");
    return p.get("status") || "";
  }, []);
  const [query, setQuery] = u1("");
  const [status, setStatus] = u1(initStatus);
  const [sortField, setSortField] = u1("serial_number");
  const [sortDir, setSortDir] = u1("asc");
  const [page, setPage] = u1(1);
  const perPage = 20;

  /* Deep link from User Management: #/sims?assignment=unassigned */
  const [assignment, setAssignment] = u1(() => (location.hash.split("?")[1] || "").includes("assignment=unassigned") ? "unassigned" : "");
  e1(() => {
    const read = () => {
      const [h, qs = ""] = location.hash.replace(/^#/, "").split("?");
      if (h !== "/sims") return;
      setAssignment(qs.includes("assignment=unassigned") ? "unassigned" : "");
      setPage(1);
    };
    window.addEventListener("hashchange", read);
    return () => window.removeEventListener("hashchange", read);
  }, []);

  const sorted = m1(() => {
    let rows = D.SIMS.slice();
    if (query) {
      const q = query.toLowerCase();
      rows = rows.filter((s) =>
      s.serial.toLowerCase().includes(q) || (s.msisdn || "").toLowerCase().includes(q) ||
      (D.USERS.find((u) => u.id === s.user_id || u.sim_ids.includes(s.id)) || {}).full_name?.toLowerCase().includes(q)
      );
    }
    if (status) rows = rows.filter((s) => s.status === status);
    if (assignment) rows = rows.filter((s) => {
      const has = !!D.USERS.find((u) => u.id === s.user_id || u.sim_ids.includes(s.id));
      return assignment === "assigned" ? has : !has;
    });
    rows.sort((a, b) => {
      const k = sortField;
      const A = k === "serial_number" ? a.serial : k === "sim_type" ? a.sim_type : k === "phone_number" ? a.msisdn : k === "data_plan" ? D.PLANS[a.plan].name : k === "data_usage" ? a.used : k === "usage_percentage" ? a.used / (D.PLANS[a.plan].limit_gb || 999) * 100 : k === "monthly_spend" ? D.PLANS[a.plan].price : a.status;
      const B = k === "serial_number" ? b.serial : k === "sim_type" ? b.sim_type : k === "phone_number" ? b.msisdn : k === "data_plan" ? D.PLANS[b.plan].name : k === "data_usage" ? b.used : k === "usage_percentage" ? b.used / (D.PLANS[b.plan].limit_gb || 999) * 100 : k === "monthly_spend" ? D.PLANS[b.plan].price : b.status;
      const dir = sortDir === "asc" ? 1 : -1;
      return A > B ? dir : A < B ? -dir : 0;
    });
    return rows;
  }, [query, status, assignment, sortField, sortDir]);

  const pageRows = sorted.slice((page - 1) * perPage, page * perPage);
  const totalPages = Math.ceil(sorted.length / perPage) || 1;
  const handleSort = (f) => {if (sortField === f) setSortDir(sortDir === "asc" ? "desc" : "asc");else {setSortField(f);setSortDir("asc");}};

  return (
    <>
      <PageHead title="SIM Management" />

      {MP_ALLOW("sim.manage") ?
      <div>
        <Button variant="secondary" icon="package-plus" onClick={(e) => { if (window.DEMO_TOAST) window.DEMO_TOAST("Purchase Additional SIM Plans opens the ordering flow in the live platform.", e); }}>Purchase Additional SIM Plans</Button>
      </div> : null}

      <Card>
        <div className="mp-mem-filters">
          <SearchInput value={query} onChange={(v) => {setQuery(v);setPage(1);}} placeholder="Search serial, number or user..." />
          <Select value={status} onChange={(v) => {setStatus(v);setPage(1);}} placeholder="All statuses"
          options={[
          { value: "Active", label: "Active" },
          { value: "Activated", label: "Activated" },
          { value: "For Activation", label: "For Activation" },
          { value: "Suspended", label: "Suspended" },
          { value: "Terminated", label: "Terminated" }]
          } />
          <Select value={assignment} onChange={(v) => {setAssignment(v);setPage(1);}} placeholder="All assignments"
          options={[
          { value: "assigned", label: "Assigned SIMs" },
          { value: "unassigned", label: "Unassigned SIMs" }]
          } />
          {query || status || assignment ?
          <div className="mp-clear">
            <Button variant="secondary" size="sm" icon="x" onClick={() => {setQuery("");setStatus("");setAssignment("");setSortField("serial_number");setSortDir("asc");}}>Clear Filters</Button>
          </div> : null}
        </div>
        <TableScroll className="mp-mem-table-wrap" narrowCards>
          <table className="mp-table">
            <thead>
              <tr>
                <th><SortHeader field="serial_number" sortField={sortField} sortDir={sortDir} onSort={handleSort}>SIM Serial</SortHeader></th>
                <th><SortHeader field="sim_type" sortField={sortField} sortDir={sortDir} onSort={handleSort}>SIM Type</SortHeader></th>
                <th><SortHeader field="status" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Status</SortHeader></th>
                <th><SortHeader field="user" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Assigned User</SortHeader></th>
                <th><SortHeader field="phone_number" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Assigned Number</SortHeader></th>
                <th><SortHeader field="data_plan" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Data Plan</SortHeader></th>
                <th><SortHeader field="data_usage" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Data Usage</SortHeader></th>
                <th><SortHeader field="usage_percentage" sortField={sortField} sortDir={sortDir} onSort={handleSort}>% Used</SortHeader></th>
                <th><SortHeader field="monthly_spend" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Monthly Spend</SortHeader></th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {pageRows.map((sim) => {
                const user = D.USERS.find((u) => u.sim_ids.includes(sim.id));
                const plan = D.PLANS[sim.plan];
                const usagePct = plan.limit_gb ? Math.round(sim.used / plan.limit_gb * 100) : 0;
                return (
                  <tr key={sim.id}>
                    <td className="mp-mono">{sim.serial}</td>
                    <td><SimTypeBadge type={sim.sim_type} /></td>
                    <td><StatusBadge status={sim.status} sim={sim} /></td>
                    <td>{user ? <a href={"#/users/" + user.id} className="mp-assigned"><Avatar initials={user.initials} size={26} tone="mist" /><span>{user.full_name}</span></a> : <span style={{ color: "var(--fg-3)" }}>—</span>}</td>
                    <td className="mp-mono">{sim.msisdn || ""}</td>
                    <td>{plan.data}</td>
                    <td>{sim.used.toFixed(1)} GB</td>
                    <td>{plan.limit_gb ? <PctIndicator pct={usagePct} /> : <span className="mp-na">N/A</span>}</td>
                    <td><strong>{gbp(plan.price)}</strong></td>
                    <td>
                      <ActionsMenu items={[
                      { label: "View Details", href: "#/sims/" + sim.id },
                      ...(MP_ALLOW("sim.manage") ? [{ label: user ? "Edit User" : "Assign User", href: "#/sims/" + sim.id + "/edit" }] : []),
                      ...(sim.status === "Active" ? [{ label: "Transfer Your Number", href: "#/sims/" + sim.id + "/transfer" }, { label: "Suspend SIM", onClick: () => { location.hash = "/sims/" + sim.id; setTimeout(() => { const b = document.querySelector(".mp-drawer-trigger, [aria-label=\"Manage SIM\"]"); if (b) b.click(); }, 300); } }] : []),
                      ...(window.MP_ESIM && window.MP_ESIM.isReady(sim) ? [{ label: "Install eSIM", href: "#/sims/" + sim.id }] : []),
  ...(sim.status === "Activated" ? [{ label: "Suspend eSIM", onClick: () => { location.hash = "/sims/" + sim.id; setTimeout(() => { const b = document.querySelector(".mp-drawer-trigger, [aria-label=\"Manage SIM\"]"); if (b) b.click(); }, 300); } }] : []),
                      ...(sim.status === "For Activation" ? [{ label: "Activate SIM", href: "#" }] : []),
                      ...(sim.status === "Suspended" ? [{ label: "Reactivate SIM", href: "#" }] : []),
                      ...(sim.status === "Terminated" ? [{ note: "SIM is terminated, can't perform any action." }] : [])]
                      } />
                    </td>
                  </tr>);

              })}
            </tbody>
          </table>
        </TableScroll>
        <div className="mp-mem-cards">
          {pageRows.map((sim) => {
            const user = D.USERS.find((u) => u.sim_ids.includes(sim.id));
            const plan = D.PLANS[sim.plan];
            const usagePct = plan.limit_gb ? Math.round(sim.used / plan.limit_gb * 100) : 0;
            return (
              <div key={sim.id} className="mp-mem-card">
                <div className="mp-mem-card-top">
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div className="mp-mem-name"><span className="mp-mono">{simLabel(sim)}</span></div>
                    <div className="mp-mem-sub mp-mono">{sim.serial}</div>
                  </div>
                  <ActionsMenu align="right" items={[
                    { label: "View Details", href: "#/sims/" + sim.id },
                    ...(MP_ALLOW("sim.manage") ? [{ label: user ? "Edit User" : "Assign User", href: "#/sims/" + sim.id + "/edit" }] : []),
                    ...(sim.status === "Active" ? [{ label: "Transfer Your Number", href: "#/sims/" + sim.id + "/transfer" }, { label: "Suspend SIM", onClick: () => { location.hash = "/sims/" + sim.id; setTimeout(() => { const b = document.querySelector(".mp-drawer-trigger, [aria-label=\"Manage SIM\"]"); if (b) b.click(); }, 300); } }] : []),
                    ...(window.MP_ESIM && window.MP_ESIM.isReady(sim) ? [{ label: "Install eSIM", href: "#/sims/" + sim.id }] : []),
  ...(sim.status === "Activated" ? [{ label: "Suspend eSIM", onClick: () => { location.hash = "/sims/" + sim.id; setTimeout(() => { const b = document.querySelector(".mp-drawer-trigger, [aria-label=\"Manage SIM\"]"); if (b) b.click(); }, 300); } }] : []),
                    ...(sim.status === "For Activation" ? [{ label: "Activate SIM", href: "#" }] : []),
                    ...(sim.status === "Suspended" ? [{ label: "Reactivate SIM", href: "#" }] : []),
                    ...(sim.status === "Terminated" ? [{ note: "SIM is terminated, can't perform any action." }] : [])
                  ]} />
                </div>
                <div className="mp-mem-card-meta">
                  <StatusBadge status={sim.status} sim={sim} />
                  <SimTypeBadge type={sim.sim_type} />
                </div>
                {user
                  ? <a href={"#/users/" + user.id} className="mp-assigned"><Avatar initials={user.initials} size={30} tone="mist" /><span>{user.full_name}</span></a>
                  : <span style={{ fontSize: 13, color: "var(--fg-3)" }}>Unassigned</span>}
                <div className="mp-card-facts">
                  <div><span>Data Plan</span><strong>{plan.data}</strong></div>
                  <div><span>Data Usage</span><strong>{sim.used.toFixed(1)} GB</strong></div>
                  <div><span>% Used</span><strong>{plan.limit_gb ? <PctIndicator pct={usagePct} /> : "—"}</strong></div>
                  <div><span>Monthly Spend</span><strong>{gbp(plan.price)}</strong></div>
                </div>
              </div>
            );
          })}
        </div>
        <div style={{ padding: "12px 16px" }}>
          <Pagination page={page} totalPages={totalPages} onChange={setPage} />
        </div>
      </Card>
    </>);

}

/* =====================================================================
   SIM MANAGEMENT — show
   ===================================================================== */
/* SimShowPage is now defined in sim-manage.jsx (loaded after this file),
   which redesigns the SIM Details page and adds the Manage SIM slide-out.
   FakeQR / UsageRing / KV / KvCell below remain global helpers it reuses. */

function FakeQR() {
  // hand-rolled simple QR-look pattern
  const cells = [];
  const seed = 12345;
  let rand = seed;
  for (let r = 0; r < 21; r++) {
    for (let c = 0; c < 21; c++) {
      rand = rand * 16807 % 2147483647;
      const filled = rand % 5 < 3;
      // corner finders
      const corner = r < 7 && c < 7 || r < 7 && c > 13 || r > 13 && c < 7;
      if (corner) {
        const onEdge = r === 0 || r === 6 || c === 0 || c === 6 || r > 13 && (r === 14 || r === 20) || c > 13 && (c === 14 || c === 20);
        const onInner = r >= 2 && r <= 4 && c >= 2 && c <= 4;
        if (onEdge || onInner) cells.push(<rect key={r + "," + c} x={c * 6} y={r * 6} width="6" height="6" fill="#1e4136" />);
      } else if (filled) {
        cells.push(<rect key={r + "," + c} x={c * 6} y={r * 6} width="6" height="6" fill="#1e4136" />);
      }
    }
  }
  return <svg viewBox="0 0 126 126" width="120" height="120">{cells}</svg>;
}

/* Circular data-usage gauge — filled arc, threshold colours, clean Unlimited state */
function UsageRing({ used, limit }) {
  const unlimited = !limit;
  const pct = unlimited ? 0 : Math.min(100, Math.round(used / limit * 100));
  const size = 136,stroke = 13,r = (size - stroke) / 2,circ = 2 * Math.PI * r;
  const tone = pct >= 97 ? "crit" : pct >= 90 ? "high" : pct >= 80 ? "warn" : "ok";
  const colors = { ok: "var(--mp-pine)", warn: "var(--mp-clay)", high: "var(--mp-clay)", crit: "var(--mp-ember)" };
  const color = unlimited ? "var(--mp-pine)" : colors[tone];
  const offset = unlimited ? 0 : circ * (1 - pct / 100);
  return (
    <div className="mp-ring" style={{ width: size, height: size }}>
      <svg width={size} height={size}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--bg-3)" strokeWidth={stroke} />
        <circle
          cx={size / 2} cy={size / 2} r={r} fill="none"
          stroke={color} strokeWidth={stroke}
          strokeDasharray={circ} strokeDashoffset={offset} strokeLinecap="round"
          transform={"rotate(-90 " + size / 2 + " " + size / 2 + ")"}
          style={{ transition: "stroke-dashoffset 600ms cubic-bezier(0.16,1,0.3,1)" }} />
      </svg>
      <div className="mp-ring-center">
        {unlimited ?
        <>
            <Icon name="infinity" size={38} className="mp-ring-inf" />
            <span className="mp-ring-sub">Unlimited</span>
          </> :

        <>
            <span className="mp-ring-pct">{pct}<i>%</i></span>
            <span className="mp-ring-sub">used</span>
          </>
        }
      </div>
    </div>);

}

function KV({ label, value }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", padding: "5px 0", fontSize: 13 }}>
      <span style={{ color: "var(--fg-3)" }}>{label}</span>
      <span style={{ fontWeight: 600, color: "var(--fg-1)" }}>{value}</span>
    </div>);

}
function KvCell({ label, value, valueClass = "", action }) {
  return (
    <div className={action ? "mp-kv-editable" : undefined}>
      <div className="mp-kv-label">{label}{action}</div>
      <div className={"mp-kv-value " + valueClass}>{value}</div>
    </div>);

}

/* =====================================================================
   SIM MANAGEMENT — edit (assign user)
   ===================================================================== */
function SimEditPage({ id }) {
  const sim = D.SIMS.find((s) => s.id === Number(id));
  const [pickedUser, setPickedUser] = u1("");
  const user = D.USERS.find((u) => u.sim_ids.includes(sim?.id));

  if (!sim) return <Empty icon="search" title="Not found" message="That SIM could not be found." />;

  return (
    <>
      <PageHead title="SIM Management" subtitle="Choose who this SIM is assigned to." />
      <BackLink href="#/sims">Back to SIMs</BackLink>

      <Card style={{ maxWidth: 720 }}>
        <div style={{ padding: 24 }}>
          <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "var(--mp-deep-forest)" }}>Edit SIM</h3>

          {user &&
          <div style={{ marginTop: 22 }}>
              <div className="mp-field-label" style={{ marginBottom: 8 }}>Currently Assigned</div>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", background: "var(--bg-2)", border: "1px solid var(--border-subtle)", padding: 14, borderRadius: 10 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  <Avatar initials={user.initials} size={40} tone="mist" />
                  <div>
                    <div style={{ fontSize: 14, fontWeight: 600 }}>{user.full_name}</div>
                    <div style={{ fontSize: 12, color: "var(--fg-3)" }}>{user.email}</div>
                  </div>
                </div>
                <Button variant="danger" size="sm">Unassign User</Button>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 12, margin: "20px 0", color: "var(--fg-3)", fontSize: 12 }}>
                <div style={{ flex: 1, height: 1, background: "var(--border-subtle)" }} />
                <span>or</span>
                <div style={{ flex: 1, height: 1, background: "var(--border-subtle)" }} />
              </div>
            </div>
          }

          <div className="mp-field" style={{ marginTop: user ? 0 : 22 }}>
            <label className="mp-field-label">{user ? "Assign a different user" : "Assign a user"}</label>
            <UserSearchPicker
            candidates={D.USERS.filter((u) => !u.sim_ids.includes(sim.id))}
            value={pickedUser} onChange={setPickedUser} />
            <div style={{ marginTop: 14 }}>
              <Button variant="primary" className={pickedUser ? "" : "is-disabled"}>Assign</Button>
            </div>
          </div>
        </div>
      </Card>
    </>);

}

/* =====================================================================
   ALERTS
   ===================================================================== */
function AlertsPage() {
  const [results, setResults] = u1(null);
  const [filter, setFilter] = u1("all");
  const isHighSeverity = (a) => (D.ALERT_KINDS[a.kind] || {}).severity === "high";
  const total = D.ALERTS.length;
  const high = D.ALERTS.filter(isHighSeverity).length;
  const low = total - high;
  const [page, setPage] = u1(1);
  const perPage = 7;
  const rows = filter === "high" ? D.ALERTS.filter(isHighSeverity) :
    filter === "low" ? D.ALERTS.filter((a) => !isHighSeverity(a)) : D.ALERTS;
  const totalPages = Math.ceil(rows.length / perPage) || 1;
  const safePage = Math.min(page, totalPages);
  const pageRows = rows.slice((safePage - 1) * perPage, safePage * perPage);
  /* Choosing a filter starts the list again, so page 3 of 4 cannot survive
     into a filter with one page. */
  const choose = (v) => { setFilter(v); setPage(1); };

  const renderAlert = (a) => {
    const k = D.ALERT_KINDS[a.kind] || { icon: "circle-check", tone: "mist" };
    return (
      <div key={a.id} className={"mp-act mp-act--" + k.tone}>
        <div className="mp-act-ic"><Icon name={k.icon} size={18} /></div>
        <div className="mp-act-body">
          <div className="mp-act-title" style={{ fontSize: 15 }}>{a.title}</div>
          <div className="mp-act-desc" style={{ fontSize: 13 }}>{a.description}</div>
          {a.batch_id && window.MP_BATCH ?
          <button type="button" className="mp-act-link"
            onClick={() => setResults(window.MP_BATCH.batchById(a.batch_id))}>View Results</button> : null}
        </div>
        <div className="mp-act-time">{fmtAgo(a.time_ago)}</div>
      </div>);

  };

  return (
    <>
      <PageHead title="Alerts" />

      <Card>
        <div role="radiogroup" aria-label="Filter alerts by priority"
          style={{ padding: 22, display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14 }}>
          <AlertSummary tone="default" label="Total Alerts" value={total} icon="bell"
            active={filter === "all"} onClick={() => choose("all")} />
          <AlertSummary tone="ember" label="High Priority" value={high} icon="triangle-alert"
            active={filter === "high"} onClick={() => choose("high")} />
          <AlertSummary tone="ok" label="Low Priority" value={low} icon="info"
            active={filter === "low"} onClick={() => choose("low")} />
        </div>
      </Card>

      <Card>
        <div className="mp-card-head"><h3>Active Alerts</h3></div>
        {pageRows.length ?
        <div className="mp-activity">
            {pageRows.map(renderAlert)}
          </div> :

        <Empty icon="bell" title="No recent alerts" message="When there are new alerts, they will appear here." />
        }
        <div style={{ padding: 12 }}>
          <Pagination page={page} totalPages={totalPages} onChange={setPage} />
        </div>
      </Card>

      {results && window.BatchResultsModal ?
      <window.BatchResultsModal batch={results} onClose={() => setResults(null)} /> : null}
    </>);

}

function AlertSummary({ tone, label, value, icon, active, onClick }) {
  // High Priority keeps the ember tint; Total + Low render as plain white cards
  // with just the value coloured. Quieter overall, lets High Priority pop.
  const isHigh = tone === "ember";
  const bg = isHigh ? "rgba(207,76,0,0.06)" : "#fff";
  const border = isHigh ? "1px solid rgba(207,76,0,0.18)" : "1px solid var(--border-subtle)";
  const valueColor = isHigh ? "var(--mp-ember)" : "var(--mp-deep-forest)";
  const iconColor = isHigh ? "var(--mp-ember)" : tone === "ok" ? "var(--mp-pine)" : "var(--fg-3)";
  return (
    <div className={"mp-alert-summary" + (active ? isHigh ? " is-active-high" : " is-active" : "")}
      style={{ background: bg, border, borderRadius: 12, padding: 18,
        display: "flex", alignItems: "center", justifyContent: "space-between" }}>
      <div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, color: "var(--fg-3)", fontSize: 12.5, fontWeight: 600 }}>
          <Icon name={icon} size={14} style={{ color: iconColor }} />
          <span>{label}</span>
        </div>
        <div style={{ fontSize: 28, fontWeight: 500, color: valueColor, marginTop: 6, letterSpacing: "-0.015em", fontVariantNumeric: "tabular-nums" }}>{value}</div>
      </div>
      <button type="button" role="radio" aria-checked={!!active} aria-label={"Show " + label}
        className={"mp-btn mp-btn--" + (active ? "primary" : "secondary") + " mp-btn--sm"}
        onClick={onClick}>View</button>
    </div>);

}

/* =====================================================================
   CO2 / ENVIRONMENTAL IMPACT — tabbed: Overview + Partners
   ===================================================================== */
function Co2Page() {

  return (
    <>
      <PageHead title="Environmental Impact" />

      <Co2OverviewTab />
    </>);

}

/* Circular progress ring used by the emissions overview */
function Co2Progress({ label, pct, info, trailing, trailingTone }) {
  const r = 38, circ = 2 * Math.PI * r, offset = circ * (1 - pct / 100);
  return (
    <StatCard label={label} info={info}
      hint={trailing ? <span style={trailingTone === "ok" ? { color: "var(--mp-pine)", fontWeight: 700 } : undefined}>{trailing}</span> : null}
      value={<svg width="90" height="90" viewBox="0 0 90 90">
        <circle cx="45" cy="45" r={r} fill="none" stroke="var(--mp-cream)" strokeWidth="7" />
        <circle cx="45" cy="45" r={r} fill="none" stroke="var(--mp-pine)" strokeWidth="7"
          strokeDasharray={circ} strokeDashoffset={offset} strokeLinecap="round"
          transform="rotate(-90 45 45)" style={{ transition: "stroke-dashoffset 600ms" }} />
        <text x="45" y="50" textAnchor="middle" style={{ fontSize: 18, fill: "var(--mp-deep-forest)", fontWeight: 700 }}>{pct}%</text>
      </svg>} />);
}

function Co2OverviewTab() {
  const c = D.CO2;
  const change = (c.net_emissions - c.prev_period) / c.prev_period * 100;
  /* Counted here rather than snapshotted at load: seed files load in an order
     this page cannot see, and a travel eSIM bought during the session would
     leave a load-time figure stale. IoT is a device category with no
     physical-vs-eSIM choice, so it is outside the adoption measure. */
  const esims = D.SIMS.filter((s) => s.sim_type === "eSIM").length;
  const physical = D.SIMS.filter((s) => s.sim_type === "Physical").length;
  const adoption = esims + physical ? Math.round(esims / (esims + physical) * 100) : 0;
  const total = c.categories.reduce((a, b) => a + b.value, 0);

  return (
    <>
      <div className="mp-grid-stats-4">
        <StatCard label="Net Emissions" info="The net CO2e emissions from your SIM fleet in the current period."
        value={c.net_emissions.toFixed(2)} valueSuffix=" kg CO₂e"
        hint={<span style={{ color: change <= 0 ? "var(--mp-pine)" : "var(--mp-ember)" }}>{change <= 0 ? "" : "+"}{change.toFixed(1)}% vs previous period</span>} />
        <Co2Progress label="Offset Coverage" pct={100} info="The % of your emissions that will be offset within the next 12 months by Meaningful Planet via verified UK nature-based environmental projects." trailing="Your mobile connectivity: fully carbon neutral" trailingTone="ok" />
        <Co2Progress label="eSIM Adoption" pct={adoption} info="eSIMs as a % of your total SIM fleet. Moving to eSIMs reduces waste and emissions from the manufacture and delivery of physical SIMs." trailing={esims + " eSIMs vs " + physical + " physical SIMs"} />
        <StatCard label="Projects Supported" info="The number of UK-based nature restoration projects that are currently being supported by your business thanks to your account with Meaningful Planet."
        value={c.projects}
        hint={<a href="https://meaningfulplanet.co.uk/impact" target="_blank" rel="noreferrer" style={{ color: "var(--mp-pine)", fontWeight: 700, textDecoration: "underline" }}>Find out more →</a>} />
      </div>

      <div className="mp-subhead" style={{ marginTop: 8 }}>
        <h2 className="mp-subhead-title">Emissions Breakdown</h2>
      </div>

      <Card>
        <div className="mp-card-head"><h3>Emissions by Category</h3></div>
        <div className="mp-card-body">
          <DonutChart data={c.categories} total={total} />
        </div>
      </Card>

      <div className="mp-seedling-strip">
        <Icon name="sprout" size={17} className="mp-seedling-strip-ic" />
        <p className="mp-seedling-strip-text">Looking to manage your company's wider carbon impact? We recommend <strong>Seedling</strong>.</p>
        <a className="mp-seedling-strip-cta" href="https://seedling.earth" target="_blank" rel="noreferrer">
          <span>Find Out More</span>
          <Icon name="arrow-up-right" size={14} />
        </a>
      </div>

      <Card>
        <div className="mp-card-head"><h3>SIM Fleet Emissions</h3></div>
        <div className="mp-card-body">
          <LineChart data={c.trend} ySuffix=" kg" />
          <p style={{ fontSize: 12, color: "var(--fg-3)", marginTop: 14 }}>
            Carbon emissions calculated using verified emission factors based on actual usage.
          </p>
        </div>
      </Card>
    </>);

}

function Co2PartnersTab() {
  const [query, setQuery] = u1("");
  const [cat, setCat] = u1("all");

  const filtered = D.PARTNERS.filter((p) => {
    if (cat !== "all" && p.category !== cat) return false;
    if (query) {
      const q = query.toLowerCase();
      if (!p.name.toLowerCase().includes(q) && !p.description.toLowerCase().includes(q) && !p.category_label.toLowerCase().includes(q)) return false;
    }
    return true;
  });

  return (
    <>
      <Card>
        <div style={{ padding: "24px 26px 22px" }}>
          <div className="mp-eyebrow-serif">Recommended Partners</div>
          <h2 style={{ fontSize: 26, fontWeight: 800, letterSpacing: "-0.02em", marginTop: 6, marginBottom: 12, lineHeight: 1.15 }}>Connect with trusted tools and solutions to advance your organisational goals.</h2>
          <p style={{ fontSize: 14, color: "var(--fg-3)", lineHeight: 1.6, margin: 0, maxWidth: 720 }}>Link your platform to trusted, expert-vetted organisations specialising in everything from carbon verification to hardware recycling. It’s the easiest way to drive operational efficiency while delivering on your green commitments.

          </p>

          <div className="mp-input-wrap" style={{ marginTop: 22 }}>
            <Icon name="search" size={14} className="mp-input-leading" />
            <input
              className="mp-input"
              type="search"
              placeholder="Search partners..."
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              style={{ height: 44, fontSize: 14 }} />
          </div>

          <div className="mp-chip-row" style={{ marginTop: 14 }}>
            {D.PARTNER_CATEGORIES.map((c) =>
            <button
              key={c.value}
              className={"mp-chip" + (cat === c.value ? " is-active" : "")}
              onClick={() => setCat(c.value)}>{c.label}</button>
            )}
          </div>
        </div>
      </Card>

      <div className="mp-partner-grid">
        {filtered.map((p) => <PartnerCard key={p.id} p={p} />)}
      </div>

      {filtered.length === 0 ?
      <Card>
          <Empty icon="search" title="No partners match" message="Try a different search term or clear the filter." />
        </Card> :
      null}
    </>);

}

/* ---------- Export ---------- */
Object.assign(window, {
  UserSearchPicker,
  DashboardPage, SimsIndexPage, SimEditPage, AlertsPage, Co2Page,
  gbp
});