diff --git a/docs/deferred-inputs.md b/docs/deferred-inputs.md
new file mode 100644
index 0000000..21dc4ff
--- /dev/null
+++ b/docs/deferred-inputs.md
@@ -0,0 +1,20 @@
+# Deferred inputs
+
+Updated: 2026-07-31
+
+## Stripe billing — Phase 7.5
+
+Needed from the operator before implementation can finish:
+
+- Add `STRIPE_SECRET_KEY` and `STRIPE_PUBLISHABLE_KEY` to the production environment.
+- Create the recurring Premium price and add `STRIPE_PRICE_PREMIUM`.
+- Create the billing webhook and add `STRIPE_WEBHOOK_SECRET`.
+- Do not store or paste secret values in the repository or chat.
+
+## Production key rotation — Phase 1.4
+
+Confirm the DataProtection keys exposed in git history have been rotated on the production host.
+
+## Progress
+
+Phases 2 through 7.9 are complete except Stripe billing. Public CV sharing, premium themes, AI call and token limits, storage limits, NAV discovery, provider market dual-write, CORS hardening, the prospect workflow, and migration-history reconciliation are pushed to `main`.
diff --git a/job-tracker-ui/src/ai-usage-card.test.tsx b/job-tracker-ui/src/ai-usage-card.test.tsx
new file mode 100644
index 0000000..ec7a7e6
--- /dev/null
+++ b/job-tracker-ui/src/ai-usage-card.test.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import "@testing-library/jest-dom";
+import { render, screen } from "@testing-library/react";
+import AiUsageCard from "./components/AiUsageCard";
+import { api } from "./api";
+
+jest.mock("./api", () => ({ api: { get: jest.fn() } }));
+
+test("shows monthly AI call and token limits", async () => {
+ (api.get as jest.Mock).mockResolvedValue({
+ data: {
+ currentMonth: { calls: 4, estimatedTokens: 12000 },
+ plan: "free",
+ monthlyCallLimit: 25,
+ monthlyTokenLimit: 100000,
+ },
+ });
+
+ render();
+
+ expect(await screen.findByText("4 of 25 generations this month")).toBeInTheDocument();
+ expect(screen.getByText("12,000 of 100,000 estimated tokens")).toBeInTheDocument();
+ expect(screen.getByLabelText("Monthly AI generations used")).toHaveAttribute("aria-valuenow", "16");
+});
diff --git a/job-tracker-ui/src/components/AiUsageCard.tsx b/job-tracker-ui/src/components/AiUsageCard.tsx
new file mode 100644
index 0000000..2d7de81
--- /dev/null
+++ b/job-tracker-ui/src/components/AiUsageCard.tsx
@@ -0,0 +1,47 @@
+import React, { useEffect, useState } from "react";
+import { Alert, Box, LinearProgress, Paper, Skeleton, Stack, Typography } from "@mui/material";
+import { api } from "../api";
+
+type Usage = {
+ currentMonth: { calls: number; estimatedTokens: number };
+ plan: string;
+ monthlyCallLimit: number;
+ monthlyTokenLimit: number;
+};
+
+export default function AiUsageCard() {
+ const [usage, setUsage] = useState(null);
+ const [failed, setFailed] = useState(false);
+
+ useEffect(() => {
+ let active = true;
+ api.get("/ai/usage")
+ .then((response) => { if (active) setUsage(response.data); })
+ .catch(() => { if (active) setFailed(true); });
+ return () => { active = false; };
+ }, []);
+
+ if (failed) return AI usage is temporarily unavailable.;
+ if (!usage) return ;
+
+ const callsPercent = Math.min(100, usage.currentMonth.calls / usage.monthlyCallLimit * 100);
+ const tokensPercent = Math.min(100, usage.currentMonth.estimatedTokens / usage.monthlyTokenLimit * 100);
+
+ return (
+
+
+ AI usage
+ {usage.plan} plan
+
+
+ {usage.currentMonth.calls.toLocaleString()} of {usage.monthlyCallLimit.toLocaleString()} generations this month
+
+
+
+ {usage.currentMonth.estimatedTokens.toLocaleString()} of {usage.monthlyTokenLimit.toLocaleString()} estimated tokens
+
+
+ Limits reset at the start of each calendar month.
+
+ );
+}
diff --git a/job-tracker-ui/src/components/SettingsView.tsx b/job-tracker-ui/src/components/SettingsView.tsx
index bd8a310..ecb6c5a 100644
--- a/job-tracker-ui/src/components/SettingsView.tsx
+++ b/job-tracker-ui/src/components/SettingsView.tsx
@@ -22,6 +22,7 @@ import ImportExportJobs from "./ImportExportJobs";
import RulesSettingsCard from "./RulesSettingsCard";
import BackupCard from "./BackupCard";
import QuickCaptureCard from "./QuickCaptureCard";
+import AiUsageCard from "./AiUsageCard";
import { ThemeModePref } from "../themePrefs";
import { useI18n } from "../i18n/I18nProvider";
@@ -197,6 +198,7 @@ export default function SettingsView({
+