diff --git a/client/src/components/Map/MapAttributionToggle.test.tsx b/client/src/components/Map/MapAttributionToggle.test.tsx deleted file mode 100644 index ada4001d8..000000000 --- a/client/src/components/Map/MapAttributionToggle.test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -// FE-MAP-ATTRIB-001 to FE-MAP-ATTRIB-003 -import { fireEvent, render } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import MapAttributionToggle from './MapAttributionToggle' - -// Outside a TranslationProvider t(key) echoes the key, so the label is asserted as its key. -const BAND = 'calc(var(--bottom-nav-h, 84px) + 12px)' - -describe('MapAttributionToggle', () => { - it('FE-MAP-ATTRIB-001: it follows a credit corner where the map has one, and keeps the locate band where it has not', () => { - const { getByRole } = render( {}} bottomOffset={BAND} />) - const style = getByRole('button').style - - // Both numbers come from the map around it first. A map without a credit corner - // defines neither variable, so the fallbacks are the old slot beside the locate button. - expect(style.right).toBe('var(--m-credit-right, 62px)') - expect(style.bottom).toBe(`var(--m-credit-bottom, ${BAND})`) - }) - - it('FE-MAP-ATTRIB-002: it is labelled, says whether the credit is open, and toggles once per tap', () => { - const onToggle = vi.fn() - const { getByRole, rerender } = render() - const button = getByRole('button') - - expect(button.getAttribute('title')).toBe('map.attribution') - expect(button.getAttribute('aria-label')).toBe('map.attribution') - expect(button.getAttribute('aria-expanded')).toBe('false') - - fireEvent.click(button) - expect(onToggle).toHaveBeenCalledTimes(1) - - rerender() - expect(getByRole('button').getAttribute('aria-expanded')).toBe('true') - }) - - it('FE-MAP-ATTRIB-003: wherever it sits, it stays above the Leaflet control corners', () => { - const { getByRole } = render( {}} bottomOffset={BAND} />) - const style = getByRole('button').style - - // index.css pins `.leaflet-bottom` to z-index 1, and the open credit lives in that - // corner. The (i) sits in the same row now, so it has to stay the one on top. - expect(style.position).toBe('absolute') - expect(style.zIndex).toBe('1000') - }) -}) diff --git a/client/src/components/Map/MapAttributionToggle.tsx b/client/src/components/Map/MapAttributionToggle.tsx deleted file mode 100644 index d42a4aa87..000000000 --- a/client/src/components/Map/MapAttributionToggle.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { Info } from 'lucide-react' -import { MAP_CONTROL_SHADOW } from './mapControlShadow' -import { useTranslation } from '../../i18n' - -interface MapAttributionToggleProps { - open: boolean - onToggle: () => void - /** - * Where the (i) sits on a map that defines no credit corner: the locate button's band, - * so the two share a line. - */ - bottomOffset: string -} - -/** - * The little (i) that stands in for the credit on a phone. - * - * Both GL engines ship one of these: below 640px they collapse their attribution to a - * button and open it on a tap. Leaflet has no such mode, so on a screen the map fills, - * its credit is a white two-line block parked in the middle of the picture. This is the - * missing half of that pattern, and it is a React button rather than surgery on - * Leaflet's own container because Leaflet rewrites that container's markup from scratch - * whenever a layer with an attribution is added or removed. - * - * Nothing is hidden that cannot be read: one tap shows the full credit, every link in - * it included, which is the same bargain the GL engines strike. - */ -export default function MapAttributionToggle({ open, onToggle, bottomOffset }: MapAttributionToggleProps) { - const { t } = useTranslation() - const label = t('map.attribution') - return ( - - ) -} diff --git a/client/src/components/Map/MapView.test.tsx b/client/src/components/Map/MapView.test.tsx index 2075c2805..d44923dbe 100644 --- a/client/src/components/Map/MapView.test.tsx +++ b/client/src/components/Map/MapView.test.tsx @@ -989,29 +989,19 @@ describe('MapView live location', () => { expect(geoMock.cycleMode).toHaveBeenCalled() }) - it('FE-COMP-MAPVIEW-077: the credit (i) is a phone control, and it opens the credit through a class on the wrapper', () => { + it('FE-COMP-MAPVIEW-077: the map draws no credit control of its own, on either width', () => { const desktop = render() + // The desktop credit is Leaflet's own, in its own container; this component adds none. expect(screen.queryByRole('button', { name: 'Map credits' })).toBeNull() desktop.unmount() Object.defineProperty(window, 'innerWidth', { configurable: true, writable: true, value: 420 }) const { container } = render() - const toggle = screen.getByRole('button', { name: 'Map credits' }) + // The phone used to get an (i) here that opened the credit through a class on the + // wrapper. The phone map now carries no visible credit at all (mobile.css), so neither + // the button nor the class it toggled is left behind. + expect(screen.queryByRole('button', { name: 'Map credits' })).toBeNull() const wrapper = container.querySelector('div.w-full.h-full.relative') as HTMLElement - // Starts closed: on a phone the map is the screen, and the credit is one tap away. - expect(toggle.getAttribute('aria-expanded')).toBe('false') - expect(wrapper.classList.contains('m-attrib-open')).toBe(false) - // The locate button's band is only the fallback; a credit corner around the map wins. - expect(toggle.style.bottom).toBe('var(--m-credit-bottom, calc(var(--bottom-nav-h, 84px) + 12px))') - - // A class on the wrapper rather than markup in Leaflet's own container, which Leaflet - // rewrites whenever a layer with an attribution comes or goes. - fireEvent.click(toggle) - expect(toggle.getAttribute('aria-expanded')).toBe('true') - expect(wrapper.classList.contains('m-attrib-open')).toBe(true) - - fireEvent.click(toggle) - expect(toggle.getAttribute('aria-expanded')).toBe('false') expect(wrapper.classList.contains('m-attrib-open')).toBe(false) }) }) diff --git a/client/src/components/Map/MapView.tsx b/client/src/components/Map/MapView.tsx index 6a043e37d..169f8bfcb 100644 --- a/client/src/components/Map/MapView.tsx +++ b/client/src/components/Map/MapView.tsx @@ -34,7 +34,6 @@ function alternativeLabelIcon(label: string, note: string, background: string, a }) } import L from 'leaflet' -import MapAttributionToggle from './MapAttributionToggle' import 'leaflet.markercluster/dist/MarkerCluster.css' import 'leaflet.markercluster/dist/MarkerCluster.Default.css' import { mapsApi } from '../../api/client' @@ -999,16 +998,6 @@ export const MapView = memo(function MapView({ ? 'calc(var(--bottom-nav-h, 84px) + 20px + var(--day-panel-h, 0px) + 12px)' : 'calc(var(--bottom-nav-h, 84px) + 12px)' - /** - * Whether the credit is showing, on a phone where it starts as the (i). - * - * Held here rather than pushed into Leaflet's own container: Leaflet rewrites that - * container's markup from scratch whenever a layer with an attribution is added or - * removed, so anything injected into it dies on the next basemap switch. A class on - * the wrapper survives that, and the CSS lives with the rest of the mobile chrome. - */ - const [attribOpen, setAttribOpen] = useState(false) - const baseLayer = useSettingsStore(s => s.settings.map_base_layer) || 'default' const updateSetting = useSettingsStore(s => s.updateSetting) const isSatellite = baseLayer === 'satellite' @@ -1027,7 +1016,7 @@ export const MapView = memo(function MapView({ return ( <> -
+
} - {/* The credit as the little (i), which is what both GL engines do on a narrow map - and Leaflet has no mode for. */} - {isMobile && ( - setAttribOpen(v => !v)} - bottomOffset={locationButtonBottom} - /> - )} {/* 20px off the sidebar, not 12: the pill is round and frosted, so at the smaller gap its shadow ran into the sidebar edge and the two read as one surface. */} diff --git a/client/src/mobile/mobile.css b/client/src/mobile/mobile.css index cc4719c9c..83d0b7c75 100644 --- a/client/src/mobile/mobile.css +++ b/client/src/mobile/mobile.css @@ -334,116 +334,27 @@ .trek-z { opacity: 1; } } -/* Map attribution clears the dock. +/* The phone map carries no visible credit. * - * Both engines park their attribution at the bottom of the map, and on a phone - * the map is the whole screen — so the credit line lands under the floating nav - * and reads as a broken bar (#2022's screenshots show it over the dock). Lift it - * by the same variable everything else clears the dock with. Leaflet and - * MapLibre both, because a phone meets either depending on the screen. */ + * Both engines park a credit at the bottom of the map, and on a phone the map is the + * whole screen, so whatever is put there sits in the middle of the picture. It has been + * a band across the bottom (#2022) and then a round (i) beside the locate button, and + * neither reads as part of this shell: a lone control under the locate button is the + * first thing the eye lands on over a full-bleed map. + * + * So on the phone it is off. The desktop map is untouched and still shows the full + * credit with its links, which is where this belongs; `.m-root` is the phone shell only. + * Both engines and both corners, because a phone meets either depending on the screen, + * and the GL containers hold nothing else — MapViewGL adds no control of its own, so + * hiding the corner hides the credit and the wordmark and nothing besides. + * + * Owner's call, made knowingly: OSM and the tile vendors ask for a visible credit. */ .m-root .leaflet-control-attribution, .m-root .maplibregl-ctrl-bottom-left, .m-root .mapboxgl-ctrl-bottom-left, .m-root .maplibregl-ctrl-bottom-right, .m-root .mapboxgl-ctrl-bottom-right { - bottom: var(--bottom-nav-h); -} - -/* ...and it is a round (i) rather than a band across the picture. - * - * Both GL engines collapse their attribution below 640px and then open it anyway, - * tucking it away only on the first drag. On a phone, where the map IS the screen, - * the first thing anybody sees is then a two-line grey ribbon over the bottom of - * it. MapViewGL now starts it collapsed; what is left here is where the little - * button sits on a phone map without a credit row, which is beside the locate - * control rather than underneath it. The trip map gives it the corner instead - * (`.m-credit-corner` below). - * - * Nothing is dropped: one tap opens the full credit, and it is still a link. */ -.m-root .maplibregl-ctrl-bottom-right, -.m-root .mapboxgl-ctrl-bottom-right { - bottom: calc(var(--bottom-nav-h) + 2px); - right: 46px; -} - -/* Leaflet has no collapsed mode at all, so it is given one: hidden until its (i) is tapped - * (`MapAttributionToggle`, which puts `m-attrib-open` on the map's wrapper). Nothing is - * lost: one tap shows the whole credit, every link in it included, which is the same - * bargain the GL engines strike on a narrow map. */ -.m-root .leaflet-control-attribution { display: none; } - -/* The control column, not just the block inside it: Leaflet sizes that column to the - credit on one line, so capping only the child leaves the text overflowing its own - box instead of wrapping. */ -.m-root .m-attrib-open .leaflet-bottom.leaflet-right { max-width: 78vw; } - -.m-root .m-attrib-open .leaflet-control-attribution { - display: block; - /* Above the (i) rather than beside it, so the block never lands under a thumb - reaching for the locate button. */ - right: 12px; - bottom: calc(var(--bottom-nav-h) + 52px); - padding: 4px 9px; - border-radius: 11px; - font-size: 10px; - line-height: 1.4; - background: color-mix(in srgb, var(--m-card) 92%, transparent); - color: var(--m-muted); - box-shadow: 0 10px 28px -12px rgba(0, 0, 0, .45); -} -.m-root .m-attrib-open .leaflet-control-attribution a { color: var(--m-ink); } - -/* On the trip map the credit has the bottom right corner to itself. - * - * Beside the locate button it read as a stray control in the middle of the band. MMapArea - * marks its layer `m-credit-corner`, defines `--m-map-floor` (the top of the dock, or of the - * stage bar on the road trip tab) and floats the round controls one credit row above that - * floor, so the corner under them is free. Both engines read the same two numbers from - * here: the GL control containers through the rules below, the Leaflet (i) through the - * variables it falls back from. Other phone maps have no such row and define neither, so - * their credit stays beside their locate button. */ -.m-root .m-credit-corner { - /* The locate button's own margin, so the right column lines up on one edge. */ - --m-credit-right: 12px; - --m-credit-bottom: calc(var(--m-map-floor) + 12px); -} - -/* The compact GL control keeps a 10px margin of its own, so its container sits that far - inside the spot the button is meant to land on. */ -.m-root .m-credit-corner .maplibregl-ctrl-bottom-right, -.m-root .m-credit-corner .mapboxgl-ctrl-bottom-right { - bottom: calc(var(--m-credit-bottom) - 10px); - right: calc(var(--m-credit-right) - 10px); -} - -/* ...and the (i) stays in that corner while the credit is open. Both GL engines pin their - button to the top of the control, so a credit that wraps carries it up the column, into - the locate button that now sits right above this corner: at two lines (20px each) the - top of the button slides under it, at three the whole button does, and the tap meant to - close the credit lands on the locate button instead. Held at the bottom it stays where - the thumb just was, and the text unfolds to its left and upward like the Leaflet credit - below. Collapsed, the control is exactly the button's height, so nothing moves until it - opens. */ -.m-root .m-credit-corner .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib-button, -.m-root .m-credit-corner .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl-attrib-button { - top: auto; - bottom: 0; -} - -/* The Mapbox wordmark is a credit too, so it shares the row rather than rising with the - band into the switcher and the compass. 6px rather than 10: the logo hangs 4px below its - own control box. MapLibre draws no wordmark here, so for it this moves an empty corner. */ -.m-root .m-credit-corner .maplibregl-ctrl-bottom-left, -.m-root .m-credit-corner .mapboxgl-ctrl-bottom-left { - bottom: calc(var(--m-credit-bottom) - 6px); -} - -/* The open Leaflet credit stays in the row, to the left of the (i), which is where the GL - engines unfold theirs. Above the (i) is the locate button now. 36px is the (i) plus a - gap; both offsets are relative, like the ones they override. */ -.m-root .m-credit-corner .m-attrib-open .leaflet-control-attribution { - right: calc(var(--m-credit-right) + 36px); - bottom: var(--m-credit-bottom); + display: none; } /* Text fields carry the row's background, not their own. diff --git a/client/src/mobile/mobileCreditCss.test.ts b/client/src/mobile/mobileCreditCss.test.ts index d258adf3d..97971e69a 100644 --- a/client/src/mobile/mobileCreditCss.test.ts +++ b/client/src/mobile/mobileCreditCss.test.ts @@ -2,20 +2,21 @@ import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' -// FE-MOB-CREDITCSS-001 to FE-MOB-CREDITCSS-005 +// FE-MOB-CREDITCSS-001 to FE-MOB-CREDITCSS-003 // -// Where the credit lands on the phone trip map is written in mobile.css, against the vendor -// control containers the GL engines draw and the Leaflet column. jsdom applies neither -// stylesheet, so these read the real file: the numbers only agree with the vendor CSS and -// with MMapArea's floor by convention, which is exactly what can drift here. +// The phone map carries no visible credit: that is a decision, and the only thing holding +// it is a rule in mobile.css against the vendor control containers. jsdom applies no +// stylesheet, so these read the real file. Written as tests because the rule is easy to +// lose: it names vendor class names nothing else in the codebase refers to, and a credit +// creeping back is a change to the map's face that no component test would catch. describe('phone map credit css', () => { // Vitest runs with the client package as its root, so cwd is stable here. const css = readFileSync(resolve(process.cwd(), 'src/mobile/mobile.css'), 'utf8') /** * Every rule in the sheet as its selector list and its declarations, comments dropped. - * Parsed rather than found by substring, because the same selector heads more than one - * rule here (the generic lift and the round (i) both name the GL bottom right corner). + * Parsed rather than found by substring, because a vendor class name also appears in the + * prose above the rules. */ const rules = css .replace(/\/\*[\s\S]*?\*\//g, '') @@ -32,63 +33,46 @@ describe('phone map credit css', () => { /** The rules whose selector list names this selector. */ const rulesFor = (selector: string) => rules.filter(rule => rule.selectors.includes(selector)) - it('FE-MOB-CREDITCSS-001: the credit corner derives both numbers from the floor MMapArea defines', () => { - const corner = rulesFor('.m-root .m-credit-corner') + it('FE-MOB-CREDITCSS-001: both engines and both corners are hidden by one rule', () => { + const hidden = rulesFor('.m-root .leaflet-control-attribution') - expect(corner).toHaveLength(1) - // The locate button's own margin on the right, a gap above the dock or the stage bar below. - expect(corner[0].body).toMatch(/--m-credit-right:\s*12px;/) - expect(corner[0].body).toMatch(/--m-credit-bottom:\s*calc\(var\(--m-map-floor\) \+ 12px\);/) + expect(hidden).toHaveLength(1) + expect(hidden[0].body).toMatch(/display:\s*none;/) + // One rule for all of them, so Leaflet, MapLibre and Mapbox cannot drift apart, and so + // the credit cannot come back on the one engine nobody happened to open. + for (const selector of [ + '.m-root .maplibregl-ctrl-bottom-left', + '.m-root .mapboxgl-ctrl-bottom-left', + '.m-root .maplibregl-ctrl-bottom-right', + '.m-root .mapboxgl-ctrl-bottom-right', + ]) { + expect(hidden[0].selectors).toContain(selector) + } }) - it('FE-MOB-CREDITCSS-002: the GL (i) lands on those numbers, net of the compact control\'s own margin', () => { - const gl = rulesFor('.m-root .m-credit-corner .maplibregl-ctrl-bottom-right') + it('FE-MOB-CREDITCSS-002: nothing else in the sheet places a credit', () => { + // The hiding rule is the last word only while no later rule moves one of these + // containers back into view. Both corners, because the GL wordmark sits in the left one. + const placed = rules.filter(rule => rule.selectors.some(s => /ctrl-bottom-(left|right)|leaflet-control-attribution/.test(s))) - expect(gl).toHaveLength(1) - // One rule for both engines, so MapLibre and Mapbox cannot end up in different corners. - expect(gl[0].selectors).toContain('.m-root .m-credit-corner .mapboxgl-ctrl-bottom-right') - // The vendor sheets give the compact attribution a 10px margin on every side. - expect(gl[0].body).toMatch(/bottom:\s*calc\(var\(--m-credit-bottom\) - 10px\);/) - expect(gl[0].body).toMatch(/right:\s*calc\(var\(--m-credit-right\) - 10px\);/) - - // The Mapbox wordmark shares the row rather than rising with the band under the compass. - const wordmark = rulesFor('.m-root .m-credit-corner .mapboxgl-ctrl-bottom-left') - expect(wordmark).toHaveLength(1) - expect(wordmark[0].selectors).toContain('.m-root .m-credit-corner .maplibregl-ctrl-bottom-left') - expect(wordmark[0].body).toMatch(/bottom:\s*calc\(var\(--m-credit-bottom\) - 6px\);/) + expect(placed).toHaveLength(1) + expect(placed[0].body).toMatch(/display:\s*none;/) }) - it('FE-MOB-CREDITCSS-003: the open Leaflet credit unfolds in the row, left of the (i), not over the locate button', () => { - const open = rulesFor('.m-root .m-credit-corner .m-attrib-open .leaflet-control-attribution') - - expect(open).toHaveLength(1) - expect(open[0].body).toMatch(/right:\s*calc\(var\(--m-credit-right\) \+ 36px\);/) - expect(open[0].body).toMatch(/bottom:\s*var\(--m-credit-bottom\);/) + it('FE-MOB-CREDITCSS-003: the credit corner and its variables are gone with it', () => { + // `m-credit-corner` was the trip map's own credit slot, `m-attrib-open` the class the + // Leaflet (i) toggled. Both are dead now; a leftover rule would place an element that + // no longer exists and read as if the credit were still somewhere on screen. + expect(css).not.toContain('m-credit-corner') + expect(css).not.toContain('m-attrib-open') + expect(css).not.toContain('--m-credit') }) - it('FE-MOB-CREDITCSS-004: phone maps without a credit row keep the credit beside their locate button', () => { - // The collections and journey maps have no `m-credit-corner`, so the unscoped rules are - // still what places their credit. - expect(rulesFor('.m-root .maplibregl-ctrl-bottom-right').some(rule => /right:\s*46px;/.test(rule.body))).toBe(true) - expect(rulesFor('.m-root .m-attrib-open .leaflet-control-attribution').some( - rule => /bottom:\s*calc\(var\(--bottom-nav-h\) \+ 52px\);/.test(rule.body), - )).toBe(true) + it('FE-MOB-CREDITCSS-004: the phone map is the only thing this touches', () => { + // Every selector is under `.m-root`, the phone shell. The desktop map keeps its full + // credit with its links, which is where it belongs. + const hidden = rulesFor('.m-root .leaflet-control-attribution') - // The band's own lift stays in MMapArea's class, where FE-MOB-MAPAREA-003 pins it. A - // corner rule setting it too would move every round control from a stylesheet. - const corner = rules.filter(rule => rule.selectors.some(s => s.includes('.m-credit-corner'))) - expect(corner).toHaveLength(5) - for (const rule of corner) expect(rule.body).not.toContain('--bottom-nav-h') - }) - - it('FE-MOB-CREDITCSS-005: an open GL credit keeps its (i) in the corner rather than under the locate button', () => { - const button = rulesFor('.m-root .m-credit-corner .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib-button') - - expect(button).toHaveLength(1) - expect(button[0].selectors).toContain('.m-root .m-credit-corner .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl-attrib-button') - // Both vendor sheets put the button at the top of the control, so a credit wrapping to - // three lines would carry it up into the locate button right above the corner. - expect(button[0].body).toMatch(/top:\s*auto;/) - expect(button[0].body).toMatch(/bottom:\s*0;/) + for (const selector of hidden[0].selectors) expect(selector.startsWith('.m-root ')).toBe(true) }) }) diff --git a/client/src/mobile/screens/trip/map/MMapArea.tsx b/client/src/mobile/screens/trip/map/MMapArea.tsx index c2845f40d..e4a5788b7 100644 --- a/client/src/mobile/screens/trip/map/MMapArea.tsx +++ b/client/src/mobile/screens/trip/map/MMapArea.tsx @@ -76,10 +76,10 @@ function useSafeInsets(probe: RefObject): SafeInsets { * the rail. The search bar that sits below the rail on the stage steps away while the * picker is open, so the rail is the lowest chrome up there. * - * Bottom: the safe area, the dock's 74px (62px tall, 12px off the bottom), the bar's lift - * (its height and the 15px gap between the dock and its foot) and the 38px credit row - * over that. That is the very line `--bottom-nav-h` puts the round controls' band on, so - * the frame ends where they begin, and they only take the two corners of it. + * Bottom: the safe area, the dock's 74px (62px tall, 12px off the bottom) and the bar's + * lift (its height and the 15px gap between the dock and its foot). That is the very line + * `--bottom-nav-h` puts the round controls' band on, so the frame ends where they begin, + * and they only take the two corners of it. * * The sides keep the 20px both engines already give a phone: nothing floats there. */ @@ -87,7 +87,7 @@ function alternativesFitPadding(insets: SafeInsets): ViewportPadding { return { top: insets.top + 12 + 50 + 42 + 12, right: 20, - bottom: insets.bottom + 74 + RT_ALT_BAR_LIFT + 38, + bottom: insets.bottom + 74 + RT_ALT_BAR_LIFT, left: 20, } } @@ -281,6 +281,24 @@ export default function MMapArea({ planner, shell }: MMapAreaProps) { * Merged through the planner's own hook rather than concatenated here, because the * sets overlap: the same petrol station found twice would be two pins on one roof. */ + /** + * The vias the phone map draws, minus the night pauses. + * + * A night pause is a pill with a moon and a day number, drawn beside the boundary where + * one travel day ends. On the desktop it is a handle: it carries a hint and can be + * dragged to move the boundary. A phone has no hover to explain it and no room to drag + * it, so all it does there is sit on the map, and it sits there for EVERY day at once — + * the markers come from the whole drive (`automaticPoints`), not from the stage on + * screen, so day 1 shows day 2's pill as well. Two labels the day filter does not reach + * read as part of the map rather than as a control. + * + * Both lists go through the same filter: the plan tab's vias carry night pauses too. + */ + const mapVias = useMemo( + () => (onStage ? planner.roadtripMapVias : planner.routeVias)?.filter(v => !v.nightPause), + [onStage, planner.roadtripMapVias, planner.routeVias], + ) + const pois = useMergedMapPois( onStage ? planner.roadtripCorridor.visible : null, onStage ? NO_POIS : poi.pois, @@ -294,27 +312,23 @@ export default function MMapArea({ planner, shell }: MMapAreaProps) { // // --m-map-floor is the top edge of whatever the map ends at: the dock, 62px tall at // safe-bottom + 12, or on the road trip tab the stage bar, which takes the band the - // round controls would otherwise sit in and is what --m-stage-lift adds. The map - // credit (the little (i)) takes the bottom right corner a gap above that floor: - // beside the locate button it read as a stray control in the middle of the band. - // The round controls float one credit row higher (a 30px button plus an 8px gap) and - // add their own 12px on top of that, still close enough to the thumb to reach - // one-handed. The whole band moves rather than the one control over the corner, so - // the compass and the locate button stay on one line, and everything that reads - // --bottom-nav-h (the compass, both engines' locate button and base-layer switcher, - // the overview stack) follows on its own. Where the credit lands is written once, in - // mobile.css under `m-credit-corner`, where the GL containers and the Leaflet (i) - // both read it. + // round controls would otherwise sit in and is what --m-stage-lift adds. The round + // controls sit straight on that floor and add their own 12px, close enough to the + // thumb to reach one-handed. Everything that reads --bottom-nav-h (the compass, both + // engines' locate button and base-layer switcher, the overview stack) follows on its + // own. The band used to float a further 38px up to leave the corner under it to the + // map credit; the phone map carries no visible credit any more (see mobile.css), so + // that row would now only be a gap over the dock. // // The metrics are classes rather than an inline --bottom-nav-h, and the lift is its // OWN variable folded into them: the compass band below is identified by being the // one element that sets that name inline, and a second one would make that ambiguous.