diff --git a/src/features/workbench/layout/workbench-layout.test.ts b/src/features/workbench/layout/workbench-layout.test.ts
index b1094c3..4f072eb 100644
--- a/src/features/workbench/layout/workbench-layout.test.ts
+++ b/src/features/workbench/layout/workbench-layout.test.ts
@@ -5,7 +5,8 @@ import {
getAgentPanelMaxWidth,
getWorkbenchBasemapTone,
getWorkbenchCameraPadding,
- getWorkbenchViewportLayout
+ getWorkbenchViewportLayout,
+ resolveMobileWorkbenchOverlayLayout
} from "./workbench-layout";
describe("workbench basemap surface tone", () => {
@@ -20,6 +21,19 @@ describe("workbench basemap surface tone", () => {
});
describe("workbench floating panels", () => {
+ it("derives mobile dock and map control offsets from one overlay stack", () => {
+ expect(resolveMobileWorkbenchOverlayLayout(true)).toEqual({
+ timelineBottom: 12,
+ dockBottom: 68,
+ mapControlBottom: 120
+ });
+ expect(resolveMobileWorkbenchOverlayLayout(false)).toEqual({
+ timelineBottom: 12,
+ dockBottom: 12,
+ mapControlBottom: 64
+ });
+ });
+
it("uses bounded desktop and wide panel widths", () => {
expect(getWorkbenchViewportLayout(1440)).toMatchObject({
agentWidth: 500,
diff --git a/src/features/workbench/layout/workbench-layout.ts b/src/features/workbench/layout/workbench-layout.ts
index d3af352..4778e2d 100644
--- a/src/features/workbench/layout/workbench-layout.ts
+++ b/src/features/workbench/layout/workbench-layout.ts
@@ -26,9 +26,29 @@ export const WORKBENCH_LAYOUT = {
mobileSheet: {
halfViewportRatio: 0.52,
fullTopGap: 68
+ },
+ mobileOverlay: {
+ edgeInset: 12,
+ gap: 8,
+ dockHeight: 44,
+ timelineSummaryHeight: 48
}
} as const;
+export function resolveMobileWorkbenchOverlayLayout(timelineVisible: boolean) {
+ const { edgeInset, gap, dockHeight, timelineSummaryHeight } =
+ WORKBENCH_LAYOUT.mobileOverlay;
+ const dockBottom = timelineVisible
+ ? edgeInset + timelineSummaryHeight + gap
+ : edgeInset;
+
+ return {
+ timelineBottom: edgeInset,
+ dockBottom,
+ mapControlBottom: dockBottom + dockHeight + gap
+ };
+}
+
export function clampAgentPanelWidth(
width: number,
viewportWidth: number,
diff --git a/src/features/workbench/map-workbench-page.tsx b/src/features/workbench/map-workbench-page.tsx
index 5e61e5d..81357fe 100644
--- a/src/features/workbench/map-workbench-page.tsx
+++ b/src/features/workbench/map-workbench-page.tsx
@@ -78,7 +78,8 @@ import {
import {
WORKBENCH_LAYOUT,
getWorkbenchBasemapTone,
- getWorkbenchLayoutCssVariables
+ getWorkbenchLayoutCssVariables,
+ resolveMobileWorkbenchOverlayLayout
} from "./layout/workbench-layout";
import { getResponsiveWorkbenchPadding } from "./map/camera";
import { exportMapViewImage } from "./map/export-view";
@@ -220,9 +221,10 @@ export function MapWorkbenchPage({
timelineMode,
timelineVisible
);
+ const mobileOverlayLayout = resolveMobileWorkbenchOverlayLayout(timelineVisible);
const timelineBottom = isLargeScreen
? timelineScaleLayout.timelineBottom
- : 12;
+ : mobileOverlayLayout.timelineBottom;
useEffect(() => {
setTimelineMode((current) => {
@@ -987,19 +989,30 @@ export function MapWorkbenchPage({
onReturnNow={handleReturnOperationalNow}
/>
-
+
+
> : null
)}
mapContent={(
@@ -1019,10 +1032,13 @@ export function MapWorkbenchPage({