// Activity — overview (forecast + last 5 tx) with separate sub-views for full
// transaction history and budgeting.

const DATE_FILTER_PRESETS = [
  { key: "all", label: "All time" },
  { key: "last7", label: "Last 7 days", days: 7 },
  { key: "last30", label: "Last 30 days", days: 30 },
  { key: "thisMonth", label: "This month", unit: "thisMonth" },
  { key: "lastMonth", label: "Last month", unit: "lastMonth" },
  { key: "thisYear", label: "This year", unit: "thisYear" },
  { key: "lastYear", label: "Last year", unit: "lastYear" },
];

const EDITABLE_CATS = [
  "Food",
  "Transport",
  "Shopping",
  "Bills",
  "Transfers",
  "Income",
  "Investments",
];

const SPEND_CATEGORY_COLORS = {
  Food: "#9BB08A",
  Transport: "#7389A8",
  Shopping: "#C9B088",
  Bills: "#D4A25A",
  Transfers: "#E8D4A8",
  Investments: "#D4B27A",
};

const INITIAL_TAGS = [
  { id: "tag-tax", name: "Tax", color: "#5B8DEF" },
  { id: "tag-family", name: "Family", color: "#9BB08A" },
  { id: "tag-work", name: "Work", color: "#D4A25A" },
];

const TAG_COLORS = [
  "#5B8DEF",
  "#9BB08A",
  "#D4A25A",
  "#C97B63",
  "#8E6CCF",
  "#53A6A6",
  "#E07A9A",
  "#7389A8",
  "#B8A268",
  "#6EA06F",
  "#D15C4A",
  "#7A8A3D",
  "#C48A3A",
  "#5C7899",
  "#A7618B",
  "#409083",
  "#956E4A",
  "#6F7684",
];

const toCents = (amount) => Math.round(Math.abs(amount) * 100);
const fromCents = (cents, sign = -1) => (sign < 0 ? -1 : 1) * (cents / 100);
const fmtMoney = (amount) =>
  `$${fmtAED(Math.abs(amount), { decimals: Math.abs(amount) < 1000 ? 2 : 0 })}`;

function getVisibleTransactions(txs) {
  return txs.flatMap((t) => {
    if (t.splitParent && t.splitActive) {
      return (t.splitChildren || []).filter((child) => !child.hidden);
    }
    if (t.splitChild) return [];
    return t.hidden ? [] : [t];
  });
}

function findTransactionById(txs, id) {
  for (const tx of txs) {
    if (tx.id === id) return tx;
    const child = tx.splitChildren?.find((line) => line.id === id);
    if (child) return child;
  }
  return null;
}

function distributeCents(totalCents, count) {
  const base = Math.floor(totalCents / count);
  const remainder = totalCents % count;
  return Array.from(
    { length: count },
    (_, i) => base + (i < remainder ? 1 : 0),
  );
}

function TransactionsScreen({
  theme,
  accent,
  initialView,
  onNav,
  onAskHimma,
  onOpenPaywall,
}) {
  const [view, setView] = React.useState(initialView || "overview"); // 'overview' | 'list' | 'budget' | 'raw' | 'recurring'

  // tx state — shared across views
  const [txs, setTxs] = React.useState(TRANSACTIONS.map((t) => ({ ...t })));
  const [tags, setTags] = React.useState(INITIAL_TAGS);
  const [editing, setEditing] = React.useState(null);
  const [tagSheetTxId, setTagSheetTxId] = React.useState(null);
  const [createTagTxId, setCreateTagTxId] = React.useState(null);
  const [manageTagsTxId, setManageTagsTxId] = React.useState(null);
  const [merchantSheetTxId, setMerchantSheetTxId] = React.useState(null);
  const [splitEditingId, setSplitEditingId] = React.useState(null);
  const [toast, setToast] = React.useState(null);
  const [recatId, setRecatId] = React.useState(null);
  const [confirmDelete, setConfirmDelete] = React.useState(null);

  // budget state — used in budget view
  const [budgets, setBudgets] = React.useState(BUDGETS);
  const [budgetSetup, setBudgetSetup] = React.useState({
    monthKey: "may",
    monthlyIncome: 2394,
    monthlyBudget: 3000,
    categoryBudgets: {},
  });
  const [editingBudget, setEditingBudget] = React.useState(false);
  const [categoryDetail, setCategoryDetail] = React.useState(null);

  const updateCategory = (id, newCat) => {
    setTxs((all) =>
      all.map((t) =>
        t.id === id
          ? { ...t, category: newCat }
          : t.splitChildren?.some((child) => child.id === id)
            ? {
                ...t,
                splitChildren: t.splitChildren.map((child) =>
                  child.id === id ? { ...child, category: newCat } : child,
                ),
              }
            : t,
      ),
    );
    setRecatId(null);
  };
  const updateMerchant = (id, merchant) => {
    setTxs((all) =>
      all.map((t) =>
        t.id === id
          ? { ...t, merchant }
          : t.splitChildren?.some((child) => child.id === id)
            ? {
                ...t,
                splitChildren: t.splitChildren.map((child) =>
                  child.id === id ? { ...child, merchant } : child,
                ),
              }
            : t,
      ),
    );
  };
  const updateTransactionTags = (id, tagIds) => {
    setTxs((all) =>
      all.map((t) =>
        t.id === id
          ? { ...t, tagIds }
          : t.splitChildren?.some((child) => child.id === id)
            ? {
                ...t,
                splitChildren: t.splitChildren.map((child) =>
                  child.id === id ? { ...child, tagIds } : child,
                ),
              }
            : t,
      ),
    );
  };
  const createAndAssignTag = (txId, name, color) => {
    const tag = {
      id: `tag-${Date.now()}`,
      name: name.trim(),
      color,
    };
    setTags((all) => [...all, tag]);
    const tx = findTransactionById(txs, txId);
    updateTransactionTags(txId, [...new Set([...(tx?.tagIds || []), tag.id])]);
    setCreateTagTxId(null);
    setTagSheetTxId(null);
    setEditing(txId);
    setToast({ title: "Tag created", body: "" });
  };
  const saveManagedTags = (nextTags) => {
    const nextIds = new Set(nextTags.map((tag) => tag.id));
    setTags(nextTags);
    setTxs((all) =>
      all.map((t) => ({
        ...t,
        tagIds: (t.tagIds || []).filter((id) => nextIds.has(id)),
        splitChildren: t.splitChildren?.map((child) => ({
          ...child,
          tagIds: (child.tagIds || []).filter((id) => nextIds.has(id)),
        })),
      })),
    );
  };
  const deleteTx = (id) => {
    setTxs((all) => all.filter((t) => t.id !== id));
    setEditing(null);
    setConfirmDelete(null);
  };
  const applySplit = (parentId, lines, wasEditing) => {
    setTxs((all) =>
      all.map((t) => {
        if (t.id !== parentId) return t;
        return {
          ...t,
          splitParent: true,
          splitActive: true,
          splitChildren: lines.map((line, index) => ({
            id: `${t.id}-split-${index + 1}`,
            splitChild: true,
            parentId: t.id,
            merchant: line.merchant || t.merchant,
            category: line.category,
            account: t.account,
            amount: fromCents(line.amountCents, t.amount < 0 ? -1 : 1),
            date: t.date,
            hidden: line.hidden,
          })),
        };
      }),
    );
    setSplitEditingId(null);
    setEditing(null);
    setToast(
      wasEditing
        ? {
            title: "Split updated.",
            body: "Your transaction split has been updated.",
          }
        : {
            title: "Split created.",
            body: `Original ${fmtMoney(Math.abs(txs.find((t) => t.id === parentId)?.amount || 0))} transaction split into ${lines.length}.`,
          },
    );
  };
  const removeSplit = (parentId) => {
    setTxs((all) =>
      all.map((t) =>
        t.id === parentId
          ? { ...t, splitParent: false, splitActive: false, splitChildren: [] }
          : t,
      ),
    );
    setSplitEditingId(null);
    setEditing(null);
    setToast({
      title: "Split removed.",
      body: "Original transaction restored.",
    });
  };

  const visibleTxs = React.useMemo(() => getVisibleTransactions(txs), [txs]);
  const editingTx = editing ? findTransactionById(txs, editing) : null;
  const tagSheetTx = tagSheetTxId
    ? findTransactionById(txs, tagSheetTxId)
    : null;
  const createTagTx = createTagTxId
    ? findTransactionById(txs, createTagTxId)
    : null;
  const manageTagsTx = manageTagsTxId
    ? findTransactionById(txs, manageTagsTxId)
    : null;
  const merchantSheetTx = merchantSheetTxId
    ? findTransactionById(txs, merchantSheetTxId)
    : null;
  const splitEditingTx = splitEditingId
    ? txs.find((t) => t.id === splitEditingId)
    : null;
  const recatTx = recatId ? findTransactionById(txs, recatId) : null;
  const deleteTxRecord = confirmDelete
    ? txs.find((t) => t.id === confirmDelete)
    : null;

  React.useEffect(() => {
    if (!toast) return undefined;
    const timer = window.setTimeout(() => setToast(null), 3200);
    return () => window.clearTimeout(timer);
  }, [toast]);

  const headerTitle =
    view === "list"
      ? "Transactions"
      : view === "raw"
        ? "Raw data"
        : view === "budget"
          ? "Budget"
          : view === "recurring"
            ? "RECURRING"
            : "Activity";

  const headerAction = (
    <button
      onClick={() => setView("overview")}
      style={{
        background: "transparent",
        border: "none",
        color: theme.textDim,
        fontFamily: FONTS.ui,
        fontSize: 12,
        fontWeight: 500,
        cursor: "pointer",
        display: "flex",
        alignItems: "center",
        gap: 4,
      }}
    >
      <Ico.chevL size={13} /> Activity
    </button>
  );

  return (
    <Screen theme={theme}>
      {view !== "recurring" && view !== "list" && view !== "budget" && (
        <AppTopbar
          theme={theme}
          accent={accent}
          onNav={onNav}
          onAskHimma={onAskHimma}
        />
      )}
      {view !== "overview" &&
        view !== "recurring" &&
        view !== "list" &&
        view !== "budget" && (
          <ScreenHeader
            title={headerTitle}
            theme={theme}
            accent={accent}
            action={headerAction}
          />
        )}

      {view === "overview" && (
        <OverviewBody
          theme={theme}
          accent={accent}
          txs={visibleTxs}
          tags={tags}
          budgets={budgets}
          onTxClick={(id) => setEditing(id)}
          onSeeAll={() => setView("list")}
          onOpenBudget={() => setView("budget")}
          onOpenRecurring={() => setView("recurring")}
          onSeeRawData={() => setView("raw")}
          onAskHimma={onAskHimma}
          onOpenPaywall={onOpenPaywall}
        />
      )}
      {view === "list" && (
        <AllBody
          theme={theme}
          accent={accent}
          txs={visibleTxs}
          tags={tags}
          onTxClick={(id) => setEditing(id)}
          onBack={() => setView("overview")}
        />
      )}
      {view === "budget" && (
        <BudgetBody
          theme={theme}
          accent={accent}
          txs={txs}
          budgets={budgets}
          budgetSetup={budgetSetup}
          onEditBudget={() => setEditingBudget(true)}
          onOpenCategory={(category) => setCategoryDetail(category)}
          onOpenTransaction={(id) => setEditing(id)}
          onBack={() => setView("overview")}
        />
      )}
      {view === "raw" && <RawSpendBody theme={theme} accent={accent} />}
      {view === "recurring" && (
        <RecurringBody
          theme={theme}
          accent={accent}
          onBack={() => setView("overview")}
        />
      )}

      {editingTx && !recatTx && !deleteTxRecord && !splitEditingTx && (
        <TransactionDetailSheet
          tx={editingTx}
          tags={tags}
          theme={theme}
          accent={accent}
          onClose={() => setEditing(null)}
          onReCategorize={() => setRecatId(editingTx.id)}
          onOpenTags={() => setTagSheetTxId(editingTx.id)}
          onOpenMerchant={() => setMerchantSheetTxId(editingTx.id)}
          onRename={(name) => updateMerchant(editingTx.id, name)}
          onDelete={() => setConfirmDelete(editingTx.id)}
          onSplit={() =>
            setSplitEditingId(
              editingTx.splitChild ? editingTx.parentId : editingTx.id,
            )
          }
        />
      )}
      {tagSheetTx && (
        <SelectTagsSheet
          tx={tagSheetTx}
          tags={tags}
          theme={theme}
          accent={accent}
          onClose={() => setTagSheetTxId(null)}
          onCreate={() => {
            setCreateTagTxId(tagSheetTx.id);
            setTagSheetTxId(null);
          }}
          onManage={() => {
            setManageTagsTxId(tagSheetTx.id);
            setTagSheetTxId(null);
          }}
          onSave={(tagIds) => {
            updateTransactionTags(tagSheetTx.id, tagIds);
            setTagSheetTxId(null);
          }}
        />
      )}
      {manageTagsTx && (
        <ManageTagsSheet
          tags={tags}
          theme={theme}
          accent={accent}
          onClose={() => setManageTagsTxId(null)}
          onBack={() => {
            setManageTagsTxId(null);
            setTagSheetTxId(manageTagsTx.id);
          }}
          onSave={(nextTags) => {
            saveManagedTags(nextTags);
            setManageTagsTxId(null);
            setTagSheetTxId(manageTagsTx.id);
          }}
        />
      )}
      {createTagTx && (
        <CreateTagSheet
          tags={tags}
          theme={theme}
          accent={accent}
          onClose={() => setCreateTagTxId(null)}
          onCancel={() => {
            setCreateTagTxId(null);
            setTagSheetTxId(createTagTx.id);
          }}
          onCreate={(name, color) =>
            createAndAssignTag(createTagTx.id, name, color)
          }
        />
      )}
      {merchantSheetTx && (
        <MerchantDetailSheet
          tx={merchantSheetTx}
          txs={visibleTxs}
          theme={theme}
          accent={accent}
          onClose={() => setMerchantSheetTxId(null)}
          onOpenTransaction={(id) => {
            setMerchantSheetTxId(null);
            setEditing(id);
          }}
        />
      )}
      {splitEditingTx && (
        <SplitTransactionSheet
          tx={splitEditingTx}
          theme={theme}
          accent={accent}
          onBack={() => setSplitEditingId(null)}
          onClose={() => {
            setSplitEditingId(null);
            setEditing(null);
          }}
          onApply={(lines) =>
            applySplit(splitEditingTx.id, lines, !!splitEditingTx.splitActive)
          }
          onRemoveSplit={() => removeSplit(splitEditingTx.id)}
        />
      )}
      {recatTx && (
        <CategoryPicker
          tx={recatTx}
          theme={theme}
          accent={accent}
          onClose={() => setRecatId(null)}
          onPick={(c) => updateCategory(recatTx.id, c)}
        />
      )}
      {deleteTxRecord && (
        <DeleteConfirmSheet
          tx={deleteTxRecord}
          theme={theme}
          accent={accent}
          onCancel={() => setConfirmDelete(null)}
          onConfirm={() => deleteTx(deleteTxRecord.id)}
        />
      )}
      {editingBudget && (
        <EditBudgetSheet
          budgets={budgets}
          budgetSetup={budgetSetup}
          txs={txs}
          theme={theme}
          accent={accent}
          onClose={() => setEditingBudget(false)}
          onSave={setBudgetSetup}
          onOpenCategory={(category) => {
            setEditingBudget(false);
            setCategoryDetail(category);
          }}
        />
      )}
      {categoryDetail && (
        <BudgetCategoryDetailSheet
          detail={categoryDetail}
          theme={theme}
          accent={accent}
          onClose={() => setCategoryDetail(null)}
          onSetBudget={() => {
            setCategoryDetail(null);
            setEditingBudget(true);
          }}
          onOpenTransaction={(id) => {
            setCategoryDetail(null);
            setEditing(id);
          }}
        />
      )}
      {toast && (
        <SplitToast
          theme={theme}
          accent={accent}
          toast={toast}
          onClose={() => setToast(null)}
        />
      )}
    </Screen>
  );
}

// ─────────────────────────────────────────────────────────────
// OVERVIEW BODY — forecast + 5 most recent tx, with See all
// ─────────────────────────────────────────────────────────────
function OverviewBody({
  theme,
  accent,
  txs,
  tags,
  budgets,
  onTxClick,
  onSeeAll,
  onOpenBudget,
  onOpenRecurring,
  onSeeRawData,
  onAskHimma,
  onOpenPaywall,
}) {
  const snap = getBudgetSnapshot(txs, budgets);
  const isPro = SUBSCRIPTION.status === "active";

  // Most recent first — TRANSACTIONS are already roughly newest-to-oldest by date.
  const recent = txs.slice(0, 3);

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        gap: 14,
        padding: "0 16px 14px",
      }}
    >
      <div>
        <SpendMonthComparisonCard
          theme={theme}
          accent={accent}
          txs={txs}
          budgets={budgets}
        />
      </div>

      <div>
        <SpendTrendCard
          theme={theme}
          accent={accent}
          txs={txs}
          onSeeRawData={onSeeRawData}
        />
      </div>

      <div>
        <ActivityInsightsCard
          theme={theme}
          accent={accent}
          txs={txs}
          showAskHimma={isPro && snap.overUnder > 0}
          onAskHimma={onAskHimma}
        />
      </div>

      <div>
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div
            role="button"
            tabIndex={0}
            onClick={onOpenBudget}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") {
                e.preventDefault();
                onOpenBudget();
              }
            }}
            style={{
              cursor: "pointer",
            }}
          >
            <SpendVsBudgetCard theme={theme} accent={accent} snap={snap} />
          </div>

          <div>
            <RecurringPreviewCard
              theme={theme}
              accent={accent}
              onSeeAll={onOpenRecurring}
            />
          </div>

          <Card theme={theme} style={{ padding: 18 }}>
            <SectionLabel theme={theme}>Latest transactions</SectionLabel>

            <div
              style={{
                display: "flex",
                flexDirection: "column",
                gap: 12,
                marginTop: 14,
              }}
            >
              {recent.map((t) => (
                <button
                  key={t.id}
                  onClick={() => onTxClick(t.id)}
                  style={{
                    width: "100%",
                    textAlign: "left",
                    background: "transparent",
                    border: "none",
                    cursor: "pointer",
                    display: "flex",
                    alignItems: "center",
                    gap: 12,
                    padding: 0,
                    color: theme.text,
                  }}
                >
                  <CategoryIcon
                    category={t.category}
                    theme={theme}
                    accent={accent}
                    size={32}
                  />
                  {t.tagIds?.length > 0 && (
                    <div
                      style={{
                        display: "flex",
                        marginLeft: -18,
                        alignSelf: "flex-end",
                        paddingBottom: 1,
                      }}
                    >
                      {t.tagIds.slice(0, 3).map((tagId, dotIndex) => {
                        const tag = tags.find((item) => item.id === tagId);
                        return (
                          <span
                            key={tagId}
                            style={{
                              width: 7,
                              height: 7,
                              borderRadius: 4,
                              background: tag?.color || accent,
                              border: `1px solid ${theme.surface}`,
                              marginLeft: dotIndex ? -2 : 0,
                            }}
                          />
                        );
                      })}
                    </div>
                  )}
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div
                      style={{
                        fontSize: 13.5,
                        color: theme.text,
                        fontWeight: 500,
                        whiteSpace: "nowrap",
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                      }}
                    >
                      {t.merchant}
                    </div>
                  </div>
                  <div
                    style={{
                      fontFamily: FONTS.mono,
                      fontSize: 13,
                      color: t.amount >= 0 ? theme.positive : theme.text,
                      fontVariantNumeric: "tabular-nums",
                      fontWeight: 500,
                      whiteSpace: "nowrap",
                    }}
                  >
                    {t.amount >= 0 ? "+" : "−"}
                    {fmtAED(Math.abs(t.amount), {
                      decimals: Math.abs(t.amount) < 1000 ? 2 : 0,
                    })}
                  </div>
                </button>
              ))}
            </div>

            <button
              onClick={onSeeAll}
              style={{
                width: "100%",
                marginTop: 14,
                padding: "0",
                background: "transparent",
                border: "none",
                cursor: "pointer",
                color: accent,
                fontFamily: FONTS.ui,
                fontSize: 12.5,
                fontWeight: 400,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                gap: 3,
              }}
            >
              See all <Ico.chevR size={12} stroke={accent} />
            </button>
          </Card>
        </div>
      </div>
    </div>
  );
}

function getSpendOutflows(txs) {
  return txs.filter((t) => t.amount < 0);
}

const RECURRING_GROUPS = [
  {
    title: "Biweekly",
    items: [
      {
        merchant: "Income",
        cadence: "Transfer from Emirates NBD",
        due: "Due on May 23",
        amount: 2287.92,
        account: "Emirates NBD",
        income: true,
        icon: "money",
        color: "#2F9E5B",
      },
    ],
  },
  {
    title: "Monthly",
    items: [
      {
        merchant: "Etisalat",
        cadence: "Monthly",
        due: "Due in 2 days",
        amount: -44.99,
        account: "ADCB",
        icon: "house",
        color: "#3C82F6",
        urgent: true,
      },
      {
        merchant: "Patreon",
        cadence: "Monthly",
        due: "Due on May 20",
        amount: -7.62,
        account: "FAB",
        icon: "patreon",
        color: "#E85B4A",
      },
    ],
  },
  {
    title: "Annual",
    items: [
      {
        merchant: "Popeyes",
        cadence: "Annual",
        due: "Due on Apr 12",
        amount: -30.15,
        account: "Emirates NBD",
        icon: "food",
        color: "#E88928",
      },
    ],
  },
  {
    title: "Inactive",
    inactive: true,
    items: [
      {
        merchant: "Spotify",
        cadence: "Monthly",
        due: "Due on May 1",
        amount: -10.99,
        account: "Wise",
        currency: "$",
        icon: "spotify",
        color: "#8A8F98",
      },
      {
        merchant: "Ring",
        cadence: "Monthly",
        due: "Due on Aug 4",
        amount: -4.99,
        account: "ADCB",
        currency: "$",
        icon: "house",
        color: "#8A8F98",
      },
    ],
  },
];

function RecurringBody({ theme, accent, onBack }) {
  const [accountFilter, setAccountFilter] = React.useState(() =>
    getDefaultAccountFilter(),
  );
  const [accountSheetOpen, setAccountSheetOpen] = React.useState(false);
  const filteredGroups = RECURRING_GROUPS.map((group) => ({
    ...group,
    items: group.items.filter((item) =>
      isAccountNameInFilter(item.account, accountFilter),
    ),
  })).filter((group) => group.items.length > 0);

  return (
    <>
      <div
        style={{
          position: "sticky",
          top: 0,
          zIndex: 30,
          padding: "12px 18px 10px",
          display: "grid",
          gridTemplateColumns: "36px 1fr 36px",
          alignItems: "center",
          background: `linear-gradient(to bottom, ${theme.bg} 88%, ${theme.bg}00)`,
          backdropFilter: "blur(16px)",
        }}
      >
        <button
          onClick={onBack}
          aria-label="Back to Activity"
          style={{
            width: 32,
            height: 32,
            border: "none",
            background: "transparent",
            color: theme.text,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            cursor: "pointer",
            padding: 0,
          }}
        >
          <Ico.arrowL size={20} stroke={theme.text} />
        </button>
        <button
          style={{
            justifySelf: "center",
            border: "none",
            background: "transparent",
            color: theme.text,
            fontFamily: FONTS.ui,
            fontSize: 14,
            fontWeight: 600,
            display: "flex",
            alignItems: "center",
            gap: 5,
            padding: "6px 8px",
            cursor: "pointer",
          }}
        >
          RECURRING TRANSACTIONS
        </button>
      </div>

      <div style={{ padding: "4px 18px 18px" }}>
        <button
          onClick={() => setAccountSheetOpen(true)}
          style={{
            height: 34,
            padding: "0 13px",
            borderRadius: 17,
            border: `1px solid ${theme.line2 || theme.line}`,
            background: "transparent",
            color: theme.text,
            fontFamily: FONTS.mono,
            fontSize: 10.5,
            letterSpacing: 1.2,
            textTransform: "uppercase",
            display: "inline-flex",
            alignItems: "center",
            gap: 6,
            cursor: "pointer",
          }}
        >
          {getAccountFilterLabel(accountFilter)}{" "}
          <Ico.chevD size={12} stroke={theme.text} />
        </button>

        <div style={{ marginTop: 18 }}>
          {filteredGroups.map((group) => (
            <RecurringGroup key={group.title} group={group} theme={theme} />
          ))}
          {filteredGroups.length === 0 && (
            <div
              style={{
                padding: 46,
                textAlign: "center",
                color: theme.textMute,
                fontFamily: FONTS.mono,
                fontSize: 11,
              }}
            >
              No recurring transactions match.
            </div>
          )}
        </div>
      </div>
      {accountSheetOpen && (
        <AccountFilterSheet
          theme={theme}
          accent={accent}
          value={accountFilter}
          onClose={() => setAccountSheetOpen(false)}
          onApply={(next) => {
            setAccountFilter(next);
            setAccountSheetOpen(false);
          }}
          onClear={() => {
            setAccountFilter(getDefaultAccountFilter());
            setAccountSheetOpen(false);
          }}
        />
      )}
    </>
  );
}

function RecurringGroup({ group, theme }) {
  return (
    <section style={{ marginBottom: 22 }}>
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: 6,
          padding: "0 2px 8px",
        }}
      >
        <SectionLabel theme={theme}>{group.title}</SectionLabel>
      </div>
      <Card theme={theme} padded={false} style={{ overflow: "hidden" }}>
        {group.items.map((item, index) => (
          <RecurringListItem
            key={`${group.title}-${item.merchant}`}
            item={item}
            theme={theme}
            inactive={group.inactive}
            last={index === group.items.length - 1}
          />
        ))}
      </Card>
    </section>
  );
}

function RecurringListItem({ item, theme, inactive, last }) {
  const amountColor = item.income ? theme.positive : theme.text;
  const amountText =
    item.currency === "$"
      ? `$${Math.abs(item.amount).toFixed(2)}`
      : `${item.income ? "+" : ""}`;

  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "36px 1fr auto",
        alignItems: "center",
        gap: 12,
        padding: "12px 14px",
        borderBottom: last ? "none" : `1px solid ${theme.line}`,
        opacity: inactive ? 0.5 : 1,
      }}
    >
      <RecurringMerchantIcon type={item.icon} color={item.color} />
      <div style={{ minWidth: 0 }}>
        <div
          style={{
            color: theme.text,
            fontFamily: FONTS.ui,
            fontSize: 13.5,
            fontWeight: 500,
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
          }}
        >
          {item.merchant}
        </div>
        <div
          style={{
            color: item.urgent ? "#B88918" : theme.textMute,
            fontFamily: FONTS.ui,
            fontSize: 11.5,
            marginTop: 3,
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
          }}
        >
          {item.cadence}, {item.due}
        </div>
      </div>
      <div
        style={{
          color: amountColor,
          fontFamily: FONTS.mono,
          fontSize: 12,
          fontWeight: 400,
          fontVariantNumeric: "tabular-nums",
          whiteSpace: "nowrap",
        }}
      >
        {item.currency === "$" ? (
          amountText
        ) : (
          <>
            {amountText}
            <Dh /> {fmtAED(Math.abs(item.amount), { decimals: 2 })}
          </>
        )}
      </div>
    </div>
  );
}

function RecurringMerchantIcon({ type, color }) {
  const common = {
    width: 32,
    height: 32,
    borderRadius: 16,
    background: `${color}18`,
    color,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    flexShrink: 0,
  };

  if (type === "patreon" || type === "spotify") {
    return (
      <div style={common}>
        <span
          style={{
            fontFamily: FONTS.ui,
            fontSize: 13,
            fontWeight: 700,
            color,
          }}
        >
          {type === "patreon" ? "P" : "S"}
        </span>
      </div>
    );
  }

  const Icon =
    type === "money" ? Ico.coin : type === "house" ? Ico.home : Ico.food;

  return (
    <div style={common}>
      <Icon size={17} stroke={color} />
    </div>
  );
}

function getRankableSpendOutflows(txs) {
  return getSpendOutflows(txs).filter(
    (t) => !["Transfers", "Investments"].includes(t.category),
  );
}

function rankSpendBy(txs, getKey, limit = 5) {
  const totals = {};
  getRankableSpendOutflows(txs).forEach((t) => {
    const key = getKey(t);
    if (!key) return;
    totals[key] = (totals[key] || 0) + Math.abs(t.amount);
  });
  return Object.entries(totals)
    .map(([label, value]) => ({ label, value }))
    .sort((a, b) => b.value - a.value)
    .slice(0, limit);
}

function SpendTrendCard({ theme, accent, txs, onSeeRawData }) {
  const currentMonthTotal = getSpendOutflows(txs).reduce(
    (sum, t) => sum + Math.abs(t.amount),
    0,
  );
  const months = [
    ...SPEND_CATEGORY_HISTORY,
    {
      month: `${TODAY.monthShort} ${TODAY.year}`,
      total: currentMonthTotal,
      current: true,
    },
  ];
  const completeMonths = SPEND_CATEGORY_HISTORY;
  const avg =
    completeMonths.reduce((s, m) => s + m.total, 0) / completeMonths.length;
  const peak = months.reduce(
    (best, m) => (m.total > best.total ? m : best),
    months[0],
  );

  return (
    <Card theme={theme} style={{ padding: 18 }}>
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "flex-start",
          gap: 12,
        }}
      >
        <div>
          <SectionLabel theme={theme}>Monthly spend trend</SectionLabel>
        </div>
        <div style={{ textAlign: "right", flexShrink: 0 }}>
          <div
            style={{
              fontFamily: FONTS.mono,
              fontSize: 9,
              color: theme.textMute,
              letterSpacing: 1,
              textTransform: "uppercase",
            }}
          >
            Avg
          </div>
          <div
            style={{
              marginTop: 3,
              fontFamily: FONTS.mono,
              fontSize: 12,
              color: theme.text,
              fontVariantNumeric: "tabular-nums",
            }}
          >
            <Dh /> {fmtAED(avg, { compact: true })}
          </div>
        </div>
      </div>

      <div style={{ marginTop: 14 }}>
        <MonthlySpendTrendChart months={months} theme={theme} accent={accent} />
      </div>

      <div
        style={{
          marginTop: 10,
          display: "flex",
          justifyContent: "space-between",
          gap: 10,
          fontFamily: FONTS.mono,
          fontSize: 10,
          color: theme.textMute,
        }}
      >
        <span>
          Peak {peak.month.split(" ")[0]} · <Dh />{" "}
          {fmtAED(peak.total, { compact: true })}
        </span>
        <span>
          {months[0].month.split(" ")[0]}-
          {months[months.length - 1].month.split(" ")[0]}
        </span>
      </div>

      {/* <div style={{ marginTop: 18 }}>
        <SpendCategoryTrendTable
          rows={categoryRows}
          months={months}
          theme={theme}
          accent={accent}
        />
        <div
          style={{
            display: "flex",
            justifyContent: "flex-end",
            paddingTop: 10,
          }}
        >
          <button
            onClick={onSeeRawData}
            style={{
              background: "transparent",
              border: "none",
              padding: "4px 0",
              color: accent,
              cursor: "pointer",
              fontFamily: FONTS.ui,
              fontSize: 12.5,
              fontWeight: 400,
              display: "flex",
              alignItems: "center",
              gap: 3,
            }}
          >
            See raw data <Ico.chevR size={12} stroke={accent} />
          </button>
        </div>
      </div> */}
    </Card>
  );
}

function MonthlySpendTrendChart({ months, theme, accent }) {
  const width = 318;
  const height = 154;
  const left = 34;
  const right = 10;
  const top = 14;
  const bottom = 28;
  const chartW = width - left - right;
  const chartH = height - top - bottom;
  const maxVal = Math.max(...months.map((m) => m.total), 1) * 1.12;
  const step = chartW / months.length;
  const barW = Math.min(28, step * 0.54);

  const points = months.map((m, i) => {
    const x = left + step * i + step / 2;
    const y = top + chartH - (m.total / maxVal) * chartH;
    return {
      x,
      y,
      value: m.total,
      label: m.month.split(" ")[0],
      current: Boolean(m.current),
    };
  });
  const completePoints = points.filter((p) => !p.current);
  const line = "M " + completePoints.map((p) => `${p.x} ${p.y}`).join(" L ");

  return (
    <svg
      width="100%"
      height={height}
      viewBox={`0 0 ${width} ${height}`}
      preserveAspectRatio="xMidYMid meet"
      style={{ display: "block", overflow: "visible" }}
    >
      {[0.33, 0.66, 1].map((g) => {
        const y = top + chartH - chartH * g;
        return (
          <line
            key={g}
            x1={left}
            x2={width - right}
            y1={y}
            y2={y}
            stroke={theme.line}
            strokeWidth={1}
          />
        );
      })}
      {points.map((p) => {
        const barH = (p.value / maxVal) * chartH;
        return (
          <g key={p.label}>
            <rect
              x={p.x - barW / 2}
              y={top + chartH - barH}
              width={barW}
              height={barH}
              rx={4}
              fill={p.current ? theme.textMute : accent}
              opacity={p.current ? 0.26 : 0.16}
            />
            <text
              x={p.x}
              y={height - 8}
              textAnchor="middle"
              fill={theme.textMute}
              fontFamily={FONTS.mono}
              fontSize="9"
            >
              {p.label}
            </text>
          </g>
        );
      })}
      {completePoints.length > 0 && (
        <path
          d={line}
          fill="none"
          stroke={accent}
          strokeWidth={1.7}
          strokeLinecap="round"
          strokeLinejoin="round"
          vectorEffect="non-scaling-stroke"
        />
      )}
      {points.map((p) => (
        <g key={`${p.label}-dot`}>
          <circle
            cx={p.x}
            cy={p.y}
            r={3.2}
            fill={p.current ? theme.textMute : accent}
          />
          <text
            x={p.x}
            y={Math.max(10, p.y - 8)}
            textAnchor="middle"
            fill={p.current ? theme.textMute : theme.text}
            fontFamily={FONTS.mono}
            fontSize="9"
          >
            {fmtAED(p.value, { compact: true })}
          </text>
        </g>
      ))}
    </svg>
  );
}

function SpendCategoryTrendTable({ rows, months, theme, accent }) {
  const cols = `116px repeat(${months.length}, 64px)`;
  const monthLabels = months.map((m) => m.month.split(" ")[0]);

  const cellBase = {
    fontFamily: FONTS.mono,
    fontSize: 10,
    fontVariantNumeric: "tabular-nums",
    display: "flex",
    alignItems: "center",
    justifyContent: "flex-end",
    minWidth: 0,
  };

  return (
    <div
      style={{
        border: `0.5px solid ${theme.line}`,
        borderRadius: 12,
        overflow: "hidden",
      }}
    >
      <div style={{ overflowX: "auto" }}>
        <div style={{ minWidth: 500 }}>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: cols,
              columnGap: 10,
              padding: "8px 12px",
              background: theme.surface2,
              borderBottom: `0.5px solid ${theme.line}`,
            }}
          >
            <div
              style={{
                fontFamily: FONTS.mono,
                fontSize: 8.5,
                color: theme.textMute,
                letterSpacing: 1,
                textTransform: "uppercase",
              }}
            >
              Top category
            </div>
            {monthLabels.map((label) => (
              <div
                key={label}
                style={{
                  ...cellBase,
                  fontSize: 8.5,
                  color: theme.textMute,
                  letterSpacing: 1,
                  textTransform: "uppercase",
                }}
              >
                {label}
              </div>
            ))}
          </div>

          {rows.map((row, i) => {
            const color = SPEND_CATEGORY_COLORS[row.category] || accent;
            return (
              <div
                key={row.category}
                style={{
                  display: "grid",
                  gridTemplateColumns: cols,
                  columnGap: 10,
                  padding: "9px 12px",
                  borderTop: i === 0 ? "none" : `0.5px solid ${theme.line}`,
                  alignItems: "center",
                }}
              >
                <div
                  style={{
                    display: "flex",
                    alignItems: "center",
                    gap: 8,
                    minWidth: 0,
                  }}
                >
                  <span
                    style={{
                      width: 8,
                      height: 8,
                      borderRadius: 2,
                      background: color,
                      flexShrink: 0,
                    }}
                  />
                  <span
                    style={{
                      fontFamily: FONTS.ui,
                      fontSize: 11.5,
                      color: theme.text,
                      fontWeight: 400,
                      whiteSpace: "nowrap",
                      overflow: "hidden",
                      textOverflow: "ellipsis",
                    }}
                  >
                    {row.category}
                  </span>
                </div>
                {row.values.map((value, idx) => (
                  <div
                    key={`${row.category}-${idx}`}
                    style={{ ...cellBase, color: theme.textDim }}
                  >
                    {fmtAED(value, { compact: true })}
                  </div>
                ))}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function getTrailingCompleteMonthRangeLabel(months = SPEND_CATEGORY_HISTORY) {
  const avgMonths = months.slice(-3);
  return `${avgMonths[0].month.split(" ")[0]}-${avgMonths[avgMonths.length - 1].month.split(" ")[0]}`;
}

function ActivityInsightsCard({
  theme,
  accent,
  txs,
  showAskHimma = false,
  onAskHimma,
}) {
  const categoryRows = rankSpendBy(txs, (t) => t.category, 5);
  const merchantRows = rankSpendBy(txs, (t) => t.merchant, 5);
  const insightLists = [
    { title: "Top 5 spend merchants", rows: merchantRows },
    { title: "Top 5 spend categories", rows: categoryRows },
  ];
  const periodLabel = `Avg. [${getTrailingCompleteMonthRangeLabel()}]`;

  return (
    <div>
      <div
        style={{
          display: "flex",
          gap: 12,
          overflowX: "auto",
          padding: "0 0 2px",
          scrollSnapType: "x mandatory",
        }}
      >
        {insightLists.map((list) => (
          <Card
            key={list.title}
            theme={theme}
            style={{
              minWidth: 286,
              maxWidth: 286,
              padding: "0 18px 16px",
              scrollSnapAlign: "start",
            }}
          >
            <InsightRankList
              title={list.title}
              periodLabel={periodLabel}
              rows={list.rows}
              theme={theme}
              accent={accent}
              last
            />
          </Card>
        ))}
      </div>
      {showAskHimma && (
        <button
          onClick={onAskHimma}
          style={{
            marginTop: 12,
            width: "100%",
            background: `${accent}14`,
            color: theme.text,
            border: `0.5px solid ${accent}55`,
            borderRadius: 12,
            padding: "11px 14px",
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            gap: 10,
            fontFamily: FONTS.ui,
            fontSize: 13,
            textAlign: "left",
          }}
        >
          <div
            style={{
              width: 24,
              height: 24,
              borderRadius: 12,
              background: `${accent}22`,
              color: accent,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              flexShrink: 0,
            }}
          >
            <Ico.sparkles size={12} />
          </div>
          <span style={{ flex: 1, color: theme.text }}>
            Ask Himma where to cut
          </span>
          <Ico.chevR size={13} stroke={theme.textDim} />
        </button>
      )}
    </div>
  );
}

function InsightRankList({ title, periodLabel, rows, theme, accent, last }) {
  const max = Math.max(...rows.map((r) => r.value), 1);

  return (
    <div
      style={{
        paddingTop: 14,
        paddingBottom: last ? 0 : 14,
        borderBottom: last ? "none" : `0.5px solid ${theme.line}`,
      }}
    >
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "baseline",
          gap: 10,
          marginBottom: 10,
        }}
      >
        <div
          style={{
            fontFamily: FONTS.mono,
            fontSize: 9.5,
            color: theme.textMute,
            textTransform: "uppercase",
            letterSpacing: 1.2,
          }}
        >
          {title}
        </div>
        <div
          style={{
            fontFamily: FONTS.mono,
            fontSize: 8.5,
            color: theme.textMute,
            whiteSpace: "nowrap",
          }}
        >
          {periodLabel}
        </div>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {rows.map((row, i) => {
          const pct = (row.value / max) * 100;
          return (
            <div
              key={`${title}-${row.label}`}
              style={{ display: "flex", alignItems: "center", gap: 9 }}
            >
              <div
                style={{
                  width: 18,
                  fontFamily: FONTS.mono,
                  fontSize: 9.5,
                  color: theme.textMute,
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {String(i + 1).padStart(2, "0")}
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div
                  style={{
                    display: "flex",
                    justifyContent: "space-between",
                    alignItems: "baseline",
                    gap: 8,
                  }}
                >
                  <span
                    style={{
                      fontSize: 12,
                      color: theme.text,
                      whiteSpace: "nowrap",
                      overflow: "hidden",
                      textOverflow: "ellipsis",
                    }}
                  >
                    {row.label}
                  </span>
                  <span
                    style={{
                      fontFamily: FONTS.mono,
                      fontSize: 10.5,
                      color: theme.textDim,
                      fontVariantNumeric: "tabular-nums",
                      whiteSpace: "nowrap",
                    }}
                  >
                    <Dh /> {fmtAED(row.value, { compact: true })}
                  </span>
                </div>
                <div
                  style={{
                    marginTop: 5,
                    height: 4,
                    borderRadius: 2,
                    background: theme.surface3,
                    overflow: "hidden",
                  }}
                >
                  <div
                    style={{
                      width: `${pct}%`,
                      height: "100%",
                      borderRadius: 2,
                      background: accent,
                      opacity: 0.72,
                    }}
                  />
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// BUDGET BODY — moved out into its own view
// ─────────────────────────────────────────────────────────────
const BUDGET_BREAKDOWN_MONTHS = [
  {
    key: "mar",
    label: "Mar",
    income: 2280,
    expenses: 914,
    net: 1366,
    spent: 914,
    budget: 3000,
  },
  {
    key: "apr",
    label: "Apr",
    income: 2464,
    expenses: 681,
    net: 1783,
    spent: 681,
    budget: 3000,
  },
  {
    key: "may",
    label: "May",
    income: 2502.51,
    expenses: 759.8,
    net: 1742.71,
    spent: 759.8,
    budget: 3000,
  },
];

const BREAKDOWN_EXPENSES = [
  {
    name: "Other",
    percent: 71,
    amount: 539,
    color: "#7389A8",
    category: "Bills",
  },
  {
    name: "Shopping",
    percent: 17.2,
    amount: 131,
    color: "#C48A3A",
    category: "Shopping",
  },
  {
    name: "Groceries",
    percent: 9,
    amount: 69,
    color: "#9BB08A",
    category: "Food",
  },
  {
    name: "Personal care",
    percent: 1.6,
    amount: 13,
    color: "#C97B63",
    category: "tx-down",
  },
];

const BREAKDOWN_MORE_EXPENSES = [
  {
    name: "Transport",
    percent: 0.8,
    amount: 6,
    color: "#7389A8",
    category: "Transport",
  },
  {
    name: "Bills",
    percent: 0.4,
    amount: 3,
    color: "#D4A25A",
    category: "Bills",
  },
];

const BREAKDOWN_INCOME = [
  {
    name: "Paycheck",
    percent: 91,
    amount: 2288,
    color: "#6EA06F",
    category: "Income",
  },
  {
    name: "Income",
    percent: 9,
    amount: 215,
    color: "#53A6A6",
    category: "Income",
  },
  {
    name: "Interest",
    percent: 0,
    amount: 0,
    color: "#D4B27A",
    category: "coin",
  },
  {
    name: "Reimbursement",
    percent: 0,
    amount: 0,
    color: "#7389A8",
    category: "download",
  },
];

const BREAKDOWN_BUDGET_ITEMS = [
  { name: "Drinks & dining", pct: 3, spent: 7, budget: 200, color: "#9BB08A" },
  {
    name: "Everything else",
    pct: 26.9,
    spent: 753,
    budget: 2800,
    color: "#7389A8",
  },
];

const CATEGORY_LAST_MONTH_SPEND = {
  Expense: 4633,
  "Auto & transport": 0,
  "Childcare & education": 0,
  "Drinks & dining": 210,
  Entertainment: 40,
  Financial: 0,
  Groceries: 145,
  Healthcare: 0,
  Household: 70,
  Other: 3616,
  "Personal care": 39,
  Shopping: 446,
};

const CATEGORY_COLOR = {
  Expense: "#7389A8",
  "Auto & transport": "#5C7899",
  "Childcare & education": "#D4A25A",
  "Drinks & dining": "#F2B36D",
  Entertainment: "#8E6CCF",
  Financial: "#53A6A6",
  Groceries: "#6EA06F",
  Healthcare: "#C97B63",
  Household: "#B8A268",
  Other: "#7389A8",
  "Personal care": "#E07A9A",
  Shopping: "#C48A3A",
};

const BUDGET_EDIT_MONTHS = [
  {
    key: "mar",
    label: "Mar",
    monthlyIncome: 2280,
    monthlyBudget: 2800,
    categoryBudgets: {
      "Drinks & dining": { amount: 185, recurring: true },
      Groceries: { amount: 150, recurring: true },
      Shopping: { amount: 500, recurring: true },
    },
  },
  {
    key: "apr",
    label: "Apr",
    monthlyIncome: 2464,
    monthlyBudget: 3000,
    categoryBudgets: {
      "Drinks & dining": { amount: 200, recurring: true },
      Groceries: { amount: 170, recurring: true },
      Shopping: { amount: 540, recurring: true },
    },
  },
  { key: "may", label: "May" },
];

function pastelBudgetTrack(color) {
  const hex = /^#([0-9a-f]{6})$/i.exec(color);
  if (!hex) return color;

  const value = hex[1];
  const amount = 0.72;
  const r = Math.round(
    parseInt(value.slice(0, 2), 16) * (1 - amount) + 255 * amount,
  );
  const g = Math.round(
    parseInt(value.slice(2, 4), 16) * (1 - amount) + 255 * amount,
  );
  const b = Math.round(
    parseInt(value.slice(4, 6), 16) * (1 - amount) + 255 * amount,
  );

  return `rgb(${r}, ${g}, ${b})`;
}

const DRINKS_TRANSACTIONS = [
  { id: "dd-1", merchant: "Xian Famous Foods", date: "Apr 30", amount: -14.32 },
  { id: "dd-2", merchant: "DoorDash", date: "Apr 22", amount: -24 },
  { id: "dd-3", merchant: "Pull Tab Coffee", date: "Apr 20", amount: -16.8 },
  { id: "dd-4", merchant: "Bento Express", date: "Apr 19", amount: -24.32 },
  {
    id: "dd-5",
    merchant: "Partners Coffee Long",
    date: "Apr 13",
    amount: -20.25,
  },
  {
    id: "dd-6",
    merchant: "Popeyes",
    date: "Apr 12",
    amount: -30.15,
    recurring: true,
  },
];

const BREAKDOWN_TRANSACTIONS = [
  {
    id: "bb-t1",
    merchant: "Withdrawal to Bill Pay",
    date: "May 2",
    amount: -402.57,
    category: "Bills",
  },
  {
    id: "bb-t2",
    merchant: "Withdrawal to Bill Pay",
    date: "May 2",
    amount: -82.67,
    category: "Bills",
  },
  {
    id: "bb-t3",
    merchant: "Official Store",
    date: "May 8",
    amount: -57.81,
    category: "Shopping",
  },
];

const SHOPPING_DETAIL = {
  name: "Shopping",
  color: "#C48A3A",
  category: "Shopping",
  months: [
    { label: "Feb", amount: 543 },
    { label: "Mar", amount: 201 },
    { label: "Apr", amount: 446 },
    { label: "May", amount: 131 },
  ],
  transactions: [
    {
      id: "bb-s1",
      merchant: "Official Store",
      date: "May 8",
      amount: -57.81,
      category: "Shopping",
    },
    {
      id: "bb-s2",
      merchant: "Mogmog",
      date: "May 8",
      amount: -57.15,
      category: "Shopping",
    },
    {
      id: "bb-s3",
      merchant: "Steinway Thrift Shop",
      date: "May 2",
      amount: -15.75,
      category: "Shopping",
    },
  ],
};

const usd = (value, decimals = Math.abs(value) < 1000 ? 2 : 0) =>
  `${value < 0 ? "-" : ""}$${Math.abs(value).toLocaleString("en-US", {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  })}`;

const aed = (value, decimals = Math.abs(value) < 1000 ? 2 : 0) => (
  <>
    {value < 0 ? "-" : ""}
    <Dh /> {fmtAED(Math.abs(value), { decimals })}
  </>
);

const BUDGET_INCOME_COLOR = "#6FA267";
const BUDGET_EXPENSE_COLOR = "#4E83B6";

function scaleBreakdownRows(rows, targetTotal) {
  const sourceTotal = rows.reduce((sum, row) => sum + row.amount, 0);
  return rows.map((row) => {
    const amount = sourceTotal ? (row.amount / sourceTotal) * targetTotal : 0;
    return {
      ...row,
      amount,
      percent: targetTotal
        ? Number(((amount / targetTotal) * 100).toFixed(1))
        : 0,
    };
  });
}

function BudgetBody({
  theme,
  accent,
  budgetSetup,
  onEditBudget,
  onOpenCategory,
  onOpenTransaction,
  onBack,
}) {
  const [monthKey, setMonthKey] = React.useState("may");
  const [tab, setTab] = React.useState("expenses");
  const [showMonths, setShowMonths] = React.useState(true);
  const month = BUDGET_BREAKDOWN_MONTHS.find((m) => m.key === monthKey);
  const monthlyBudget = budgetSetup?.monthlyBudget || month.budget;
  const expenseRows = scaleBreakdownRows(BREAKDOWN_EXPENSES, month.expenses);
  const moreExpenseRows = scaleBreakdownRows(
    BREAKDOWN_MORE_EXPENSES,
    month.expenses,
  );
  const incomeRows = scaleBreakdownRows(BREAKDOWN_INCOME, month.income);
  const spent = month.spent;
  const explicitRows = Object.entries(budgetSetup?.categoryBudgets || {}).map(
    ([name, item]) => ({
      name,
      spent: CATEGORY_LAST_MONTH_SPEND[name] === 210 ? 7 : 0,
      budget: Number(item.amount) || 0,
      color: CATEGORY_COLOR[name] || "#7389A8",
    }),
  );
  const sampleRows = explicitRows.some((row) => row.name === "Drinks & dining")
    ? []
    : [
        {
          name: "Drinks & dining",
          spent: 7,
          budget: 200,
          color: CATEGORY_COLOR["Drinks & dining"],
        },
      ];
  const categoryRows = [...explicitRows, ...sampleRows];
  const explicitBudget = categoryRows.reduce((sum, row) => sum + row.budget, 0);
  const explicitSpent = categoryRows.reduce((sum, row) => sum + row.spent, 0);
  const budgetRows = [
    ...categoryRows,
    {
      name: "Everything else",
      spent: Math.max(0, spent - explicitSpent),
      budget: Math.max(0, monthlyBudget - explicitBudget),
      color: "#7389A8",
    },
  ].map((row) => ({
    ...row,
    pct: row.budget ? Number(((row.spent / row.budget) * 100).toFixed(1)) : 0,
  }));
  const usedPct = monthlyBudget ? (spent / monthlyBudget) * 100 : 0;
  return (
    <div
      style={{
        padding: "0 16px 18px",
        display: "flex",
        flexDirection: "column",
        gap: 14,
      }}
    >
      <BudgetPageHeader
        theme={theme}
        accent={accent}
        monthsOpen={showMonths}
        onBack={onBack}
        onCalendar={() => setShowMonths((v) => !v)}
      />

      {showMonths && (
        <Card theme={theme} style={{ padding: 14 }}>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(3, 1fr)",
              gap: 8,
            }}
          >
            {BUDGET_BREAKDOWN_MONTHS.map((m) => (
              <button
                key={m.key}
                onClick={() => setMonthKey(m.key)}
                style={{
                  background:
                    m.key === monthKey ? theme.surface2 : "transparent",
                  border: `0.5px solid ${m.key === monthKey ? accent : theme.line2}`,
                  borderRadius: 12,
                  padding: 10,
                  cursor: "pointer",
                  color: theme.text,
                }}
              >
                <TinyMonthBars
                  income={m.income}
                  expenses={m.expenses}
                  selected={m.key === monthKey}
                />
                <div
                  style={{
                    marginTop: 8,
                    fontFamily: FONTS.mono,
                    fontSize: 11,
                    color: m.key === monthKey ? theme.text : theme.textMute,
                  }}
                >
                  {m.label}
                </div>
              </button>
            ))}
          </div>
          <div
            style={{
              marginTop: 14,
              display: "flex",
              flexDirection: "column",
              gap: 9,
            }}
          >
            <CashFlowRow
              label="Income"
              value={usd(month.income)}
              color={BUDGET_INCOME_COLOR}
              theme={theme}
            />
            <CashFlowRow
              label="Expenses"
              value={usd(-month.expenses)}
              color={BUDGET_EXPENSE_COLOR}
              theme={theme}
            />
            <div style={{ height: 1, background: theme.line, opacity: 0.55 }} />
            <CashFlowRow
              label="Net Cash Flow"
              value={usd(month.net)}
              theme={theme}
            />
          </div>
        </Card>
      )}

      <Card theme={theme} style={{ padding: 0, overflow: "hidden" }}>
        <div style={{ padding: "17px 18px 0" }}>
          <SectionLabel theme={theme}>Category Breakdown</SectionLabel>
        </div>
        <div style={{ padding: 16 }}>
          <SegmentedTabs
            active={tab}
            onChange={setTab}
            theme={theme}
            accent={accent}
          />
          {tab === "expenses" && (
            <BreakdownExpensesTab
              theme={theme}
              accent={accent}
              rows={expenseRows}
              moreRows={moreExpenseRows}
              total={month.expenses}
              onOpenCategory={(item) =>
                onOpenCategory({
                  ...SHOPPING_DETAIL,
                  name: item.name,
                  color: item.color,
                  category: item.category,
                })
              }
            />
          )}
          {tab === "budget" && (
            <BreakdownBudgetTab
              theme={theme}
              accent={accent}
              usedPct={usedPct}
              spent={spent}
              budget={monthlyBudget}
              items={budgetRows}
              onEditBudget={onEditBudget}
              onOpenCategory={(item) =>
                onOpenCategory({
                  name: item.name,
                  color: item.color,
                  category: item.name === "Drinks & dining" ? "Food" : "Bills",
                  months: [
                    { label: "Dec", amount: 120 },
                    { label: "Jan", amount: 164 },
                    { label: "Feb", amount: 188 },
                    { label: "Mar", amount: 155 },
                    {
                      label: "Apr",
                      amount:
                        CATEGORY_LAST_MONTH_SPEND[item.name] || item.spent,
                    },
                    { label: "May", amount: item.spent },
                  ],
                  transactions:
                    item.name === "Drinks & dining"
                      ? DRINKS_TRANSACTIONS
                      : BREAKDOWN_TRANSACTIONS,
                })
              }
            />
          )}
          {tab === "income" && (
            <BreakdownIncomeTab
              theme={theme}
              accent={accent}
              rows={incomeRows}
              total={month.income}
              onOpenCategory={(item) =>
                onOpenCategory({
                  ...SHOPPING_DETAIL,
                  name: item.name,
                  color: item.color,
                  category: "Income",
                })
              }
            />
          )}
        </div>
      </Card>

      <LargestTransactionsCard
        theme={theme}
        accent={accent}
        onOpenTransaction={onOpenTransaction}
      />
    </div>
  );
}

function BudgetPageHeader({ theme, accent, monthsOpen, onBack, onCalendar }) {
  return (
    <div
      style={{
        position: "sticky",
        top: 0,
        zIndex: 30,
        margin: "0 -16px",
        padding: "12px 18px 10px",
        display: "grid",
        gridTemplateColumns: "36px 1fr 36px",
        alignItems: "center",
        background: `linear-gradient(to bottom, ${theme.bg} 88%, ${theme.bg}00)`,
        backdropFilter: "blur(16px)",
      }}
    >
      <button
        onClick={onBack}
        aria-label="Back to Activity"
        style={budgetIconButtonStyle(theme)}
      >
        <Ico.arrowL size={20} stroke={theme.text} />
      </button>
      <div
        style={{
          justifySelf: "center",
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 14,
          fontWeight: 600,
          padding: "6px 8px",
        }}
      >
        BREAKDOWN & BUDGET
      </div>
      <button
        onClick={onCalendar}
        aria-label="Toggle months"
        style={budgetIconButtonStyle(theme, monthsOpen)}
      >
        <Ico.calendar size={17} stroke={monthsOpen ? accent : theme.text} />
      </button>
    </div>
  );
}

function budgetIconButtonStyle(theme, active = false) {
  return {
    width: 32,
    height: 32,
    border: "none",
    background: active ? theme.surface : "transparent",
    borderRadius: 16,
    color: theme.text,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    cursor: "pointer",
  };
}

function TinyMonthBars({ income, expenses, selected }) {
  const max = Math.max(income, expenses);
  const incomeColor = selected ? BUDGET_INCOME_COLOR : "#A9B6A5";
  const expenseColor = selected ? BUDGET_EXPENSE_COLOR : "#A3B0BD";
  return (
    <div
      style={{
        height: 34,
        display: "flex",
        alignItems: "flex-end",
        justifyContent: "center",
        gap: 5,
      }}
    >
      <div
        style={{
          width: 10,
          height: `${Math.max(8, (income / max) * 30)}px`,
          borderRadius: 3,
          background: incomeColor,
        }}
      />
      <div
        style={{
          width: 10,
          height: `${Math.max(8, (expenses / max) * 30)}px`,
          borderRadius: 3,
          background: expenseColor,
        }}
      />
    </div>
  );
}

function CashFlowRow({ label, value, color, theme }) {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "1fr auto",
        alignItems: "center",
        gap: 12,
      }}
    >
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: 8,
          fontFamily: FONTS.ui,
          fontSize: 13,
          color: theme.text,
        }}
      >
        {color && (
          <span
            style={{
              width: 8,
              height: 8,
              borderRadius: 999,
              background: color,
            }}
          />
        )}
        {label}
      </div>
      <div
        style={{
          fontFamily: FONTS.mono,
          fontSize: 13,
          fontWeight: 400,
          color: theme.text,
          fontVariantNumeric: "tabular-nums",
        }}
      >
        {value}
      </div>
    </div>
  );
}

function SegmentedTabs({ active, onChange, theme, accent }) {
  const tabs = [
    ["expenses", "Expenses"],
    ["budget", "Budget"],
    ["income", "Income"],
  ];
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(3, 1fr)",
        background: theme.surface2,
        border: `0.5px solid ${theme.line}`,
        borderRadius: 999,
        padding: 3,
      }}
    >
      {tabs.map(([key, label]) => (
        <button
          key={key}
          onClick={() => onChange(key)}
          style={{
            border: "none",
            borderRadius: 999,
            padding: "8px 0",
            background: active === key ? accent : "transparent",
            color: active === key ? theme.bg : theme.textDim,
            fontFamily: FONTS.ui,
            fontSize: 12,
            cursor: "pointer",
          }}
        >
          {label}
        </button>
      ))}
    </div>
  );
}

function BreakdownExpensesTab({
  theme,
  accent,
  rows,
  moreRows,
  total,
  onOpenCategory,
}) {
  const [expanded, setExpanded] = React.useState(false);
  const visibleRows = expanded ? [...rows, ...moreRows] : rows;
  return (
    <div style={{ marginTop: 18 }}>
      <div style={{ display: "flex", justifyContent: "center" }}>
        <Donut
          segments={rows.map((x) => ({
            key: x.name,
            value: x.amount,
            color: x.color,
          }))}
          size={154}
          stroke={18}
          theme={theme}
          centerValue={
            <>
              <Dh /> {fmtAED(total)}
            </>
          }
          centerLabel="Spent this month"
          centerLabelBelow
          centerLabelStyle={{
            fontFamily: FONTS.ui,
            fontSize: 10,
            letterSpacing: 0,
            textTransform: "none",
            color: "#000",
            fontWeight: 400,
          }}
        />
      </div>
      <BreakdownRows
        rows={visibleRows}
        theme={theme}
        accent={accent}
        subtitle="expenses"
        onClick={onOpenCategory}
      />
      <button
        onClick={() => setExpanded((v) => !v)}
        style={{
          width: "100%",
          marginTop: 16,
          border: `0.5px solid ${theme.line2}`,
          background: "transparent",
          borderRadius: 999,
          padding: "12px",
          color: theme.text,
          fontFamily: FONTS.mono,
          fontSize: 11,
          letterSpacing: 1.3,
          textTransform: "uppercase",
          cursor: "pointer",
        }}
      >
        {expanded ? "Show Less" : "See More"}
      </button>
    </div>
  );
}

function BreakdownIncomeTab({ theme, accent, rows, total, onOpenCategory }) {
  return (
    <div style={{ marginTop: 18 }}>
      <div style={{ display: "flex", justifyContent: "center" }}>
        <Donut
          segments={rows.map((x) => ({
            key: x.name,
            value: Math.max(1, x.amount),
            color: x.color,
          }))}
          size={154}
          stroke={18}
          theme={theme}
          centerValue={usd(total)}
          centerLabel="earned this month"
          centerLabelBelow
          centerLabelStyle={{
            fontFamily: FONTS.ui,
            fontSize: 10,
            letterSpacing: 0,
            textTransform: "none",
            color: "#000",
            fontWeight: 400,
          }}
        />
      </div>
      <BreakdownRows
        rows={rows}
        theme={theme}
        accent={accent}
        subtitle="income"
        income
        onClick={onOpenCategory}
      />
    </div>
  );
}

function BreakdownRows({
  rows,
  theme,
  accent,
  subtitle,
  income = false,
  onClick,
}) {
  return (
    <div
      style={{
        marginTop: 10,
        display: "flex",
        flexDirection: "column",
        gap: 10,
      }}
    >
      {rows.map((row) => (
        <button
          key={row.name}
          onClick={() => onClick(row)}
          style={{
            border: "none",
            background: "transparent",
            display: "grid",
            gridTemplateColumns: "34px 1fr auto",
            alignItems: "center",
            gap: 10,
            padding: "7px 0",
            color: theme.text,
            textAlign: "left",
            cursor: "pointer",
          }}
        >
          <div
            style={{
              width: 34,
              height: 34,
              borderRadius: 999,
              background: row.color,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: theme.bg,
            }}
          >
            <CategoryIcon
              category={row.category}
              theme={{ ...theme, surface2: "transparent", line: "transparent" }}
              accent={accent}
              size={24}
            />
          </div>
          <span>
            <span
              style={{
                display: "block",
                fontFamily: FONTS.ui,
                fontSize: 13,
                fontWeight: 400,
              }}
            >
              {row.name}
            </span>
            <span
              style={{
                display: "block",
                fontFamily: FONTS.ui,
                fontSize: 11,
                color: theme.textMute,
                marginTop: 2,
              }}
            >
              {row.percent}% of {subtitle}
            </span>
          </span>
          <span
            style={{
              fontFamily: FONTS.mono,
              fontSize: 13,
              color: theme.text,
              fontVariantNumeric: "tabular-nums",
            }}
          >
            {income && row.amount > 0 ? "+" : ""}
            {aed(row.amount, 0)}
          </span>
        </button>
      ))}
    </div>
  );
}

function BreakdownBudgetTab({
  theme,
  accent,
  usedPct,
  spent,
  budget,
  items,
  onEditBudget,
  onOpenCategory,
}) {
  return (
    <div style={{ marginTop: 18 }}>
      <SemiGauge pct={usedPct} theme={theme} accent={accent} />
      <div style={{ textAlign: "center", marginTop: -48, marginBottom: 18 }}>
        <div
          style={{
            fontFamily: FONTS.ui,
            fontSize: 12,
            color: theme.textMute,
            fontWeight: 400,
          }}
        >
          {usedPct.toFixed(1)}%
        </div>
        <div
          style={{
            marginTop: 2,
            fontFamily: FONTS.mono,
            fontSize: 22,
            color: theme.text,
          }}
        >
          {aed(spent, 0)}
        </div>
        <div
          style={{
            marginTop: 1,
            fontFamily: FONTS.ui,
            fontSize: 12,
            color: "#000",
          }}
        >
          {aed(budget, 0)} budget
        </div>
      </div>
      <div
        style={{
          marginTop: 12,
          display: "flex",
          flexDirection: "column",
          gap: 10,
        }}
      >
        {items.map((item) => (
          <button
            key={item.name}
            onClick={() => onOpenCategory(item)}
            style={{
              width: "100%",
              textAlign: "left",
              border: `0.5px solid ${theme.line}`,
              borderRadius: 14,
              padding: 12,
              background: "#fff",
              color: theme.text,
              cursor: "pointer",
            }}
          >
            <div
              style={{
                display: "flex",
                alignItems: "center",
                gap: 8,
                color: theme.text,
                fontFamily: FONTS.ui,
                fontSize: 13,
                fontWeight: 400,
              }}
            >
              <div
                style={{
                  width: 24,
                  height: 24,
                  borderRadius: 999,
                  background: item.color,
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                  color: theme.bg,
                  flexShrink: 0,
                }}
              >
                <CategoryIcon
                  category={item.name === "Drinks & dining" ? "Food" : "Bills"}
                  theme={{
                    ...theme,
                    surface2: "transparent",
                    line: "transparent",
                  }}
                  accent={accent}
                  size={17}
                />
              </div>
              <span>{item.name}</span>
            </div>
            <div
              style={{
                height: 8,
                background: pastelBudgetTrack(item.color),
                borderRadius: 999,
                overflow: "hidden",
                marginTop: 10,
              }}
            >
              <div
                style={{
                  width: `${item.pct}%`,
                  height: "100%",
                  background: item.color,
                }}
              />
            </div>
            <div
              style={{
                marginTop: 7,
                display: "flex",
                justifyContent: "space-between",
                gap: 10,
                color: theme.textMute,
                fontFamily: FONTS.ui,
                fontSize: 12,
                fontWeight: 400,
              }}
            >
              <span>{item.pct}%</span>
              <span
                style={{
                  fontFamily: FONTS.ui,
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {aed(item.spent, 0)} of {aed(item.budget, 0)}
              </span>
            </div>
          </button>
        ))}
      </div>
      <button
        onClick={onEditBudget}
        style={{
          margin: "16px auto 0",
          display: "block",
          border: "none",
          borderBottom: `0.5px solid ${accent}`,
          background: "transparent",
          color: accent,
          fontFamily: FONTS.mono,
          fontSize: 12,
          fontWeight: 600,
          letterSpacing: 1.2,
          textTransform: "uppercase",
          padding: "0 0 3px",
          cursor: "pointer",
        }}
      >
        <Ico.compose size={12} /> Edit Budget
      </button>
    </div>
  );
}

function SemiGauge({ pct, theme, accent }) {
  const clamped = Math.max(0, Math.min(100, pct));
  return (
    <svg
      width="100%"
      height="118"
      viewBox="0 0 220 118"
      style={{ display: "block" }}
    >
      <path
        d="M30 106 A80 80 0 0 1 190 106"
        fill="none"
        stroke={theme.line2}
        strokeWidth="18"
        strokeLinecap="round"
      />
      <path
        d="M30 106 A80 80 0 0 1 190 106"
        fill="none"
        stroke={accent}
        strokeWidth="18"
        strokeLinecap="round"
        pathLength="100"
        strokeDasharray={`${clamped} ${100 - clamped}`}
      />
    </svg>
  );
}

function LargestTransactionsCard({ theme, accent, onOpenTransaction }) {
  return (
    <Card theme={theme} style={{ padding: 18 }}>
      <SectionLabel theme={theme}>Largest Transactions</SectionLabel>
      <div
        style={{
          marginTop: 14,
          display: "flex",
          flexDirection: "column",
          gap: 12,
        }}
      >
        {BREAKDOWN_TRANSACTIONS.map((tx) => (
          <button
            key={tx.id}
            onClick={() => onOpenTransaction("t5")}
            style={{
              border: "none",
              background: "transparent",
              display: "grid",
              gridTemplateColumns: "34px 1fr auto",
              gap: 10,
              alignItems: "center",
              padding: 0,
              textAlign: "left",
              cursor: "pointer",
              color: theme.text,
            }}
          >
            <CategoryIcon
              category={tx.category}
              theme={theme}
              accent={accent}
              size={34}
            />
            <span style={{ minWidth: 0 }}>
              <span
                style={{
                  display: "block",
                  fontFamily: FONTS.ui,
                  fontSize: 13,
                  fontWeight: 400,
                  whiteSpace: "nowrap",
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                }}
              >
                {tx.merchant}
              </span>
              <span
                style={{
                  display: "block",
                  marginTop: 2,
                  fontFamily: FONTS.ui,
                  fontSize: 11,
                  color: theme.textMute,
                }}
              >
                {tx.date}
              </span>
            </span>
            <span
              style={{
                fontFamily: FONTS.mono,
                fontSize: 12.5,
                fontVariantNumeric: "tabular-nums",
              }}
            >
              {aed(tx.amount)}
            </span>
          </button>
        ))}
      </div>
    </Card>
  );
}

function BudgetCategoryDetailSheet({
  detail,
  theme,
  accent,
  onClose,
  onSetBudget,
  onOpenTransaction,
}) {
  const [month, setMonth] = React.useState("May");
  const [sort, setSort] = React.useState("NEWEST");
  const rows =
    sort === "NEWEST"
      ? detail.transactions
      : [...detail.transactions].reverse();
  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 125,
        background: "rgba(0,0,0,0.55)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          maxHeight: "86%",
          overflow: "auto",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "14px 18px 34px",
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "34px 1fr 34px",
            alignItems: "center",
          }}
        >
          <span />
          <SectionLabel theme={theme} style={{ textAlign: "center" }}>
            Category Detail
          </SectionLabel>
          <button onClick={onClose} style={budgetIconButtonStyle(theme)}>
            <Ico.close size={16} />
          </button>
        </div>
        <div
          style={{
            marginTop: 18,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "center",
            gap: 10,
            textAlign: "center",
          }}
        >
          <div
            style={{
              width: 46,
              height: 46,
              borderRadius: 999,
              background: detail.color,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <CategoryIcon
              category={detail.category}
              theme={{ ...theme, surface2: "transparent", line: "transparent" }}
              accent={accent}
              size={30}
            />
          </div>
          <div
            style={{
              fontFamily: FONTS.ui,
              fontSize: 22,
              color: theme.text,
              textAlign: "center",
            }}
          >
            {detail.name}
          </div>
        </div>
        <button
          onClick={onSetBudget}
          style={{
            width: "100%",
            marginTop: 16,
            border: `0.5px solid ${theme.line2}`,
            borderRadius: 14,
            background: "transparent",
            padding: "13px 14px",
            color: theme.text,
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            fontFamily: FONTS.ui,
            fontSize: 13,
            cursor: "pointer",
          }}
        >
          Set a budget <Ico.compose size={15} />
        </button>
        <div
          style={{
            marginTop: 16,
            display: "flex",
            gap: 10,
            overflowX: "auto",
            paddingBottom: 2,
          }}
        >
          {detail.months.map((m) => (
            <button
              key={m.label}
              onClick={() => setMonth(m.label)}
              style={{
                minWidth: 114,
                height: 64,
                border: "none",
                borderRadius: 8,
                background: month === m.label ? detail.color : theme.surface2,
                color: month === m.label ? theme.bg : theme.textMute,
                display: "flex",
                flexDirection: "column",
                alignItems: "center",
                justifyContent: "center",
                gap: 5,
                flex: "0 0 auto",
                cursor: "pointer",
              }}
            >
              <span
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 15,
                  color: month === m.label ? theme.bg : theme.textMute,
                  fontVariantNumeric: "tabular-nums",
                  lineHeight: 1,
                }}
              >
                {aed(m.amount, 0)}
              </span>
              <span
                style={{
                  fontFamily: FONTS.ui,
                  fontSize: 12,
                  color: month === m.label ? theme.bg : theme.textMute,
                  lineHeight: 1,
                }}
              >
                {m.label}
              </span>
            </button>
          ))}
        </div>
        <div
          style={{
            marginTop: 14,
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <span
            style={{
              fontFamily: FONTS.ui,
              fontSize: 12,
              color: theme.textMute,
            }}
          >
            Sort by
          </span>
          <button
            onClick={() =>
              setSort((v) => (v === "NEWEST" ? "OLDEST" : "NEWEST"))
            }
            style={{
              border: `0.5px solid ${theme.line2}`,
              background: "transparent",
              borderRadius: 999,
              padding: "6px 10px",
              color: theme.text,
              fontFamily: FONTS.ui,
              fontSize: 12,
              display: "flex",
              gap: 5,
              alignItems: "center",
              cursor: "pointer",
            }}
          >
            {sort} <Ico.chevD size={12} />
          </button>
        </div>
        <div
          style={{
            marginTop: 14,
            display: "flex",
            flexDirection: "column",
            gap: 12,
          }}
        >
          {rows.map((tx) => (
            <button
              key={tx.id}
              onClick={() => onOpenTransaction("t5")}
              style={{
                border: "none",
                background: "transparent",
                display: "grid",
                gridTemplateColumns: "34px 1fr auto",
                alignItems: "center",
                gap: 10,
                color: theme.text,
                textAlign: "left",
                padding: 0,
              }}
            >
              <CategoryIcon
                category={detail.category}
                theme={theme}
                accent={accent}
                size={34}
              />
              <span>
                <span
                  style={{
                    display: "flex",
                    alignItems: "center",
                    gap: 6,
                    fontFamily: FONTS.ui,
                    fontSize: 13,
                    fontWeight: 600,
                  }}
                >
                  {tx.merchant}
                  {tx.recurring && <Ico.refresh size={12} stroke={accent} />}
                </span>
                <span
                  style={{
                    display: "block",
                    marginTop: 2,
                    fontFamily: FONTS.ui,
                    fontSize: 11,
                    color: theme.textMute,
                  }}
                >
                  {tx.date}
                </span>
              </span>
              <span style={{ fontFamily: FONTS.mono, fontSize: 12.5 }}>
                {usd(tx.amount)}
              </span>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// RAW SPEND BODY — day x month matrix
// ─────────────────────────────────────────────────────────────
function RawSpendBody({ theme, accent }) {
  const matrix = getRawSpendMatrix();
  const months = matrix.months;
  const total = months.reduce((s, m) => s + m.total, 0);
  const colTemplate = `54px repeat(${months.length}, 74px) 76px`;
  const minWidth = 54 + months.length * 74 + 76;

  return (
    <>
      <div style={{ padding: "0 16px 14px" }}>
        <Card theme={theme} style={{ padding: 18 }}>
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              alignItems: "flex-start",
              gap: 12,
            }}
          >
            <div
              style={{
                marginTop: 6,
                fontFamily: FONTS.ui,
                fontSize: 12.5,
                color: theme.textDim,
                lineHeight: 1.45,
              }}
            >
              Daily raw outflow totals for the same six full months used in the
              trend table.
            </div>
          </div>
        </Card>
      </div>

      <div style={{ padding: "0 16px 16px" }}>
        <Card theme={theme} padded={false} style={{ overflow: "hidden" }}>
          <div style={{ overflowX: "auto" }}>
            <div style={{ minWidth }}>
              <div
                style={{
                  display: "grid",
                  gridTemplateColumns: colTemplate,
                  columnGap: 10,
                  padding: "8px 12px",
                  background: theme.surface2,
                  borderBottom: `0.5px solid ${theme.line}`,
                }}
              >
                <RawHeaderCell theme={theme} align="left">
                  Day
                </RawHeaderCell>
                {months.map((m) => (
                  <RawHeaderCell key={m.key} theme={theme}>
                    {m.label}
                  </RawHeaderCell>
                ))}
                <RawHeaderCell theme={theme}>Row total</RawHeaderCell>
              </div>

              {matrix.rows.map((row, i) => {
                const rowTotal = row.values.reduce((s, v) => s + (v || 0), 0);
                return (
                  <div
                    key={row.day}
                    style={{
                      display: "grid",
                      gridTemplateColumns: colTemplate,
                      columnGap: 10,
                      padding: "8px 12px",
                      borderTop: i === 0 ? "none" : `0.5px solid ${theme.line}`,
                      alignItems: "center",
                    }}
                  >
                    <div
                      style={{
                        fontFamily: FONTS.mono,
                        fontSize: 10.5,
                        color: theme.text,
                        fontWeight: 600,
                        fontVariantNumeric: "tabular-nums",
                      }}
                    >
                      {row.day}
                    </div>
                    {row.values.map((value, idx) => (
                      <RawValueCell
                        key={`${row.day}-${months[idx].key}`}
                        value={value}
                        theme={theme}
                      />
                    ))}
                    <RawValueCell value={rowTotal} theme={theme} strong />
                  </div>
                );
              })}

              <div
                style={{
                  display: "grid",
                  gridTemplateColumns: colTemplate,
                  columnGap: 10,
                  padding: "9px 12px",
                  background: `${accent}10`,
                  borderTop: `0.5px solid ${theme.line2}`,
                }}
              >
                <RawHeaderCell theme={theme} align="left">
                  Total
                </RawHeaderCell>
                {months.map((m) => (
                  <RawValueCell
                    key={`${m.key}-total`}
                    value={m.total}
                    theme={theme}
                    strong
                  />
                ))}
                <RawValueCell value={total} theme={theme} strong />
              </div>
            </div>
          </div>
        </Card>
      </div>
    </>
  );
}

function RawHeaderCell({ children, theme, align = "right" }) {
  return (
    <div
      style={{
        fontFamily: FONTS.mono,
        fontSize: 8.5,
        color: theme.textMute,
        letterSpacing: 1,
        textTransform: "uppercase",
        display: "flex",
        alignItems: "center",
        justifyContent: align === "left" ? "flex-start" : "flex-end",
      }}
    >
      {children}
    </div>
  );
}

function RawValueCell({ value, theme, strong }) {
  return (
    <div
      style={{
        fontFamily: FONTS.mono,
        fontSize: 10,
        color:
          value == null ? theme.textMute : strong ? theme.text : theme.textDim,
        fontWeight: strong ? 600 : 400,
        fontVariantNumeric: "tabular-nums",
        display: "flex",
        alignItems: "center",
        justifyContent: "flex-end",
        whiteSpace: "nowrap",
      }}
    >
      {value == null ? "-" : fmtAED(value, { compact: value >= 1000 })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// ALL BODY (full transaction list with filters)
// ─────────────────────────────────────────────────────────────
const SORT_OPTIONS = [
  { key: "newest", label: "NEWEST" },
  { key: "oldest", label: "OLDEST" },
  { key: "highest", label: "HIGHEST VALUE" },
];

function AllBody({ theme, accent, txs, tags, onTxClick, onBack }) {
  const [categories, setCategories] = React.useState([]);
  const [accounts, setAccounts] = React.useState(() =>
    getDefaultAccountFilter(),
  );
  const [q, setQ] = React.useState("");
  const [searchOpen, setSearchOpen] = React.useState(false);
  const [sortKey, setSortKey] = React.useState("newest");
  const [sortOpen, setSortOpen] = React.useState(false);
  const [dateFilter, setDateFilter] = React.useState(() => ({
    key: "all",
    start: "",
    end: "",
  }));
  const [dateSheetOpen, setDateSheetOpen] = React.useState(false);
  const [categorySheetOpen, setCategorySheetOpen] = React.useState(false);
  const [accountSheetOpen, setAccountSheetOpen] = React.useState(false);
  const dateAnchor = React.useMemo(() => getDateFilterAnchor(txs), [txs]);
  const dateRange = React.useMemo(
    () => getDateFilterRange(dateFilter, dateAnchor),
    [dateFilter, dateAnchor],
  );

  const filtered = txs
    .filter(
      (t) =>
        (categories.length === 0 || categories.includes(t.category)) &&
        isTxInAccountFilter(t, accounts) &&
        isTxInDateRange(t, dateRange) &&
        (q === "" || t.merchant.toLowerCase().includes(q.toLowerCase())),
    )
    .sort((a, b) => sortTransactions(a, b, sortKey));
  const activeSort = SORT_OPTIONS.find((option) => option.key === sortKey);

  return (
    <>
      <TransactionsListHeader
        theme={theme}
        onBack={onBack}
        searchOpen={searchOpen}
        onToggleSearch={() => {
          setSearchOpen((open) => !open);
          if (searchOpen) setQ("");
        }}
      />

      {(searchOpen || q) && (
        <div style={{ padding: "0 18px 12px" }}>
          <div
            style={{
              background: theme.surface,
              border: `0.5px solid ${theme.line}`,
              borderRadius: 14,
              padding: "10px 14px",
              display: "flex",
              gap: 10,
              alignItems: "center",
            }}
          >
            <Ico.search size={15} stroke={theme.textMute} />
            <input
              value={q}
              onChange={(e) => setQ(e.target.value)}
              placeholder="Search merchants"
              autoFocus
              style={{
                flex: 1,
                background: "transparent",
                border: "none",
                outline: "none",
                color: theme.text,
                fontSize: 13,
                fontFamily: FONTS.ui,
              }}
            />
            <button
              onClick={() => {
                setQ("");
                setSearchOpen(false);
              }}
              style={{
                background: "transparent",
                border: "none",
                color: theme.textMute,
                cursor: "pointer",
                padding: 0,
              }}
            >
              <Ico.close size={13} />
            </button>
          </div>
        </div>
      )}

      {/* Date filter */}
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          gap: 6,
          padding: "0 16px 12px",
        }}
      >
        <div
          style={{
            display: "inline-flex",
            alignItems: "center",
            gap: 6,
            minWidth: 0,
            overflowX: "auto",
            flex: 1,
          }}
        >
          <FilterPill
            theme={theme}
            label={getDateFilterLabel(dateFilter)}
            onClick={() => setDateSheetOpen(true)}
          />
          <FilterPill
            theme={theme}
            label={getCategoryFilterLabel(categories)}
            onClick={() => setCategorySheetOpen(true)}
          />
          <FilterPill
            theme={theme}
            label={getAccountFilterLabel(accounts)}
            onClick={() => setAccountSheetOpen(true)}
          />
        </div>
      </div>

      <div style={{ position: "relative", padding: "0 18px 14px" }}>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "flex-end",
            gap: 4,
            color: theme.textMute,
            fontFamily: FONTS.mono,
            fontSize: 10.5,
            letterSpacing: 1.1,
            textTransform: "uppercase",
          }}
        >
          Sort by
          <button
            type="button"
            onClick={() => setSortOpen((open) => !open)}
            style={{
              border: "none",
              background: "transparent",
              color: theme.text,
              cursor: "pointer",
              padding: "2px 0",
              fontFamily: FONTS.mono,
              fontSize: 10.5,
              letterSpacing: 1.1,
              textDecoration: "underline",
              textUnderlineOffset: 3,
              display: "inline-flex",
              alignItems: "center",
              gap: 2,
            }}
          >
            {activeSort?.label || "NEWEST"} <Ico.chevD size={11} />
          </button>
        </div>
        {sortOpen && (
          <SortMenu
            theme={theme}
            value={sortKey}
            onPick={(next) => {
              setSortKey(next);
              setSortOpen(false);
            }}
          />
        )}
      </div>

      <TransactionsFeed
        theme={theme}
        accent={accent}
        txs={filtered}
        tags={tags}
        onTxClick={onTxClick}
      />
      {dateSheetOpen && (
        <DateFilterSheet
          theme={theme}
          accent={accent}
          value={dateFilter}
          anchorDate={dateAnchor}
          onClose={() => setDateSheetOpen(false)}
          onApply={(next) => {
            setDateFilter(next);
            setDateSheetOpen(false);
          }}
          onClear={() => {
            setDateFilter({ key: "all", start: "", end: "" });
            setDateSheetOpen(false);
          }}
        />
      )}
      {categorySheetOpen && (
        <CategoryFilterSheet
          theme={theme}
          accent={accent}
          value={categories}
          onClose={() => setCategorySheetOpen(false)}
          onApply={(next) => {
            setCategories(next);
            setCategorySheetOpen(false);
          }}
          onClear={() => {
            setCategories([]);
            setCategorySheetOpen(false);
          }}
        />
      )}
      {accountSheetOpen && (
        <AccountFilterSheet
          theme={theme}
          accent={accent}
          value={accounts}
          onClose={() => setAccountSheetOpen(false)}
          onApply={(next) => {
            setAccounts(next);
            setAccountSheetOpen(false);
          }}
          onClear={() => {
            setAccounts(getDefaultAccountFilter());
            setAccountSheetOpen(false);
          }}
        />
      )}
    </>
  );
}

function FilterPill({ theme, label, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        height: 34,
        padding: "0 13px",
        borderRadius: 17,
        border: `0.5px solid ${theme.line2}`,
        background: theme.surface,
        color: theme.text,
        fontFamily: FONTS.mono,
        fontSize: 10.5,
        letterSpacing: 1.2,
        textTransform: "uppercase",
        display: "inline-flex",
        alignItems: "center",
        gap: 7,
        cursor: "pointer",
        whiteSpace: "nowrap",
        flexShrink: 0,
      }}
    >
      {label} <Ico.chevD size={12} />
    </button>
  );
}

function TransactionsListHeader({ theme, onBack, searchOpen, onToggleSearch }) {
  return (
    <div
      style={{
        position: "sticky",
        top: 0,
        zIndex: 30,
        padding: "12px 18px 10px",
        display: "grid",
        gridTemplateColumns: "36px 1fr 36px",
        alignItems: "center",
        background: `linear-gradient(to bottom, ${theme.bg} 88%, ${theme.bg}00)`,
        backdropFilter: "blur(16px)",
      }}
    >
      <button
        onClick={onBack}
        aria-label="Back to Activity"
        style={{
          width: 32,
          height: 32,
          border: "none",
          background: "transparent",
          color: theme.text,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          cursor: "pointer",
          padding: 0,
        }}
      >
        <Ico.arrowL size={20} stroke={theme.text} />
      </button>
      <div
        style={{
          justifySelf: "center",
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 14,
          fontWeight: 600,
          padding: "6px 8px",
        }}
      >
        TRANSACTIONS
      </div>
      <button
        type="button"
        onClick={onToggleSearch}
        aria-label="Search merchants"
        style={{
          width: 32,
          height: 32,
          border: "none",
          background: searchOpen ? theme.surface : "transparent",
          borderRadius: 16,
          color: theme.text,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          cursor: "pointer",
          padding: 0,
        }}
      >
        <Ico.search size={17} stroke={theme.text} />
      </button>
    </div>
  );
}

function SortMenu({ theme, value, onPick, options = SORT_OPTIONS }) {
  return (
    <div
      style={{
        position: "absolute",
        top: 24,
        right: 18,
        zIndex: 40,
        minWidth: 150,
        background: theme.surface,
        border: `0.5px solid ${theme.line}`,
        borderRadius: 12,
        boxShadow: theme.shadow?.modal,
        padding: 4,
      }}
    >
      {options.map((option) => (
        <button
          key={option.key}
          type="button"
          onClick={() => onPick(option.key)}
          style={{
            width: "100%",
            border: "none",
            background: value === option.key ? theme.surface2 : "transparent",
            color: theme.text,
            borderRadius: 9,
            padding: "9px 10px",
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            cursor: "pointer",
            fontFamily: FONTS.mono,
            fontSize: 10.5,
            letterSpacing: 1.1,
            textAlign: "left",
          }}
        >
          {option.label}
          <span
            style={{
              width: 16,
              color: value === option.key ? theme.text : "transparent",
            }}
          >
            <Ico.check size={14} />
          </span>
        </button>
      ))}
    </div>
  );
}

function DateFilterSheet({
  theme,
  accent,
  value,
  anchorDate,
  onClose,
  onApply,
  onClear,
}) {
  const [pending, setPending] = React.useState(value);
  const pickPreset = (key) => setPending({ key, start: "", end: "" });
  const setCustomDate = (field, nextValue) =>
    setPending((current) => ({
      ...current,
      key: "custom",
      [field]: nextValue,
    }));

  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 118,
        background: "rgba(0,0,0,0.52)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 18px 32px",
          boxShadow: theme.shadow?.sheet,
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <SectionLabel theme={theme}>Date range</SectionLabel>
          <button
            type="button"
            onClick={onClear}
            style={{
              border: "none",
              background: "transparent",
              color: accent,
              fontFamily: FONTS.mono,
              fontSize: 10,
              letterSpacing: 1.2,
              textTransform: "uppercase",
              cursor: "pointer",
              padding: "6px 0",
            }}
          >
            Clear filters
          </button>
        </div>

        <div style={{ display: "grid", gap: 4, marginTop: 12 }}>
          {DATE_FILTER_PRESETS.map((preset) => (
            <DatePresetRow
              key={preset.key}
              theme={theme}
              label={preset.label}
              active={pending.key === preset.key}
              onClick={() => pickPreset(preset.key)}
            />
          ))}
        </div>

        <div style={{ marginTop: 18 }}>
          <SectionLabel theme={theme}>Custom</SectionLabel>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "1fr 1fr",
              gap: 10,
              marginTop: 10,
            }}
          >
            <DateInput
              theme={theme}
              label="Start"
              value={pending.start}
              max={pending.end || toISODate(anchorDate)}
              onChange={(next) => setCustomDate("start", next)}
            />
            <DateInput
              theme={theme}
              label="End"
              value={pending.end}
              min={pending.start}
              max={toISODate(anchorDate)}
              onChange={(next) => setCustomDate("end", next)}
            />
          </div>
        </div>

        <button
          type="button"
          onClick={() => onApply(pending)}
          style={{
            width: "100%",
            height: 46,
            border: "none",
            borderRadius: 14,
            background: accent,
            color: theme.bg,
            fontFamily: FONTS.mono,
            fontSize: 11,
            fontWeight: 700,
            letterSpacing: 1.4,
            textTransform: "uppercase",
            cursor: "pointer",
            marginTop: 20,
          }}
        >
          Apply
        </button>
      </div>
    </div>
  );
}

function CategoryFilterSheet({
  theme,
  accent,
  value,
  onClose,
  onApply,
  onClear,
}) {
  const [pending, setPending] = React.useState(value);
  const toggleCategory = (category) =>
    setPending((current) =>
      current.includes(category)
        ? current.filter((c) => c !== category)
        : [...current, category],
    );

  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 118,
        background: "rgba(0,0,0,0.52)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 18px 32px",
          boxShadow: theme.shadow?.sheet,
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <SectionLabel theme={theme}>Category</SectionLabel>
          <div
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 12,
            }}
          >
            <button
              type="button"
              onClick={() => setPending(EDITABLE_CATS)}
              style={{
                border: "none",
                background: "transparent",
                color: accent,
                fontFamily: FONTS.mono,
                fontSize: 10,
                letterSpacing: 1.2,
                textTransform: "uppercase",
                cursor: "pointer",
                padding: "6px 0",
              }}
            >
              Select all
            </button>
            <button
              type="button"
              onClick={onClear}
              style={{
                border: "none",
                background: "transparent",
                color: accent,
                fontFamily: FONTS.mono,
                fontSize: 10,
                letterSpacing: 1.2,
                textTransform: "uppercase",
                cursor: "pointer",
                padding: "6px 0",
              }}
            >
              Clear filters
            </button>
          </div>
        </div>

        <div style={{ display: "grid", gap: 4, marginTop: 12 }}>
          {EDITABLE_CATS.map((category) => (
            <CategoryFilterRow
              key={category}
              theme={theme}
              accent={accent}
              category={category}
              active={pending.includes(category)}
              onClick={() => toggleCategory(category)}
            />
          ))}
        </div>

        <button
          type="button"
          onClick={() => onApply(pending)}
          style={{
            width: "100%",
            height: 46,
            border: "none",
            borderRadius: 14,
            background: accent,
            color: theme.bg,
            fontFamily: FONTS.mono,
            fontSize: 11,
            fontWeight: 700,
            letterSpacing: 1.4,
            textTransform: "uppercase",
            cursor: "pointer",
            marginTop: 20,
          }}
        >
          Apply
        </button>
      </div>
    </div>
  );
}

function CategoryFilterRow({ theme, accent, category, active, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        width: "100%",
        border: "none",
        background: active ? theme.surface2 : "transparent",
        color: theme.text,
        borderRadius: 12,
        padding: "10px 12px",
        display: "grid",
        gridTemplateColumns: "32px 1fr 18px",
        alignItems: "center",
        gap: 12,
        cursor: "pointer",
        textAlign: "left",
      }}
    >
      <CategoryIcon
        category={category}
        theme={theme}
        accent={accent}
        size={30}
      />
      <span
        style={{
          fontFamily: FONTS.ui,
          fontSize: 14,
          fontWeight: active ? 600 : 400,
        }}
      >
        {category}
      </span>
      <span
        style={{
          width: 18,
          height: 18,
          color: active ? theme.text : "transparent",
        }}
      >
        <Ico.check size={16} />
      </span>
    </button>
  );
}

function AccountFilterSheet({
  theme,
  accent,
  value,
  onClose,
  onApply,
  onClear,
}) {
  const [pending, setPending] = React.useState(value);
  const allSelected = pending.length === BANK_ACCOUNTS.length;
  const toggleAccount = (accountId) =>
    setPending((current) =>
      current.includes(accountId)
        ? current.filter((id) => id !== accountId)
        : [...current, accountId],
    );

  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 118,
        background: "rgba(0,0,0,0.52)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 18px 32px",
          boxShadow: theme.shadow?.sheet,
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <SectionLabel theme={theme}>Accounts</SectionLabel>
          <div
            style={{ display: "inline-flex", alignItems: "center", gap: 12 }}
          >
            <button
              type="button"
              onClick={() => setPending(getDefaultAccountFilter())}
              style={filterSheetTextButtonStyle(accent)}
            >
              Select all
            </button>
            <button
              type="button"
              onClick={onClear}
              style={filterSheetTextButtonStyle(accent)}
            >
              Clear filters
            </button>
          </div>
        </div>

        <div style={{ display: "grid", gap: 4, marginTop: 12 }}>
          {BANK_ACCOUNTS.map((account) => (
            <AccountFilterRow
              key={account.id}
              theme={theme}
              account={account}
              active={allSelected || pending.includes(account.id)}
              onClick={() => toggleAccount(account.id)}
            />
          ))}
        </div>

        <button
          type="button"
          onClick={() => onApply(pending)}
          style={{
            width: "100%",
            height: 46,
            border: "none",
            borderRadius: 14,
            background: accent,
            color: theme.bg,
            fontFamily: FONTS.mono,
            fontSize: 11,
            fontWeight: 700,
            letterSpacing: 1.4,
            textTransform: "uppercase",
            cursor: "pointer",
            marginTop: 20,
          }}
        >
          Apply
        </button>
      </div>
    </div>
  );
}

function AccountFilterRow({ theme, account, active, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        width: "100%",
        border: "none",
        background: active ? theme.surface2 : "transparent",
        color: theme.text,
        borderRadius: 12,
        padding: "10px 12px",
        display: "grid",
        gridTemplateColumns: "32px 1fr 18px",
        alignItems: "center",
        gap: 12,
        cursor: "pointer",
        textAlign: "left",
      }}
    >
      <BrandLogo name={account.bank} size={30} />
      <span style={{ minWidth: 0 }}>
        <span
          style={{
            display: "block",
            fontFamily: FONTS.ui,
            fontSize: 14,
            fontWeight: active ? 600 : 400,
            color: theme.text,
          }}
        >
          {account.bank}
        </span>
        <span
          style={{
            display: "block",
            marginTop: 2,
            fontFamily: FONTS.mono,
            fontSize: 9.5,
            letterSpacing: 1,
            textTransform: "uppercase",
            color: theme.textMute,
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
          }}
        >
          {account.type} · {account.last}
        </span>
      </span>
      <span
        style={{
          width: 18,
          height: 18,
          color: active ? theme.text : "transparent",
        }}
      >
        <Ico.check size={16} />
      </span>
    </button>
  );
}

function DatePresetRow({ theme, label, active, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        width: "100%",
        border: "none",
        background: active ? theme.surface2 : "transparent",
        color: theme.text,
        borderRadius: 12,
        padding: "12px 12px",
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        cursor: "pointer",
        fontFamily: FONTS.ui,
        fontSize: 14,
        fontWeight: active ? 600 : 400,
      }}
    >
      {label}
      <span
        style={{
          width: 18,
          height: 18,
          color: active ? theme.text : "transparent",
        }}
      >
        <Ico.check size={16} />
      </span>
    </button>
  );
}

function DateInput({ theme, label, value, min, max, onChange }) {
  return (
    <label
      style={{
        display: "grid",
        gap: 6,
        color: theme.textMute,
        fontFamily: FONTS.mono,
        fontSize: 10,
        letterSpacing: 1.1,
        textTransform: "uppercase",
      }}
    >
      {label}
      <input
        type="date"
        value={value}
        min={min || undefined}
        max={max || undefined}
        onChange={(e) => onChange(e.target.value)}
        style={{
          width: "100%",
          boxSizing: "border-box",
          background: theme.surface2,
          border: `0.5px solid ${theme.line}`,
          borderRadius: 12,
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 13,
          padding: "10px 10px",
          outline: "none",
        }}
      />
    </label>
  );
}

function getDateFilterAnchor(txs) {
  const dates = txs.map((t) => parseTxDate(t.date)).filter(Boolean);
  if (!dates.length) return new Date(2026, 0, 1);
  return new Date(Math.max(...dates.map((d) => d.getTime())));
}

function getDateFilterLabel(filter) {
  if (filter.key === "custom") {
    if (filter.start && filter.end) return "CUSTOM";
    if (filter.start) return "FROM " + formatShortDate(filter.start);
    if (filter.end) return "UNTIL " + formatShortDate(filter.end);
    return "CUSTOM";
  }
  const preset = DATE_FILTER_PRESETS.find((p) => p.key === filter.key);
  return (preset?.label || "All time").toUpperCase();
}

function getCategoryFilterLabel(categories) {
  if (categories.length === 0) return "CATEGORY";
  if (categories.length === 1) return categories[0].toUpperCase();
  return `${categories.length} CATEGORIES`;
}

function getDefaultAccountFilter() {
  return BANK_ACCOUNTS.map((account) => account.id);
}

function getAccountFilterLabel(accounts) {
  if (accounts.length === BANK_ACCOUNTS.length) return "ACCOUNTS";
  if (accounts.length === 0) return "NO ACCOUNTS";
  if (accounts.length === 1) {
    const account = BANK_ACCOUNTS.find((item) => item.id === accounts[0]);
    return (account?.bank || "ACCOUNTS").toUpperCase();
  }
  return `${accounts.length} ACCOUNTS`;
}

function getDateFilterRange(filter, anchorDate) {
  if (filter.key === "all") return null;
  if (filter.key === "custom") {
    return {
      start: filter.start ? parseISODate(filter.start) : null,
      end: filter.end ? parseISODate(filter.end) : null,
    };
  }

  const preset = DATE_FILTER_PRESETS.find((p) => p.key === filter.key);
  if (!preset) return null;
  if (preset.days) {
    const start = new Date(anchorDate);
    start.setDate(start.getDate() - preset.days + 1);
    return { start: startOfDay(start), end: endOfDay(anchorDate) };
  }
  if (preset.unit === "thisMonth") {
    return {
      start: new Date(anchorDate.getFullYear(), anchorDate.getMonth(), 1),
      end: endOfDay(anchorDate),
    };
  }
  if (preset.unit === "lastMonth") {
    const y = anchorDate.getFullYear();
    const m = anchorDate.getMonth() - 1;
    return {
      start: new Date(y, m, 1),
      end: endOfDay(new Date(y, m + 1, 0)),
    };
  }
  if (preset.unit === "thisYear") {
    return {
      start: new Date(anchorDate.getFullYear(), 0, 1),
      end: endOfDay(anchorDate),
    };
  }
  if (preset.unit === "lastYear") {
    const y = anchorDate.getFullYear() - 1;
    return {
      start: new Date(y, 0, 1),
      end: endOfDay(new Date(y, 11, 31)),
    };
  }
  return null;
}

function isTxInDateRange(tx, range) {
  if (!range) return true;
  const date = parseTxDate(tx.date);
  if (!date) return true;
  if (range.start && date < startOfDay(range.start)) return false;
  if (range.end && date > endOfDay(range.end)) return false;
  return true;
}

function isTxInAccountFilter(tx, accountIds) {
  return isAccountNameInFilter(tx.account, accountIds);
}

function isAccountNameInFilter(accountName, accountIds) {
  if (accountIds.length === BANK_ACCOUNTS.length) return true;
  if (accountIds.length === 0) return false;
  const selectedBanks = BANK_ACCOUNTS.filter((account) =>
    accountIds.includes(account.id),
  ).map((account) => account.bank.toLowerCase());
  const txAccount = accountName.toLowerCase();
  return selectedBanks.some((bank) => txAccount.includes(bank.toLowerCase()));
}

function filterSheetTextButtonStyle(accent) {
  return {
    border: "none",
    background: "transparent",
    color: accent,
    fontFamily: FONTS.mono,
    fontSize: 10,
    letterSpacing: 1.2,
    textTransform: "uppercase",
    cursor: "pointer",
    padding: "6px 0",
  };
}

function sortTransactions(a, b, sortKey) {
  if (sortKey === "oldest") {
    return parseTxDate(a.date) - parseTxDate(b.date);
  }
  if (sortKey === "highest") {
    return Math.abs(b.amount) - Math.abs(a.amount);
  }
  return parseTxDate(b.date) - parseTxDate(a.date);
}

function parseTxDate(label) {
  const parsed = new Date(`${label} 2026`);
  return Number.isNaN(parsed.getTime()) ? null : startOfDay(parsed);
}

function parseISODate(value) {
  const [year, month, day] = value.split("-").map(Number);
  return startOfDay(new Date(year, month - 1, day));
}

function toISODate(date) {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
}

function formatShortDate(value) {
  const date = parseISODate(value);
  return date
    .toLocaleDateString("en-AE", { day: "numeric", month: "short" })
    .toUpperCase();
}

function startOfDay(date) {
  const next = new Date(date);
  next.setHours(0, 0, 0, 0);
  return next;
}

function endOfDay(date) {
  const next = new Date(date);
  next.setHours(23, 59, 59, 999);
  return next;
}

// ─────────────────────────────────────────────────────────────
// Shared: transactions feed (grouped by date)
// ─────────────────────────────────────────────────────────────
function TransactionsFeed({
  theme,
  accent,
  txs,
  tags = INITIAL_TAGS,
  onTxClick,
  hideEmpty,
}) {
  const groups = {};
  txs.forEach((t) => {
    if (!groups[t.date]) groups[t.date] = [];
    groups[t.date].push(t);
  });

  return (
    <div style={{ padding: "0 16px" }}>
      {Object.keys(groups).length === 0 && !hideEmpty && (
        <div
          style={{
            padding: 60,
            textAlign: "center",
            color: theme.textMute,
            fontFamily: FONTS.mono,
            fontSize: 11,
          }}
        >
          No transactions match.
        </div>
      )}
      {Object.entries(groups).map(([date, rows]) => {
        const dayTotal = rows.reduce((s, t) => s + t.amount, 0);
        return (
          <div key={date} style={{ marginBottom: 14 }}>
            <div
              style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "center",
                padding: "4px 6px 8px",
              }}
            >
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 10,
                  color: theme.textMute,
                  textTransform: "uppercase",
                  letterSpacing: 1.2,
                }}
              >
                {date}
              </div>
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 10,
                  color: theme.textMute,
                }}
              >
                {dayTotal >= 0 ? "+" : "−"}
                <Dh /> {fmtAED(Math.abs(dayTotal))}
              </div>
            </div>
            <Card theme={theme} padded={false}>
              {rows.map((t, i) => (
                <button
                  key={t.id}
                  onClick={() => onTxClick(t.id)}
                  style={{
                    width: "100%",
                    textAlign: "left",
                    background: "transparent",
                    border: "none",
                    cursor: "pointer",
                    display: "flex",
                    alignItems: "center",
                    gap: 12,
                    padding: "11px 14px",
                    borderBottom:
                      i < rows.length - 1
                        ? `0.5px solid ${theme.line}`
                        : "none",
                    color: theme.text,
                  }}
                >
                  <CategoryIcon
                    category={t.category}
                    theme={theme}
                    accent={accent}
                    size={32}
                  />
                  {t.tagIds?.length > 0 && (
                    <div
                      style={{
                        display: "flex",
                        marginLeft: -18,
                        alignSelf: "flex-end",
                        paddingBottom: 1,
                      }}
                    >
                      {t.tagIds.slice(0, 3).map((tagId, dotIndex) => {
                        const tag = tags.find((item) => item.id === tagId);
                        return (
                          <span
                            key={tagId}
                            style={{
                              width: 7,
                              height: 7,
                              borderRadius: 4,
                              background: tag?.color || accent,
                              border: `1px solid ${theme.surface}`,
                              marginLeft: dotIndex ? -2 : 0,
                            }}
                          />
                        );
                      })}
                    </div>
                  )}
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div
                      style={{
                        fontSize: 13.5,
                        color: theme.text,
                        fontWeight: 500,
                        whiteSpace: "nowrap",
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                      }}
                    >
                      {t.merchant}
                    </div>
                    <div
                      style={{
                        fontSize: 11,
                        color: theme.textMute,
                        fontFamily: FONTS.mono,
                        marginTop: 2,
                      }}
                    >
                      {t.category} · {t.account}
                    </div>
                  </div>
                  <div
                    style={{
                      fontFamily: FONTS.mono,
                      fontSize: 13,
                      color: t.amount >= 0 ? theme.positive : theme.text,
                      fontVariantNumeric: "tabular-nums",
                      fontWeight: 500,
                      whiteSpace: "nowrap",
                    }}
                  >
                    {t.amount >= 0 ? "+" : "−"}
                    {fmtAED(Math.abs(t.amount), {
                      decimals: Math.abs(t.amount) < 1000 ? 2 : 0,
                    })}
                  </div>
                  {t.splitChild && (
                    <div
                      title="Split transaction"
                      style={{
                        width: 22,
                        height: 22,
                        borderRadius: 11,
                        background: theme.surface2,
                        border: `0.5px solid ${theme.line}`,
                        color: accent,
                        display: "flex",
                        alignItems: "center",
                        justifyContent: "center",
                        flexShrink: 0,
                      }}
                    >
                      <Ico.tx size={12} />
                    </div>
                  )}
                </button>
              ))}
            </Card>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Spend vs budget hero card
// ─────────────────────────────────────────────────────────────
function SpendVsBudgetCard({ theme, accent, snap }) {
  const ahead = snap.paceDeltaPct < 0; // spending below pace
  const over = snap.totalSpent > snap.totalBudget;
  const paceColor = over
    ? theme.negative
    : ahead
      ? theme.positive
      : theme.warning;
  const paceWord = over ? "over budget" : ahead ? "under pace" : "over pace";
  const totalUsedPct = (snap.totalSpent / snap.totalBudget) * 100;
  const previewCategories = snap.items.filter((it) =>
    ["Food", "Shopping"].includes(it.category),
  );

  return (
    <Card theme={theme} style={{ padding: 18 }}>
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "flex-start",
        }}
      >
        <div>
          <SectionLabel theme={theme}>Budget</SectionLabel>
        </div>
        <div style={{ textAlign: "right" }}>
          <div
            style={{
              fontFamily: FONTS.mono,
              fontSize: 12,
              color: theme.text,
              marginTop: 4,
              fontVariantNumeric: "tabular-nums",
            }}
          >
            <Dh /> {fmtAED(snap.totalSpent, { compact: true })} of <Dh />{" "}
            {fmtAED(snap.totalBudget, { compact: true })}
          </div>
        </div>
      </div>

      {/* Combined progress bar */}
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 42px",
          alignItems: "center",
          gap: 10,
          marginTop: 14,
        }}
      >
        <BudgetTrack
          theme={theme}
          accent={accent}
          spent={snap.totalSpent}
          budget={snap.totalBudget}
          projected={snap.totalProjected}
        />
        <span
          style={{
            fontFamily: FONTS.mono,
            fontSize: 11.5,
            color: theme.textMute,
            fontVariantNumeric: "tabular-nums",
            textAlign: "right",
            whiteSpace: "nowrap",
          }}
        >
          {totalUsedPct.toFixed(0)}%
        </span>
      </div>

      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 12,
          marginTop: 16,
        }}
      >
        {previewCategories.map((it, index) => (
          <BudgetPreviewRow
            key={it.category}
            item={it}
            theme={theme}
            barColor={index === 0 ? "#ff912ccc" : "#cb4fffb8"}
          />
        ))}
      </div>

      <div
        style={{
          display: "flex",
          justifyContent: "center",
          paddingTop: 12,
        }}
      >
        <span
          style={{
            color: accent,
            fontFamily: FONTS.ui,
            fontSize: 12.5,
            fontWeight: 400,
            display: "flex",
            alignItems: "center",
            gap: 3,
          }}
        >
          See all <Ico.chevR size={12} stroke={accent} />
        </span>
      </div>
    </Card>
  );
}

const RECURRING_PREVIEW = [
  { merchant: "Du", due: "Monthly (in 3 days)", amount: 184.45 },
  { merchant: "Etisalat", due: "Monthly (in 2 days)", amount: 44.99 },
  { merchant: "Patreon", due: "Monthly (on May 20)", amount: 7.62 },
];

function RecurringPreviewCard({ theme, accent, onSeeAll }) {
  return (
    <Card theme={theme} style={{ padding: 18 }}>
      <SectionLabel theme={theme}>Recurring Transactions</SectionLabel>

      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 12,
          marginTop: 14,
        }}
      >
        {RECURRING_PREVIEW.map((item) => (
          <div
            key={item.merchant}
            style={{
              display: "grid",
              gridTemplateColumns: "1fr auto",
              alignItems: "center",
              gap: 14,
            }}
          >
            <div style={{ minWidth: 0 }}>
              <div
                style={{
                  color: theme.text,
                  fontFamily: FONTS.ui,
                  fontSize: 13,
                  fontWeight: 500,
                  whiteSpace: "nowrap",
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                }}
              >
                {item.merchant}
              </div>
              <div
                style={{
                  color: theme.textMute,
                  fontFamily: FONTS.ui,
                  fontSize: 11,
                  marginTop: 3,
                }}
              >
                {item.due}
              </div>
            </div>
            <div
              style={{
                color: theme.text,
                fontFamily: FONTS.mono,
                fontSize: 12,
                fontWeight: 400,
                fontVariantNumeric: "tabular-nums",
                whiteSpace: "nowrap",
              }}
            >
              <Dh /> {fmtAED(item.amount, { decimals: 2 })}
            </div>
          </div>
        ))}
      </div>

      <button
        onClick={onSeeAll}
        style={{
          width: "100%",
          marginTop: 14,
          padding: "0",
          background: "transparent",
          border: "none",
          cursor: "pointer",
          color: accent,
          fontFamily: FONTS.ui,
          fontSize: 12.5,
          fontWeight: 400,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          gap: 3,
        }}
      >
        See all <Ico.chevR size={12} stroke={accent} />
      </button>
    </Card>
  );
}

function BudgetPreviewRow({ item, theme, barColor }) {
  const usedPct = Math.min(item.pct * 100, 100);

  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "72px 1fr 42px",
        alignItems: "center",
        gap: 10,
      }}
    >
      <span
        style={{
          fontSize: 13,
          color: theme.text,
          whiteSpace: "nowrap",
        }}
      >
        {item.category}
      </span>
      <div
        style={{
          height: 8,
          background: theme.surface2,
          borderRadius: 4,
          overflow: "hidden",
        }}
      >
        <div
          style={{
            width: `${usedPct}%`,
            height: "100%",
            background: barColor,
            borderRadius: 4,
          }}
        />
      </div>
      <span
        style={{
          fontFamily: FONTS.mono,
          fontSize: 11.5,
          color: theme.textMute,
          fontVariantNumeric: "tabular-nums",
          textAlign: "right",
          whiteSpace: "nowrap",
        }}
      >
        {(item.pct * 100).toFixed(0)}%
      </span>
    </div>
  );
}

// Single bar with three layers: spent (solid), projected-extension (lighter), and a cap marker.
// Track width is max(budget, projected) so it always fits.
function BudgetTrack({ theme, accent, spent, budget, projected }) {
  const trackVal = Math.max(budget, projected);
  const spentPct = (spent / trackVal) * 100;
  const projExtraPct = (Math.max(0, projected - spent) / trackVal) * 100;
  const capPct = (budget / trackVal) * 100;
  const overProj = projected > budget;

  return (
    <div
      style={{
        position: "relative",
        height: 16,
        background: theme.surface2,
        borderRadius: 4,
        overflow: "visible",
      }}
    >
      {/* solid spent */}
      <div
        style={{
          position: "absolute",
          top: 0,
          bottom: 0,
          left: 0,
          width: `${spentPct}%`,
          background: "#2c5bff",
          borderRadius: 4,
        }}
      />
      {/* projected extension */}
      <div
        style={{
          position: "absolute",
          top: 0,
          bottom: 0,
          left: `${spentPct}%`,
          width: `${projExtraPct}%`,
          background: "#f0f3ff",
          opacity: 0.28,
          borderRadius: 4,
        }}
      />
      {/* cap marker */}
      <div
        style={{
          position: "absolute",
          top: -3,
          bottom: -3,
          left: `${capPct}%`,
          width: 1.5,
          background: theme.text,
          opacity: 0.55,
        }}
      />
    </div>
  );
}

function SpendMonthComparisonCard({ theme, accent, txs, budgets }) {
  const [compareKey, setCompareKey] = React.useState("previous");
  const [compareOpen, setCompareOpen] = React.useState(false);
  const snap = getBudgetSnapshot(txs, budgets);
  const compareOptions = getBudgetedSpendCompareOptions();
  const selectedCompare =
    compareOptions.find((option) => option.key === compareKey) ||
    compareOptions[0];

  return (
    <Card theme={theme} style={{ padding: 18, overflow: "visible", border: 0 }}>
      <SectionLabel theme={theme}>Spend this month</SectionLabel>
      <div
        style={{
          marginTop: 12,
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          gap: 16,
        }}
      >
        <div style={{ minWidth: 0 }}>
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: 7,
              fontFamily: FONTS.display,
              fontSize: 30,
              lineHeight: 1,
              color: theme.text,
              letterSpacing: -0.5,
              fontVariantNumeric: "tabular-nums",
            }}
          >
            <Dh size={19} color={accent} style={{ transform: "none" }} />
            <span>{fmtAED(snap.totalSpent)}</span>
          </div>
          <div
            style={{
              marginTop: 8,
              display: "flex",
              alignItems: "center",
              gap: 7,
              fontFamily: FONTS.ui,
              fontSize: 12.5,
              color: accent,
            }}
          >
            <span
              style={{
                width: 8,
                height: 8,
                borderRadius: 999,
                background: accent,
                display: "inline-block",
              }}
            />
            {TODAY.monthName}
            <div style={{ position: "relative", marginLeft: 4 }}>
              <button
                type="button"
                onClick={() => setCompareOpen((open) => !open)}
                style={{
                  border: "none",
                  borderBottom: `1px solid ${theme.textMute}`,
                  borderRadius: 0,
                  padding: "0 0 1px",
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 5,
                  fontFamily: FONTS.ui,
                  fontSize: 12.5,
                  fontWeight: 400,
                  color: theme.textMute,
                  background: "transparent",
                  cursor: "pointer",
                }}
              >
                <span
                  style={{
                    width: 8,
                    height: 8,
                    borderRadius: 999,
                    background: theme.textMute,
                    display: "inline-block",
                  }}
                />
                {selectedCompare.label}
                <Ico.chevD size={12} stroke={theme.textMute} />
              </button>
              {compareOpen && (
                <div
                  style={{
                    position: "absolute",
                    top: 24,
                    left: 0,
                    zIndex: 10,
                    minWidth: 150,
                    padding: 4,
                    borderRadius: 12,
                    background: theme.surface,
                    border: `0.5px solid ${theme.line2}`,
                    boxShadow: theme.shadow.popover,
                    textAlign: "left",
                  }}
                >
                  {compareOptions.map((option) => (
                    <button
                      key={option.key}
                      type="button"
                      onClick={() => {
                        setCompareKey(option.key);
                        setCompareOpen(false);
                      }}
                      style={{
                        width: "100%",
                        border: "none",
                        borderRadius: 8,
                        padding: "8px 9px",
                        background:
                          option.key === selectedCompare.key
                            ? theme.surface2
                            : "transparent",
                        color: theme.text,
                        cursor: "pointer",
                        fontFamily: FONTS.ui,
                        fontSize: 12,
                        fontWeight: 400,
                        textAlign: "left",
                      }}
                    >
                      {option.label}
                    </button>
                  ))}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>

      <MonthSpendComparisonChart
        theme={theme}
        accent={accent}
        current={getCurrentSpendSeries(txs)}
        comparisons={selectedCompare.series}
        budget={snap.totalBudget}
      />
    </Card>
  );
}

function getCurrentSpendSeries(txs) {
  const daily = Array.from({ length: TODAY.daysInMonth }, () => 0);
  txs.forEach((t) => {
    if (t.amount >= 0 || !BUDGET_CATEGORIES.includes(t.category)) return;
    const [dayText, monthShort] = t.date.split(" ");
    if (monthShort !== TODAY.monthShort) return;
    const day = parseInt(dayText, 10);
    if (Number.isFinite(day) && day >= 1 && day <= TODAY.daysInMonth) {
      daily[day - 1] += Math.abs(t.amount);
    }
  });
  return daily.reduce((out, value, i) => {
    out.push((out[i - 1] || 0) + value);
    return out;
  }, []);
}

function getBudgetedSpendCompareOptions() {
  const monthlySeries = SPEND_CATEGORY_HISTORY.map((month) =>
    getBudgetedSpendMonthSeries(month),
  );
  const previous = monthlySeries[monthlySeries.length - 1];
  const avgMonths = monthlySeries.slice(-3);
  const avgDays = Array.from({ length: TODAY.daysInMonth }, (_, i) => {
    const sum = avgMonths.reduce(
      (total, month) => total + month.days[Math.min(i, month.days.length - 1)],
      0,
    );
    return sum / avgMonths.length;
  });
  const avgLabel = `Avg. of ${getTrailingCompleteMonthRangeLabel()}`;

  return [
    {
      key: "previous",
      label: previous.label,
      series: [{ key: "previous", days: previous.days }],
    },
    { key: "avg", label: avgLabel, series: [{ key: "avg", days: avgDays }] },
  ];
}

function getBudgetedSpendMonthSeries(month) {
  const total = BUDGET_CATEGORIES.reduce(
    (sum, category) => sum + (month.categories[category] || 0),
    0,
  );
  const [monthShort, yearText] = month.month.split(" ");
  const monthIndex = MONTH_NAMES_SHORT.indexOf(monthShort);
  const daysInMonth = new Date(
    parseInt(yearText, 10),
    monthIndex + 1,
    0,
  ).getDate();
  const weights = Array.from({ length: daysInMonth }, (_, i) => {
    const day = i + 1;
    const regular = 0.86 + ((day * 5) % 8) / 18;
    const weekendLift = day % 7 === 5 || day % 7 === 6 ? 1.24 : 1;
    const billLift = [1, 3, 5, 15].includes(day) ? 1.75 : 1;
    return regular * weekendLift * billLift;
  });
  const unit = total / weights.reduce((sum, value) => sum + value, 0);
  let running = 0;

  return {
    label: monthShort,
    total,
    days: weights.map((weight) => {
      running += Math.round(weight * unit);
      return running;
    }),
  };
}

function MonthSpendComparisonChart({
  theme,
  accent,
  current,
  comparisons,
  budget,
}) {
  const [hoveredKey, setHoveredKey] = React.useState(null);
  const width = 320;
  const height = 214;
  const left = 4;
  const right = 4;
  const top = 24;
  const bottom = 30;
  const chartW = width - left - right;
  const chartH = height - top - bottom;
  const labels = [1, 8, 15, 22, 29];
  const visibleCurrent = current.map((value, i) =>
    i < TODAY.day ? value : null,
  );
  const maxVal =
    Math.max(
      budget,
      ...comparisons.flatMap((series) => series.days),
      ...visibleCurrent.filter((value) => value != null),
      1,
    ) * 1.08;
  const pointFor = (value, day) => ({
    x: left + ((day - 1) / (TODAY.daysInMonth - 1)) * chartW,
    y: top + chartH - (value / maxVal) * chartH,
  });
  const currentPoints = visibleCurrent
    .map((value, i) =>
      value == null ? null : { ...pointFor(value, i + 1), value },
    )
    .filter(Boolean);
  const comparisonPaths = comparisons.map((series) => {
    const points = series.days
      .slice(0, TODAY.daysInMonth)
      .map((value, i) => ({ ...pointFor(value, i + 1), value }));
    return {
      ...series,
      points,
      path: "M " + points.map((p) => `${p.x} ${p.y}`).join(" L "),
    };
  });
  const currentPath =
    "M " + currentPoints.map((p) => `${p.x} ${p.y}`).join(" L ");
  const areaPath =
    currentPath +
    ` L ${currentPoints[currentPoints.length - 1].x} ${top + chartH} L ${left} ${top + chartH} Z`;
  const budgetY = pointFor(budget, 1).y;
  const currentDot = currentPoints[currentPoints.length - 1];
  const comparisonDots = comparisonPaths.map((series) => ({
    key: series.key,
    point: series.points[series.points.length - 1],
  }));
  const hoverPoints = [
    currentDot && { key: "current", point: currentDot, color: accent },
    ...comparisonPaths.map((series) => ({
      key: series.key,
      point: series.points[series.points.length - 1],
      color: theme.textMute,
    })),
  ].filter(Boolean);
  const hoveredPoint = hoverPoints.find((item) => item.key === hoveredKey);

  return (
    <svg
      width="100%"
      height={height}
      viewBox={`0 0 ${width} ${height}`}
      preserveAspectRatio="none"
      style={{ display: "block", overflow: "visible" }}
    >
      <line
        x1={left}
        x2={width - right}
        y1={budgetY}
        y2={budgetY}
        stroke={theme.textMute}
        strokeWidth={1}
        strokeDasharray="5 5"
        opacity={0.42}
        vectorEffect="non-scaling-stroke"
      />
      <rect
        x={left}
        y={budgetY - 11}
        width={96}
        height={22}
        rx={5}
        fill={theme.surface3}
        opacity={0.82}
      />
      <text
        x={left + 6}
        y={budgetY + 4}
        fill={theme.textDim}
        fontFamily={FONTS.ui}
        fontSize="12"
      >
        {fmtAED(budget, { compact: true })} budget
      </text>
      <path d={areaPath} fill={accent} opacity={0.12} />
      {comparisonPaths.map((series) => (
        <path
          key={series.key}
          d={series.path}
          fill="none"
          stroke={theme.textMute}
          strokeWidth={1.4}
          strokeDasharray="5 5"
          strokeLinecap="round"
          strokeLinejoin="round"
          opacity={
            series.key === "avg" && comparisonPaths.length > 1 ? 0.78 : 0.56
          }
          vectorEffect="non-scaling-stroke"
        />
      ))}
      {comparisonPaths.map((series) => (
        <path
          key={`${series.key}-hover`}
          d={series.path}
          fill="none"
          stroke="transparent"
          strokeWidth={16}
          strokeLinecap="round"
          strokeLinejoin="round"
          onMouseEnter={() => setHoveredKey(series.key)}
          onMouseLeave={() => setHoveredKey(null)}
          vectorEffect="non-scaling-stroke"
        />
      ))}
      <path
        d={currentPath}
        fill="none"
        stroke={accent}
        strokeWidth={2.2}
        strokeLinecap="round"
        strokeLinejoin="round"
        vectorEffect="non-scaling-stroke"
      />
      <path
        d={currentPath}
        fill="none"
        stroke="transparent"
        strokeWidth={16}
        strokeLinecap="round"
        strokeLinejoin="round"
        onMouseEnter={() => setHoveredKey("current")}
        onMouseLeave={() => setHoveredKey(null)}
        vectorEffect="non-scaling-stroke"
      />
      {currentDot && (
        <circle cx={currentDot.x} cy={currentDot.y} r={4} fill={accent} />
      )}
      {comparisonDots.map(({ key, point }) => (
        <circle
          key={key}
          cx={point.x}
          cy={point.y}
          r={3.4}
          fill={theme.textMute}
          opacity={key === "avg" && comparisonDots.length > 1 ? 0.78 : 0.56}
        />
      ))}
      {hoveredPoint && (
        <g pointerEvents="none">
          <rect
            x={Math.min(
              width - right - 56,
              Math.max(left, hoveredPoint.point.x - 28),
            )}
            y={Math.max(2, hoveredPoint.point.y - 29)}
            width={56}
            height={20}
            rx={5}
            fill={theme.surface3}
            opacity={0.94}
          />
          <text
            x={Math.min(
              width - right - 28,
              Math.max(left + 28, hoveredPoint.point.x),
            )}
            y={Math.max(16, hoveredPoint.point.y - 15)}
            textAnchor="middle"
            fill={hoveredPoint.color}
            fontFamily={FONTS.mono}
            fontSize="10"
            fontWeight="600"
          >
            {fmtAED(hoveredPoint.point.value, { compact: true })}
          </text>
        </g>
      )}
      <line
        x1={left}
        x2={width - right}
        y1={top + chartH}
        y2={top + chartH}
        stroke={theme.line}
        strokeWidth={1}
        vectorEffect="non-scaling-stroke"
      />
      {labels.map((day) => {
        const p = pointFor(0, day);
        return (
          <text
            key={day}
            x={p.x}
            y={height - 6}
            textAnchor="middle"
            fill={theme.textMute}
            fontFamily={FONTS.mono}
            fontSize="11"
            fontWeight="500"
          >
            {String(day).padStart(2, "0")}
          </text>
        );
      })}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Per-category budget bar row
// ─────────────────────────────────────────────────────────────
function BudgetBar({ item, theme, accent }) {
  const overProj = item.projected > item.budget;
  const projColor = overProj ? theme.negative : theme.textDim;
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        gap: 12,
        padding: "4px 4px",
      }}
    >
      <CategoryIcon
        category={item.category}
        theme={theme}
        accent={accent}
        size={32}
      />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "baseline",
            gap: 8,
          }}
        >
          <span style={{ fontSize: 13, color: theme.text, fontWeight: 500 }}>
            {item.category}
          </span>
          <span
            style={{
              fontFamily: FONTS.mono,
              fontSize: 11.5,
              color: theme.text,
              fontVariantNumeric: "tabular-nums",
              whiteSpace: "nowrap",
            }}
          >
            <Dh /> {fmtAED(item.spent, { decimals: item.spent < 1000 ? 0 : 0 })}
            <span style={{ color: theme.textMute }}>
              {" "}
              / {fmtAED(item.budget, { compact: true })}
            </span>
          </span>
        </div>
        <div style={{ marginTop: 6 }}>
          <BudgetTrack
            theme={theme}
            accent={accent}
            spent={item.spent}
            budget={item.budget}
            projected={item.projected}
          />
        </div>
        <div
          style={{
            marginTop: 5,
            fontFamily: FONTS.mono,
            fontSize: 9.5,
            color: theme.textMute,
            display: "flex",
            justifyContent: "space-between",
          }}
        >
          <span>{(item.pct * 100).toFixed(0)}% used</span>
          <span style={{ color: projColor }}>
            {overProj ? (
              <>
                proj. <Dh /> {fmtAED(item.projected, { compact: true })} · +
                {fmtAED(item.projected - item.budget)} over
              </>
            ) : (
              <>
                proj. <Dh /> {fmtAED(item.projected, { compact: true })} ·{" "}
                {fmtAED(item.budget - item.projected)} left
              </>
            )}
          </span>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Forecast card — Pro-gated
// ─────────────────────────────────────────────────────────────
function ForecastCard({
  theme,
  accent,
  snap,
  isPro,
  onAskHimma,
  onOpenPaywall,
}) {
  const [infoOpen, setInfoOpen] = React.useState(false);
  const [infoHover, setInfoHover] = React.useState(false);
  const over = snap.overUnder > 0;
  const showInfo = infoOpen || infoHover;

  if (!isPro) {
    return (
      <Card
        theme={theme}
        style={{ padding: 18, borderStyle: "dashed", position: "relative" }}
      >
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: 8,
            marginBottom: 6,
          }}
        >
          <Ico.lock size={12} stroke={theme.textMute} />
          <SectionLabel theme={theme}>Spend this month</SectionLabel>
        </div>
        <div
          style={{
            fontFamily: FONTS.display,
            fontSize: 22,
            color: theme.textMute,
            letterSpacing: -0.4,
            filter: "blur(5px)",
            userSelect: "none",
          }}
        >
          <Dh /> 4,351
        </div>
        <button
          onClick={onOpenPaywall}
          style={{
            marginTop: 14,
            width: "100%",
            background: accent,
            color: theme.bg,
            border: "none",
            padding: "12px",
            borderRadius: 12,
            fontFamily: FONTS.ui,
            fontSize: 13,
            fontWeight: 600,
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            gap: 6,
          }}
        >
          Unlock with Pro <Ico.arrowUR size={13} stroke={theme.bg} />
        </button>
      </Card>
    );
  }

  const stats = getForecastWindowStats();
  const fullStats = {
    avg: stats.soFar.avg + stats.remaining.avg,
    min: stats.soFar.min + stats.remaining.min,
    max: stats.soFar.max + stats.remaining.max,
  };

  const rows = [
    {
      key: "soFar",
      label: "Spend so far",
      range: `Day [1-${TODAY.day}]`,
      value: snap.totalSpent,
      stats: stats.soFar,
      kind: "actual",
    },
    {
      key: "remaining",
      label: "Spend remaining",
      range: `Day [${TODAY.day + 1}-${TODAY.daysInMonth}]`,
      stats: stats.remaining,
      kind: "projected",
    },
    {
      key: "forecast",
      label: "Month-end forecast",
      range: `Day [1-${TODAY.daysInMonth}]`,
      value: snap.totalProjected,
      stats: fullStats,
      kind: "highlight",
    },
  ];
  const remainingDays = Math.max(0, TODAY.daysInMonth - TODAY.day);
  const remainingToBudget = Math.max(0, snap.totalBudget - snap.totalSpent);
  const dailyBudgetLeft =
    remainingDays > 0 ? remainingToBudget / remainingDays : 0;
  const forecastDelta = snap.totalProjected - snap.totalBudget;

  return (
    <Card
      theme={theme}
      style={{ padding: 18, position: "relative", overflow: "visible" }}
    >
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          gap: 8,
          marginBottom: 12,
        }}
      >
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <SectionLabel theme={theme}>Month-end forecast</SectionLabel>
          <div style={{ position: "relative", display: "flex" }}>
            <button
              type="button"
              aria-label="About month-end forecast"
              aria-expanded={showInfo}
              title="About this forecast"
              onClick={() => setInfoOpen((v) => !v)}
              onMouseEnter={() => setInfoHover(true)}
              onMouseLeave={() => setInfoHover(false)}
              onFocus={() => setInfoHover(true)}
              onBlur={() => {
                setInfoHover(false);
                setInfoOpen(false);
              }}
              style={{
                width: 18,
                height: 18,
                borderRadius: 9,
                border: `0.5px solid ${theme.line2}`,
                background: showInfo ? `${accent}18` : "transparent",
                color: showInfo ? accent : theme.textMute,
                padding: 0,
                cursor: "pointer",
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                flexShrink: 0,
              }}
            >
              <Ico.info size={12} stroke={showInfo ? accent : theme.textMute} />
            </button>
            {showInfo && (
              <div
                role="tooltip"
                style={{
                  position: "absolute",
                  top: 24,
                  left: -92,
                  zIndex: 10,
                  width: 238,
                  padding: "10px 12px",
                  borderRadius: 12,
                  background: theme.surface2,
                  border: `0.5px solid ${theme.line2}`,
                  boxShadow: "0 12px 28px rgba(0,0,0,0.28)",
                  color: theme.textDim,
                  fontFamily: FONTS.ui,
                  fontSize: 11.5,
                  lineHeight: 1.45,
                  textTransform: "none",
                  letterSpacing: 0,
                }}
              >
                Min, max and avg use the last {stats.monthsCount} full months,
                scaled to each part of this month.{" "}
                {TODAY.monthShort.toUpperCase()} shows your current spend so far
                and projected month-end total.
              </div>
            )}
          </div>
        </div>
        <div
          style={{
            fontFamily: FONTS.mono,
            fontSize: 9,
            color: theme.textMute,
            letterSpacing: 0.5,
          }}
        >
          Last {stats.monthsCount} mo
        </div>
      </div>

      {over && (
        <button
          onClick={onAskHimma}
          style={{
            marginTop: 14,
            width: "100%",
            background: `${accent}14`,
            color: theme.text,
            border: `0.5px solid ${accent}55`,
            borderRadius: 12,
            padding: "11px 14px",
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            gap: 10,
            fontFamily: FONTS.ui,
            fontSize: 13,
            textAlign: "left",
          }}
        >
          <div
            style={{
              width: 24,
              height: 24,
              borderRadius: 12,
              background: `${accent}22`,
              color: accent,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              flexShrink: 0,
            }}
          >
            <Ico.sparkles size={12} />
          </div>
          <span style={{ flex: 1, color: theme.text }}>
            Ask Himma where to cut
          </span>
          <Ico.chevR size={13} stroke={theme.textDim} />
        </button>
      )}
    </Card>
  );
}

// Consolidated 3-row forecast table: spend so far, spend remaining, and a
// highlighted month-end forecast row, each compared against avg/min/max history.
function ForecastTable({ theme, accent, rows }) {
  const fmt = (v) =>
    fmtAED(Math.round(v), { compact: v >= 10000, decimals: 0 });
  const cols = "3fr 0.9fr 0.9fr 0.9fr 1fr";
  const sepRight = `0.5px solid ${theme.line}`;
  const currentMonthLabel = TODAY.monthShort.slice(0, 3).toUpperCase();

  const headerCell = (label, separator = false) => (
    <div
      style={{
        fontFamily: FONTS.mono,
        fontSize: 8.5,
        letterSpacing: 1,
        textTransform: "uppercase",
        color: theme.textMute,
        borderRight: separator ? sepRight : "none",
        paddingRight: separator ? 12 : 0,
        display: "flex",
        alignItems: "center",
        justifyContent: "flex-end",
      }}
    >
      {label}
    </div>
  );

  const statCell = (value) => (
    <div
      style={{
        fontFamily: FONTS.mono,
        fontSize: 10,
        color: theme.textDim,
        fontVariantNumeric: "tabular-nums",
        display: "flex",
        alignItems: "flex-start",
        justifyContent: "flex-end",
      }}
    >
      {fmt(value)}
    </div>
  );

  return (
    <div
      style={{
        border: `0.5px solid ${theme.line}`,
        borderRadius: 12,
        overflow: "hidden",
      }}
    >
      <div
        style={{
          display: "grid",
          gridTemplateColumns: cols,
          columnGap: 12,
          padding: "8px 12px",
          background: theme.surface2,
          borderBottom: `0.5px solid ${theme.line}`,
        }}
      >
        <div
          style={{
            fontFamily: FONTS.mono,
            fontSize: 8.5,
            letterSpacing: 1,
            textTransform: "uppercase",
            color: theme.textMute,
            display: "flex",
            alignItems: "center",
          }}
        >
          Period
        </div>
        {headerCell("Min")}
        {headerCell("Max")}
        {headerCell("Avg", true)}
        {headerCell(currentMonthLabel)}
      </div>

      {rows.map((row, i) => {
        const highlight = row.kind === "highlight";
        const hasValue = row.value !== undefined;
        const deltaPct =
          hasValue && row.stats.avg > 0
            ? ((row.value - row.stats.avg) / row.stats.avg) * 100
            : null;
        const deltaOver = deltaPct !== null && deltaPct >= 0;
        const deltaColor =
          deltaPct === null
            ? theme.textMute
            : deltaOver
              ? theme.negative
              : theme.positive;

        return (
          <div
            key={row.key}
            style={{
              display: "grid",
              gridTemplateColumns: cols,
              columnGap: 12,
              alignItems: "stretch",
              padding: "10px 12px",
              background: highlight ? `${accent}10` : "transparent",
              borderTop: i === 0 ? "none" : `0.5px solid ${theme.line}`,
            }}
          >
            <div
              style={{
                display: "flex",
                flexDirection: "column",
                justifyContent: "center",
              }}
            >
              <div
                style={{
                  fontFamily: FONTS.ui,
                  fontSize: 12,
                  color: theme.text,
                  fontWeight: highlight ? 600 : 500,
                }}
              >
                {row.label}
              </div>
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 9.5,
                  color: theme.textMute,
                  marginTop: 2,
                  letterSpacing: 0.3,
                }}
              >
                {row.range}
              </div>
            </div>
            {statCell(row.stats.min)}
            {statCell(row.stats.max)}
            <div
              style={{
                fontFamily: FONTS.mono,
                fontSize: 10,
                color: theme.textDim,
                fontVariantNumeric: "tabular-nums",
                borderRight: sepRight,
                paddingRight: 12,
                display: "flex",
                alignItems: "flex-start",
                justifyContent: "flex-end",
              }}
            >
              {fmt(row.stats.avg)}
            </div>
            <div
              style={{
                display: "flex",
                flexDirection: "column",
                alignItems: "flex-end",
                justifyContent: "flex-start",
              }}
            >
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 10,
                  color: theme.text,
                  fontWeight: 600,
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {hasValue ? fmt(row.value) : ""}
              </div>
              {deltaPct !== null && (
                <div
                  style={{
                    fontFamily: FONTS.mono,
                    fontSize: 9.5,
                    color: deltaColor,
                    fontWeight: 600,
                    fontVariantNumeric: "tabular-nums",
                    marginTop: 2,
                    letterSpacing: 0.3,
                  }}
                >
                  {deltaOver ? "+" : "−"}
                  {Math.abs(deltaPct).toFixed(0)}%
                </div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Budget dashboard flow
// ─────────────────────────────────────────────────────────────
function EditBudgetSheet({
  budgetSetup,
  theme,
  accent,
  onClose,
  onSave,
  onOpenCategory,
}) {
  const [draft, setDraft] = React.useState(budgetSetup);
  const [mode, setMode] = React.useState("dashboard");
  const [monthKey, setMonthKey] = React.useState(budgetSetup.monthKey || "may");
  const [category, setCategory] = React.useState(null);
  const [toast, setToast] = React.useState(null);
  const monthSnapshot = BUDGET_EDIT_MONTHS.find(
    (month) => month.key === monthKey,
  );
  const displayedDraft =
    monthKey === "may" ? draft : { ...draft, ...monthSnapshot, monthKey };
  const explicitTotal = Object.values(displayedDraft.categoryBudgets).reduce(
    (sum, item) => sum + (Number(item.amount) || 0),
    0,
  );
  const explicitLastMonth = Object.keys(displayedDraft.categoryBudgets).reduce(
    (sum, name) => sum + (CATEGORY_LAST_MONTH_SPEND[name] || 0),
    0,
  );
  const update = (next) => {
    setDraft(next);
    onSave(next);
  };
  const saveCategory = (name, amount, recurring) => {
    const creating = !draft.categoryBudgets[name];
    update({
      ...draft,
      categoryBudgets: {
        ...draft.categoryBudgets,
        [name]: { amount, recurring },
      },
    });
    setCategory(null);
    if (creating) {
      setMode("add");
      setToast("New budget created");
    } else {
      setMode("dashboard");
    }
  };
  const removeCategory = (name) => {
    const next = { ...draft.categoryBudgets };
    delete next[name];
    update({ ...draft, categoryBudgets: next });
  };

  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 120,
        background: theme.bg,
        overflow: "auto",
      }}
    >
      <BudgetFlowHeader
        theme={theme}
        onBack={mode === "dashboard" ? onClose : () => setMode("dashboard")}
      />
      <div style={{ padding: "0 16px 22px" }}>
        {mode === "dashboard" && (
          <BudgetDashboardContent
            theme={theme}
            accent={accent}
            draft={displayedDraft}
            monthKey={monthKey}
            onMonthChange={setMonthKey}
            editable={monthKey === "may"}
            explicitTotal={explicitTotal}
            explicitLastMonth={explicitLastMonth}
            onEditIncome={() => setMode("income")}
            onEditBudget={() => setMode("budget")}
            onAdd={() => setMode("add")}
            onDone={onClose}
            onDelete={removeCategory}
            onEditCategory={(name) => {
              setCategory(name);
              setMode("category");
            }}
          />
        )}
        {mode === "income" && (
          <MonthlyIncomeEditor
            theme={theme}
            value={draft.monthlyIncome}
            onSave={(monthlyIncome) => {
              update({ ...draft, monthlyIncome });
              setMode("dashboard");
            }}
          />
        )}
        {mode === "budget" && (
          <MonthlyBudgetEditor
            theme={theme}
            income={draft.monthlyIncome}
            value={draft.monthlyBudget}
            onSave={(monthlyBudget) => {
              update({ ...draft, monthlyBudget });
              setMode("dashboard");
            }}
          />
        )}
        {mode === "add" && (
          <AddBudgetSheet
            theme={theme}
            accent={accent}
            draft={draft}
            toast={toast}
            onToastClose={() => setToast(null)}
            onClose={() => setMode("dashboard")}
            onSelect={(name) => {
              setCategory(name);
              setMode("category");
            }}
          />
        )}
        {mode === "category" && (
          <BudgetByCategorySheet
            theme={theme}
            accent={accent}
            draft={draft}
            category={category}
            onClose={() => setMode("add")}
            onSave={saveCategory}
            onOpenCategory={onOpenCategory}
          />
        )}
      </div>
    </div>
  );
}

function BudgetFlowHeader({ theme, onBack }) {
  return (
    <div
      style={{
        position: "sticky",
        top: 0,
        zIndex: 30,
        display: "grid",
        gridTemplateColumns: "36px 1fr 36px",
        alignItems: "center",
        padding: "12px 18px 10px",
        background: `linear-gradient(to bottom, ${theme.bg} 88%, ${theme.bg}00)`,
        backdropFilter: "blur(16px)",
      }}
    >
      <button
        onClick={onBack}
        aria-label="Back"
        style={{
          width: 32,
          height: 32,
          border: "none",
          background: "transparent",
          color: theme.text,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          cursor: "pointer",
          padding: 0,
        }}
      >
        <Ico.arrowL size={20} stroke={theme.text} />
      </button>
      <div
        style={{
          justifySelf: "center",
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 14,
          fontWeight: 600,
          display: "flex",
          alignItems: "center",
          padding: "6px 8px",
        }}
      >
        BUDGET DASHBOARD
      </div>
      <span />
    </div>
  );
}

function BudgetDashboardContent({
  theme,
  accent,
  draft,
  monthKey,
  onMonthChange,
  editable,
  explicitTotal,
  explicitLastMonth,
  onEditIncome,
  onEditBudget,
  onAdd,
  onDone,
  onDelete,
  onEditCategory,
}) {
  const savings = draft.monthlyIncome - draft.monthlyBudget;
  const rows = Object.entries(draft.categoryBudgets).map(([name, item]) => ({
    name,
    lastMonth: CATEGORY_LAST_MONTH_SPEND[name] || 0,
    amount: item.amount,
    editable: true,
  }));
  rows.push({
    name: "Everything else",
    lastMonth: Math.max(0, 4633 - explicitLastMonth),
    amount: Math.max(0, draft.monthlyBudget - explicitTotal),
    editable: false,
  });
  return (
    <div
      style={{
        minHeight: "calc(100vh - 76px)",
        display: "flex",
        flexDirection: "column",
        gap: 12,
      }}
    >
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(3, 1fr)",
          gap: 8,
          marginTop: 14,
        }}
      >
        {BUDGET_EDIT_MONTHS.map((m) => (
          <button
            key={m.key}
            onClick={() => onMonthChange(m.key)}
            style={{
              border: `0.5px solid ${m.key === monthKey ? accent : theme.line2}`,
              background: m.key === monthKey ? theme.surface2 : "transparent",
              borderRadius: 999,
              padding: "9px 0",
              color: theme.text,
              fontFamily: FONTS.mono,
              fontSize: 12,
              cursor: "pointer",
            }}
          >
            {m.label}
          </button>
        ))}
      </div>
      <Card theme={theme} style={{ padding: 16 }}>
        <SectionLabel theme={theme}>Monthly Budget</SectionLabel>
        <div style={{ height: 1, background: theme.line, margin: "14px 0" }} />
        <Card theme={theme} style={{ padding: 14, background: theme.surface2 }}>
          <div
            style={{
              fontFamily: FONTS.ui,
              fontSize: 14,
              fontWeight: 500,
              color: theme.text,
              marginBottom: 8,
            }}
          >
            Budget Basics
          </div>
          <BudgetEditRow
            theme={theme}
            label="Monthly income"
            amount={draft.monthlyIncome}
            onClick={editable ? onEditIncome : undefined}
          />
          <BudgetEditRow
            theme={theme}
            label="Monthly budget"
            amount={draft.monthlyBudget}
            onClick={editable ? onEditBudget : undefined}
          />
          <div style={{ height: 1, background: theme.line, margin: "8px 0" }} />
          <BudgetEditRow
            theme={theme}
            label="Monthly savings"
            amount={savings}
          />
        </Card>
        <SectionLabel theme={theme} style={{ marginTop: 18 }}>
          Category & Group Budgets
        </SectionLabel>
        <div
          style={{
            marginTop: 10,
            display: "flex",
            flexDirection: "column",
            gap: 10,
          }}
        >
          {rows.map((row) => (
            <div
              key={row.name}
              style={{
                display: "grid",
                gridTemplateColumns: "34px 1fr auto",
                alignItems: "center",
                gap: 10,
                border: `0.5px solid ${theme.line}`,
                borderRadius: 14,
                padding: 10,
                background: "#fff",
              }}
            >
              <CategoryIcon
                category={
                  row.name === "Shopping"
                    ? "Shopping"
                    : row.name === "Groceries" || row.name === "Drinks & dining"
                      ? "Food"
                      : "Bills"
                }
                theme={theme}
                accent={accent}
                size={34}
              />
              <div>
                <div
                  style={{
                    fontFamily: FONTS.ui,
                    fontSize: 13,
                    fontWeight: 400,
                    color: theme.text,
                  }}
                >
                  {row.name}
                </div>
                <div
                  style={{
                    fontFamily: FONTS.mono,
                    fontSize: 10.5,
                    color: theme.textMute,
                  }}
                >
                  {aed(row.lastMonth, 0)} last month
                </div>
              </div>
              <div
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 8,
                  fontFamily: FONTS.mono,
                  fontSize: 12,
                  color: theme.text,
                }}
              >
                {aed(row.amount, 0)}
                {editable && row.editable && (
                  <button
                    onClick={() => onEditCategory(row.name)}
                    style={plainIconButton(theme)}
                  >
                    <Ico.compose size={14} stroke={accent} />
                  </button>
                )}
                {editable && row.editable && (
                  <button
                    onClick={() => onDelete(row.name)}
                    style={plainIconButton(theme)}
                  >
                    <Ico.trash size={14} stroke={theme.negative || "#D15C4A"} />
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
        {editable && (
          <button
            onClick={onAdd}
            style={{
              ...primaryBudgetButton(theme, accent),
              background: "#000",
              fontWeight: 500,
            }}
          >
            Add Category or Group
          </button>
        )}
        <button onClick={onDone} style={secondaryBudgetButton(theme)}>
          Done
        </button>
      </Card>
    </div>
  );
}

function BudgetEditRow({ theme, label, amount, onClick }) {
  return (
    <button
      onClick={onClick}
      disabled={!onClick}
      style={{
        width: "100%",
        border: "none",
        background: "transparent",
        padding: "9px 0",
        display: "grid",
        gridTemplateColumns: onClick ? "1fr auto 22px" : "1fr auto",
        alignItems: "center",
        gap: 8,
        color: theme.text,
        textAlign: "left",
      }}
    >
      <span
        style={{ fontFamily: FONTS.ui, fontSize: 13, color: theme.textDim }}
      >
        {label}
      </span>
      <span style={{ fontFamily: FONTS.mono, fontSize: 13 }}>
        {aed(amount, 0)}
      </span>
      {onClick && <Ico.compose size={14} />}
    </button>
  );
}

function MonthlyIncomeEditor({ theme, value, onSave }) {
  const [amount, setAmount] = React.useState(String(value || 2394));
  const numeric = Number(amount) || 0;
  return (
    <BudgetLargeCard
      theme={theme}
      label="Monthly Income"
      title="Let's set your monthly income."
      helper="Based on your accounts, we estimated your monthly take-home pay at AED 2,394."
    >
      <CurrencyInput
        theme={theme}
        label="Monthly income"
        value={amount}
        onChange={setAmount}
      />
      <BudgetBars
        theme={theme}
        accent={theme.positive}
        value={numeric}
        months={["Nov", "Dec", "Jan", "Feb", "Mar", "Apr"]}
        data={[2100, 2320, 2394, 2410, 2280, 2464]}
        compact
      />
      <button onClick={() => onSave(numeric)} style={budgetSaveButton(theme)}>
        Save
      </button>
    </BudgetLargeCard>
  );
}

function MonthlyBudgetEditor({ theme, income, value, onSave }) {
  const [amount, setAmount] = React.useState(String(value || 0));
  const budget = Number(amount) || 0;
  const savings = income - budget;
  return (
    <BudgetLargeCard
      theme={theme}
      label="Monthly Budget"
      title="Now, let's define your monthly budget."
      helper="We'll subtract your monthly budget from your income to calculate your potential savings."
    >
      <CalcLine theme={theme} label="Monthly income" amount={income} />
      <div style={mathMark(theme)}>-</div>
      <Card theme={theme} style={{ padding: 14, background: theme.surface2 }}>
        <CurrencyInput
          theme={theme}
          label="Monthly budget"
          value={amount}
          onChange={setAmount}
        />
      </Card>
      <div style={mathMark(theme)}>=</div>
      <CalcLine theme={theme} label="Monthly savings" amount={savings} />
      <div
        style={{
          textAlign: "center",
          fontFamily: FONTS.ui,
          fontSize: 13,
          color: theme.text,
        }}
      >
        At this rate, you'll save {aed(savings * 12, 0)} per year!
      </div>
      <button onClick={() => onSave(budget)} style={budgetSaveButton(theme)}>
        Save
      </button>
    </BudgetLargeCard>
  );
}

function AddBudgetSheet({
  theme,
  accent,
  draft,
  toast,
  onToastClose,
  onClose,
  onSelect,
}) {
  return (
    <BottomSheetShell
      theme={theme}
      title="Add Category or Group Budget"
      onClose={onClose}
    >
      {toast && (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: 8,
            padding: 10,
            marginBottom: 10,
            borderRadius: 12,
            background: `${theme.positive}18`,
            color: theme.text,
            fontFamily: FONTS.ui,
            fontSize: 13,
          }}
        >
          <Ico.check size={15} stroke={theme.positive} /> {toast}
          <button
            onClick={onToastClose}
            style={{ ...plainIconButton(theme), marginLeft: "auto" }}
          >
            <Ico.close size={14} />
          </button>
        </div>
      )}
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {Object.keys(CATEGORY_LAST_MONTH_SPEND).map((name) => {
          const existing = draft.categoryBudgets[name];
          return (
            <button
              key={name}
              onClick={() => onSelect(name)}
              style={{
                border: `0.5px solid ${theme.line}`,
                background: "#fff",
                borderRadius: 14,
                padding: 10,
                display: "grid",
                gridTemplateColumns: "34px 1fr auto",
                alignItems: "center",
                gap: 10,
                color: theme.text,
                textAlign: "left",
              }}
            >
              <div
                style={{
                  width: 34,
                  height: 34,
                  borderRadius: 999,
                  background: CATEGORY_COLOR[name],
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                  color: theme.bg,
                }}
              >
                <CategoryIcon
                  category={
                    name === "Shopping"
                      ? "Shopping"
                      : name === "Groceries" || name === "Drinks & dining"
                        ? "Food"
                        : "Bills"
                  }
                  theme={{
                    ...theme,
                    surface2: "transparent",
                    line: "transparent",
                  }}
                  accent={accent}
                  size={24}
                />
              </div>
              <span>
                <span
                  style={{
                    display: "block",
                    fontFamily: FONTS.ui,
                    fontSize: 13,
                    fontWeight: 400,
                  }}
                >
                  {name}
                </span>
                <span
                  style={{
                    display: "block",
                    fontFamily: FONTS.mono,
                    fontSize: 10.5,
                    color: theme.textMute,
                  }}
                >
                  {aed(CATEGORY_LAST_MONTH_SPEND[name], 0)} last month
                </span>
              </span>
              {existing ? (
                <span
                  style={{
                    display: "flex",
                    alignItems: "center",
                    gap: 6,
                    fontFamily: FONTS.mono,
                    fontSize: 12,
                  }}
                >
                  {aed(existing.amount, 0)} <Ico.compose size={14} />
                </span>
              ) : (
                <Ico.plus size={16} stroke={accent} />
              )}
            </button>
          );
        })}
      </div>
    </BottomSheetShell>
  );
}

function BudgetByCategorySheet({
  theme,
  accent,
  draft,
  category,
  onClose,
  onSave,
  onOpenCategory,
}) {
  const current = draft.categoryBudgets[category]?.amount || "";
  const [amount, setAmount] = React.useState(String(current));
  const [future, setFuture] = React.useState(true);
  const numeric = Number(amount) || 0;
  const others = Object.entries(draft.categoryBudgets)
    .filter(([name]) => name !== category)
    .reduce((sum, [, item]) => sum + (Number(item.amount) || 0), 0);
  const detail = {
    ...SHOPPING_DETAIL,
    name: category,
    category,
    color: CATEGORY_COLOR[category] || accent,
    months: [
      {
        label: "Feb",
        amount: Math.round((CATEGORY_LAST_MONTH_SPEND[category] || 0) * 1.22),
      },
      {
        label: "Mar",
        amount: Math.round((CATEGORY_LAST_MONTH_SPEND[category] || 0) * 0.45),
      },
      { label: "Apr", amount: CATEGORY_LAST_MONTH_SPEND[category] || 0 },
      { label: "May", amount: numeric },
    ],
    transactions: SHOPPING_DETAIL.transactions.map((tx, index) => ({
      ...tx,
      id: `budget-${category}-${index}`,
      category,
    })),
  };
  return (
    <BottomSheetShell
      theme={theme}
      title="Budget by Category"
      onClose={onClose}
    >
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          gap: 8,
          marginBottom: 14,
        }}
      >
        <CategoryIcon
          category={category === "Shopping" ? "Shopping" : "Food"}
          theme={theme}
          accent={accent}
          size={42}
        />
        <div
          style={{
            fontFamily: FONTS.ui,
            fontSize: 22,
            fontWeight: 400,
            color: theme.text,
            textAlign: "center",
          }}
        >
          {category}
        </div>
      </div>
      <CurrencyInput
        theme={theme}
        label="budget for May"
        value={amount}
        onChange={setAmount}
        boxed
      />
      <div
        style={{
          marginTop: 10,
          display: "flex",
          alignItems: "center",
          gap: 6,
          color: theme.textMute,
          fontFamily: FONTS.ui,
          fontSize: 12,
        }}
      >
        Available budget: {aed(draft.monthlyBudget - others - numeric, 0)}
      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          gap: 8,
          marginTop: 12,
        }}
      >
        <StatMini
          theme={theme}
          label="Spent last month"
          value={CATEGORY_LAST_MONTH_SPEND[category] || 0}
        />
        <StatMini
          theme={theme}
          label="Monthly average"
          value={Math.round((CATEGORY_LAST_MONTH_SPEND[category] || 0) * 0.86)}
        />
      </div>
      <BudgetBars
        theme={theme}
        accent={CATEGORY_COLOR[category] || accent}
        value={numeric}
        months={["Dec", "Jan", "Feb", "Mar", "Apr", "May"]}
        data={[120, 164, 188, 155, CATEGORY_LAST_MONTH_SPEND[category] || 0, 7]}
      />
      <button
        onClick={() => onOpenCategory(detail)}
        style={{
          ...underlinedLink(accent),
          display: "block",
          margin: "14px auto 0",
        }}
      >
        View Transactions
      </button>
      <button
        onClick={() => setFuture((v) => !v)}
        style={{
          width: "100%",
          marginTop: 12,
          border: "none",
          background: "transparent",
          display: "grid",
          gridTemplateColumns: "1fr 44px",
          alignItems: "center",
          gap: 8,
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 13,
          textAlign: "left",
        }}
      >
        Apply to all future months{" "}
        <span
          style={{
            height: 24,
            borderRadius: 999,
            background: future ? accent : theme.line2,
            position: "relative",
          }}
        >
          <span
            style={{
              position: "absolute",
              top: 3,
              left: future ? 23 : 3,
              width: 18,
              height: 18,
              borderRadius: 999,
              background: theme.bg,
            }}
          />
        </span>
      </button>
      <button
        onClick={() => onSave(category, numeric, future)}
        style={primaryBudgetButton(theme, accent)}
      >
        Save
      </button>
    </BottomSheetShell>
  );
}

function BudgetLargeCard({ theme, label, title, helper, children }) {
  return (
    <Card
      theme={theme}
      style={{
        minHeight: "calc(100vh - 108px)",
        padding: 18,
        display: "flex",
        flexDirection: "column",
      }}
    >
      <SectionLabel theme={theme}>{label}</SectionLabel>
      <div style={{ height: 1, background: theme.line, margin: "14px 0" }} />
      <div
        style={{
          fontFamily: FONTS.display,
          fontSize: 25,
          lineHeight: 1.1,
          color: theme.text,
        }}
      >
        {title}
      </div>
      <div
        style={{
          marginTop: 8,
          fontFamily: FONTS.ui,
          fontSize: 13,
          lineHeight: 1.4,
          color: theme.textDim,
        }}
      >
        {helper}
      </div>
      <div
        style={{
          marginTop: 18,
          flex: 1,
          display: "flex",
          flexDirection: "column",
          gap: 14,
        }}
      >
        {children}
      </div>
    </Card>
  );
}

function CurrencyInput({ theme, label, value, onChange, boxed = false }) {
  if (boxed) {
    return (
      <label style={{ display: "block", textAlign: "center" }}>
        <div
          style={{
            fontFamily: FONTS.mono,
            fontSize: 10.5,
            textTransform: "uppercase",
            letterSpacing: 1.2,
            color: theme.textMute,
            marginBottom: 8,
          }}
        >
          {label}
        </div>
        <div
          style={{
            border: `0.5px solid ${theme.line2}`,
            borderRadius: 14,
            padding: 12,
          }}
        >
          <CurrencyInputInner theme={theme} value={value} onChange={onChange} />
        </div>
      </label>
    );
  }

  return (
    <label style={{ display: "block", textAlign: "center" }}>
      <div
        style={{
          fontFamily: FONTS.mono,
          fontSize: 10.5,
          textTransform: "uppercase",
          letterSpacing: 1.2,
          color: theme.textMute,
        }}
      >
        {label}
      </div>
      <CurrencyInputInner theme={theme} value={value} onChange={onChange} />
    </label>
  );
}

function CurrencyInputInner({ theme, value, onChange }) {
  return (
    <div
      style={{
        marginTop: 5,
        display: "flex",
        justifyContent: "center",
        alignItems: "baseline",
        gap: 6,
      }}
    >
      <span
        style={{ fontFamily: FONTS.display, fontSize: 25, color: theme.text }}
      >
        <Dh />
      </span>
      <input
        type="number"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        style={{
          width: 142,
          background: "transparent",
          border: "none",
          borderBottom: `1px solid ${theme.text}`,
          outline: "none",
          color: theme.text,
          fontFamily: FONTS.display,
          fontSize: 34,
          textAlign: "center",
          fontVariantNumeric: "tabular-nums",
        }}
      />
    </div>
  );
}

function BudgetBars({ theme, accent, value, months, data, compact = false }) {
  const max = Math.max(value * 1.5, ...data, 1);
  const chartHeight = compact ? 82 : 126;
  const barMaxHeight = compact ? 68 : 108;
  const topPad = compact ? 14 : 20;
  const lineTop = topPad + (1 - value / max) * barMaxHeight;
  return (
    <div
      style={{
        marginTop: 4,
        padding: `${topPad}px 6px 4px`,
        position: "relative",
        height: compact ? 116 : 166,
      }}
    >
      <div
        style={{
          position: "absolute",
          left: 4,
          right: 46,
          top: `${lineTop}px`,
          borderTop: `1px dashed ${theme.textMute}`,
        }}
      />
      <div
        style={{
          position: "absolute",
          right: 0,
          top: `${lineTop - 7}px`,
          fontFamily: FONTS.mono,
          fontSize: 10,
          color: theme.text,
        }}
      >
        {aed(value, 0)}
      </div>
      <div
        style={{
          height: chartHeight,
          display: "grid",
          gridTemplateColumns: `repeat(${months.length}, 1fr)`,
          gap: 10,
          alignItems: "end",
          justifyItems: "center",
          paddingRight: 46,
        }}
      >
        {data.map((v, i) => (
          <div
            key={months[i]}
            style={{
              width: 18,
              height: `${Math.max(8, (v / max) * barMaxHeight)}px`,
              background: accent,
              borderRadius: "7px 7px 3px 3px",
              opacity: 0.9,
            }}
          />
        ))}
      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: `repeat(${months.length}, 1fr)`,
          gap: 10,
          paddingRight: 46,
          marginTop: 8,
          fontFamily: FONTS.mono,
          fontSize: 10,
          color: theme.textMute,
          textAlign: "center",
        }}
      >
        {months.map((m) => (
          <span key={m}>{m}</span>
        ))}
      </div>
    </div>
  );
}

function CalcLine({ theme, label, amount }) {
  return (
    <div style={{ textAlign: "center" }}>
      <div
        style={{ fontFamily: FONTS.mono, fontSize: 10.5, color: theme.text }}
      >
        {label}
      </div>
      <div
        style={{
          marginTop: 5,
          fontFamily: FONTS.display,
          fontSize: 30,
          color: theme.text,
        }}
      >
        {aed(amount, 0)}
      </div>
    </div>
  );
}

function BottomSheetShell({ theme, title, onClose, children }) {
  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 130,
        background: "rgba(0,0,0,0.55)",
        display: "flex",
        alignItems: "flex-end",
      }}
    >
      <div
        style={{
          width: "100%",
          maxHeight: "86%",
          overflow: "auto",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "14px 18px 34px",
        }}
      >
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "34px 1fr 34px",
            alignItems: "center",
            marginBottom: 14,
          }}
        >
          <span />
          <SectionLabel theme={theme} style={{ textAlign: "center" }}>
            {title}
          </SectionLabel>
          <button onClick={onClose} style={budgetIconButtonStyle(theme)}>
            <Ico.close size={16} />
          </button>
        </div>
        {children}
      </div>
    </div>
  );
}

function StatMini({ theme, label, value }) {
  return (
    <Card
      theme={theme}
      style={{
        padding: 12,
        background: theme.surface2,
        textAlign: "center",
        minHeight: 70,
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      <div
        style={{ fontFamily: FONTS.ui, fontSize: 11, color: theme.textMute }}
      >
        {label}
      </div>
      <div
        style={{
          marginTop: 4,
          fontFamily: FONTS.mono,
          fontSize: 14,
          color: theme.text,
        }}
      >
        {aed(value, 0)}
      </div>
    </Card>
  );
}

function plainIconButton(theme) {
  return {
    width: 22,
    height: 22,
    border: "none",
    background: "transparent",
    color: theme.text,
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    padding: 0,
    cursor: "pointer",
  };
}

function primaryBudgetButton(theme, accent) {
  return {
    marginTop: 14,
    width: "100%",
    background: accent,
    color: theme.bg,
    border: "none",
    padding: "14px",
    borderRadius: 14,
    fontFamily: FONTS.ui,
    fontSize: 14,
    fontWeight: 400,
    textTransform: "uppercase",
    cursor: "pointer",
  };
}

function budgetSaveButton(theme) {
  return {
    marginTop: "auto",
    width: "100%",
    background: "#000",
    color: "#fff",
    border: "none",
    padding: "14px",
    borderRadius: 14,
    fontFamily: FONTS.ui,
    fontSize: 14,
    fontWeight: 500,
    cursor: "pointer",
  };
}

function secondaryBudgetButton(theme) {
  return {
    marginTop: 10,
    width: "100%",
    background: "#fff",
    color: theme.text,
    border: `0.5px solid ${theme.line2}`,
    padding: "14px",
    borderRadius: 14,
    fontFamily: FONTS.ui,
    fontSize: 14,
    fontWeight: 500,
    textTransform: "uppercase",
    cursor: "pointer",
  };
}

function underlinedLink(accent) {
  return {
    alignSelf: "center",
    border: "none",
    borderBottom: `0.5px solid ${accent}`,
    background: "transparent",
    color: accent,
    fontFamily: FONTS.mono,
    fontSize: 10.5,
    letterSpacing: 1.2,
    textTransform: "uppercase",
    padding: "0 0 3px",
    cursor: "pointer",
  };
}

function mathMark(theme) {
  return {
    textAlign: "center",
    fontFamily: FONTS.display,
    fontSize: 24,
    color: theme.textMute,
  };
}

// ─────────────────────────────────────────────────────────────
// Existing actions sheet + category picker (unchanged)
// ─────────────────────────────────────────────────────────────
function TransactionDetailSheet({
  tx,
  tags,
  theme,
  accent,
  onClose,
  onReCategorize,
  onOpenTags,
  onOpenMerchant,
  onRename,
  onDelete,
  onSplit,
}) {
  const [hidden, setHidden] = React.useState(!!tx.hidden);
  const [renaming, setRenaming] = React.useState(false);
  const [draftName, setDraftName] = React.useState(tx.merchant);
  const skipNameCommitRef = React.useRef(false);
  React.useEffect(() => {
    setDraftName(tx.merchant);
  }, [tx.merchant]);
  const commitName = () => {
    if (skipNameCommitRef.current) {
      skipNameCommitRef.current = false;
      return;
    }
    const next = draftName.trim();
    if (next && next !== tx.merchant) onRename(next);
    else setDraftName(tx.merchant);
    setRenaming(false);
  };
  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 120,
        background: "rgba(0,0,0,0.55)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 20px 34px",
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            display: "grid",
            gridTemplateColumns: "34px 1fr 34px",
            alignItems: "center",
            gap: 8,
            padding: "2px 0 16px",
          }}
        >
          <button onClick={onClose} style={iconButtonStyle(theme)}>
            <Ico.arrowL size={19} />
          </button>
          {renaming ? (
            <input
              value={draftName}
              autoFocus
              onChange={(e) => setDraftName(e.target.value)}
              onBlur={commitName}
              onKeyDown={(e) => {
                if (e.key === "Enter") e.currentTarget.blur();
                if (e.key === "Escape") {
                  skipNameCommitRef.current = true;
                  setDraftName(tx.merchant);
                  setRenaming(false);
                }
              }}
              style={{
                minWidth: 0,
                width: "100%",
                border: `0.5px solid ${theme.line2}`,
                borderRadius: 12,
                background: theme.surface2,
                color: theme.text,
                padding: "8px 10px",
                fontFamily: FONTS.ui,
                fontSize: 15,
                textAlign: "center",
                outline: "none",
              }}
            />
          ) : (
            <div
              style={{
                textAlign: "center",
                color: theme.text,
                fontSize: 15,
                fontWeight: 400,
                whiteSpace: "nowrap",
                overflow: "hidden",
                textOverflow: "ellipsis",
              }}
            >
              {tx.merchant}
            </div>
          )}
          <button
            onClick={() => setRenaming(true)}
            style={iconButtonStyle(theme)}
          >
            <Ico.compose size={17} />
          </button>
        </div>

        <div style={{ textAlign: "center", padding: "4px 0 18px" }}>
          <div
            style={{
              fontFamily: FONTS.display,
              fontSize: 22,
              color: tx.amount >= 0 ? theme.positive : theme.text,
              letterSpacing: 0,
              fontVariantNumeric: "tabular-nums",
            }}
          >
            {tx.amount >= 0 ? "+" : "−"}
            <Dh /> {fmtAED(Math.abs(tx.amount), { decimals: 2 })}
          </div>
          <button
            onClick={onReCategorize}
            style={{
              marginTop: 12,
              border: 0,
              background: theme.surface2,
              color: theme.text,
              borderRadius: 999,
              padding: "8px 12px",
              display: "inline-flex",
              alignItems: "center",
              gap: 7,
              fontFamily: FONTS.ui,
              fontSize: 12.5,
              cursor: "pointer",
            }}
          >
            <CategoryIcon
              category={tx.category}
              theme={theme}
              accent={accent}
              size={24}
            />
            {tx.category}
            <Ico.chevD size={12} />
          </button>
        </div>

        <Card theme={theme} padded={false} style={{ overflow: "hidden" }}>
          <DetailRow label="Date" value={tx.date} theme={theme} />
          <button onClick={onOpenMerchant} style={rowButtonReset()}>
            <DetailRow label="Merchant" value={tx.merchant} theme={theme}>
              <span
                style={{ display: "inline-flex", alignItems: "center", gap: 8 }}
              >
                <span>{tx.merchant}</span>
                <Ico.chevR size={14} stroke={theme.textDim} />
              </span>
            </DetailRow>
          </button>
          <button onClick={onOpenTags} style={rowButtonReset()}>
            <DetailRow label="Tag" theme={theme}>
              <span
                style={{
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 8,
                  justifyContent: "flex-end",
                }}
              >
                <TransactionTagPills
                  tagIds={tx.tagIds || []}
                  tags={tags}
                  theme={theme}
                />
                <Ico.chevR size={14} stroke={theme.textDim} />
              </span>
            </DetailRow>
          </button>
          <DetailRow label="Hide Transaction" theme={theme}>
            <Switch
              theme={theme}
              accent={accent}
              value={hidden}
              onChange={() => setHidden((v) => !v)}
            />
          </DetailRow>
          <button
            onClick={onSplit}
            style={{
              width: "100%",
              border: "none",
              background: "transparent",
              padding: 0,
              cursor: "pointer",
            }}
          >
            <DetailRow label="Split Transaction" theme={theme} last>
              <Ico.chevR size={14} stroke={theme.textDim} />
            </DetailRow>
          </button>
        </Card>

        <div
          style={{
            padding: "14px 4px 0",
            color: theme.textMute,
            fontFamily: FONTS.mono,
            fontSize: 11,
            lineHeight: 1.5,
          }}
        >
          Synced from linked account: {tx.account}
        </div>
      </div>
    </div>
  );
}

function rowButtonReset() {
  return {
    width: "100%",
    border: "none",
    background: "transparent",
    padding: 0,
    cursor: "pointer",
    textAlign: "left",
  };
}

function TransactionTagPills({ tagIds, tags, theme }) {
  const selected = tagIds
    .map((id) => tags.find((tag) => tag.id === id))
    .filter(Boolean);
  if (selected.length === 0)
    return <span style={{ color: theme.textMute }}>None</span>;
  return (
    <span
      style={{
        display: "inline-flex",
        gap: 5,
        flexWrap: "wrap",
        justifyContent: "flex-end",
      }}
    >
      {selected.slice(0, 2).map((tag) => (
        <span
          key={tag.id}
          style={{
            display: "inline-flex",
            alignItems: "center",
            gap: 5,
            maxWidth: 116,
            padding: "5px 8px",
            borderRadius: 999,
            background: `${tag.color}22`,
            color: theme.text,
            fontSize: 11.5,
          }}
        >
          <span
            style={{
              width: 6,
              height: 6,
              borderRadius: 3,
              background: tag.color,
              flexShrink: 0,
            }}
          />
          <span
            style={{
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap",
            }}
          >
            {tag.name}
          </span>
        </span>
      ))}
      {selected.length > 2 && (
        <span style={{ color: theme.textMute, fontSize: 12 }}>
          +{selected.length - 2}
        </span>
      )}
    </span>
  );
}

function DetailRow({ label, value, theme, children, last }) {
  return (
    <div
      style={{
        minHeight: 48,
        padding: "0 14px",
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        gap: 12,
        borderBottom: last ? "none" : `0.5px solid ${theme.line}`,
      }}
    >
      <div style={{ color: theme.textDim, fontSize: 13 }}>{label}</div>
      <div
        style={{
          color: theme.text,
          fontSize: 13,
          fontWeight: 400,
          textAlign: "right",
        }}
      >
        {children || value}
      </div>
    </div>
  );
}

function iconButtonStyle(theme) {
  return {
    width: 34,
    height: 34,
    border: "none",
    background: "transparent",
    color: theme.text,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    cursor: "pointer",
    padding: 0,
  };
}

function Switch({ theme, accent, value, onChange }) {
  return (
    <button
      onClick={onChange}
      style={{
        width: 44,
        height: 26,
        border: "none",
        borderRadius: 13,
        background: value ? accent : theme.line2,
        padding: 3,
        cursor: "pointer",
        display: "flex",
        justifyContent: value ? "flex-end" : "flex-start",
      }}
    >
      <span
        style={{
          width: 20,
          height: 20,
          borderRadius: 10,
          background: "#fff",
          boxShadow: "0 1px 4px rgba(0,0,0,0.18)",
        }}
      />
    </button>
  );
}

// Delete confirmation — discloses metric impact before removing the tx.
function DeleteConfirmSheet({ tx, theme, accent, onCancel, onConfirm }) {
  return (
    <div
      onClick={onCancel}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 140,
        background: "rgba(0,0,0,0.6)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 20px 28px",
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            width: 48,
            height: 48,
            borderRadius: 24,
            margin: "4px auto 14px",
            background: `${theme.negative}18`,
            color: theme.negative,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          <Ico.close size={22} sw={2.2} />
        </div>

        <div
          style={{
            fontFamily: FONTS.display,
            fontSize: 20,
            color: theme.text,
            letterSpacing: -0.3,
            textAlign: "center",
          }}
        >
          Delete this transaction?
        </div>
        <div
          style={{
            fontSize: 13,
            color: theme.textDim,
            marginTop: 10,
            lineHeight: 1.5,
            textAlign: "center",
            padding: "0 6px",
          }}
        >
          Your spending, budget pacing and other metrics will be readjusted as
          if <b style={{ color: theme.text }}>{tx.merchant}</b> (
          {tx.amount >= 0 ? "+" : "−"}
          {fmtAED(Math.abs(tx.amount), {
            decimals: Math.abs(tx.amount) < 1000 ? 2 : 0,
          })}
          ) never happened. Are you OK with that?
        </div>

        <div style={{ display: "flex", gap: 10, marginTop: 22 }}>
          <button
            onClick={onCancel}
            style={{
              flex: 1,
              background: "transparent",
              border: `0.5px solid ${theme.line2}`,
              borderRadius: 14,
              padding: "13px",
              color: theme.text,
              fontFamily: FONTS.ui,
              fontSize: 13.5,
              fontWeight: 500,
              cursor: "pointer",
            }}
          >
            Cancel
          </button>
          <button
            onClick={onConfirm}
            style={{
              flex: 1,
              background: theme.negative,
              border: "none",
              borderRadius: 14,
              padding: "13px",
              color: "#fff",
              fontFamily: FONTS.ui,
              fontSize: 13.5,
              fontWeight: 600,
              cursor: "pointer",
            }}
          >
            Delete
          </button>
        </div>
      </div>
    </div>
  );
}

function SplitTransactionSheet({
  tx,
  theme,
  accent,
  onBack,
  onClose,
  onApply,
  onRemoveSplit,
}) {
  const existing = tx.splitActive && tx.splitChildren?.length >= 2;
  const originalCents = toCents(tx.amount);
  const makeLine = (index, amountCents) => ({
    id: `line-${Date.now()}-${index}`,
    merchant: tx.merchant,
    category: tx.category || null,
    amountCents,
    hidden: false,
  });
  const [mode, setMode] = React.useState("equal");
  const [modeMenuOpen, setModeMenuOpen] = React.useState(false);
  const [confirmRemove, setConfirmRemove] = React.useState(false);
  const [lines, setLines] = React.useState(() => {
    if (existing) {
      return tx.splitChildren.map((child, index) => ({
        id: child.id,
        merchant: child.merchant || tx.merchant,
        category: child.category || null,
        amountCents: toCents(child.amount),
        hidden: !!child.hidden,
      }));
    }
    return distributeCents(originalCents, 2).map((amount, index) =>
      makeLine(index, amount),
    );
  });
  const lastRef = React.useRef(null);
  React.useEffect(() => {
    lastRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
  }, [lines.length]);
  const total = lines.reduce((s, line) => s + line.amountCents, 0);
  const valid =
    lines.length >= 2 &&
    lines.every((line) => line.category && line.amountCents > 0) &&
    total === originalCents;
  const helper =
    total < originalCents
      ? `Remaining: $${fmtAED((originalCents - total) / 100, { decimals: 2 })}`
      : total > originalCents
        ? `Over by: $${fmtAED((total - originalCents) / 100, { decimals: 2 })}`
        : "Ready to apply";
  const rebalance = (next) => {
    const amounts = distributeCents(originalCents, next.length);
    return next.map((line, index) => ({
      ...line,
      amountCents: amounts[index],
    }));
  };
  const updateLine = (id, patch, forceCustom) => {
    if (forceCustom) setMode("custom");
    setLines((current) =>
      current.map((line) => (line.id === id ? { ...line, ...patch } : line)),
    );
  };
  const addLine = () => {
    setLines((current) => {
      const next = [...current, makeLine(current.length, 0)];
      return mode === "equal" ? rebalance(next) : next;
    });
  };
  const removeLine = (id) => {
    setLines((current) => {
      if (current.length <= 2) return current;
      const next = current.filter((line) => line.id !== id);
      return mode === "equal" ? rebalance(next) : next;
    });
  };
  const setEqual = () => {
    setMode("equal");
    setLines((current) => rebalance(current));
  };
  const selectMode = (nextMode) => {
    setModeMenuOpen(false);
    if (nextMode === "equal") {
      setEqual();
      return;
    }
    setMode("custom");
  };
  const splitActionButtonStyle = {
    width: "100%",
    height: 34,
    padding: "0 13px",
    borderRadius: 17,
    border: `0.5px solid ${theme.line2}`,
    background: theme.surface,
    color: theme.text,
    fontFamily: FONTS.mono,
    fontSize: 10.5,
    letterSpacing: 1.2,
    textTransform: "uppercase",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    gap: 7,
    cursor: "pointer",
    whiteSpace: "nowrap",
  };

  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 160,
        background: theme.bg,
        display: "flex",
        flexDirection: "column",
        animation: "himma-slide 220ms cubic-bezier(.2,.8,.25,1)",
      }}
    >
      <div
        style={{
          padding: "12px 18px 10px",
          display: "grid",
          gridTemplateColumns: "36px 1fr 36px",
          alignItems: "center",
        }}
      >
        <button onClick={onBack} style={iconButtonStyle(theme)}>
          <Ico.arrowL size={20} />
        </button>
        <div
          style={{
            textAlign: "center",
            color: theme.text,
            fontFamily: FONTS.mono,
            fontSize: 11,
            letterSpacing: 1.4,
            fontWeight: 600,
          }}
        >
          SPLIT TRANSACTION
        </div>
        <button onClick={onClose} style={iconButtonStyle(theme)}>
          <Ico.close size={18} />
        </button>
      </div>

      <div style={{ flex: 1, overflowY: "auto", padding: "4px 18px 92px" }}>
        <Card theme={theme} style={{ padding: 16, border: 0 }}>
          <div style={{ color: theme.text, fontSize: 15, fontWeight: 400 }}>
            {tx.merchant}
          </div>
          <div
            style={{
              marginTop: 6,
              color: theme.text,
              fontFamily: FONTS.display,
              fontSize: 22,
            }}
          >
            {tx.amount >= 0 ? "+" : "−"}
            <Dh /> {fmtAED(Math.abs(tx.amount), { decimals: 2 })}
          </div>
          <div
            style={{
              marginTop: 4,
              color: theme.textMute,
              fontFamily: FONTS.mono,
              fontSize: 11,
            }}
          >
            {tx.date}
          </div>
        </Card>

        <div
          style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            alignItems: "stretch",
            gap: 8,
            margin: "16px 0 12px",
          }}
        >
          <div style={{ position: "relative", minWidth: 0 }}>
            <button
              type="button"
              onClick={() => setModeMenuOpen((open) => !open)}
              style={splitActionButtonStyle}
            >
              {mode === "equal" ? "EQUAL" : "CUSTOM"} <Ico.chevD size={12} />
            </button>
            {modeMenuOpen && (
              <div
                style={{
                  position: "absolute",
                  top: 40,
                  left: 0,
                  right: 0,
                  zIndex: 50,
                  background: theme.surface,
                  border: `0.5px solid ${theme.line}`,
                  borderRadius: 12,
                  boxShadow: theme.shadow?.modal,
                  padding: 4,
                }}
              >
                {["equal", "custom"].map((option) => (
                  <button
                    key={option}
                    type="button"
                    onClick={() => selectMode(option)}
                    style={{
                      width: "100%",
                      border: "none",
                      background:
                        mode === option ? theme.surface2 : "transparent",
                      color: theme.text,
                      borderRadius: 9,
                      padding: "9px 10px",
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "space-between",
                      cursor: "pointer",
                      fontFamily: FONTS.mono,
                      fontSize: 10.5,
                      letterSpacing: 1.1,
                      textTransform: "uppercase",
                    }}
                  >
                    {option}
                    {mode === option && <Ico.check size={13} />}
                  </button>
                ))}
              </div>
            )}
          </div>
          <button
            type="button"
            onClick={addLine}
            style={splitActionButtonStyle}
          >
            <Ico.plus size={13} /> ADD SPLIT
          </button>
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {lines.map((line, index) => (
            <SplitLineCard
              key={line.id}
              refEl={index === lines.length - 1 ? lastRef : null}
              line={line}
              removable={lines.length > 2}
              theme={theme}
              accent={accent}
              onChange={(patch, custom) => updateLine(line.id, patch, custom)}
              onRemove={() => removeLine(line.id)}
            />
          ))}
        </div>
        {mode === "custom" && (
          <div
            style={{
              padding: "12px 4px 0",
              color: valid ? theme.positive : theme.textDim,
              fontSize: 12.5,
              fontFamily: FONTS.mono,
            }}
          >
            {helper}
          </div>
        )}
      </div>

      <div
        style={{
          position: "absolute",
          left: 0,
          right: 0,
          bottom: 0,
          padding: "12px 18px 26px",
          background: `linear-gradient(to top, ${theme.bg} 82%, ${theme.bg}00)`,
          display: "grid",
          gap: 10,
        }}
      >
        <button
          onClick={() => (existing ? setConfirmRemove(true) : onBack())}
          style={{
            border: 0,
            background: "transparent",
            color: existing ? theme.negative : theme.text,
            borderRadius: 14,
            fontFamily: FONTS.mono,
            fontSize: 13,
            fontWeight: 600,
            cursor: "pointer",
            textDecoration: "underline",
          }}
        >
          REMOVE SPLIT
        </button>
        <button
          disabled={!valid}
          onClick={() => onApply(lines)}
          style={{
            border: "none",
            background: valid ? "#071124" : theme.line2,
            color: valid ? "#FFFFFF" : theme.textMute,
            borderRadius: 14,
            padding: "14px",
            fontFamily: FONTS.ui,
            fontSize: 13,
            fontWeight: 700,
            cursor: valid ? "pointer" : "default",
          }}
        >
          APPLY SPLIT
        </button>
      </div>
      {confirmRemove && (
        <ConfirmMiniSheet
          theme={theme}
          title="Remove split?"
          body="This will restore the original transaction and delete the split entries."
          onCancel={() => setConfirmRemove(false)}
          onConfirm={onRemoveSplit}
        />
      )}
    </div>
  );
}

function SplitLineCard({
  line,
  removable,
  theme,
  accent,
  onChange,
  onRemove,
  refEl,
}) {
  return (
    <div ref={refEl}>
      <Card theme={theme} style={{ padding: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <div
            style={{
              flex: 1,
              minWidth: 0,
              color: theme.text,
              fontSize: 13.5,
              fontWeight: 600,
              whiteSpace: "nowrap",
              overflow: "hidden",
              textOverflow: "ellipsis",
            }}
          >
            {line.merchant}
          </div>
          {removable && (
            <button
              onClick={onRemove}
              style={{
                ...iconButtonStyle(theme),
                background: theme.surface2,
                borderRadius: 17,
              }}
            >
              <Ico.minus size={15} />
            </button>
          )}
        </div>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "1fr 112px",
            gap: 10,
            marginTop: 12,
          }}
        >
          <select
            value={line.category || ""}
            onChange={(e) =>
              onChange({ category: e.target.value || null }, false)
            }
            style={{
              minWidth: 0,
              border: `0.5px solid ${theme.line2}`,
              borderRadius: 14,
              background: theme.surface2,
              color: theme.text,
              padding: "10px 10px",
              fontFamily: FONTS.ui,
              fontSize: 12.5,
            }}
          >
            <option value="">Category</option>
            {EDITABLE_CATS.map((cat) => (
              <option key={cat} value={cat}>
                {cat}
              </option>
            ))}
          </select>
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: 5,
              border: `0.5px solid ${theme.line2}`,
              borderRadius: 14,
              background: theme.surface2,
              padding: "0 10px",
              color: theme.text,
            }}
          >
            <input
              value={(line.amountCents / 100).toFixed(2)}
              inputMode="decimal"
              onChange={(e) =>
                onChange(
                  {
                    amountCents: Math.max(
                      0,
                      Math.round(Number(e.target.value || 0) * 100),
                    ),
                  },
                  true,
                )
              }
              style={{
                width: "100%",
                border: "none",
                outline: "none",
                background: "transparent",
                color: theme.text,
                fontFamily: FONTS.mono,
                fontSize: 13,
              }}
            />
          </div>
        </div>
        <div
          style={{
            marginTop: 12,
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <div style={{ color: theme.textDim, fontSize: 12 }}>
            Hide transaction
          </div>
          <Switch
            theme={theme}
            accent={accent}
            value={line.hidden}
            onChange={() => onChange({ hidden: !line.hidden }, false)}
          />
        </div>
      </Card>
    </div>
  );
}

function ConfirmMiniSheet({ theme, title, body, onCancel, onConfirm }) {
  return (
    <div
      onClick={onCancel}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 190,
        background: "rgba(0,0,0,0.55)",
        display: "flex",
        alignItems: "flex-end",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          padding: "24px 20px 30px",
        }}
      >
        <div
          style={{
            color: theme.text,
            fontFamily: FONTS.display,
            fontSize: 22,
            textAlign: "center",
          }}
        >
          {title}
        </div>
        <div
          style={{
            color: theme.textDim,
            fontSize: 13,
            lineHeight: 1.5,
            marginTop: 10,
            textAlign: "center",
          }}
        >
          {body}
        </div>
        <div style={{ display: "flex", gap: 10, marginTop: 22 }}>
          <button
            onClick={onCancel}
            style={{
              flex: 1,
              border: `0.5px solid ${theme.line2}`,
              background: "transparent",
              color: theme.text,
              borderRadius: 14,
              padding: 13,
            }}
          >
            Cancel
          </button>
          <button
            onClick={onConfirm}
            style={{
              flex: 1,
              border: "none",
              background: theme.negative,
              color: "#fff",
              borderRadius: 14,
              padding: 13,
            }}
          >
            Remove Split
          </button>
        </div>
      </div>
    </div>
  );
}

function SplitToast({ theme, accent, toast, onClose }) {
  return (
    <div
      style={{
        position: "absolute",
        left: 18,
        right: 18,
        top: 18,
        zIndex: 220,
        background: "#fff",
        color: "#1B1A18",
        borderRadius: 16,
        boxShadow: "0 14px 34px rgba(0,0,0,0.24)",
        padding: "13px 12px",
        display: "grid",
        gridTemplateColumns: "30px 1fr 30px",
        gap: 10,
        alignItems: "center",
      }}
    >
      <div
        style={{
          width: 30,
          height: 30,
          borderRadius: 15,
          background: "#2F9E5B18",
          color: "#2F9E5B",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <Ico.check size={16} />
      </div>
      <div>
        <div style={{ fontSize: 13.5, fontWeight: 700 }}>{toast.title}</div>
        {toast.body && (
          <div style={{ fontSize: 12, color: "#625E55", marginTop: 2 }}>
            {toast.body}
          </div>
        )}
      </div>
      <button
        onClick={onClose}
        style={{
          border: "none",
          background: "transparent",
          color: "#625E55",
          cursor: "pointer",
        }}
      >
        <Ico.close size={15} />
      </button>
    </div>
  );
}

function SheetFrame({ theme, z = 130, onClose, children, maxHeight = "86%" }) {
  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: z,
        background: "rgba(0,0,0,0.55)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          maxHeight,
          overflow: "auto",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 20px 30px",
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 14,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>
        {children}
      </div>
    </div>
  );
}

function SheetTitle({ title, theme, onClose }) {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "1fr 34px",
        alignItems: "center",
        gap: 8,
        paddingBottom: 14,
      }}
    >
      <SectionLabel theme={theme}>{title}</SectionLabel>
      <button onClick={onClose} style={iconButtonStyle(theme)}>
        <Ico.close size={17} />
      </button>
    </div>
  );
}

function SelectTagsSheet({
  tx,
  tags,
  theme,
  accent,
  onClose,
  onCreate,
  onManage,
  onSave,
}) {
  const [q, setQ] = React.useState("");
  const [selected, setSelected] = React.useState(tx.tagIds || []);
  const filtered = tags.filter((tag) =>
    tag.name.toLowerCase().includes(q.trim().toLowerCase()),
  );
  const toggle = (id) =>
    setSelected((ids) =>
      ids.includes(id) ? ids.filter((x) => x !== id) : [...ids, id],
    );
  return (
    <SheetFrame theme={theme} onClose={onClose}>
      <SheetTitle title="SELECT TAGS" theme={theme} onClose={onClose} />
      <SearchBox q={q} setQ={setQ} theme={theme} placeholder="Search" />
      <div style={{ minHeight: 178, padding: "14px 0" }}>
        {filtered.length === 0 ? (
          <div
            style={{
              height: 150,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: theme.textMute,
              fontFamily: FONTS.mono,
              fontSize: 11,
              textAlign: "center",
            }}
          >
            {tags.length === 0 ? "No tags yet." : "No tags match."}
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {filtered.map((tag) => {
              const active = selected.includes(tag.id);
              return (
                <button
                  key={tag.id}
                  onClick={() => toggle(tag.id)}
                  style={{
                    minHeight: 44,
                    borderRadius: 14,
                    border: `0.5px solid ${active ? tag.color : theme.line}`,
                    background: active ? `${tag.color}18` : theme.surface2,
                    color: theme.text,
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "space-between",
                    padding: "0 13px",
                    cursor: "pointer",
                  }}
                >
                  <span
                    style={{
                      display: "inline-flex",
                      alignItems: "center",
                      gap: 9,
                      minWidth: 0,
                    }}
                  >
                    <span
                      style={{
                        width: 9,
                        height: 9,
                        borderRadius: 5,
                        background: tag.color,
                        flexShrink: 0,
                      }}
                    />
                    <span
                      style={{
                        fontSize: 13,
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                        whiteSpace: "nowrap",
                      }}
                    >
                      {tag.name}
                    </span>
                  </span>
                  {active && <Ico.check size={16} stroke={tag.color} />}
                </button>
              );
            })}
          </div>
        )}
      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr auto auto",
          alignItems: "center",
          gap: 10,
        }}
      >
        <button
          onClick={onCreate}
          style={{
            border: "none",
            background: "transparent",
            color: theme.text,
            display: "inline-flex",
            alignItems: "center",
            gap: 7,
            cursor: "pointer",
            padding: 0,
          }}
        >
          <span
            style={{
              width: 28,
              height: 28,
              borderRadius: 14,
              border: `0.5px solid ${theme.line2}`,
              display: "inline-flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <Ico.plus size={15} />
          </span>
          <span
            style={{
              textDecoration: "underline",
              textUnderlineOffset: 3,
              fontSize: 13,
            }}
          >
            Create
          </span>
        </button>
        <PillButton theme={theme} onClick={onManage}>
          MANAGE TAGS
        </PillButton>
        <PillButton
          theme={theme}
          accent={accent}
          filled
          onClick={() => onSave(selected)}
        >
          SAVE
        </PillButton>
      </div>
    </SheetFrame>
  );
}

function CreateTagSheet({ tags, theme, accent, onClose, onCancel, onCreate }) {
  const [name, setName] = React.useState("");
  const [color, setColor] = React.useState(TAG_COLORS[0]);
  const trimmed = name.trim();
  const duplicate = tags.some(
    (tag) => tag.name.toLowerCase() === trimmed.toLowerCase(),
  );
  const invalid = !trimmed || duplicate;
  return (
    <SheetFrame theme={theme} onClose={onClose}>
      <SheetTitle title="CREATE NEW TAG" theme={theme} onClose={onClose} />
      <div
        style={{ height: 1, background: theme.line, margin: "0 -20px 16px" }}
      />
      <label style={{ display: "block", position: "relative" }}>
        {name && (
          <span
            style={{
              position: "absolute",
              top: 6,
              left: 14,
              color: theme.textMute,
              fontFamily: FONTS.mono,
              fontSize: 9,
              letterSpacing: 1.1,
              textTransform: "uppercase",
            }}
          >
            Tag name
          </span>
        )}
        <input
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Tag name"
          autoFocus
          style={{
            width: "100%",
            boxSizing: "border-box",
            border: `0.5px solid ${duplicate ? theme.negative : theme.line2}`,
            borderRadius: 14,
            background: theme.surface2,
            color: theme.text,
            padding: name ? "22px 14px 8px" : "14px",
            outline: "none",
            fontFamily: FONTS.ui,
            fontSize: 14,
          }}
        />
      </label>
      {duplicate && (
        <div style={{ color: theme.negative, fontSize: 11, marginTop: 7 }}>
          A tag with this name already exists.
        </div>
      )}
      <SectionLabel theme={theme} style={{ marginTop: 22, marginBottom: 12 }}>
        Pick a color
      </SectionLabel>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(6, 1fr)",
          rowGap: 14,
          justifyItems: "center",
        }}
      >
        {TAG_COLORS.map((swatch) => (
          <button
            key={swatch}
            onClick={() => setColor(swatch)}
            aria-label={`Pick ${swatch}`}
            style={{
              width: 34,
              height: 34,
              borderRadius: 17,
              border:
                color === swatch
                  ? `2px solid ${theme.text}`
                  : "2px solid transparent",
              background: "transparent",
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              cursor: "pointer",
            }}
          >
            <span
              style={{
                width: 24,
                height: 24,
                borderRadius: 12,
                background: swatch,
              }}
            />
          </button>
        ))}
      </div>
      <button
        disabled={invalid}
        onClick={() => onCreate(trimmed, color)}
        style={{
          width: "100%",
          marginTop: 24,
          height: 46,
          border: "none",
          borderRadius: 23,
          background: invalid ? theme.line2 : accent,
          color: invalid ? theme.textMute : theme.bg,
          fontFamily: FONTS.mono,
          fontSize: 11,
          letterSpacing: 1.2,
          fontWeight: 700,
          cursor: invalid ? "default" : "pointer",
        }}
      >
        CREATE NEW TAG
      </button>
      <button
        onClick={onCancel}
        style={{
          width: "100%",
          marginTop: 12,
          border: "none",
          background: "transparent",
          color: theme.textDim,
          fontSize: 13,
          cursor: "pointer",
        }}
      >
        CANCEL
      </button>
    </SheetFrame>
  );
}

function ManageTagsSheet({ tags, theme, accent, onClose, onBack, onSave }) {
  const [draft, setDraft] = React.useState(tags.map((tag) => ({ ...tag })));
  const normalizedNames = draft.map((tag) => tag.name.trim().toLowerCase());
  const hasInvalid = draft.some((tag, index) => {
    const name = tag.name.trim().toLowerCase();
    return !name || normalizedNames.indexOf(name) !== index;
  });
  const updateTag = (id, patch) => {
    setDraft((all) =>
      all.map((tag) => (tag.id === id ? { ...tag, ...patch } : tag)),
    );
  };
  const deleteTag = (id) => {
    setDraft((all) => all.filter((tag) => tag.id !== id));
  };
  return (
    <SheetFrame theme={theme} onClose={onClose} maxHeight="90%">
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "34px 1fr 34px",
          alignItems: "center",
          gap: 8,
          paddingBottom: 14,
        }}
      >
        <button onClick={onBack} style={iconButtonStyle(theme)}>
          <Ico.arrowL size={18} />
        </button>
        <SectionLabel theme={theme} style={{ textAlign: "center" }}>
          MANAGE TAGS
        </SectionLabel>
        <button onClick={onClose} style={iconButtonStyle(theme)}>
          <Ico.close size={17} />
        </button>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        {draft.length === 0 ? (
          <div
            style={{
              minHeight: 150,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: theme.textMute,
              fontFamily: FONTS.mono,
              fontSize: 11,
            }}
          >
            No tags to manage.
          </div>
        ) : (
          draft.map((tag) => {
            const trimmed = tag.name.trim().toLowerCase();
            const duplicate =
              trimmed &&
              normalizedNames.filter((name) => name === trimmed).length > 1;
            const invalid = !trimmed || duplicate;
            return (
              <Card key={tag.id} theme={theme} style={{ padding: 12 }}>
                <div
                  style={{
                    display: "grid",
                    gridTemplateColumns: "1fr 34px",
                    gap: 10,
                    alignItems: "center",
                  }}
                >
                  <input
                    value={tag.name}
                    onChange={(e) =>
                      updateTag(tag.id, { name: e.target.value })
                    }
                    style={{
                      minWidth: 0,
                      border: `0.5px solid ${invalid ? theme.negative : theme.line2}`,
                      borderRadius: 12,
                      background: theme.surface2,
                      color: theme.text,
                      padding: "10px 12px",
                      outline: "none",
                      fontFamily: FONTS.ui,
                      fontSize: 13,
                    }}
                  />
                  <button
                    onClick={() => deleteTag(tag.id)}
                    aria-label={`Delete ${tag.name}`}
                    style={{ ...iconButtonStyle(theme), color: theme.negative }}
                  >
                    <Ico.trash size={16} />
                  </button>
                </div>
                {invalid && (
                  <div
                    style={{
                      color: theme.negative,
                      fontSize: 11,
                      marginTop: 7,
                    }}
                  >
                    {duplicate
                      ? "Tag names must be unique."
                      : "Tag name is required."}
                  </div>
                )}
                <div
                  style={{
                    display: "grid",
                    gridTemplateColumns: "repeat(9, 1fr)",
                    gap: 8,
                    marginTop: 12,
                  }}
                >
                  {TAG_COLORS.map((swatch) => (
                    <button
                      key={swatch}
                      onClick={() => updateTag(tag.id, { color: swatch })}
                      aria-label={`Set ${tag.name} color`}
                      style={{
                        width: 24,
                        height: 24,
                        borderRadius: 12,
                        border:
                          tag.color === swatch
                            ? `2px solid ${theme.text}`
                            : `1px solid ${theme.line}`,
                        background: swatch,
                        cursor: "pointer",
                      }}
                    />
                  ))}
                </div>
              </Card>
            );
          })
        )}
      </div>
      <button
        disabled={hasInvalid}
        onClick={() =>
          onSave(draft.map((tag) => ({ ...tag, name: tag.name.trim() })))
        }
        style={{
          width: "100%",
          marginTop: 18,
          height: 46,
          border: "none",
          borderRadius: 23,
          background: hasInvalid ? theme.line2 : accent,
          color: hasInvalid ? theme.textMute : theme.bg,
          fontFamily: FONTS.mono,
          fontSize: 11,
          letterSpacing: 1.2,
          fontWeight: 700,
          cursor: hasInvalid ? "default" : "pointer",
        }}
      >
        SAVE CHANGES
      </button>
    </SheetFrame>
  );
}

function SearchBox({ q, setQ, theme, placeholder }) {
  return (
    <div
      style={{
        background: theme.surface2,
        border: `0.5px solid ${theme.line}`,
        borderRadius: 14,
        padding: "11px 13px",
        display: "flex",
        gap: 9,
        alignItems: "center",
      }}
    >
      <Ico.search size={15} stroke={theme.textMute} />
      <input
        value={q}
        onChange={(e) => setQ(e.target.value)}
        placeholder={placeholder}
        style={{
          flex: 1,
          minWidth: 0,
          border: "none",
          background: "transparent",
          outline: "none",
          color: theme.text,
          fontFamily: FONTS.ui,
          fontSize: 13,
        }}
      />
    </div>
  );
}

function PillButton({ children, theme, accent, filled, onClick }) {
  return (
    <button
      onClick={onClick}
      style={{
        height: 34,
        borderRadius: 17,
        border: `0.5px solid ${filled ? accent : theme.line2}`,
        background: filled ? accent : "transparent",
        color: filled ? theme.bg : theme.text,
        padding: "0 13px",
        fontFamily: FONTS.mono,
        fontSize: 10,
        letterSpacing: 1.1,
        cursor: "pointer",
        whiteSpace: "nowrap",
      }}
    >
      {children}
    </button>
  );
}

function MerchantDetailSheet({
  tx,
  txs,
  theme,
  accent,
  onClose,
  onOpenTransaction,
}) {
  const [sort, setSort] = React.useState("newest");
  const [sortOpen, setSortOpen] = React.useState(false);
  const analytics = React.useMemo(
    () => getMerchantAnalytics(tx, txs),
    [tx, txs],
  );
  const sorted = [...analytics.transactions].sort((a, b) =>
    sortMerchantTransactions(a, b, sort),
  );
  const maxMonth = Math.max(...analytics.months.map((m) => m.total), 1);
  const selectedMonth = analytics.months[analytics.months.length - 1]?.key;
  return (
    <SheetFrame theme={theme} onClose={onClose} maxHeight="90%">
      <SheetTitle title="MERCHANT DETAIL" theme={theme} onClose={onClose} />
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          gap: 9,
          padding: "4px 0 18px",
        }}
      >
        <MerchantAvatar
          merchant={analytics.name}
          theme={theme}
          accent={accent}
          size={58}
        />
        <div style={{ color: theme.text, fontSize: 16, fontWeight: 600 }}>
          {analytics.name}
        </div>
      </div>
      <div style={{ overflowX: "auto", paddingBottom: 8 }}>
        <div
          style={{
            minWidth: 330,
            display: "grid",
            gridTemplateColumns: `repeat(${analytics.months.length}, 1fr)`,
            gap: 10,
            alignItems: "end",
            height: 142,
          }}
        >
          {analytics.months.map((month) => (
            <button
              key={month.key}
              style={{
                border: "none",
                background: "transparent",
                color: theme.text,
                padding: 0,
                cursor: "pointer",
                display: "flex",
                flexDirection: "column",
                alignItems: "center",
                justifyContent: "flex-end",
                gap: 6,
              }}
            >
              <div style={{ fontFamily: FONTS.mono, fontSize: 10 }}>
                {fmtMoney(month.total)}
              </div>
              <div
                style={{
                  width: 30,
                  height: Math.max(12, (month.total / maxMonth) * 78),
                  borderRadius: "8px 8px 3px 3px",
                  background:
                    month.key === selectedMonth ? accent : theme.line2,
                }}
              />
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 10,
                  color: theme.textMute,
                }}
              >
                {month.label}
              </div>
            </button>
          ))}
        </div>
      </div>
      <Card theme={theme} style={{ marginTop: 12, padding: 14 }}>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(4, 1fr)",
            gap: 8,
          }}
        >
          {analytics.stats.map((stat) => (
            <div key={stat.label} style={{ textAlign: "center" }}>
              <div
                style={{
                  fontFamily: FONTS.mono,
                  fontSize: 9,
                  color: theme.textMute,
                  textTransform: "uppercase",
                  letterSpacing: 0.8,
                }}
              >
                {stat.label}
              </div>
              <div
                style={{
                  marginTop: 5,
                  fontFamily: FONTS.mono,
                  fontSize: 12,
                  color: theme.text,
                  fontWeight: 700,
                }}
              >
                {stat.value}
              </div>
            </div>
          ))}
        </div>
      </Card>
      <div
        style={{
          position: "relative",
          display: "flex",
          justifyContent: "flex-end",
          alignItems: "center",
          gap: 7,
          margin: "16px 0 10px",
          color: theme.textMute,
          fontFamily: FONTS.mono,
          fontSize: 10.5,
          textTransform: "uppercase",
          letterSpacing: 1.1,
        }}
      >
        Sort by{" "}
        <PillButton theme={theme} onClick={() => setSortOpen((v) => !v)}>
          {MERCHANT_SORTS.find((x) => x.key === sort)?.label || "NEWEST"}{" "}
          <Ico.chevD size={10} />
        </PillButton>
        {sortOpen && (
          <SortMenu
            theme={theme}
            value={sort}
            options={MERCHANT_SORTS}
            onPick={(next) => {
              setSort(next);
              setSortOpen(false);
            }}
          />
        )}
      </div>
      <Card theme={theme} padded={false} style={{ overflow: "hidden" }}>
        {sorted.map((item, index) => (
          <button
            key={item.id}
            onClick={() => onOpenTransaction(item.id)}
            style={{
              ...rowButtonReset(),
              display: "flex",
              alignItems: "center",
              gap: 12,
              padding: "11px 14px",
              color: theme.text,
              borderBottom:
                index < sorted.length - 1
                  ? `0.5px solid ${theme.line}`
                  : "none",
            }}
          >
            <CategoryIcon
              category={item.category}
              theme={theme}
              accent={accent}
              size={32}
            />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div
                style={{
                  fontSize: 13.5,
                  whiteSpace: "nowrap",
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                }}
              >
                {item.merchant}
              </div>
              <div
                style={{
                  marginTop: 2,
                  fontFamily: FONTS.mono,
                  fontSize: 11,
                  color: theme.textMute,
                }}
              >
                {item.date}
              </div>
            </div>
            <div
              style={{
                fontFamily: FONTS.mono,
                fontSize: 13,
                color: item.amount >= 0 ? theme.positive : theme.text,
                fontVariantNumeric: "tabular-nums",
              }}
            >
              {item.amount >= 0 ? "+" : "−"}
              {fmtAED(Math.abs(item.amount), {
                decimals: Math.abs(item.amount) < 1000 ? 2 : 0,
              })}
            </div>
          </button>
        ))}
      </Card>
    </SheetFrame>
  );
}

function MerchantAvatar({ merchant, theme, accent, size }) {
  const initial = merchant.trim().charAt(0).toUpperCase() || "M";
  return (
    <div
      style={{
        width: size,
        height: size,
        borderRadius: size / 2,
        background: `${accent}22`,
        color: accent,
        border: `0.5px solid ${theme.line2}`,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        fontFamily: FONTS.display,
        fontSize: 26,
      }}
    >
      {initial}
    </div>
  );
}

const MERCHANT_SORTS = [
  { key: "newest", label: "NEWEST" },
  { key: "oldest", label: "OLDEST" },
  { key: "highest", label: "HIGHEST AMOUNT" },
  { key: "lowest", label: "LOWEST AMOUNT" },
];

function getMerchantAnalytics(tx, txs) {
  const key = getMerchantKey(tx);
  const matched = txs.filter((item) => getMerchantKey(item) === key);
  const months = getRecentMonths(4).map((month) => ({
    ...month,
    total: matched
      .filter((item) => month.key === getTxMonthKey(item))
      .reduce((sum, item) => sum + Math.abs(item.amount), 0),
  }));
  const currentKey = months[months.length - 1]?.key;
  const current = matched.filter((item) => getTxMonthKey(item) === currentKey);
  const avg = matched.length
    ? matched.reduce((sum, item) => sum + Math.abs(item.amount), 0) /
      matched.length
    : 0;
  const currentYear = 2026;
  return {
    name: canonicalMerchantName(tx.merchant),
    transactions: matched,
    months,
    stats: [
      { label: "This month", value: `${current.length}x` },
      { label: "Avg. spent", value: fmtMoney(avg) },
      { label: `${currentYear - 1} total`, value: fmtMoney(0) },
      {
        label: `${currentYear} total`,
        value: fmtMoney(
          matched.reduce((sum, item) => sum + Math.abs(item.amount), 0),
        ),
      },
    ],
  };
}

function getMerchantKey(tx) {
  return tx.merchantId || normalizeMerchantName(tx.merchant);
}

function normalizeMerchantName(name) {
  return name
    .toLowerCase()
    .replace(/['’]/g, "")
    .replace(/#?\d+/g, "")
    .replace(/[^a-z\s]/g, " ")
    .replace(/\bjoe\s+s\b/g, "joes")
    .replace(/\s+/g, " ")
    .trim();
}

function canonicalMerchantName(name) {
  const normalized = normalizeMerchantName(name);
  if (normalized === "trader joes" || normalized === "trader joe s")
    return "Trader Joe's";
  return name.replace(/\s*#?\d+\s*$/, "").trim();
}

function getRecentMonths(count) {
  const labels = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];
  const endMonth = 5;
  return Array.from({ length: count }, (_, i) => {
    const month = endMonth - count + 1 + i;
    return {
      key: `2026-${String(month).padStart(2, "0")}`,
      label: labels[month - 1],
    };
  });
}

function getTxMonthKey(tx) {
  const match = String(tx.date).match(/([A-Za-z]{3})/);
  const labels = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];
  const month =
    Math.max(
      0,
      labels.findIndex(
        (label) => label.toLowerCase() === match?.[1]?.toLowerCase(),
      ),
    ) + 1 || 4;
  return `2026-${String(month).padStart(2, "0")}`;
}

function sortMerchantTransactions(a, b, sort) {
  if (sort === "highest") return Math.abs(b.amount) - Math.abs(a.amount);
  if (sort === "lowest") return Math.abs(a.amount) - Math.abs(b.amount);
  return sortTransactions(a, b, sort === "oldest" ? "oldest" : "newest");
}

function CategoryPicker({ tx, theme, accent, onClose, onPick }) {
  return (
    <div
      onClick={onClose}
      style={{
        position: "absolute",
        inset: 0,
        zIndex: 130,
        background: "rgba(0,0,0,0.6)",
        display: "flex",
        alignItems: "flex-end",
        animation: "himma-fade 200ms",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "100%",
          background: theme.surface,
          borderRadius: "24px 24px 0 0",
          borderTop: `0.5px solid ${theme.line2}`,
          padding: "10px 20px 34px",
          animation: "himma-slide 260ms cubic-bezier(.2,.8,.25,1)",
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            paddingBottom: 10,
          }}
        >
          <div
            style={{
              width: 40,
              height: 4,
              borderRadius: 2,
              background: theme.line2,
            }}
          />
        </div>

        <div
          style={{
            display: "grid",
            gridTemplateColumns: "34px 1fr 34px",
            alignItems: "center",
            gap: 8,
          }}
        >
          <button onClick={onClose} style={iconButtonStyle(theme)}>
            <Ico.arrowL size={19} />
          </button>
          <div
            style={{
              fontFamily: FONTS.display,
              fontSize: 20,
              color: theme.text,
              letterSpacing: -0.3,
              textAlign: "center",
            }}
          >
            Change category
          </div>
          <div />
        </div>

        <div
          style={{
            marginTop: 16,
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            gap: 8,
          }}
        >
          {EDITABLE_CATS.map((c) => {
            const active = c === tx.category;
            return (
              <button
                key={c}
                onClick={() => onPick(c)}
                style={{
                  background: active ? `${accent}15` : theme.surface2,
                  border: `0.5px solid ${active ? accent + "55" : theme.line}`,
                  borderRadius: 12,
                  padding: "12px 12px",
                  display: "flex",
                  alignItems: "center",
                  gap: 10,
                  cursor: "pointer",
                  textAlign: "left",
                  color: theme.text,
                }}
              >
                <CategoryIcon
                  category={c}
                  theme={theme}
                  accent={accent}
                  size={28}
                />
                <span style={{ fontSize: 12.5, fontWeight: 500, flex: 1 }}>
                  {c}
                </span>
                {active && <Ico.check size={13} stroke={accent} sw={2} />}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { TransactionsScreen });
