diff --git a/src/components/layout/__tests__/auth-shell-coach-hoist.test.ts b/src/components/layout/__tests__/auth-shell-coach-hoist.test.ts
index 7774acae1..67893ea11 100644
--- a/src/components/layout/__tests__/auth-shell-coach-hoist.test.ts
+++ b/src/components/layout/__tests__/auth-shell-coach-hoist.test.ts
@@ -51,6 +51,14 @@ describe("v1.4.34 IW-B — CoachLaunchProvider hoist", () => {
expect(source).toContain("");
});
+ it("gates the LayoutCoachFab on `!demoMode` so demo visitors can't hit the proxy-blocked send (v1.16.13)", () => {
+ const source = readFileSync(AUTH_SHELL_PATH, "utf8");
+ // `/api/insights/chat` is not in the proxy's DEMO_MUTATION_ALLOWLIST,
+ // so a tappable FAB in demo mode produces a raw 403 on send. The mount
+ // must be conditioned on the demo flag.
+ expect(source).toContain("{!demoMode && }");
+ });
+
it("no longer mounts any Coach surface in the routed insights layout", () => {
const source = readFileSync(INSIGHTS_LAYOUT_PATH, "utf8");
// The provider import drops; the drawer mount lives on the shell.
diff --git a/src/components/layout/auth-shell.tsx b/src/components/layout/auth-shell.tsx
index 02202979a..02fb68705 100644
--- a/src/components/layout/auth-shell.tsx
+++ b/src/components/layout/auth-shell.tsx
@@ -272,7 +272,12 @@ export function AuthShell({
-
+ {/* v1.16.13 — the Coach FAB stays hidden in demo mode. Its send hits
+ `/api/insights/chat`, which is not in the proxy's
+ `DEMO_MUTATION_ALLOWLIST`, so a demo visitor who tapped it and sent
+ got a raw 403. Demo is read-only by design; the FAB has no job
+ here, so it's mounted only outside demo mode. */}
+ {!demoMode && }
);
}