diff --git a/.changeset/fix-notification-banner.md b/.changeset/fix-notification-banner.md
new file mode 100644
index 0000000000..d8e80978c7
--- /dev/null
+++ b/.changeset/fix-notification-banner.md
@@ -0,0 +1,7 @@
+---
+sable: patch
+---
+
+fix: in-app notification banner placement
+
+Render `NotificationBanner` in `ClientLayout` so it occupies the full viewport width as `position: fixed` and doesn't displace any page content. Previously it was rendered inside `Room.tsx`, which caused layout shift and meant it only appeared while a room was open.
diff --git a/src/app/components/notification-banner/NotificationBanner.css.ts b/src/app/components/notification-banner/NotificationBanner.css.ts
index 1ddfacda3b..4a29d24d78 100644
--- a/src/app/components/notification-banner/NotificationBanner.css.ts
+++ b/src/app/components/notification-banner/NotificationBanner.css.ts
@@ -23,12 +23,11 @@ const slideOut = keyframes({
},
});
-// Floats at the top of the chat area, starting after the icon sidebar.
+// Floats at the top of the viewport, spanning full width on all platforms.
export const BannerContainer = style({
position: 'fixed',
top: 0,
- // 66px = sidebar icon strip width — overridden to 0 on mobile below
- left: toRem(66),
+ left: 0,
right: 0,
zIndex: 9999,
display: 'flex',
@@ -37,13 +36,6 @@ export const BannerContainer = style({
padding: config.space.S400,
pointerEvents: 'none',
alignItems: 'stretch',
-
- '@media': {
- // On narrow screens the sidebar collapses, so span the full width.
- '(max-width: 768px)': {
- left: 0,
- },
- },
});
export const Banner = style({
diff --git a/src/app/features/room/Room.tsx b/src/app/features/room/Room.tsx
index c960d431bc..b7aef9107b 100644
--- a/src/app/features/room/Room.tsx
+++ b/src/app/features/room/Room.tsx
@@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { Box, Line } from 'folds';
import { useParams } from 'react-router-dom';
import { isKeyHotkey } from 'is-hotkey';
+import { useAtomValue } from 'jotai';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
@@ -13,7 +14,6 @@ import { useMatrixClient } from '$hooks/useMatrixClient';
import { useRoomMembers } from '$hooks/useRoomMembers';
import { CallView } from '$features/call/CallView';
import { WidgetsDrawer } from '$features/widgets/WidgetsDrawer';
-import { useAtomValue } from 'jotai';
import { callChatAtom } from '$state/callEmbed';
import { RoomViewHeader } from './RoomViewHeader';
import { MembersDrawer } from './MembersDrawer';
diff --git a/src/app/pages/client/ClientLayout.tsx b/src/app/pages/client/ClientLayout.tsx
index 4bbd4068fc..9cb4a3f416 100644
--- a/src/app/pages/client/ClientLayout.tsx
+++ b/src/app/pages/client/ClientLayout.tsx
@@ -1,5 +1,6 @@
import { ReactNode } from 'react';
import { Box } from 'folds';
+import { NotificationBanner } from '$components/notification-banner';
type ClientLayoutProps = {
nav: ReactNode;
@@ -8,6 +9,7 @@ type ClientLayoutProps = {
export function ClientLayout({ nav, children }: ClientLayoutProps) {
return (
+
{nav}
{children}
diff --git a/src/app/pages/client/ClientNonUIFeatures.tsx b/src/app/pages/client/ClientNonUIFeatures.tsx
index 3116c4c566..56c333065b 100644
--- a/src/app/pages/client/ClientNonUIFeatures.tsx
+++ b/src/app/pages/client/ClientNonUIFeatures.tsx
@@ -7,7 +7,6 @@ import { getReactCustomHtmlParser, LINKIFY_OPTS } from '$plugins/react-custom-ht
import { sanitizeCustomHtml } from '$utils/sanitize';
import { roomToUnreadAtom } from '$state/room/roomToUnread';
import LogoSVG from '$public/res/svg/cinny.svg';
-import { NotificationBanner } from '$components/notification-banner';
import LogoUnreadSVG from '$public/res/svg/cinny-unread.svg';
import LogoHighlightSVG from '$public/res/svg/cinny-highlight.svg';
import NotificationSound from '$public/sound/notification.ogg';
@@ -559,7 +558,6 @@ export function ClientNonUIFeatures({ children }: ClientNonUIFeaturesProps) {
-
{children}
>
);