From f36627ba443dd5ce89ed56cba3af10886779e22d Mon Sep 17 00:00:00 2001
From: Thomas Petersen <thomasp@squareup.com>
Date: Sun, 28 Jun 2026 10:55:45 -0400
Subject: [PATCH] Fix channel header shared blur layering

Co-authored-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>
---
 desktop/playwright.config.ts                  |   1 +
 .../channels/ui/AgentSessionThreadPanel.tsx   |   6 +-
 .../ui/ChannelManagementAuxiliaryPanel.tsx    |   3 +
 .../channels/ui/ChannelManagementSheet.tsx    |   7 +-
 .../src/features/channels/ui/ChannelPane.tsx  |  25 +++-
 .../features/channels/ui/ChannelScreen.tsx    |   1 +
 .../channels/ui/ChannelScreenHeader.tsx       |   3 +
 .../channels/ui/RightAuxiliaryPane.tsx        |   6 +-
 desktop/src/features/chat/ui/ChatHeader.tsx   |   8 +-
 .../messages/ui/MessageThreadPanel.tsx        |  12 +-
 .../features/profile/ui/UserProfilePanel.tsx  |   3 +-
 .../profile/ui/UserProfilePanelFrame.tsx      |   4 +-
 .../profile/ui/UserProfilePanelUtils.ts       |   1 +
 .../shared/layout/AuxiliaryPanelHeader.tsx    |  13 +-
 .../channel-shared-header-backdrop.spec.ts    | 134 ++++++++++++++++++
 15 files changed, 212 insertions(+), 15 deletions(-)
 create mode 100644 desktop/tests/e2e/channel-shared-header-backdrop.spec.ts

diff --git a/desktop/playwright.config.ts b/desktop/playwright.config.ts
index 5d41362770..b1fc4af5fd 100644
--- a/desktop/playwright.config.ts
+++ b/desktop/playwright.config.ts
@@ -22,6 +22,7 @@ export default defineConfig({
         "**/smoke.spec.ts",
         "**/navigation.spec.ts",
         "**/channels.spec.ts",
+        "**/channel-shared-header-backdrop.spec.ts",
         "**/badge.spec.ts",
         "**/channel-browser.spec.ts",
         "**/messaging.spec.ts",
diff --git a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
index 65bb97b3f8..286d770210 100644
--- a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
+++ b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
@@ -39,6 +39,7 @@ type AgentSessionThreadPanelProps = {
   onBackToProfile: () => void;
   onClose: () => void;
   widthPx: number;
+  transparentChrome?: boolean;
 };
 
 export function AgentSessionThreadPanel({
@@ -52,6 +53,7 @@ export function AgentSessionThreadPanel({
   onBackToProfile,
   onClose,
   widthPx,
+  transparentChrome = false,
 }: AgentSessionThreadPanelProps) {
   const isLive = isManagedAgentActive(agent);
   const isOverlay = useIsThreadPanelOverlay();
@@ -176,7 +178,9 @@ export function AgentSessionThreadPanel({
   if (isSplitLayout) {
     return (
       <div className="flex min-h-0 flex-1 flex-col">
-        <AuxiliaryPanelHeader>{agentHeaderContent}</AuxiliaryPanelHeader>
+        <AuxiliaryPanelHeader transparent={transparentChrome}>
+          {agentHeaderContent}
+        </AuxiliaryPanelHeader>
         {agentBody}
       </div>
     );
diff --git a/desktop/src/features/channels/ui/ChannelManagementAuxiliaryPanel.tsx b/desktop/src/features/channels/ui/ChannelManagementAuxiliaryPanel.tsx
index 0a917ecac0..ccbabbac23 100644
--- a/desktop/src/features/channels/ui/ChannelManagementAuxiliaryPanel.tsx
+++ b/desktop/src/features/channels/ui/ChannelManagementAuxiliaryPanel.tsx
@@ -17,6 +17,7 @@ type ChannelManagementAuxiliaryPanelProps = {
   ) => void;
   threadPanelWidthPx: number;
   useSplitAuxiliaryPane: boolean;
+  transparentChrome?: boolean;
 };
 
 export function ChannelManagementAuxiliaryPanel({
@@ -30,6 +31,7 @@ export function ChannelManagementAuxiliaryPanel({
   onThreadPanelResizeStart,
   threadPanelWidthPx,
   useSplitAuxiliaryPane,
+  transparentChrome = false,
 }: ChannelManagementAuxiliaryPanelProps) {
   const panel = (
     <ChannelManagementSheet
@@ -44,6 +46,7 @@ export function ChannelManagementAuxiliaryPanel({
         }
       }}
       open={true}
+      transparentChrome={transparentChrome}
     />
   );
 
diff --git a/desktop/src/features/channels/ui/ChannelManagementSheet.tsx b/desktop/src/features/channels/ui/ChannelManagementSheet.tsx
index 59c922af4e..1edbaf84b4 100644
--- a/desktop/src/features/channels/ui/ChannelManagementSheet.tsx
+++ b/desktop/src/features/channels/ui/ChannelManagementSheet.tsx
@@ -88,6 +88,7 @@ type ChannelManagementSheetProps = {
   onDeleted?: () => void;
   onOpenChange: (open: boolean) => void;
   open: boolean;
+  transparentChrome?: boolean;
 };
 
 const DEFAULT_EPHEMERAL_TTL_SECONDS = 7 * 24 * 60 * 60;
@@ -100,6 +101,7 @@ export function ChannelManagementSheet({
   onDeleted,
   onOpenChange,
   open,
+  transparentChrome = false,
 }: ChannelManagementSheetProps) {
   const { isDark } = useTheme();
   const isSplitLayout = layout === "split";
@@ -348,6 +350,7 @@ export function ChannelManagementSheet({
             isDeleteDialogOpen={isDeleteDialogOpen}
             isOwner={isOwner}
             isSplitLayout={isSplitLayout}
+            transparentChrome={transparentChrome}
             joinChannelMutation={joinChannelMutation}
             leaveChannelMutation={leaveChannelMutation}
             memberCount={memberCount}
@@ -628,6 +631,7 @@ type ChannelManagementPanelContentProps = {
   isDeleteDialogOpen: boolean;
   isOwner: boolean;
   isSplitLayout: boolean;
+  transparentChrome?: boolean;
   joinChannelMutation: ChannelMutation;
   leaveChannelMutation: ChannelMutation;
   memberCount: number;
@@ -659,6 +663,7 @@ function ChannelManagementPanelContent({
   isDeleteDialogOpen,
   isOwner,
   isSplitLayout,
+  transparentChrome = false,
   joinChannelMutation,
   leaveChannelMutation,
   memberCount,
@@ -680,7 +685,7 @@ function ChannelManagementPanelContent({
   return (
     <>
       {isSplitLayout ? (
-        <AuxiliaryPanelHeader>
+        <AuxiliaryPanelHeader transparent={transparentChrome}>
           <AuxiliaryPanelHeaderGroup>
             {activeView === "canvas" ? (
               <Button
diff --git a/desktop/src/features/channels/ui/ChannelPane.tsx b/desktop/src/features/channels/ui/ChannelPane.tsx
index c0c5b19b0b..7ba74fae4d 100644
--- a/desktop/src/features/channels/ui/ChannelPane.tsx
+++ b/desktop/src/features/channels/ui/ChannelPane.tsx
@@ -613,6 +613,13 @@ export const ChannelPane = React.memo(function ChannelPane({
       }),
     [agentSessionAgents, openAgentSessionPubkey, profilePanelPubkey, profiles],
   );
+  const hasSplitAuxiliaryPane =
+    useSplitAuxiliaryPane &&
+    (channelManagementOpen ||
+      Boolean(threadHeadMessage) ||
+      shouldShowThreadSkeleton ||
+      Boolean(activeChannel && selectedAgent) ||
+      Boolean(profilePanelPubkey));
   const wrapAux = (panel: React.ReactNode, testId: string) =>
     useSplitAuxiliaryPane ? (
       <RightAuxiliaryPane
@@ -628,7 +635,18 @@ export const ChannelPane = React.memo(function ChannelPane({
       panel
     );
   return (
-    <div className="flex min-h-0 min-w-0 flex-1 flex-row overflow-hidden">
+    <div className="relative flex min-h-0 min-w-0 flex-1 flex-row overflow-hidden">
+      {!isSinglePanelView ? (
+        <div
+          aria-hidden="true"
+          className={cn(
+            "pointer-events-none absolute inset-x-0 top-0 z-30 bg-background/80 backdrop-blur-md supports-backdrop-filter:bg-background/70 dark:bg-background/70 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/55",
+            channelChrome.headerHeight,
+          )}
+          data-testid="channel-shared-header-backdrop"
+        />
+      ) : null}
+
       {!isSinglePanelView ? (
         <section
           aria-label="Channel messages and composer"
@@ -829,6 +847,7 @@ export const ChannelPane = React.memo(function ChannelPane({
           onThreadPanelResizeStart={onThreadPanelResizeStart}
           threadPanelWidthPx={threadPanelWidthPx}
           useSplitAuxiliaryPane={useSplitAuxiliaryPane}
+          transparentChrome={hasSplitAuxiliaryPane}
         />
       ) : threadHeadMessage ? (
         (() => {
@@ -849,6 +868,7 @@ export const ChannelPane = React.memo(function ChannelPane({
                 useSplitAuxiliaryPane ? false : isSinglePanelView
               }
               layout={useSplitAuxiliaryPane ? "split" : "standalone"}
+              transparentChrome={useSplitAuxiliaryPane}
               onCancelEdit={onCancelEdit}
               onCancelReply={onCancelThreadReply}
               onClose={onCloseThread}
@@ -900,6 +920,7 @@ export const ChannelPane = React.memo(function ChannelPane({
                 useSplitAuxiliaryPane ? false : isSinglePanelView
               }
               layout={useSplitAuxiliaryPane ? "split" : "standalone"}
+              transparentChrome={useSplitAuxiliaryPane}
               onClose={onCloseThread}
               widthPx={threadPanelWidthPx}
             />
@@ -929,6 +950,7 @@ export const ChannelPane = React.memo(function ChannelPane({
                 useSplitAuxiliaryPane ? false : isSinglePanelView
               }
               layout={useSplitAuxiliaryPane ? "split" : "standalone"}
+              transparentChrome={useSplitAuxiliaryPane}
               profiles={profiles}
               onBackToProfile={() => onOpenProfilePanel(selectedAgent.pubkey)}
               onClose={onCloseAgentSession}
@@ -946,6 +968,7 @@ export const ChannelPane = React.memo(function ChannelPane({
                 useSplitAuxiliaryPane ? false : isSinglePanelView
               }
               layout={useSplitAuxiliaryPane ? "split" : "standalone"}
+              transparentChrome={useSplitAuxiliaryPane}
               onClose={onCloseProfilePanel}
               onOpenDm={onOpenDm}
               onOpenProfile={onOpenProfilePanel}
diff --git a/desktop/src/features/channels/ui/ChannelScreen.tsx b/desktop/src/features/channels/ui/ChannelScreen.tsx
index 13164cf5eb..a1e91c2c9f 100644
--- a/desktop/src/features/channels/ui/ChannelScreen.tsx
+++ b/desktop/src/features/channels/ui/ChannelScreen.tsx
@@ -725,6 +725,7 @@ export function ChannelScreen({
       }}
       onToggleMembers={() => setIsMembersSidebarOpen((prev) => !prev)}
       showHeaderContent={!isSinglePanelView}
+      transparentChrome={activeChannel?.channelType !== "forum"}
     />
   );
 
diff --git a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx
index 311d22449e..fe1ae897d6 100644
--- a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx
+++ b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx
@@ -26,6 +26,7 @@ type ChannelScreenHeaderProps = {
   isAddBotOpen?: boolean;
   isJoining?: boolean;
   showHeaderContent?: boolean;
+  transparentChrome?: boolean;
   onAddBotOpenChange?: (open: boolean) => void;
   onJoinChannel?: () => Promise<void>;
   onManageChannel: () => void;
@@ -46,6 +47,7 @@ export function ChannelScreenHeader({
   isJoining = false,
   onAddBotOpenChange,
   showHeaderContent = true,
+  transparentChrome = false,
   onJoinChannel,
   onManageChannel,
   onToggleMembers,
@@ -120,6 +122,7 @@ export function ChannelScreenHeader({
         />
       }
       title={activeChannelTitle}
+      transparentChrome={transparentChrome}
       visibility={activeChannel?.visibility}
     />
   );
diff --git a/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx b/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
index 66f6c77007..e81f18f532 100644
--- a/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
+++ b/desktop/src/features/channels/ui/RightAuxiliaryPane.tsx
@@ -2,7 +2,6 @@ import type * as React from "react";
 
 import { THREAD_PANEL_MIN_WIDTH_PX } from "@/shared/hooks/useThreadPanelWidth";
 import { cn } from "@/shared/lib/cn";
-import { PANEL_ENTER_MOTION_CLASS } from "@/shared/ui/OverlayPanelBackdrop";
 
 type RightAuxiliaryPaneProps = {
   canResetWidth: boolean;
@@ -26,8 +25,7 @@ export function RightAuxiliaryPane({
   return (
     <aside
       className={cn(
-        "group/right-pane relative flex h-full shrink-0 flex-col overflow-hidden bg-background before:pointer-events-none before:absolute before:bottom-0 before:left-0 before:top-0 before:z-40 before:w-px before:bg-border/80 before:content-['']",
-        PANEL_ENTER_MOTION_CLASS,
+        "group/right-pane relative flex h-full shrink-0 flex-col overflow-hidden bg-background before:pointer-events-none before:absolute before:bottom-0 before:left-0 before:top-0 before:z-50 before:w-px before:bg-border/80 before:content-['']",
       )}
       data-testid={testId}
       style={{
@@ -39,7 +37,7 @@ export function RightAuxiliaryPane({
     >
       <button
         aria-label="Resize panel"
-        className="peer/right-pane-resize group/right-pane-resize absolute inset-y-0 left-0 z-40 w-3 -translate-x-1/2 cursor-col-resize"
+        className="peer/right-pane-resize group/right-pane-resize absolute inset-y-0 left-0 z-50 w-3 -translate-x-1/2 cursor-col-resize"
         data-testid="right-auxiliary-pane-resize-handle"
         onDoubleClick={canResetWidth ? onResetWidth : undefined}
         onPointerDown={onResizeStart}
diff --git a/desktop/src/features/chat/ui/ChatHeader.tsx b/desktop/src/features/chat/ui/ChatHeader.tsx
index 39d8b46dc7..3d98fcdfbb 100644
--- a/desktop/src/features/chat/ui/ChatHeader.tsx
+++ b/desktop/src/features/chat/ui/ChatHeader.tsx
@@ -32,6 +32,8 @@ type ChatHeaderProps = {
   mode?: "home" | "channel" | "agents" | "workflows" | "pulse" | "projects";
   overlaysContent?: boolean;
   statusBadge?: React.ReactNode;
+  /** Render the chrome wrapper without an individual backdrop when a parent supplies shared blur. */
+  transparentChrome?: boolean;
 };
 
 const HEADER_ICON_CLASS = "h-4 w-4 text-muted-foreground";
@@ -93,6 +95,7 @@ export function ChatHeader({
   mode = "channel",
   overlaysContent = false,
   statusBadge,
+  transparentChrome = false,
 }: ChatHeaderProps) {
   const trimmedDescription = description?.trim() ?? "";
 
@@ -171,7 +174,10 @@ export function ChatHeader({
     <div
       ref={chromeWrapperRef}
       className={cn(
-        "pointer-events-none relative z-30 overflow-hidden rounded-tl-xl bg-background/80 backdrop-blur-md supports-backdrop-filter:bg-background/70 dark:bg-background/70 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/55",
+        "pointer-events-none relative z-40 overflow-visible rounded-tl-xl",
+        transparentChrome
+          ? "bg-transparent"
+          : "bg-background/80 backdrop-blur-md supports-backdrop-filter:bg-background/70 dark:bg-background/70 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/55",
         channelChrome.negativeMargin,
       )}
     >
diff --git a/desktop/src/features/messages/ui/MessageThreadPanel.tsx b/desktop/src/features/messages/ui/MessageThreadPanel.tsx
index b45449e8f0..39f0f2eb1f 100644
--- a/desktop/src/features/messages/ui/MessageThreadPanel.tsx
+++ b/desktop/src/features/messages/ui/MessageThreadPanel.tsx
@@ -88,6 +88,7 @@ type MessageThreadPanelProps = {
   threadHeadVideoReviewContext?: VideoReviewContext;
   toolbarExtraActions?: React.ReactNode;
   widthPx: number;
+  transparentChrome?: boolean;
   isFollowingThread?: boolean;
   isMessageUnreadById?: (messageId: string) => boolean;
   onFollowThread?: () => void;
@@ -103,6 +104,7 @@ type MessageThreadPanelSkeletonProps = {
   layout?: "standalone" | "split";
   onClose: () => void;
   widthPx: number;
+  transparentChrome?: boolean;
 };
 
 function canManageMessage(
@@ -225,6 +227,7 @@ export function MessageThreadPanelSkeleton({
   layout = "standalone",
   onClose,
   widthPx,
+  transparentChrome = false,
 }: MessageThreadPanelSkeletonProps) {
   const isOverlay = useIsThreadPanelOverlay();
   const isFloatingOverlay = isOverlay && !isSinglePanelView;
@@ -296,7 +299,9 @@ export function MessageThreadPanelSkeleton({
   if (isSplitLayout) {
     return (
       <div className="relative flex min-h-0 flex-1 flex-col">
-        <AuxiliaryPanelHeader>{threadHeaderContent}</AuxiliaryPanelHeader>
+        <AuxiliaryPanelHeader transparent={transparentChrome}>
+          {threadHeaderContent}
+        </AuxiliaryPanelHeader>
         {threadBody}
         <ThreadComposerSkeleton />
       </div>
@@ -379,6 +384,7 @@ export function MessageThreadPanel({
   threadTypingPubkeys,
   toolbarExtraActions,
   widthPx,
+  transparentChrome = false,
 }: MessageThreadPanelProps) {
   const threadBodyRef = React.useRef<HTMLDivElement>(null);
   const threadContentRef = React.useRef<HTMLDivElement>(null);
@@ -943,7 +949,9 @@ export function MessageThreadPanel({
   if (isSplitLayout) {
     return (
       <div className="relative flex min-h-0 flex-1 flex-col">
-        <AuxiliaryPanelHeader>{threadHeaderContent}</AuxiliaryPanelHeader>
+        <AuxiliaryPanelHeader transparent={transparentChrome}>
+          {threadHeaderContent}
+        </AuxiliaryPanelHeader>
         {threadScrollRegion}
         {threadFooter}
       </div>
diff --git a/desktop/src/features/profile/ui/UserProfilePanel.tsx b/desktop/src/features/profile/ui/UserProfilePanel.tsx
index abc7d828dc..1dffd252d7 100644
--- a/desktop/src/features/profile/ui/UserProfilePanel.tsx
+++ b/desktop/src/features/profile/ui/UserProfilePanel.tsx
@@ -95,7 +95,6 @@ import type {
 } from "@/shared/api/types";
 import { UserProfilePanelFrame } from "@/features/profile/ui/UserProfilePanelFrame";
 import { getUserProfilePanelHeaderContent } from "@/features/profile/ui/UserProfilePanelHeaderContent";
-
 export type { ProfilePanelTab, ProfilePanelView };
 
 export function UserProfilePanel({
@@ -116,6 +115,7 @@ export function UserProfilePanel({
   tab: controlledTab,
   view: controlledView,
   widthPx,
+  transparentChrome = false,
 }: UserProfilePanelProps) {
   const isOverlay = useIsThreadPanelOverlay();
   const isFloatingOverlay = isOverlay && !isSinglePanelView;
@@ -993,6 +993,7 @@ export function UserProfilePanel({
       profileBody={profileBody}
       splitPaneClamp={splitPaneClamp}
       widthPx={widthPx}
+      transparentChrome={transparentChrome}
     />
   );
 }
diff --git a/desktop/src/features/profile/ui/UserProfilePanelFrame.tsx b/desktop/src/features/profile/ui/UserProfilePanelFrame.tsx
index ba0d1f831f..3d2cce566d 100644
--- a/desktop/src/features/profile/ui/UserProfilePanelFrame.tsx
+++ b/desktop/src/features/profile/ui/UserProfilePanelFrame.tsx
@@ -27,6 +27,7 @@ type UserProfilePanelFrameProps = {
   profileBody: React.ReactNode;
   splitPaneClamp: boolean;
   widthPx: number;
+  transparentChrome?: boolean;
 };
 
 export function UserProfilePanelFrame({
@@ -46,12 +47,13 @@ export function UserProfilePanelFrame({
   profileBody,
   splitPaneClamp,
   widthPx,
+  transparentChrome = false,
 }: UserProfilePanelFrameProps) {
   if (isSplitLayout) {
     return (
       <>
         <div className="flex min-h-0 flex-1 flex-col">
-          <AuxiliaryPanelHeader>
+          <AuxiliaryPanelHeader transparent={transparentChrome}>
             {headerLeftContent}
             {headerActions}
           </AuxiliaryPanelHeader>
diff --git a/desktop/src/features/profile/ui/UserProfilePanelUtils.ts b/desktop/src/features/profile/ui/UserProfilePanelUtils.ts
index 30aaada342..478f352593 100644
--- a/desktop/src/features/profile/ui/UserProfilePanelUtils.ts
+++ b/desktop/src/features/profile/ui/UserProfilePanelUtils.ts
@@ -110,6 +110,7 @@ export type UserProfilePanelProps = {
   tab?: ProfilePanelTab;
   view?: ProfilePanelView;
   widthPx: number;
+  transparentChrome?: boolean;
 };
 
 export function deriveProfileChannels(
diff --git a/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx b/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx
index 406354b9ed..3c28f014c7 100644
--- a/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx
+++ b/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx
@@ -3,7 +3,10 @@ import type * as React from "react";
 import { channelChrome } from "@/shared/layout/chromeLayout";
 import { cn } from "@/shared/lib/cn";
 
-type AuxiliaryPanelHeaderProps = React.ComponentProps<"div">;
+type AuxiliaryPanelHeaderProps = React.ComponentProps<"div"> & {
+  /** Render header content without its own backdrop for a shared parent chrome. */
+  transparent?: boolean;
+};
 type AuxiliaryPanelHeaderGroupProps = React.ComponentProps<"div">;
 type AuxiliaryPanelTitleProps = React.ComponentProps<"h2">;
 
@@ -11,19 +14,23 @@ type AuxiliaryPanelTitleProps = React.ComponentProps<"h2">;
 export function AuxiliaryPanelHeader({
   className,
   children,
+  transparent = false,
   ...props
 }: AuxiliaryPanelHeaderProps) {
   return (
     <div
       className={cn(
-        "pointer-events-none relative z-30 bg-background/80 backdrop-blur-md supports-backdrop-filter:bg-background/70 dark:bg-background/70 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/55",
+        "pointer-events-none relative z-40 overflow-visible",
+        transparent
+          ? "bg-transparent"
+          : "bg-background/80 backdrop-blur-md supports-backdrop-filter:bg-background/70 dark:bg-background/70 dark:backdrop-blur-xl dark:supports-backdrop-filter:bg-background/55",
         channelChrome.negativeMargin,
         className,
       )}
       {...props}
     >
       <div
-        className="pointer-events-auto relative z-30 shrink-0 cursor-default select-none px-5 py-2"
+        className="pointer-events-auto relative z-40 shrink-0 cursor-default select-none px-5 py-2"
         data-tauri-drag-region
       >
         <div className="flex h-9 min-w-0 items-center gap-2.5">{children}</div>
diff --git a/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts b/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts
new file mode 100644
index 0000000000..901d1477a7
--- /dev/null
+++ b/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts
@@ -0,0 +1,134 @@
+import { expect, test } from "@playwright/test";
+
+import { waitForAnimations } from "../helpers/animations";
+import { installMockBridge } from "../helpers/bridge";
+
+type MockMessageWindow = Window & {
+  __BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
+    channelName: string;
+    content: string;
+    parentEventId?: string | null;
+    pubkey?: string;
+  }) => { id: string } | undefined;
+  __BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
+    channelName: string;
+  }) => boolean;
+};
+
+const CHANNEL_NAME = "engineering";
+const MOCK_IDENTITY_PUBKEY = "deadbeef".repeat(8);
+const ALICE_PUBKEY =
+  "953d3363262e86b770419834c53d2446409db6d918a57f8f339d495d54ab001f";
+
+async function waitForMockLiveSubscription(
+  page: import("@playwright/test").Page,
+  channelName: string,
+) {
+  await expect
+    .poll(async () => {
+      return page.evaluate((name) => {
+        return (
+          (
+            window as MockMessageWindow
+          ).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName: name }) ??
+          false
+        );
+      }, channelName);
+    })
+    .toBe(true);
+}
+
+test.describe("channel shared header backdrop", () => {
+  test.use({ viewport: { width: 1280, height: 720 } });
+
+  test("spans channel and split auxiliary columns with one backdrop", async ({
+    page,
+  }) => {
+    await installMockBridge(page);
+    await page.goto("/");
+    await page.getByTestId(`channel-${CHANNEL_NAME}`).click();
+    await expect(page.getByTestId("chat-title")).toHaveText(CHANNEL_NAME);
+    await waitForMockLiveSubscription(page, CHANNEL_NAME);
+
+    const rootId = await page.evaluate(
+      ({ channelName, pubkey }) =>
+        (window as MockMessageWindow).__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
+          channelName,
+          content: "Root message for shared header backdrop coverage.",
+          pubkey,
+        })?.id ?? null,
+      { channelName: CHANNEL_NAME, pubkey: MOCK_IDENTITY_PUBKEY },
+    );
+    expect(rootId).not.toBeNull();
+
+    await page.evaluate(
+      ({ channelName, parentEventId, pubkey }) => {
+        (window as MockMessageWindow).__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
+          channelName,
+          content: "Reply that opens a split thread panel.",
+          parentEventId,
+          pubkey,
+        });
+      },
+      {
+        channelName: CHANNEL_NAME,
+        parentEventId: rootId,
+        pubkey: ALICE_PUBKEY,
+      },
+    );
+
+    const replyButton = page.locator('[data-testid^="reply-message-"]').first();
+    await expect(replyButton).toBeVisible();
+    await replyButton.click({ force: true });
+    await expect(page.getByTestId("message-thread-panel")).toBeVisible();
+
+    const sharedBackdrop = page.getByTestId("channel-shared-header-backdrop");
+    await expect(sharedBackdrop).toHaveCount(1);
+
+    const chatHeader = page.getByTestId("chat-header");
+    const auxiliaryResizeHandle = page.getByTestId(
+      "right-auxiliary-pane-resize-handle",
+    );
+
+    const [
+      hostBox,
+      backdropBox,
+      backdropFilter,
+      backdropZIndex,
+      headerZIndex,
+      resizeHandleZIndex,
+      auxiliaryPaneAnimationName,
+    ] = await Promise.all([
+      page.getByTestId("channel-drop-zone").locator("..").boundingBox(),
+      sharedBackdrop.boundingBox(),
+      sharedBackdrop.evaluate(
+        (element) => getComputedStyle(element).backdropFilter,
+      ),
+      sharedBackdrop.evaluate((element) =>
+        Number(getComputedStyle(element).zIndex),
+      ),
+      chatHeader.evaluate((element) =>
+        Number(getComputedStyle(element.parentElement ?? element).zIndex),
+      ),
+      auxiliaryResizeHandle.evaluate((element) =>
+        Number(getComputedStyle(element).zIndex),
+      ),
+      page
+        .getByTestId("message-thread-panel")
+        .evaluate((element) => getComputedStyle(element).animationName),
+    ]);
+
+    expect(hostBox).not.toBeNull();
+    expect(backdropBox).not.toBeNull();
+    expect(Math.round(backdropBox?.x ?? 0)).toBe(Math.round(hostBox?.x ?? 0));
+    expect(Math.round(backdropBox?.width ?? 0)).toBe(
+      Math.round(hostBox?.width ?? 0),
+    );
+    expect(backdropFilter).not.toBe("none");
+    expect(headerZIndex).toBeGreaterThan(backdropZIndex);
+    expect(resizeHandleZIndex).toBeGreaterThan(backdropZIndex);
+    expect(auxiliaryPaneAnimationName).toBe("none");
+
+    await waitForAnimations(page);
+  });
+});
