diff --git a/global/src/global-app.jsx b/global/src/global-app.jsx
new file mode 100644
index 0000000..b8f7001
--- /dev/null
+++ b/global/src/global-app.jsx
@@ -0,0 +1,70 @@
+import { useState, useEffect } from 'react';
+import { ToastProvider, NavProvider, AuthProvider, useNav, Header, Footer, PushPrompt } from './global-ui.jsx';
+import HomePage from './global-home.jsx';
+import ArticlePage, { ArticlesListPage } from './global-articles.jsx';
+import { AboutPage, PrivacyPage, TermsPage, EditorialPage, NotFoundPage, PersianOnlyPage, CategoryPage } from './global-pages.jsx';
+
+function getRoute() {
+ const path = window.location.pathname;
+ const search = window.location.search;
+ if (path === '/' || path === '') return { page: 'home' };
+ if (path === '/articles') return { page: 'articles', q: new URLSearchParams(search).get('q') || '' };
+ if (path.startsWith('/article/')) return { page: 'article', slug: path.replace('/article/', '').replace(/\/$/, '') };
+ if (path.startsWith('/category/')) return { page: 'category', cat: path.replace('/category/', '').replace(/\/$/, '') };
+ if (path === '/about') return { page: 'about' };
+ if (path === '/privacy') return { page: 'privacy' };
+ if (path === '/terms') return { page: 'terms' };
+ if (path === '/editorial-policy') return { page: 'editorial' };
+ if (path === '/persian-only') return { page: 'persian-only' };
+ return { page: '404' };
+}
+
+function AppInner() {
+ const { page: navPage, navigate } = useNav();
+ const [route, setRoute] = useState(getRoute());
+
+ useEffect(() => {
+ function onPop() { setRoute(getRoute()); }
+ window.addEventListener('popstate', onPop);
+ return () => window.removeEventListener('popstate', onPop);
+ }, []);
+
+ // Keep route in sync when NavProvider navigate() is called
+ useEffect(() => { setRoute(getRoute()); }, [navPage]);
+
+ function renderPage() {
+ switch (route.page) {
+ case 'home': return