+ );
+}
+
+/**
+ * A contextual "this is a paid feature" dialog with a plan picker that starts
+ * Stripe checkout. Reused across upsell points (AI categorization, bank
+ * connections, connected accounts); each passes its own copy and `source`.
+ */
+export function UpgradeDialog({
+ open,
+ onOpenChange,
+ title,
+ description,
+ source,
+}: {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ title: string;
+ description: string;
+ source: UpsellSource;
+}) {
+ const { pricing, locale } = usePage