diff --git a/app/(shell)/focus/FocusModeClient.tsx b/app/(shell)/focus/FocusModeClient.tsx
index 0d824d61..b9b95456 100644
--- a/app/(shell)/focus/FocusModeClient.tsx
+++ b/app/(shell)/focus/FocusModeClient.tsx
@@ -169,6 +169,8 @@ interface FocusModeClientProps {
founderReadiness?: FounderReadiness | null;
/** Owner-facing First-Light readiness (ALL owners) — drives the momentum strip. */
firstLightReadiness?: FirstLightReadiness | null;
+ /** F2: brief continuity — carry-over since the owner's last visit (counts only). */
+ briefContinuity?: { snoozedCount: number; awaitingReplyCount: number } | null;
}
type ActionDecision = "approved" | "skipped" | "dismissed";
@@ -269,6 +271,7 @@ export function FocusModeClient({
isFounder = false,
founderReadiness = null,
firstLightReadiness = null,
+ briefContinuity = null,
}: FocusModeClientProps) {
const router = useRouter();
const copy = getVerticalCopy(vertical);
@@ -926,6 +929,29 @@ export function FocusModeClient({
{!isFounder && firstLightReadiness && (
)}
+ {/* F2: brief continuity — the brief "remembers" overnight. Static, counts only,
+ renders ONLY when there's real carry-over (no clutter on an empty board). */}
+ {briefContinuity &&
+ (briefContinuity.awaitingReplyCount > 0 || briefContinuity.snoozedCount > 0) && (
+
+ Since you were last here
+ {briefContinuity.awaitingReplyCount > 0 && (
+
+
+ {briefContinuity.awaitingReplyCount} awaiting reply
+
+ )}
+ {briefContinuity.snoozedCount > 0 && (
+
+
+ {briefContinuity.snoozedCount} snoozed, coming back
+
+ )}
+
+ )}
{simpleView ? (
<>
{/* Simple mode (reframe v2): greeting + the Single-Action Queue ONLY - ONE
diff --git a/app/(shell)/focus/page.tsx b/app/(shell)/focus/page.tsx
index be550a6b..3af3704a 100644
--- a/app/(shell)/focus/page.tsx
+++ b/app/(shell)/focus/page.tsx
@@ -248,29 +248,49 @@ export default async function FocusPage({ searchParams }: { searchParams: Search
let clientCount = 0;
let pendingRecoveryCount = 0;
let approvedCount = 0;
+ let snoozedCount = 0;
+ let awaitingReplyCount = 0;
if (profile?.tenant_id) {
- const [clientCountRes, pendingCountRes, approvedCountRes] = await Promise.all([
- supabase
- .from("pulse_clients")
- .select("id", { count: "exact", head: true })
- .eq("tenant_id", profile.tenant_id),
- supabase
- .from("recovery_items")
- .select("id", { count: "exact", head: true })
- .eq("tenant_id", profile.tenant_id)
- .not("status", "in", '("approved","dismissed")'),
- supabase
- .from("recovery_items")
- .select("id", { count: "exact", head: true })
- .eq("tenant_id", profile.tenant_id)
- .eq("status", "approved"),
- ]);
+ const [clientCountRes, pendingCountRes, approvedCountRes, snoozedCountRes, sentCountRes] =
+ await Promise.all([
+ supabase
+ .from("pulse_clients")
+ .select("id", { count: "exact", head: true })
+ .eq("tenant_id", profile.tenant_id),
+ supabase
+ .from("recovery_items")
+ .select("id", { count: "exact", head: true })
+ .eq("tenant_id", profile.tenant_id)
+ .not("status", "in", '("approved","dismissed")'),
+ supabase
+ .from("recovery_items")
+ .select("id", { count: "exact", head: true })
+ .eq("tenant_id", profile.tenant_id)
+ .eq("status", "approved"),
+ // F2: brief continuity — items the owner snoozed (coming back) ...
+ supabase
+ .from("recovery_items")
+ .select("id", { count: "exact", head: true })
+ .eq("tenant_id", profile.tenant_id)
+ .eq("status", "snoozed"),
+ // ... and items already sent, awaiting a client reply.
+ supabase
+ .from("recovery_items")
+ .select("id", { count: "exact", head: true })
+ .eq("tenant_id", profile.tenant_id)
+ .eq("status", "sent"),
+ ]);
clientCount = clientCountRes.count ?? 0;
pendingRecoveryCount = pendingCountRes.count ?? 0;
approvedCount = approvedCountRes.count ?? 0;
+ snoozedCount = snoozedCountRes.count ?? 0;
+ awaitingReplyCount = sentCountRes.count ?? 0;
}
const firstLightAchieved = lifetimeRecoveredCents > 0;
const firstLightReadiness = { clientCount, pendingRecoveryCount, approvedCount, firstLightAchieved };
+ // F2: brief continuity — the brief "remembers" overnight so the owner sees carry-over,
+ // not just a flat list (counts only, honest).
+ const briefContinuity = { snoozedCount, awaitingReplyCount };
// Founder panel keeps its exact shape + founder-only gating.
const founderReadiness:
| { pulseConnected: boolean; clientCount: number; pendingRecoveryCount: number; firstLightAchieved: boolean }
@@ -425,6 +445,7 @@ export default async function FocusPage({ searchParams }: { searchParams: Search
isFounder={isFounder}
founderReadiness={founderReadiness}
firstLightReadiness={firstLightReadiness}
+ briefContinuity={briefContinuity}
/>
);