diff --git a/.changeset/fn-8766-task-detail-popup-spacing.md b/.changeset/fn-8766-task-detail-popup-spacing.md
new file mode 100644
index 0000000000..122aaf14c1
--- /dev/null
+++ b/.changeset/fn-8766-task-detail-popup-spacing.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Align the floating Task Detail popup close control with its header edge.
+category: fix
+dev: Moves only Task Detail desktop resize targets outboard while retaining shared scrollbar clearance.
diff --git a/packages/dashboard/app/components/FloatingWindow.css b/packages/dashboard/app/components/FloatingWindow.css
index e886df6196..4c73392c14 100644
--- a/packages/dashboard/app/components/FloatingWindow.css
+++ b/packages/dashboard/app/components/FloatingWindow.css
@@ -261,6 +261,35 @@ Phone sheets are strictly below 768px. At exactly 768px this query must not matc
FNXC:ChatModal 2026-06-22-14:49:
On mobile/narrow app viewports, opening Quick Chat should present the full Chat modal as a full-screen sheet instead of a small draggable desktop window. Scope this to the chat FloatingWindow and override the inline desktop geometry only at the mobile breakpoint; desktop pop-out behavior remains movable/resizable.
*/
+/*
+FNXC:TaskDetailLayout 2026-08-03-19:36:
+FN-8766 keeps the desktop Task Detail popup's visible header/content edge symmetric while
+preserving the shared body's scrollbar clearance for every other FloatingWindow consumer. This
+headerless host owns its close button, so remove only its visible body gutter and move its desktop
+east resize hit areas outside the painted shell; the scrollbar remains fully usable and the close
+control does not sit behind a resize target. Tablet retains its existing touch geometry and phones
+remain full-screen sheets below.
+*/
+.floating-window--task-detail:not(.floating-window--tablet-viewport) {
+ overflow: visible;
+}
+
+.floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__body {
+ margin-inline-end: 0;
+}
+
+.floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--e {
+ right: calc(var(--space-sm) * -1);
+}
+
+.floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--ne {
+ right: calc(var(--space-lg) * -1);
+}
+
+.floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--se {
+ right: calc(var(--space-lg) * -1);
+}
+
/*
FNXC:ModalTouchGeometry 2026-07-26-13:25:
FN-8606 migrated core and workflow dialogs share FloatingWindow's pointer contract. Their
@@ -452,6 +481,7 @@ all floating affordances so persisted desktop geometry cannot imply a draggable
*/
.floating-window--task-detail {
inset: 0 !important;
+ overflow: hidden !important;
width: 100vw !important;
height: 100dvh !important;
min-width: 0 !important;
diff --git a/packages/dashboard/app/components/__tests__/FloatingWindow.test.tsx b/packages/dashboard/app/components/__tests__/FloatingWindow.test.tsx
index ca79dd8c72..76e06a9b8a 100644
--- a/packages/dashboard/app/components/__tests__/FloatingWindow.test.tsx
+++ b/packages/dashboard/app/components/__tests__/FloatingWindow.test.tsx
@@ -161,12 +161,14 @@ describe("FloatingWindow", () => {
expect(cssRuleContaining(floatingWindowCss, ".floating-window__resize-handle--ne", "right: 0;")).toContain("right: 0;");
expect(cssRuleContaining(floatingWindowCss, ".floating-window__resize-handle--se", "right: 0;")).toContain("right: 0;");
- // No shared caller may move a right handle back into the reserved scrollbar
- // gutter, nor override the body gutter, AT DESKTOP WIDTHS. Mobile full-screen
- // sheet overrides (inside @media) are legitimate and excluded from this scan.
+ /*
+ FNXC:TaskDetailLayout 2026-08-03-19:36:
+ FN-8766 is the sole desktop exception: its header-owned close control requires a symmetric
+ painted edge, so its gutter is removed only while its east resize targets move outboard.
+ Every unrelated consumer keeps the shared scrollbar-clearance geometry.
+ */
const desktopAppCss = stripAtMediaBlocks(allAppCss);
for (const callerClass of [
- "floating-window--task-detail",
"floating-window--automation",
"floating-window--mission-interview",
"floating-window--pr-create",
@@ -182,14 +184,20 @@ describe("FloatingWindow", () => {
expect(bodyRules.some((rule) => /margin-inline-end\s*:/.test(rule)), callerClass).toBe(false);
}
+ const desktopTaskBody = cssRuleContaining(
+ desktopAppCss,
+ ".floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__body",
+ "margin-inline-end",
+ );
+ expect(desktopTaskBody).toContain("margin-inline-end: 0;");
+ expect(cssRuleContaining(desktopAppCss, ".floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--e", "right")).toContain("right: calc(var(--space-sm) * -1);");
+ expect(cssRuleContaining(desktopAppCss, ".floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--ne", "right")).toContain("right: calc(var(--space-lg) * -1);");
+ expect(cssRuleContaining(desktopAppCss, ".floating-window--task-detail:not(.floating-window--tablet-viewport) .floating-window__resize-handle--se", "right")).toContain("right: calc(var(--space-lg) * -1);");
+
/*
- FNXC:MobileTaskPopups 2026-07-17-08:20:
- Regression guard for the mobile task-detail left-shift fix: the full-screen
- task-detail sheet hides all resize handles, so FN-8015's inherited
- `margin-inline-end: var(--space-lg)` body gutter only added dead space on the
- right and shifted the whole panel left. The mobile breakpoint must zero it so
- `.detail-body`'s own padding defines both insets equally. This is the sole
- legitimate body-gutter override and lives only inside the mobile @media block.
+ FNXC:MobileTaskPopups 2026-08-03-19:36:
+ The full-screen task-detail sheet hides every resize handle, so the inherited gutter must
+ remain zero and the desktop outboard-target host must resume clipping for sheet geometry.
*/
const mobileTaskDetailBody = cssRuleContaining(
allAppCss,
@@ -197,7 +205,7 @@ describe("FloatingWindow", () => {
"margin-inline-end",
);
expect(mobileTaskDetailBody).toContain("margin-inline-end: 0;");
- expect(cssRulesForClass(desktopAppCss, "floating-window--task-detail").some((rule) => rule.includes("floating-window__body"))).toBe(false);
+ expect(cssRuleContaining(allAppCss, ".floating-window--task-detail", "overflow: hidden !important;")).toContain("overflow: hidden !important;");
/*
FNXC:ModalTouchGeometry 2026-08-01-03:48:
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
index 053bc1ae12..829c3f6266 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
@@ -24,6 +24,7 @@ import {
setupTaskDetailModalHooks,
} from "./TaskDetailModal.test-helpers";
import { TaskDetailModal, TaskDetailContent } from "../TaskDetailModal";
+import { FloatingWindow } from "../FloatingWindow";
import {
assertModalGeometryRecoveryAndSheetContracts,
assertRenderedModalTouchGeometry,
@@ -856,6 +857,63 @@ describe("TaskDetailModal", () => {
}
});
+ it("keeps the floating task header symmetric without sacrificing its resize targets", () => {
+ const floatingCss = readFileSync(resolve(__dirname, "../FloatingWindow.css"), "utf8");
+ const desktopTaskSelector = ".floating-window--task-detail:not(.floating-window--tablet-viewport)";
+ const taskPopupBody = getExactCssRuleBlock(floatingCss, `${desktopTaskSelector} .floating-window__body`);
+ const sharedBody = getExactCssRuleBlock(floatingCss, ".floating-window__body");
+ const header = getExactCssRuleBlock(readDashboardStylesSource(), ".modal-header");
+ const eastResize = getExactCssRuleBlock(floatingCss, `${desktopTaskSelector} .floating-window__resize-handle--e`);
+ const northEastResize = getExactCssRuleBlock(floatingCss, `${desktopTaskSelector} .floating-window__resize-handle--ne`);
+ const southEastResize = getExactCssRuleBlock(floatingCss, `${desktopTaskSelector} .floating-window__resize-handle--se`);
+ const onRequestClose = vi.fn();
+
+ /*
+ FNXC:TaskDetailLayout 2026-08-03-19:36:
+ The shared body reserves desktop scrollbar clearance. Task Detail moves only its resize
+ hit areas outboard, so the embedded header retains matching tokenized edges.
+ */
+ expect(sharedBody).toContain("margin-inline-end: var(--space-lg);");
+ expect(taskPopupBody).toContain("margin-inline-end: 0;");
+ expect(header).toContain("padding: var(--modal-padding);");
+ expect(eastResize).toContain("right: calc(var(--space-sm) * -1);");
+ expect(northEastResize).toContain("right: calc(var(--space-lg) * -1);");
+ expect(southEastResize).toContain("right: calc(var(--space-lg) * -1);");
+
+ const { baseElement, unmount } = render(
+
+
+ ,
+ );
+
+ const popup = baseElement.querySelector("[data-testid='floating-window-task-detail-inset']");
+ const close = screen.getByRole("button", { name: "Close" });
+ expect(popup).toHaveClass("floating-window--task-detail");
+ expect(popup?.querySelector(".task-detail-content--embedded > .modal-header")).toContainElement(close);
+ expect(close).toHaveClass("task-detail-floating-close");
+ expect(popup?.querySelectorAll(".floating-window__resize-handle")).toHaveLength(8);
+ fireEvent.click(close);
+ expect(onRequestClose).toHaveBeenCalledTimes(1);
+ unmount();
+ });
+
it("uses production FloatingWindow geometry for touch drag, eight-direction resize, recovery, and sheets", () => {
const mount = () => render(