diff --git a/client/src/components/Map/MapView.tsx b/client/src/components/Map/MapView.tsx
index 607df1f1..57d59202 100644
--- a/client/src/components/Map/MapView.tsx
+++ b/client/src/components/Map/MapView.tsx
@@ -569,7 +569,12 @@ export const MapView = memo(function MapView({
// Desktop browsers only get IP-based geolocation (city-level accuracy),
// so the button would be misleading. Mobile, where real GPS lives, keeps it.
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
- const locationButtonBottom = 'calc(var(--bottom-nav-h, 84px) + 12px)'
+ // When the day-detail panel is open it slides up over the map (bottom: navh+20,
+ // height var(--day-panel-h)) and covers the button's band, so lift the button
+ // above it; otherwise keep the plain bottom-nav offset. #1348
+ const locationButtonBottom = hasDayDetail
+ ? 'calc(var(--bottom-nav-h, 84px) + 20px + var(--day-panel-h, 0px) + 12px)'
+ : 'calc(var(--bottom-nav-h, 84px) + 12px)'
return (
<>
diff --git a/client/src/components/Map/MapViewGL.tsx b/client/src/components/Map/MapViewGL.tsx
index 65e790a3..9d6f3526 100644
--- a/client/src/components/Map/MapViewGL.tsx
+++ b/client/src/components/Map/MapViewGL.tsx
@@ -727,7 +727,12 @@ export function MapViewGL({
// Desktop browsers only get IP-based geolocation (city-level accuracy),
// so the button would be misleading. Mobile, where real GPS lives, keeps it.
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
- const buttonBottom = 'calc(var(--bottom-nav-h, 84px) + 12px)'
+ // When the day-detail panel is open it slides up over the map (bottom: navh+20,
+ // height var(--day-panel-h)) and covers the button's band, so lift the button
+ // above it; otherwise keep the plain bottom-nav offset. #1348
+ const buttonBottom = hasDayDetail
+ ? 'calc(var(--bottom-nav-h, 84px) + 20px + var(--day-panel-h, 0px) + 12px)'
+ : 'calc(var(--bottom-nav-h, 84px) + 12px)'
return (
diff --git a/client/src/components/Planner/DayDetailPanel.test.tsx b/client/src/components/Planner/DayDetailPanel.test.tsx
index a70fd9d5..cf9642a1 100644
--- a/client/src/components/Planner/DayDetailPanel.test.tsx
+++ b/client/src/components/Planner/DayDetailPanel.test.tsx
@@ -51,6 +51,16 @@ describe('DayDetailPanel', () => {
expect(document.body).toBeInTheDocument();
});
+ it('FE-PLANNER-DAYDETAIL-063: publishes its height to --day-panel-h and resets it on unmount (#1348)', () => {
+ document.documentElement.style.removeProperty('--day-panel-h');
+ const { unmount } = render(
);
+ // The panel publishes its measured height so the map's mobile GPS button can
+ // sit above it instead of being hidden behind it.
+ expect(document.documentElement.style.getPropertyValue('--day-panel-h')).not.toBe('');
+ unmount();
+ expect(document.documentElement.style.getPropertyValue('--day-panel-h')).toBe('0px');
+ });
+
it('FE-PLANNER-DAYDETAIL-002: returns null when day prop is null', () => {
render(
);
expect(document.querySelector('[style*="position: fixed"]')).toBeNull();
diff --git a/client/src/components/Planner/DayDetailPanel.tsx b/client/src/components/Planner/DayDetailPanel.tsx
index c7dad60d..71d5c93c 100644
--- a/client/src/components/Planner/DayDetailPanel.tsx
+++ b/client/src/components/Planner/DayDetailPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react'
+import React, { useState, useEffect, useRef } from 'react'
import ReactDOM from 'react-dom'
import { X, Sun, Cloud, CloudRain, CloudSnow, CloudDrizzle, CloudLightning, Wind, Droplets, Sunrise, Sunset, Hotel, Calendar, MapPin, LogIn, LogOut, Hash, Pencil, Plane, Utensils, Train, Car, Ship, Ticket, FileText, Users, ChevronsDown, ChevronsUp } from 'lucide-react'
@@ -86,6 +86,27 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
updateAccommodationField, handleRemoveAccommodation,
} = useDayDetail(day, days, tripId, lat, lng, language, onAccommodationChange)
+ // Publish the panel's live height as a root CSS var so the map's mobile GPS
+ // button can sit just above the panel instead of being hidden behind it (#1348).
+ // The card grows/shrinks (collapse, content, ≤60vh), so track it live.
+ const cardRef = useRef
(null)
+ useEffect(() => {
+ const el = cardRef.current
+ if (!el) return
+ const root = document.documentElement
+ const publish = () => root.style.setProperty('--day-panel-h', `${el.offsetHeight}px`)
+ publish()
+ let ro: ResizeObserver | undefined
+ if (typeof ResizeObserver !== 'undefined') {
+ ro = new ResizeObserver(publish)
+ ro.observe(el)
+ }
+ return () => {
+ ro?.disconnect()
+ root.style.setProperty('--day-panel-h', '0px')
+ }
+ }, [])
+
if (!day) return null
const formattedDate = day.date ? new Date(day.date + 'T00:00:00Z').toLocaleDateString(
@@ -98,7 +119,7 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
return (