diff --git a/src/App.jsx b/src/App.jsx
index b52371d..301773a 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -50,10 +50,34 @@ const LayoutWrapper = ({ children, currentPageName }) => Layout ?
{children}
: <>{children}>;
+// Routes that render for anyone, signed in or not. LandingPage is pure marketing
+// markup — it reads no entities and never touches useAuth — so the only thing the
+// auth gate ever did for it was bounce visitors to a Google login before they
+// could read what the product is. Its CTAs point at /Dashboard, which is still
+// gated, so signing in stays one click away.
+const PUBLIC_ROUTES = new Set(['/LandingPage']);
+
+const isPublicRoute = (pathname) => {
+ // Tolerate a trailing slash so /LandingPage/ isn't quietly sent to login.
+ const normalized = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname;
+ return PUBLIC_ROUTES.has(normalized);
+};
+
const AuthenticatedApp = () => {
const { isLoadingAuth, isLoadingPublicSettings, authError, isAuthenticated, navigateToLogin } = useAuth();
const location = useLocation();
+ // Ahead of both gates below. The spinner would stall this page on a network
+ // round-trip it has no use for, and the auth gate would redirect away from it —
+ // either one defeats the point of a public page.
+ if (isPublicRoute(location.pathname)) {
+ return (
+
+ } />
+
+ );
+ }
+
// Show loading spinner while checking app public settings or auth
if (isLoadingPublicSettings || isLoadingAuth) {
return (
@@ -92,14 +116,6 @@ const AuthenticatedApp = () => {
// Render the main app
- if (location.pathname === '/LandingPage') {
- return (
-
- } />
-
- );
- }
-
return (