diff --git a/CLAUDE.md b/CLAUDE.md
index 4fdda1c..3a4b5f9 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -140,9 +140,10 @@ Technology stack:
- `/admin/dashboard`, `/admin/upload` - Admin interfaces
**Layout** (`app/layout.tsx`):
-- Theme provider (dark mode via next-themes)
-- Site header with navigation (site-header.tsx)
-- Footer, toast notifications, Vercel Analytics, Google Analytics
+- Owns the only document/app shell: ``, `
`, theme provider, analytics, toast notifications, and floating chat bubble
+- Renders `LayoutContent`, which owns the site header, scrollable page wrapper, and footer visibility
+- Chat routes hide the footer for a full-screen chat experience
+- Locale routes under `app/[locale]/layout.tsx` are nested providers only; they must not render another ``, ``, header, footer, analytics, or theme provider
**Navigation** (`config/site.ts`): Home, Chat, About, Proceedings, Acts, Constitution
@@ -372,20 +373,25 @@ These client components wrap server components to trigger GA events on mount.
- Smooth scrolling when at bottom
**Benefits**:
-- ✅ Users can read previous messages without interruption
-- ✅ Auto-scroll still works when at bottom
-- ✅ Much better mobile experience
-- ✅ No more jumping/jarring scrolls during message streaming
+- ✅ Users can read previous messages without interruption
+- ✅ Auto-scroll still works when at bottom
+- ✅ Much better mobile experience
+- ✅ No more jumping/jarring scrolls during message streaming
### 2. Duplicate Navigation Bar Fix
-**Issue**: Chat page showed duplicate elements at top and bottom - main navigation bar at top, and footer appearing at bottom below chat area, cluttering the interface.
+**Issue**: Chat pages showed duplicate page chrome: a main navigation bar at the top and another navigation/footer region lower on the page. On locale routes such as `/en/chat`, the app could feel like two pages were rendered inside one page.
-**Solution**: Created `LayoutContent` component to conditionally hide footer on chat pages while keeping the main navigation. The footer itself already contains only the attribution text (no duplicate nav items), but it appeared as clutter in the chat interface.
+**Root cause**: `app/[locale]/layout.tsx` was rendering a second full app shell inside the root shell, including ``, ``, `ThemeProvider`, `SiteHeader`, `Footer`, analytics, toast notifications, and floating chat. React also hit a hydration mismatch because Urdu line-height CSS was rendered as inline `
-
-
-
-
-
-
-
-
-
+ {children}
+
+
)
}
diff --git a/app/layout.tsx b/app/layout.tsx
index 7e6a6a4..83467c0 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -4,10 +4,8 @@ import { Metadata } from "next"
import { siteConfig } from "@/config/site"
import { fontSans } from "@/lib/fonts"
import { cn } from "@/lib/utils"
-import { SiteHeader } from "@/components/site-header"
import { TailwindIndicator } from "@/components/tailwind-indicator"
import { ThemeProvider } from "@/components/theme-provider"
-import { Footer } from "@/components/footer"
import { Toaster } from "@/components/ui/toaster"
import { Analytics } from "@vercel/analytics/react"
import { GoogleAnalytics } from "@/components/google-analytics"
diff --git a/components/floating-chat-bubble.tsx b/components/floating-chat-bubble.tsx
index ca8e483..687793f 100644
--- a/components/floating-chat-bubble.tsx
+++ b/components/floating-chat-bubble.tsx
@@ -52,15 +52,14 @@ export function FloatingChatBubble() {
"Hello! I am Numainda, your guide to Pakistan's constitutional and electoral information. How may I assist you today?",
},
],
- onResponse: (response) => {
- if// Don't auto-scroll here; let the useEffect handle it
- setIsGenerating(false)
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
- }
+ onResponse: () => {
+ setIsGenerating(false)
},
onError: (error) => {
if (error) setIsGenerating(false)
},
+ })
+
// Track if user is at bottom of messages
const handleScroll = useCallback(() => {
if (!messagesContainerRef.current) return
@@ -84,12 +83,10 @@ export function FloatingChatBubble() {
if (isOpen) {
shouldAutoScrollRef.current = true
}
- }, [dRef.current?.scrollIntoView({ behavior: "smooth" })
- }
- }, [messages, isOpen])
+ }, [isOpen])
// Hide on homepage and chat page (they have their own chat UI)
- if (pathname === "/" || pathname === "/chat") {
+ if (pathname === "/" || pathname.includes("/chat")) {
return null
}
diff --git a/components/footer.tsx b/components/footer.tsx
index c952b68..f9988dc 100644
--- a/components/footer.tsx
+++ b/components/footer.tsx
@@ -8,8 +8,8 @@ import { cn } from "@/lib/utils"
export function Footer({ className }: { className?: string }) {
const pathname = usePathname()
- // Hide footer on the chat page (full-screen chat experience)
- if (pathname === "/chat") {
+ // Hide footer on chat pages (full-screen chat experience)
+ if (pathname.includes("/chat")) {
return null
}
diff --git a/styles/globals.css b/styles/globals.css
index 428d374..710cf96 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -71,4 +71,14 @@
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
+
+ [lang="ur"] {
+ line-height: 2;
+ }
+
+ [lang="ur"] h1,
+ [lang="ur"] h2,
+ [lang="ur"] h3 {
+ line-height: 1.6;
+ }
}