diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
index 010e597..80f65b3 100644
--- a/src/components/Layout.tsx
+++ b/src/components/Layout.tsx
@@ -2,7 +2,7 @@ import { useState, useRef, lazy, Suspense } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { nip19 } from 'nostr-tools';
import { cn } from '@/lib/utils';
-import { CustomizeNavSheet } from '@/components/CustomizeNavSheet';
+import { isNativePlatform } from '@/lib/platform';
import { useNavPreferences, useDesktopNavPreferences, type NavTab } from '@/hooks/useNavPreferences';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
@@ -15,9 +15,7 @@ import {
DropdownMenuSeparator,
} from '@/components/ui/dropdown-menu';
import { LoginArea } from '@/components/auth/LoginArea';
-import { LoginDialog } from '@/components/auth/LoginDialog';
import { useSasquatchGuide } from '@/hooks/useSasquatchGuide';
-import { BackupReminder } from '@/components/BackupReminder';
import { LanguageToggle } from '@/components/LanguageToggle';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useTranslation } from '@/contexts/LanguageContext';
@@ -54,7 +52,6 @@ import {
} from 'lucide-react';
import { OfflineIndicator } from '@/components/OfflineIndicator';
import { UserStatusIndicator } from '@/components/UserStatusIndicator';
-import { SetStatusDialog } from '@/components/SetStatusDialog';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { useAuthor } from '@/hooks/useAuthor';
import { genUserName } from '@/lib/genUserName';
@@ -76,6 +73,35 @@ const LazyCashuMenuBalance = lazy(() =>
const LazySasquatchGuide = lazy(() =>
import('@/components/SasquatchGuide').then((m) => ({ default: m.SasquatchGuide })),
);
+// On-demand modals — only rendered after the user opens them, so keep them out
+// of the always-loaded Layout chunk.
+const LazyCustomizeNavSheet = lazy(() =>
+ import('@/components/CustomizeNavSheet').then((m) => ({ default: m.CustomizeNavSheet })),
+);
+const LazySetStatusDialog = lazy(() =>
+ import('@/components/SetStatusDialog').then((m) => ({ default: m.SetStatusDialog })),
+);
+const LazyLoginDialog = lazy(() =>
+ import('@/components/auth/LoginDialog').then((m) => ({ default: m.LoginDialog })),
+);
+const LazyBackupReminder = lazy(() =>
+ import('@/components/BackupReminder').then((m) => ({ default: m.BackupReminder })),
+);
+
+/**
+ * Cheap synchronous hint that a Cashu wallet MIGHT exist, used to decide
+ * whether to even load the (large) wallet chunk. On native the seed lives in
+ * the OS KeyStore which we can't query synchronously, so we always load there;
+ * on web `useCashu` persists the mnemonic in localStorage under this key.
+ */
+function hasCashuWalletHint(): boolean {
+ if (isNativePlatform()) return true;
+ try {
+ return !!localStorage.getItem('cashu-mnemonic');
+ } catch {
+ return false;
+ }
+}
interface LayoutProps {
children: React.ReactNode;
@@ -371,9 +397,11 @@ function MobileNav({
{isWallet ? (
<>
Ecash
-