diff --git a/index.html b/index.html
index 4744fff..f805654 100644
--- a/index.html
+++ b/index.html
@@ -20,7 +20,7 @@
-
+
diff --git a/src/components/app/AppContent.test.ts b/src/components/app/AppContent.test.ts
index 5f4fe29..e9b5dd0 100644
--- a/src/components/app/AppContent.test.ts
+++ b/src/components/app/AppContent.test.ts
@@ -198,3 +198,34 @@ test('capability refresh consumes the discovery roster without adding its own re
assert.match(hook, /onSessionsChangeRef\.current\?\.\(/);
assert.doesNotMatch(refreshCallback, /api\.externalSessions/);
});
+
+test('standalone chrome keeps app UI below a separate opaque safe-area surface', () => {
+ const appContent = readFileSync(new URL('./AppContent.tsx', import.meta.url), 'utf8');
+ const styles = readFileSync(new URL('../../index.css', import.meta.url), 'utf8');
+ const documentHtml = readFileSync(new URL('../../../index.html', import.meta.url), 'utf8');
+ const themeContext = readFileSync(new URL('../../contexts/ThemeContext.jsx', import.meta.url), 'utf8');
+ const opaqueChromeSources = [
+ '../main-content/view/subcomponents/MainContentStateView.tsx',
+ '../sidebar/view/subcomponents/SidebarContent.tsx',
+ '../sidebar/view/subcomponents/SidebarCollapsed.tsx',
+ ].map((source) => readFileSync(new URL(source, import.meta.url), 'utf8'));
+
+ assert.match(appContent, /className="pwa-status-bar-surface"/);
+ assert.match(appContent, /className="app-shell fixed inset-0 flex bg-background"/);
+ assert.match(styles, /\.pwa-status-bar-surface\s*\{/);
+ assert.match(styles, /background: hsl\(var\(--background\)\)/);
+ assert.doesNotMatch(styles, /\.pwa-status-bar-surface[\s\S]{0,400}backdrop-filter/);
+ assert.match(documentHtml, /apple-mobile-web-app-status-bar-style" content="black"/);
+ assert.doesNotMatch(documentHtml, /black-translucent/);
+ assert.doesNotMatch(themeContext, /black-translucent/);
+ assert.match(styles, /body \.app-shell,[\s\S]*top: var\(--safe-area-inset-top\) !important/);
+ assert.match(styles, /left: var\(--safe-area-inset-left\) !important/);
+ assert.match(styles, /right: var\(--safe-area-inset-right\) !important/);
+ assert.match(styles, /\.fixed\.inset-0:not\(\.app-shell\)/);
+ assert.doesNotMatch(styles, /body\.pwa-mode \.fixed\.inset-0\s*\{/);
+ assert.doesNotMatch(styles, /\.pwa-header-safe[\s\S]{0,160}padding-top: 0/);
+ for (const source of opaqueChromeSources) {
+ assert.doesNotMatch(source, /backdrop-blur/);
+ assert.match(source, /bg-background/);
+ }
+});
diff --git a/src/components/app/AppContent.tsx b/src/components/app/AppContent.tsx
index e098df9..f981eef 100644
--- a/src/components/app/AppContent.tsx
+++ b/src/components/app/AppContent.tsx
@@ -635,7 +635,8 @@ function AppContentInner() {
}, []);
return (
-
+
+
{!isMobile ? (
diff --git a/src/components/main-content/view/subcomponents/MainContentStateView.tsx b/src/components/main-content/view/subcomponents/MainContentStateView.tsx
index aacfbb1..98009c8 100644
--- a/src/components/main-content/view/subcomponents/MainContentStateView.tsx
+++ b/src/components/main-content/view/subcomponents/MainContentStateView.tsx
@@ -13,7 +13,7 @@ export default function MainContentStateView({ mode, isMobile, onMenuClick }: Ma
return (
{isMobile && (
-
+
)}
diff --git a/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx b/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx
index 9410734..0c76f29 100644
--- a/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx
+++ b/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx
@@ -19,7 +19,7 @@ export default function SidebarCollapsed({
t,
}: SidebarCollapsedProps) {
return (
-
+
{/* Expand button with brand logo */}