@mailwoman/react 10.0.0 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/README.md +18 -16
  2. package/fonts.css +97 -22
  3. package/lib/common/About.tsx +10 -10
  4. package/lib/common/ClientOnly.tsx +2 -14
  5. package/lib/common/CopyButton.tsx +9 -3
  6. package/lib/common/LoadingIndicator.tsx +13 -5
  7. package/lib/common/PresetChips.tsx +11 -8
  8. package/lib/common/confidence-tiers.ts +8 -7
  9. package/lib/common/cx.ts +3 -1
  10. package/lib/common/text-tokens.ts +10 -13
  11. package/lib/common/useBuildInfo.ts +54 -0
  12. package/lib/common/useClipboard.ts +2 -11
  13. package/lib/common.ts +22 -0
  14. package/lib/index.ts +27 -18
  15. package/lib/map/AppIdentity.tsx +89 -0
  16. package/lib/map/CompareToggle.tsx +8 -31
  17. package/lib/map/DebugInfo.tsx +75 -0
  18. package/lib/map/Geocoder.tsx +65 -50
  19. package/lib/map/GeocoderControls.tsx +425 -141
  20. package/lib/map/GraticuleLayer.tsx +56 -0
  21. package/lib/map/MapCanvas.tsx +26 -13
  22. package/lib/map/MapChipRow.tsx +4 -8
  23. package/lib/map/MapCompass.tsx +18 -25
  24. package/lib/map/MapControlStack.tsx +11 -10
  25. package/lib/map/MapFooter.tsx +5 -17
  26. package/lib/map/MapProgressBar.tsx +10 -13
  27. package/lib/map/MapSearchBar.tsx +31 -17
  28. package/lib/map/MapSheet.tsx +24 -15
  29. package/lib/map/OverlayLayers.tsx +14 -3
  30. package/lib/map/PlaceAutocomplete.tsx +12 -21
  31. package/lib/map/PlaceMarker.tsx +10 -4
  32. package/lib/map/ResolvedPlaceLayers.tsx +14 -15
  33. package/lib/map/ResultCamera.tsx +10 -31
  34. package/lib/map/ResultOverlay.tsx +14 -16
  35. package/lib/map/ResultPanel.tsx +1 -20
  36. package/lib/map/VersionPicker.tsx +10 -19
  37. package/lib/map/fake-runtime.ts +46 -19
  38. package/lib/map/geometry.ts +14 -47
  39. package/lib/map/graticule.ts +80 -0
  40. package/lib/map/map-debug.ts +4 -2
  41. package/lib/map/place-render.ts +30 -62
  42. package/lib/map/types.ts +57 -116
  43. package/lib/map/useCompareState.ts +5 -4
  44. package/lib/map/useGeocode.ts +7 -5
  45. package/lib/map/useMapBearing.ts +13 -13
  46. package/lib/map/useMapLabelPick.ts +21 -30
  47. package/lib/map/useMapPlaceRender.ts +3 -7
  48. package/lib/map/usePlaceAutocomplete.ts +44 -50
  49. package/lib/map.ts +92 -0
  50. package/lib/pipeline/CandidatePicker.tsx +13 -5
  51. package/lib/pipeline/ConfidenceCell.tsx +2 -2
  52. package/lib/pipeline/FailureDiagnostic.tsx +8 -2
  53. package/lib/pipeline/PipelineExplorer.tsx +6 -3
  54. package/lib/pipeline/QueryForm.tsx +5 -2
  55. package/lib/pipeline/ResolvedPlace.tsx +2 -2
  56. package/lib/pipeline/SpanHighlight.tsx +7 -5
  57. package/lib/pipeline/TimingPanel.tsx +1 -1
  58. package/lib/pipeline/TreeView.tsx +2 -2
  59. package/lib/pipeline/copy.ts +22 -25
  60. package/lib/pipeline/presets.ts +15 -13
  61. package/lib/pipeline/types.ts +20 -17
  62. package/lib/pipeline/useParsePipeline.ts +16 -13
  63. package/lib/pipeline.ts +36 -0
  64. package/lib/poi/AbstainPanel.tsx +1 -1
  65. package/lib/poi/LiveResultsBlock.tsx +2 -1
  66. package/lib/poi/POIExplorer.tsx +29 -17
  67. package/lib/poi/QueryInput.tsx +1 -1
  68. package/lib/poi/SubjectPanel.tsx +4 -3
  69. package/lib/poi/runtime.ts +14 -16
  70. package/lib/poi/types.ts +58 -47
  71. package/lib/poi/usePOISearch.ts +91 -82
  72. package/lib/poi.ts +40 -0
  73. package/lib/runtime/useReleaseRuntime.ts +122 -90
  74. package/lib/search/SearchModal.tsx +478 -0
  75. package/lib/search/search.css +282 -0
  76. package/lib/search/types.ts +68 -0
  77. package/lib/search.ts +11 -0
  78. package/out/common/About.d.ts +6 -6
  79. package/out/common/About.d.ts.map +1 -1
  80. package/out/common/About.js +1 -1
  81. package/out/common/About.js.map +1 -1
  82. package/out/common/ClientOnly.d.ts +2 -11
  83. package/out/common/ClientOnly.d.ts.map +1 -1
  84. package/out/common/ClientOnly.js +1 -13
  85. package/out/common/ClientOnly.js.map +1 -1
  86. package/out/common/CopyButton.d.ts +9 -3
  87. package/out/common/CopyButton.d.ts.map +1 -1
  88. package/out/common/CopyButton.js.map +1 -1
  89. package/out/common/LoadingIndicator.d.ts +13 -5
  90. package/out/common/LoadingIndicator.d.ts.map +1 -1
  91. package/out/common/LoadingIndicator.js.map +1 -1
  92. package/out/common/PresetChips.d.ts +11 -8
  93. package/out/common/PresetChips.d.ts.map +1 -1
  94. package/out/common/PresetChips.js.map +1 -1
  95. package/out/common/confidence-tiers.d.ts +8 -7
  96. package/out/common/confidence-tiers.d.ts.map +1 -1
  97. package/out/common/confidence-tiers.js +7 -6
  98. package/out/common/confidence-tiers.js.map +1 -1
  99. package/out/common/cx.d.ts +3 -1
  100. package/out/common/cx.d.ts.map +1 -1
  101. package/out/common/cx.js +3 -1
  102. package/out/common/cx.js.map +1 -1
  103. package/out/common/text-tokens.d.ts +6 -11
  104. package/out/common/text-tokens.d.ts.map +1 -1
  105. package/out/common/text-tokens.js +6 -3
  106. package/out/common/text-tokens.js.map +1 -1
  107. package/out/common/useBuildInfo.d.ts +27 -0
  108. package/out/common/useBuildInfo.d.ts.map +1 -0
  109. package/out/common/useBuildInfo.js +32 -0
  110. package/out/common/useBuildInfo.js.map +1 -0
  111. package/out/common/useClipboard.d.ts +1 -3
  112. package/out/common/useClipboard.d.ts.map +1 -1
  113. package/out/common/useClipboard.js +2 -11
  114. package/out/common/useClipboard.js.map +1 -1
  115. package/out/common.d.ts +22 -0
  116. package/out/common.d.ts.map +1 -0
  117. package/out/common.js +15 -0
  118. package/out/common.js.map +1 -0
  119. package/out/index.d.ts +26 -16
  120. package/out/index.d.ts.map +1 -1
  121. package/out/index.js +21 -15
  122. package/out/index.js.map +1 -1
  123. package/out/map/AppIdentity.d.ts +46 -0
  124. package/out/map/AppIdentity.d.ts.map +1 -0
  125. package/out/map/AppIdentity.js +16 -0
  126. package/out/map/AppIdentity.js.map +1 -0
  127. package/out/map/CompareToggle.d.ts +8 -31
  128. package/out/map/CompareToggle.d.ts.map +1 -1
  129. package/out/map/CompareToggle.js +4 -1
  130. package/out/map/CompareToggle.js.map +1 -1
  131. package/out/map/DebugInfo.d.ts +27 -0
  132. package/out/map/DebugInfo.d.ts.map +1 -0
  133. package/out/map/DebugInfo.js +36 -0
  134. package/out/map/DebugInfo.js.map +1 -0
  135. package/out/map/Geocoder.d.ts +41 -30
  136. package/out/map/Geocoder.d.ts.map +1 -1
  137. package/out/map/Geocoder.js +23 -37
  138. package/out/map/Geocoder.js.map +1 -1
  139. package/out/map/GeocoderControls.d.ts +15 -44
  140. package/out/map/GeocoderControls.d.ts.map +1 -1
  141. package/out/map/GeocoderControls.js +250 -39
  142. package/out/map/GeocoderControls.js.map +1 -1
  143. package/out/map/GraticuleLayer.d.ts +30 -0
  144. package/out/map/GraticuleLayer.d.ts.map +1 -0
  145. package/out/map/GraticuleLayer.js +25 -0
  146. package/out/map/GraticuleLayer.js.map +1 -0
  147. package/out/map/MapCanvas.d.ts +26 -13
  148. package/out/map/MapCanvas.d.ts.map +1 -1
  149. package/out/map/MapCanvas.js +5 -2
  150. package/out/map/MapCanvas.js.map +1 -1
  151. package/out/map/MapChipRow.d.ts +4 -8
  152. package/out/map/MapChipRow.d.ts.map +1 -1
  153. package/out/map/MapChipRow.js.map +1 -1
  154. package/out/map/MapCompass.d.ts +14 -21
  155. package/out/map/MapCompass.d.ts.map +1 -1
  156. package/out/map/MapCompass.js +5 -1
  157. package/out/map/MapCompass.js.map +1 -1
  158. package/out/map/MapControlStack.d.ts +11 -10
  159. package/out/map/MapControlStack.d.ts.map +1 -1
  160. package/out/map/MapControlStack.js +4 -1
  161. package/out/map/MapControlStack.js.map +1 -1
  162. package/out/map/MapFooter.d.ts +5 -16
  163. package/out/map/MapFooter.d.ts.map +1 -1
  164. package/out/map/MapFooter.js +0 -14
  165. package/out/map/MapFooter.js.map +1 -1
  166. package/out/map/MapProgressBar.d.ts +10 -13
  167. package/out/map/MapProgressBar.d.ts.map +1 -1
  168. package/out/map/MapProgressBar.js.map +1 -1
  169. package/out/map/MapSearchBar.d.ts +16 -17
  170. package/out/map/MapSearchBar.d.ts.map +1 -1
  171. package/out/map/MapSearchBar.js +6 -0
  172. package/out/map/MapSearchBar.js.map +1 -1
  173. package/out/map/MapSheet.d.ts +15 -12
  174. package/out/map/MapSheet.d.ts.map +1 -1
  175. package/out/map/MapSheet.js +8 -12
  176. package/out/map/MapSheet.js.map +1 -1
  177. package/out/map/OverlayLayers.d.ts +8 -2
  178. package/out/map/OverlayLayers.d.ts.map +1 -1
  179. package/out/map/OverlayLayers.js +3 -3
  180. package/out/map/OverlayLayers.js.map +1 -1
  181. package/out/map/PlaceAutocomplete.d.ts +12 -21
  182. package/out/map/PlaceAutocomplete.d.ts.map +1 -1
  183. package/out/map/PlaceAutocomplete.js +2 -1
  184. package/out/map/PlaceAutocomplete.js.map +1 -1
  185. package/out/map/PlaceMarker.d.ts +10 -4
  186. package/out/map/PlaceMarker.d.ts.map +1 -1
  187. package/out/map/PlaceMarker.js +3 -1
  188. package/out/map/PlaceMarker.js.map +1 -1
  189. package/out/map/ResolvedPlaceLayers.d.ts +14 -15
  190. package/out/map/ResolvedPlaceLayers.d.ts.map +1 -1
  191. package/out/map/ResolvedPlaceLayers.js +1 -1
  192. package/out/map/ResolvedPlaceLayers.js.map +1 -1
  193. package/out/map/ResultCamera.d.ts +10 -31
  194. package/out/map/ResultCamera.d.ts.map +1 -1
  195. package/out/map/ResultCamera.js +3 -28
  196. package/out/map/ResultCamera.js.map +1 -1
  197. package/out/map/ResultOverlay.d.ts +14 -16
  198. package/out/map/ResultOverlay.d.ts.map +1 -1
  199. package/out/map/ResultOverlay.js +1 -2
  200. package/out/map/ResultOverlay.js.map +1 -1
  201. package/out/map/ResultPanel.d.ts +1 -20
  202. package/out/map/ResultPanel.d.ts.map +1 -1
  203. package/out/map/ResultPanel.js.map +1 -1
  204. package/out/map/VersionPicker.d.ts +7 -19
  205. package/out/map/VersionPicker.d.ts.map +1 -1
  206. package/out/map/VersionPicker.js +5 -2
  207. package/out/map/VersionPicker.js.map +1 -1
  208. package/out/map/fake-runtime.d.ts +9 -11
  209. package/out/map/fake-runtime.d.ts.map +1 -1
  210. package/out/map/fake-runtime.js +45 -19
  211. package/out/map/fake-runtime.js.map +1 -1
  212. package/out/map/geometry.d.ts +13 -34
  213. package/out/map/geometry.d.ts.map +1 -1
  214. package/out/map/geometry.js +9 -34
  215. package/out/map/geometry.js.map +1 -1
  216. package/out/map/graticule.d.ts +17 -0
  217. package/out/map/graticule.d.ts.map +1 -0
  218. package/out/map/graticule.js +67 -0
  219. package/out/map/graticule.js.map +1 -0
  220. package/out/map/map-debug.d.ts +4 -2
  221. package/out/map/map-debug.d.ts.map +1 -1
  222. package/out/map/map-debug.js +1 -1
  223. package/out/map/map-debug.js.map +1 -1
  224. package/out/map/place-render.d.ts +25 -45
  225. package/out/map/place-render.d.ts.map +1 -1
  226. package/out/map/place-render.js +4 -39
  227. package/out/map/place-render.js.map +1 -1
  228. package/out/map/types.d.ts +57 -113
  229. package/out/map/types.d.ts.map +1 -1
  230. package/out/map/types.js +1 -10
  231. package/out/map/types.js.map +1 -1
  232. package/out/map/useCompareState.d.ts +5 -4
  233. package/out/map/useCompareState.d.ts.map +1 -1
  234. package/out/map/useCompareState.js +3 -3
  235. package/out/map/useCompareState.js.map +1 -1
  236. package/out/map/useGeocode.d.ts +5 -3
  237. package/out/map/useGeocode.d.ts.map +1 -1
  238. package/out/map/useGeocode.js +4 -4
  239. package/out/map/useGeocode.js.map +1 -1
  240. package/out/map/useMapBearing.d.ts +11 -11
  241. package/out/map/useMapBearing.d.ts.map +1 -1
  242. package/out/map/useMapBearing.js +6 -11
  243. package/out/map/useMapBearing.js.map +1 -1
  244. package/out/map/useMapLabelPick.d.ts +4 -14
  245. package/out/map/useMapLabelPick.d.ts.map +1 -1
  246. package/out/map/useMapLabelPick.js +21 -30
  247. package/out/map/useMapLabelPick.js.map +1 -1
  248. package/out/map/useMapPlaceRender.d.ts +3 -7
  249. package/out/map/useMapPlaceRender.d.ts.map +1 -1
  250. package/out/map/useMapPlaceRender.js +2 -6
  251. package/out/map/useMapPlaceRender.js.map +1 -1
  252. package/out/map/usePlaceAutocomplete.d.ts +30 -28
  253. package/out/map/usePlaceAutocomplete.d.ts.map +1 -1
  254. package/out/map/usePlaceAutocomplete.js +6 -33
  255. package/out/map/usePlaceAutocomplete.js.map +1 -1
  256. package/out/map.d.ts +67 -0
  257. package/out/map.d.ts.map +1 -0
  258. package/out/map.js +45 -0
  259. package/out/map.js.map +1 -0
  260. package/out/pipeline/CandidatePicker.d.ts +12 -2
  261. package/out/pipeline/CandidatePicker.d.ts.map +1 -1
  262. package/out/pipeline/CandidatePicker.js +1 -1
  263. package/out/pipeline/CandidatePicker.js.map +1 -1
  264. package/out/pipeline/ConfidenceCell.d.ts +2 -2
  265. package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
  266. package/out/pipeline/ConfidenceCell.js +1 -1
  267. package/out/pipeline/FailureDiagnostic.d.ts +8 -2
  268. package/out/pipeline/FailureDiagnostic.d.ts.map +1 -1
  269. package/out/pipeline/FailureDiagnostic.js +3 -0
  270. package/out/pipeline/FailureDiagnostic.js.map +1 -1
  271. package/out/pipeline/PipelineExplorer.d.ts +6 -2
  272. package/out/pipeline/PipelineExplorer.d.ts.map +1 -1
  273. package/out/pipeline/PipelineExplorer.js +1 -1
  274. package/out/pipeline/PipelineExplorer.js.map +1 -1
  275. package/out/pipeline/QueryForm.d.ts +5 -2
  276. package/out/pipeline/QueryForm.d.ts.map +1 -1
  277. package/out/pipeline/QueryForm.js.map +1 -1
  278. package/out/pipeline/ResolvedPlace.d.ts +1 -1
  279. package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
  280. package/out/pipeline/SpanHighlight.d.ts +4 -3
  281. package/out/pipeline/SpanHighlight.d.ts.map +1 -1
  282. package/out/pipeline/SpanHighlight.js +3 -2
  283. package/out/pipeline/SpanHighlight.js.map +1 -1
  284. package/out/pipeline/TimingPanel.d.ts +1 -1
  285. package/out/pipeline/TreeView.d.ts +1 -1
  286. package/out/pipeline/TreeView.js.map +1 -1
  287. package/out/pipeline/copy.d.ts +1 -1
  288. package/out/pipeline/copy.d.ts.map +1 -1
  289. package/out/pipeline/copy.js +4 -3
  290. package/out/pipeline/copy.js.map +1 -1
  291. package/out/pipeline/presets.d.ts +5 -4
  292. package/out/pipeline/presets.d.ts.map +1 -1
  293. package/out/pipeline/presets.js +15 -13
  294. package/out/pipeline/presets.js.map +1 -1
  295. package/out/pipeline/types.d.ts +20 -17
  296. package/out/pipeline/types.d.ts.map +1 -1
  297. package/out/pipeline/types.js +2 -4
  298. package/out/pipeline/types.js.map +1 -1
  299. package/out/pipeline/useParsePipeline.d.ts +14 -9
  300. package/out/pipeline/useParsePipeline.d.ts.map +1 -1
  301. package/out/pipeline/useParsePipeline.js +7 -8
  302. package/out/pipeline/useParsePipeline.js.map +1 -1
  303. package/out/pipeline.d.ts +33 -0
  304. package/out/pipeline.d.ts.map +1 -0
  305. package/out/pipeline.js +21 -0
  306. package/out/pipeline.js.map +1 -0
  307. package/out/poi/AbstainPanel.d.ts +1 -1
  308. package/out/poi/LiveResultsBlock.d.ts +2 -1
  309. package/out/poi/LiveResultsBlock.d.ts.map +1 -1
  310. package/out/poi/LiveResultsBlock.js.map +1 -1
  311. package/out/poi/POIExplorer.d.ts +22 -12
  312. package/out/poi/POIExplorer.d.ts.map +1 -1
  313. package/out/poi/POIExplorer.js +11 -10
  314. package/out/poi/POIExplorer.js.map +1 -1
  315. package/out/poi/QueryInput.d.ts +1 -1
  316. package/out/poi/SubjectPanel.d.ts +2 -2
  317. package/out/poi/SubjectPanel.d.ts.map +1 -1
  318. package/out/poi/SubjectPanel.js +2 -1
  319. package/out/poi/SubjectPanel.js.map +1 -1
  320. package/out/poi/runtime.d.ts +5 -14
  321. package/out/poi/runtime.d.ts.map +1 -1
  322. package/out/poi/runtime.js +14 -16
  323. package/out/poi/runtime.js.map +1 -1
  324. package/out/poi/types.d.ts +53 -45
  325. package/out/poi/types.d.ts.map +1 -1
  326. package/out/poi/types.js +2 -4
  327. package/out/poi/types.js.map +1 -1
  328. package/out/poi/usePOISearch.d.ts +30 -17
  329. package/out/poi/usePOISearch.d.ts.map +1 -1
  330. package/out/poi/usePOISearch.js +48 -64
  331. package/out/poi/usePOISearch.js.map +1 -1
  332. package/out/poi.d.ts +23 -0
  333. package/out/poi.d.ts.map +1 -0
  334. package/out/poi.js +15 -0
  335. package/out/poi.js.map +1 -0
  336. package/out/runtime/useReleaseRuntime.d.ts +63 -74
  337. package/out/runtime/useReleaseRuntime.d.ts.map +1 -1
  338. package/out/runtime/useReleaseRuntime.js +31 -32
  339. package/out/runtime/useReleaseRuntime.js.map +1 -1
  340. package/out/{runtime/index.d.ts → runtime.d.ts} +1 -1
  341. package/out/runtime.d.ts.map +1 -0
  342. package/out/{runtime/index.js → runtime.js} +1 -1
  343. package/out/runtime.js.map +1 -0
  344. package/out/search/SearchModal.d.ts +40 -0
  345. package/out/search/SearchModal.d.ts.map +1 -0
  346. package/out/search/SearchModal.js +255 -0
  347. package/out/search/SearchModal.js.map +1 -0
  348. package/out/search/types.d.ts +65 -0
  349. package/out/search/types.d.ts.map +1 -0
  350. package/out/search/types.js +13 -0
  351. package/out/search/types.js.map +1 -0
  352. package/out/search.d.ts +11 -0
  353. package/out/search.d.ts.map +1 -0
  354. package/out/search.js +9 -0
  355. package/out/search.js.map +1 -0
  356. package/package.json +73 -165
  357. package/styles.css +482 -266
  358. package/tokens/index.css +24 -6
  359. package/tokens/tokens.json +114 -6
  360. package/lib/common/index.ts +0 -22
  361. package/lib/map/BackendControl.tsx +0 -51
  362. package/lib/map/index.ts +0 -95
  363. package/lib/pipeline/index.ts +0 -36
  364. package/lib/poi/index.ts +0 -39
  365. package/out/common/index.d.ts +0 -22
  366. package/out/common/index.d.ts.map +0 -1
  367. package/out/common/index.js +0 -15
  368. package/out/common/index.js.map +0 -1
  369. package/out/map/BackendControl.d.ts +0 -32
  370. package/out/map/BackendControl.d.ts.map +0 -1
  371. package/out/map/BackendControl.js +0 -8
  372. package/out/map/BackendControl.js.map +0 -1
  373. package/out/map/index.d.ts +0 -69
  374. package/out/map/index.d.ts.map +0 -1
  375. package/out/map/index.js +0 -46
  376. package/out/map/index.js.map +0 -1
  377. package/out/pipeline/index.d.ts +0 -33
  378. package/out/pipeline/index.d.ts.map +0 -1
  379. package/out/pipeline/index.js +0 -21
  380. package/out/pipeline/index.js.map +0 -1
  381. package/out/poi/index.d.ts +0 -23
  382. package/out/poi/index.d.ts.map +0 -1
  383. package/out/poi/index.js +0 -15
  384. package/out/poi/index.js.map +0 -1
  385. package/out/runtime/index.d.ts.map +0 -1
  386. package/out/runtime/index.js.map +0 -1
  387. package/styleframe.config.ts +0 -329
  388. package/vitest.node.config.ts +0 -20
  389. /package/lib/{runtime/index.ts → runtime.ts} +0 -0
package/styles.css CHANGED
@@ -1,7 +1,7 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
  * @mailwoman/react — component styles.
3
3
  *
4
- * Plain, `mw-`-prefixed classes. Every colour, family and radius here names a
4
+ * Plain, `mw-`-prefixed classes. Every color, family and radius here names a
5
5
  * SEMANTIC token from `tokens.css`, which this file requires a host to load —
6
6
  * `@mailwoman/react/tokens.css`, and `fonts.css` beside it for the brand face.
7
7
  * There are no inline fallbacks, on purpose: a fallback is what let eight
@@ -29,6 +29,9 @@
29
29
  */
30
30
  @import url("./tokens/index.css") layer(tokens);
31
31
 
32
+ /* The docs search modal keeps its rules beside its component. */
33
+ @import url("./lib/search/search.css") layer(components);
34
+
32
35
  @layer reset {
33
36
  /*
34
37
  * Every box is measured by its border. The default is `content-box`, where `width`, `height` and `max-height`
@@ -86,7 +89,7 @@
86
89
  }
87
90
 
88
91
  /*
89
- * A default face for a host that sets none. Wrapped in `:where()` so it carries ZERO specificity: Docusaurus's own
92
+ * A default face for a host that sets none. Wrapped in `:where()` so it carries zero specificity: Docusaurus's own
90
93
  * `body` rule wins on the docs site and keeps that page's typography, while Storybook and a bare React host — which
91
94
  * declare nothing — stop falling back to the user agent's serif.
92
95
  */
@@ -101,7 +104,7 @@
101
104
  @layer components {
102
105
  .mw-poi-explorer,
103
106
  .mw-pipeline-explorer {
104
- max-width: 720px;
107
+ max-width: 45rem;
105
108
  font-size: 0.95rem;
106
109
  }
107
110
 
@@ -110,7 +113,7 @@
110
113
  .mw-field {
111
114
  display: flex;
112
115
  flex-direction: column;
113
- gap: 0.5rem;
116
+ gap: var(--space-3);
114
117
  }
115
118
 
116
119
  .mw-field label {
@@ -119,10 +122,10 @@
119
122
  }
120
123
 
121
124
  .mw-field input {
122
- padding: 0.5rem 0.75rem;
125
+ padding: var(--space-3) var(--space-4);
123
126
  font: inherit;
124
127
  border: 1px solid var(--control-border);
125
- border-radius: 6px;
128
+ border-radius: var(--radius-control);
126
129
  background: var(--color-background-raised);
127
130
  color: var(--color-text-primary);
128
131
  }
@@ -132,16 +135,16 @@
132
135
  }
133
136
 
134
137
  .mw-field button[type="submit"] {
135
- padding: 0.5rem 0.75rem;
138
+ padding: var(--space-3) var(--space-4);
136
139
  background: var(--color-accent);
137
140
  color: var(--color-accent-contrast);
138
141
  border: 0;
139
- border-radius: 6px;
142
+ border-radius: var(--radius-control);
140
143
  font-weight: 600;
141
144
  cursor: pointer;
142
145
  display: inline-flex;
143
146
  align-items: center;
144
- gap: 0.4rem;
147
+ gap: var(--space-2);
145
148
  align-self: flex-start;
146
149
  }
147
150
 
@@ -161,14 +164,14 @@
161
164
  * reachable by keyboard.
162
165
  */
163
166
  .mw-presets {
164
- margin-top: 0.75rem;
167
+ margin-top: var(--space-4);
165
168
  display: flex;
166
169
  flex-wrap: nowrap;
167
170
  overflow-x: auto;
168
171
  scrollbar-width: none;
169
- gap: 0.4rem;
172
+ gap: var(--space-2);
170
173
  align-items: baseline;
171
- padding-bottom: 0.15rem;
174
+ padding-bottom: var(--space-0);
172
175
  }
173
176
 
174
177
  .mw-presets::-webkit-scrollbar {
@@ -186,16 +189,16 @@
186
189
  .mw-presets__label {
187
190
  font-size: 0.85rem;
188
191
  color: var(--color-text-secondary);
189
- margin-right: 0.25rem;
192
+ margin-right: var(--space-1);
190
193
  }
191
194
 
192
195
  .mw-chip {
193
196
  font-size: 0.8rem;
194
- padding: 0.25rem 0.55rem;
197
+ padding: var(--space-1) var(--space-3);
195
198
  background: var(--control-background);
196
199
  color: var(--color-text-primary);
197
200
  border: 1px solid var(--control-border);
198
- border-radius: 4px;
201
+ border-radius: var(--radius-tight);
199
202
  font-weight: 500;
200
203
  cursor: pointer;
201
204
  font-family: inherit;
@@ -217,11 +220,11 @@
217
220
 
218
221
  .mw-btn {
219
222
  font-size: 0.8rem;
220
- padding: 0.25rem 0.55rem;
223
+ padding: var(--space-1) var(--space-3);
221
224
  background: var(--control-background);
222
225
  color: var(--color-text-primary);
223
226
  border: 1px solid var(--control-border);
224
- border-radius: 4px;
227
+ border-radius: var(--radius-tight);
225
228
  cursor: pointer;
226
229
  font-family: inherit;
227
230
  }
@@ -240,14 +243,14 @@
240
243
  /* #region Result panel + errors */
241
244
 
242
245
  .mw-result {
243
- margin-top: 1.5rem;
246
+ margin-top: var(--space-6);
244
247
  }
245
248
 
246
249
  .mw-result__header {
247
250
  display: flex;
248
251
  justify-content: space-between;
249
252
  align-items: center;
250
- margin-bottom: 0.75rem;
253
+ margin-bottom: var(--space-4);
251
254
  }
252
255
 
253
256
  .mw-result__header h2 {
@@ -259,7 +262,7 @@
259
262
  display: flex;
260
263
  justify-content: space-between;
261
264
  align-items: center;
262
- margin-bottom: 0.4rem;
265
+ margin-bottom: var(--space-2);
263
266
  }
264
267
 
265
268
  .mw-panel__header h3 {
@@ -283,7 +286,7 @@
283
286
  /* #region KindBadge */
284
287
 
285
288
  .mw-kind {
286
- margin-bottom: 0.5rem;
289
+ margin-bottom: var(--space-3);
287
290
  font-size: 0.9rem;
288
291
  }
289
292
 
@@ -297,7 +300,7 @@
297
300
  }
298
301
 
299
302
  .mw-kind__alternatives {
300
- margin: 0.25rem 0 0 1rem;
303
+ margin: var(--space-1) 0 0 var(--space-5);
301
304
  padding: 0;
302
305
  list-style: disc;
303
306
  }
@@ -309,14 +312,14 @@
309
312
  .mw-subject__row {
310
313
  display: flex;
311
314
  align-items: center;
312
- gap: 0.5rem;
313
- margin-bottom: 0.5rem;
315
+ gap: var(--space-3);
316
+ margin-bottom: var(--space-3);
314
317
  }
315
318
 
316
319
  .mw-subject__chip {
317
320
  display: inline-block;
318
- padding: 0.2rem 0.6rem;
319
- border-radius: 999px;
321
+ padding: var(--space-1) var(--space-3);
322
+ border-radius: var(--radius-pill);
320
323
  background: var(--color-accent-background);
321
324
  color: var(--color-accent);
322
325
  font-weight: 600;
@@ -325,8 +328,8 @@
325
328
 
326
329
  .mw-subject__badge {
327
330
  display: inline-block;
328
- padding: 0.2rem 0.5rem;
329
- border-radius: 999px;
331
+ padding: var(--space-1) var(--space-3);
332
+ border-radius: var(--radius-pill);
330
333
  background: var(--color-state-warning-background);
331
334
  color: var(--color-state-warning);
332
335
  font-size: 0.75rem;
@@ -342,8 +345,8 @@
342
345
 
343
346
  .mw-subject__qid {
344
347
  display: inline-block;
345
- padding: 0.2rem 0.5rem;
346
- border-radius: 999px;
348
+ padding: var(--space-1) var(--space-3);
349
+ border-radius: var(--radius-pill);
347
350
  background: var(--color-background-sunken);
348
351
  color: var(--color-text-primary);
349
352
  font-family: var(--font-family-code);
@@ -357,7 +360,7 @@
357
360
  }
358
361
 
359
362
  .mw-subject__note {
360
- margin: 0 0 0.75rem;
363
+ margin: 0 0 var(--space-4);
361
364
  font-size: 0.85rem;
362
365
  opacity: 0.8;
363
366
  }
@@ -365,8 +368,8 @@
365
368
  .mw-subject__detail {
366
369
  display: grid;
367
370
  grid-template-columns: auto 1fr;
368
- gap: 0.25rem 0.75rem;
369
- margin: 0 0 0.75rem;
371
+ gap: var(--space-1) var(--space-4);
372
+ margin: 0 0 var(--space-4);
370
373
  font-size: 0.9rem;
371
374
  }
372
375
 
@@ -384,13 +387,13 @@
384
387
  /* #region OverpassQL block */
385
388
 
386
389
  .mw-overpass {
387
- margin-top: 0.75rem;
390
+ margin-top: var(--space-4);
388
391
  }
389
392
 
390
393
  .mw-overpass__code {
391
394
  margin: 0;
392
- padding: 0.75rem;
393
- border-radius: 6px;
395
+ padding: var(--space-4);
396
+ border-radius: var(--radius-control);
394
397
  background: var(--control-background);
395
398
  font-family: var(--font-family-code);
396
399
  font-size: 0.85rem;
@@ -403,11 +406,11 @@
403
406
  /* #region Live results */
404
407
 
405
408
  .mw-live {
406
- margin-top: 1rem;
409
+ margin-top: var(--space-5);
407
410
  }
408
411
 
409
412
  .mw-live__caption {
410
- margin: 0 0 0.4rem;
413
+ margin: 0 0 var(--space-2);
411
414
  font-size: 0.85rem;
412
415
  color: var(--color-text-secondary);
413
416
  }
@@ -418,16 +421,16 @@
418
421
  padding: 0;
419
422
  display: flex;
420
423
  flex-direction: column;
421
- gap: 0.35rem;
424
+ gap: var(--space-2);
422
425
  }
423
426
 
424
427
  .mw-live__results li {
425
428
  display: flex;
426
429
  justify-content: space-between;
427
430
  align-items: baseline;
428
- gap: 0.75rem;
429
- padding: 0.4rem 0.6rem;
430
- border-radius: 6px;
431
+ gap: var(--space-4);
432
+ padding: var(--space-2) var(--space-3);
433
+ border-radius: var(--radius-control);
431
434
  background: var(--control-background);
432
435
  font-size: 0.9rem;
433
436
  }
@@ -449,13 +452,13 @@
449
452
  .mw-components {
450
453
  width: 100%;
451
454
  border-collapse: collapse;
452
- margin: 0.75rem 0;
455
+ margin: var(--space-4) 0;
453
456
  font-size: 0.9rem;
454
457
  }
455
458
 
456
459
  .mw-components th,
457
460
  .mw-components td {
458
- padding: 0.4rem 0.6rem;
461
+ padding: var(--space-2) var(--space-3);
459
462
  text-align: left;
460
463
  border-bottom: 1px solid var(--color-separator);
461
464
  }
@@ -478,27 +481,27 @@
478
481
  .mw-conf {
479
482
  display: flex;
480
483
  align-items: center;
481
- gap: 0.35rem;
482
- min-width: 80px;
484
+ gap: var(--space-2);
485
+ min-width: 5rem;
483
486
  }
484
487
 
485
488
  .mw-conf__bar {
486
- height: 6px;
487
- border-radius: 3px;
488
- min-width: 4px;
489
+ height: 0.375rem;
490
+ border-radius: var(--radius-pill);
491
+ min-width: 0.25rem;
489
492
  transition: width 0.2s ease;
490
493
  }
491
494
 
492
495
  .mw-conf__bar--high {
493
- background: #22c55e;
496
+ background: var(--color-confidence-high);
494
497
  }
495
498
 
496
499
  .mw-conf__bar--mid {
497
- background: #f59e0b;
500
+ background: var(--color-confidence-mid);
498
501
  }
499
502
 
500
503
  .mw-conf__bar--low {
501
- background: #ef4444;
504
+ background: var(--color-confidence-low);
502
505
  }
503
506
 
504
507
  .mw-conf__value {
@@ -511,22 +514,22 @@
511
514
  /* #region Resolved place */
512
515
 
513
516
  .mw-resolved {
514
- margin-top: 1rem;
515
- padding: 0.75rem;
517
+ margin-top: var(--space-5);
518
+ padding: var(--space-4);
516
519
  border: 1px solid var(--color-separator);
517
- border-radius: 6px;
520
+ border-radius: var(--radius-control);
518
521
  background: var(--color-background-canvas);
519
522
  }
520
523
 
521
524
  .mw-resolved h2 {
522
- margin: 0 0 0.5rem;
525
+ margin: 0 0 var(--space-3);
523
526
  font-size: 1rem;
524
527
  }
525
528
 
526
529
  .mw-resolved dl {
527
530
  display: grid;
528
531
  grid-template-columns: auto 1fr;
529
- gap: 0.25rem 0.75rem;
532
+ gap: var(--space-1) var(--space-4);
530
533
  margin: 0;
531
534
  }
532
535
 
@@ -540,9 +543,9 @@
540
543
  }
541
544
 
542
545
  .mw-resolved__dual {
543
- margin: 0.5rem 0 0;
544
- padding: 0.4rem 0.6rem;
545
- border-radius: 6px;
546
+ margin: var(--space-3) 0 0;
547
+ padding: var(--space-2) var(--space-3);
548
+ border-radius: var(--radius-control);
546
549
  background: var(--color-state-info-background);
547
550
  font-size: 0.9rem;
548
551
  }
@@ -552,12 +555,12 @@
552
555
  /* #region Candidate picker */
553
556
 
554
557
  .mw-candidates {
555
- margin-top: 1rem;
558
+ margin-top: var(--space-5);
556
559
  }
557
560
 
558
561
  .mw-candidates h2 {
559
562
  font-size: 1rem;
560
- margin: 0 0 0.5rem;
563
+ margin: 0 0 var(--space-3);
561
564
  }
562
565
 
563
566
  .mw-candidates__list {
@@ -566,16 +569,16 @@
566
569
  padding: 0;
567
570
  display: flex;
568
571
  flex-direction: column;
569
- gap: 0.35rem;
572
+ gap: var(--space-2);
570
573
  }
571
574
 
572
575
  .mw-candidates__btn {
573
576
  display: flex;
574
577
  align-items: baseline;
575
- gap: 0.6rem;
578
+ gap: var(--space-3);
576
579
  width: 100%;
577
580
  text-align: left;
578
- padding: 0.4rem 0.6rem;
581
+ padding: var(--space-2) var(--space-3);
579
582
  border: 1px solid var(--color-separator);
580
583
  border-radius: var(--radius-control);
581
584
  background: var(--control-background);
@@ -625,8 +628,8 @@
625
628
  flex-direction: column;
626
629
  align-items: center;
627
630
  justify-content: center;
628
- gap: 0.75rem;
629
- padding: 1.5rem;
631
+ gap: var(--space-4);
632
+ padding: var(--space-6);
630
633
  }
631
634
 
632
635
  .mw-loading__label {
@@ -639,14 +642,14 @@
639
642
  .mw-pulse {
640
643
  display: flex;
641
644
  flex-direction: column;
642
- gap: 0.5rem;
645
+ gap: var(--space-3);
643
646
  width: 100%;
644
- max-width: 320px;
647
+ max-width: 20rem;
645
648
  }
646
649
 
647
650
  .mw-pulse__bar {
648
651
  height: 0.75rem;
649
- border-radius: 4px;
652
+ border-radius: var(--radius-pill);
650
653
  background: var(--color-background-sunken);
651
654
  animation: mw-pulse-fade 1.4s ease-in-out infinite;
652
655
  }
@@ -713,9 +716,9 @@
713
716
  .mw-staged {
714
717
  display: flex;
715
718
  flex-direction: column;
716
- gap: 0.5rem;
719
+ gap: var(--space-3);
717
720
  width: 100%;
718
- max-width: 360px;
721
+ max-width: 22.5rem;
719
722
  list-style: none;
720
723
  margin: 0;
721
724
  padding: 0;
@@ -724,9 +727,9 @@
724
727
  .mw-staged__step {
725
728
  display: flex;
726
729
  align-items: center;
727
- gap: 0.6rem;
728
- padding: 0.4rem 0.6rem;
729
- border-radius: 4px;
730
+ gap: var(--space-3);
731
+ padding: var(--space-2) var(--space-3);
732
+ border-radius: var(--radius-tight);
730
733
  font-size: 0.85rem;
731
734
  transition:
732
735
  background 0.3s,
@@ -801,12 +804,12 @@
801
804
  /*
802
805
  * The <MapCanvas> wrapper. Sizing is the host's call (pass `style`/`className`), but a min-height keeps
803
806
  * the map from collapsing to zero when a consumer forgets. The inner <Map> fills 100% of this box.
804
- * The host must ALSO import `maplibre-gl/dist/maplibre-gl.css` for the map's own control/canvas styles.
807
+ * The host must also import `maplibre-gl/dist/maplibre-gl.css` for the map's own control/canvas styles.
805
808
  */
806
809
  .mw-demo-map {
807
810
  position: relative;
808
811
  width: 100%;
809
- min-height: 320px;
812
+ min-height: 20rem;
810
813
  overflow: hidden;
811
814
  }
812
815
 
@@ -819,7 +822,7 @@
819
822
  position: relative;
820
823
  width: 100%;
821
824
  height: 100%;
822
- min-height: 480px;
825
+ min-height: 30rem;
823
826
  }
824
827
 
825
828
  .mw-geocoder-demo__map {
@@ -827,38 +830,13 @@
827
830
  inset: 0;
828
831
  }
829
832
 
830
- .mw-demo-controls {
831
- position: absolute;
832
- top: 1rem;
833
- left: 1rem;
834
- z-index: 2;
835
- width: min(360px, calc(100% - 2rem));
836
- max-height: calc(100% - 2rem);
837
- overflow-y: auto;
838
- padding: 1rem;
839
- border-radius: 10px;
840
- background: color-mix(in srgb, var(--color-background-raised) 92%, transparent);
841
- box-shadow: 0 2px 16px rgba(0, 0, 0, 0.18);
842
- font-size: 0.95rem;
843
- }
844
-
845
- @media (max-width: 600px) {
846
- .mw-demo-controls {
847
- top: auto;
848
- bottom: 1rem;
849
- left: 1rem;
850
- right: 1rem;
851
- width: auto;
852
- }
853
- }
854
-
855
833
  /* #endregion */
856
834
 
857
835
  /* #region Demo control field (version / compare-version selects) */
858
836
 
859
837
  .mw-demo-control {
860
838
  display: grid;
861
- gap: 0.3rem;
839
+ gap: var(--space-1);
862
840
  width: 100%;
863
841
  }
864
842
 
@@ -871,10 +849,16 @@
871
849
 
872
850
  .mw-demo-control__select {
873
851
  width: 100%;
874
- padding: 0.4rem;
852
+ /*
853
+ * The release labels are long ("v9.1.0 — the suffix-boundary cure (model v4.4.0)") and a native select clips
854
+ * the selected option at the field's edge with no ellipsis, so the string ended mid-word and its closing
855
+ * parenthesis never rendered. The full text rides the element's `title` (see VersionPicker).
856
+ */
857
+ text-overflow: ellipsis;
858
+ padding: var(--space-2);
875
859
  font: inherit;
876
860
  border: 1px solid var(--control-border);
877
- border-radius: 6px;
861
+ border-radius: var(--radius-control);
878
862
  background: var(--color-background-raised);
879
863
  color: var(--color-text-primary);
880
864
  }
@@ -891,7 +875,7 @@
891
875
  .mw-demo-backend,
892
876
  .mw-demo-compare {
893
877
  display: grid;
894
- gap: 0.35rem;
878
+ gap: var(--space-2);
895
879
  justify-items: start;
896
880
  font-size: var(--font-size-footnote);
897
881
  }
@@ -905,32 +889,58 @@
905
889
  .mw-demo-compare__toggle {
906
890
  display: inline-flex;
907
891
  align-items: center;
908
- gap: 0.5rem;
892
+ gap: var(--space-3);
909
893
  cursor: pointer;
910
894
  }
911
895
 
912
896
  .mw-demo-compare__status {
913
- margin: 0.25rem 0 0;
897
+ margin: var(--space-1) 0 0;
914
898
  font-size: 0.8rem;
915
899
  color: var(--color-text-secondary);
916
900
  }
917
901
 
902
+ /* The debug record: label/value pairs a reporter reads off, sized to the sheet rather than the page. The value
903
+ column wraps because a user-agent string is long and truncating the one field that identifies the browser
904
+ would defeat the row. */
905
+ .mw-debug-info {
906
+ display: grid;
907
+ gap: var(--space-1);
908
+ width: 100%;
909
+ font-size: var(--font-size-caption);
910
+ }
911
+
912
+ .mw-debug-info__row {
913
+ display: grid;
914
+ grid-template-columns: minmax(6rem, auto) 1fr;
915
+ gap: var(--space-3);
916
+ align-items: baseline;
917
+ }
918
+
919
+ .mw-debug-info__label {
920
+ color: var(--color-text-tertiary);
921
+ }
922
+
923
+ .mw-debug-info__value {
924
+ overflow-wrap: anywhere;
925
+ color: var(--color-text-secondary);
926
+ }
927
+
918
928
  /* #endregion */
919
929
 
920
930
  /* #region Place autocomplete listbox (reuses .mw-chip) */
921
931
 
922
932
  .mw-demo-suggest {
923
- margin-top: 0.75rem;
933
+ margin-top: var(--space-4);
924
934
  display: flex;
925
935
  flex-wrap: wrap;
926
- gap: 0.4rem;
936
+ gap: var(--space-2);
927
937
  align-items: baseline;
928
938
  }
929
939
 
930
940
  .mw-demo-suggest__label {
931
941
  font-size: 0.85rem;
932
942
  color: var(--color-text-secondary);
933
- margin-right: 0.25rem;
943
+ margin-right: var(--space-1);
934
944
  }
935
945
 
936
946
  .mw-chip--active {
@@ -943,36 +953,36 @@
943
953
  /* #region Span ribbon (SpanHighlight) — each tagged span is a column: the text on top, tinted by tier, the tag beneath */
944
954
 
945
955
  .mw-spans {
946
- margin: 0.5rem 0 1rem 0;
956
+ margin: var(--space-3) 0 var(--space-5) 0;
947
957
  }
948
958
 
949
959
  .mw-spans__legend {
950
960
  display: flex;
951
961
  align-items: center;
952
- gap: 0.35rem;
962
+ gap: var(--space-2);
953
963
  font-size: 0.7rem;
954
964
  text-transform: uppercase;
955
965
  letter-spacing: 0.04em;
956
966
  color: var(--color-text-secondary);
957
- margin-bottom: 0.5rem;
967
+ margin-bottom: var(--space-3);
958
968
  }
959
969
 
960
970
  .mw-spans__swatch {
961
971
  display: inline-block;
962
972
  width: 0.8rem;
963
973
  height: 0.8rem;
964
- border-radius: 2px;
965
- margin-left: 0.4rem;
974
+ border-radius: var(--radius-tick);
975
+ margin-left: var(--space-2);
966
976
  }
967
977
 
968
978
  .mw-spans__track {
969
979
  display: flex;
970
980
  flex-wrap: wrap;
971
981
  align-items: flex-end;
972
- row-gap: 1.5rem;
973
- padding: 0.5rem 0.6rem;
982
+ row-gap: var(--space-6);
983
+ padding: var(--space-3) var(--space-3);
974
984
  border: 1px solid var(--color-separator);
975
- border-radius: 6px;
985
+ border-radius: var(--radius-control);
976
986
  background: var(--color-background-raised);
977
987
  font-family: var(--font-family-code);
978
988
  font-size: 0.9rem;
@@ -986,13 +996,20 @@
986
996
  }
987
997
 
988
998
  .mw-spans__text {
989
- padding: 0.05rem 0.1rem;
999
+ padding: var(--space-0) var(--space-0);
990
1000
  border-bottom: 2px solid transparent;
991
1001
  white-space: pre;
992
1002
  }
993
1003
 
1004
+ /*
1005
+ * Each segment is a column sized to max(text, tag), so a long tag under a short span widens the segment — which is
1006
+ * why `350 5th Ave` renders spread out. What it did not have was any space BETWEEN neighboring tags, so the row
1007
+ * read as one run-on word: `house_numberstreetstreet_suffix locality regionpostcode`. The padding separates the
1008
+ * tags and, because the segment sizes to the tag, spreads the text above them to match.
1009
+ */
994
1010
  .mw-spans__tag {
995
- margin-top: 0.15rem;
1011
+ margin-top: var(--space-0);
1012
+ padding-inline: var(--space-1);
996
1013
  font-size: 0.6rem;
997
1014
  line-height: 1;
998
1015
  text-align: center;
@@ -1008,40 +1025,44 @@
1008
1025
  color: var(--color-text-tertiary);
1009
1026
  }
1010
1027
 
1011
- /* The tier tints match .mw-conf__bar--high/--mid/--low. */
1028
+ /*
1029
+ * The tier tints match `.mw-conf__bar--high/--mid/--low` — which the sentence that stood here also claimed, while
1030
+ * the two painted different greens. Both now read the confidence tokens, so the claim is carried by the values
1031
+ * rather than by the comment.
1032
+ */
1012
1033
  .mw-spans__seg--high .mw-spans__text {
1013
- background: rgba(26, 168, 77, 0.18);
1014
- border-bottom-color: #1aa84d;
1034
+ background: var(--color-confidence-high-tint);
1035
+ border-bottom-color: var(--color-confidence-high);
1015
1036
  }
1016
1037
 
1017
1038
  .mw-spans__seg--mid .mw-spans__text {
1018
- background: rgba(230, 168, 0, 0.18);
1019
- border-bottom-color: #e6a800;
1039
+ background: var(--color-confidence-mid-tint);
1040
+ border-bottom-color: var(--color-confidence-mid);
1020
1041
  }
1021
1042
 
1022
1043
  .mw-spans__seg--low .mw-spans__text {
1023
- background: rgba(216, 80, 74, 0.18);
1024
- border-bottom-color: #d8504a;
1044
+ background: var(--color-confidence-low-tint);
1045
+ border-bottom-color: var(--color-confidence-low);
1025
1046
  }
1026
1047
 
1027
1048
  .mw-spans__swatch--high {
1028
- background: #1aa84d;
1049
+ background: var(--color-confidence-high);
1029
1050
  }
1030
1051
 
1031
1052
  .mw-spans__swatch--mid {
1032
- background: #e6a800;
1053
+ background: var(--color-confidence-mid);
1033
1054
  }
1034
1055
 
1035
1056
  .mw-spans__swatch--low {
1036
- background: #d8504a;
1057
+ background: var(--color-confidence-low);
1037
1058
  }
1038
1059
 
1039
1060
  /* #endregion */
1040
1061
 
1041
- /* #region Stage timing (TimingPanel) — a stacked bar by wall-clock, stage hues, never the confidence colours */
1062
+ /* #region Stage timing (TimingPanel) — a stacked bar by wall-clock, stage hues, never the confidence colors */
1042
1063
 
1043
1064
  .mw-timing {
1044
- margin: 1rem 0;
1065
+ margin: var(--space-5) 0;
1045
1066
  font-size: 0.8rem;
1046
1067
  }
1047
1068
 
@@ -1052,7 +1073,7 @@
1052
1073
  text-transform: uppercase;
1053
1074
  letter-spacing: 0.05em;
1054
1075
  color: var(--color-text-secondary);
1055
- margin-bottom: 0.35rem;
1076
+ margin-bottom: var(--space-2);
1056
1077
  }
1057
1078
 
1058
1079
  .mw-timing__total {
@@ -1066,7 +1087,7 @@
1066
1087
  display: flex;
1067
1088
  width: 100%;
1068
1089
  height: 0.7rem;
1069
- border-radius: 4px;
1090
+ border-radius: var(--radius-tight);
1070
1091
  overflow: hidden;
1071
1092
  background: var(--color-background-sunken);
1072
1093
  }
@@ -1078,15 +1099,15 @@
1078
1099
  .mw-timing__legend {
1079
1100
  display: flex;
1080
1101
  flex-wrap: wrap;
1081
- gap: 0.25rem 1rem;
1082
- margin-top: 0.4rem;
1102
+ gap: var(--space-1) var(--space-5);
1103
+ margin-top: var(--space-2);
1083
1104
  color: var(--color-text-secondary);
1084
1105
  }
1085
1106
 
1086
1107
  .mw-timing__item {
1087
1108
  display: inline-flex;
1088
1109
  align-items: center;
1089
- gap: 0.35rem;
1110
+ gap: var(--space-2);
1090
1111
  }
1091
1112
 
1092
1113
  .mw-timing__ms {
@@ -1098,19 +1119,19 @@
1098
1119
  display: inline-block;
1099
1120
  width: 0.7rem;
1100
1121
  height: 0.7rem;
1101
- border-radius: 2px;
1122
+ border-radius: var(--radius-tick);
1102
1123
  }
1103
1124
 
1104
1125
  .mw-timing__seg--shape {
1105
- background: #3578e5;
1126
+ background: var(--color-stage-shape);
1106
1127
  }
1107
1128
 
1108
1129
  .mw-timing__seg--classify {
1109
- background: #8b5cf6;
1130
+ background: var(--color-stage-classify);
1110
1131
  }
1111
1132
 
1112
1133
  .mw-timing__seg--resolve {
1113
- background: #14b8a6;
1134
+ background: var(--color-stage-resolve);
1114
1135
  }
1115
1136
 
1116
1137
  /* #endregion */
@@ -1118,36 +1139,36 @@
1118
1139
  /* #region Containment tree (TreeView) — nested lists with a guide rail per level */
1119
1140
 
1120
1141
  .mw-tree {
1121
- margin: 0.5rem 0 0 0;
1142
+ margin: var(--space-3) 0 0 0;
1122
1143
  }
1123
1144
 
1124
1145
  .mw-tree__children {
1125
1146
  list-style: none;
1126
1147
  margin: 0;
1127
- padding-left: 1.1rem;
1148
+ padding-left: var(--space-5);
1128
1149
  }
1129
1150
 
1130
1151
  /* Nested levels get a guide rail; the outermost list sits flush. */
1131
1152
  .mw-tree__children .mw-tree__children {
1132
1153
  border-left: 1px solid var(--control-border);
1133
- margin-left: 0.3rem;
1154
+ margin-left: var(--space-1);
1134
1155
  }
1135
1156
 
1136
1157
  .mw-tree__node {
1137
- margin: 0.15rem 0;
1158
+ margin: var(--space-0) 0;
1138
1159
  }
1139
1160
 
1140
1161
  .mw-tree__row {
1141
1162
  display: inline-flex;
1142
1163
  align-items: baseline;
1143
- gap: 0.5rem;
1164
+ gap: var(--space-3);
1144
1165
  font-size: 0.85rem;
1145
1166
  }
1146
1167
 
1147
1168
  .mw-tree__tag {
1148
1169
  font-weight: 600;
1149
- padding: 0 0.3rem;
1150
- border-radius: 3px;
1170
+ padding: 0 var(--space-1);
1171
+ border-radius: var(--radius-tick);
1151
1172
  border-bottom: 2px solid transparent;
1152
1173
  }
1153
1174
 
@@ -1162,18 +1183,18 @@
1162
1183
  }
1163
1184
 
1164
1185
  .mw-tree__tag--high {
1165
- background: rgba(26, 168, 77, 0.18);
1166
- border-bottom-color: #1aa84d;
1186
+ background: var(--color-confidence-high-tint);
1187
+ border-bottom-color: var(--color-confidence-high);
1167
1188
  }
1168
1189
 
1169
1190
  .mw-tree__tag--mid {
1170
- background: rgba(230, 168, 0, 0.18);
1171
- border-bottom-color: #e6a800;
1191
+ background: var(--color-confidence-mid-tint);
1192
+ border-bottom-color: var(--color-confidence-mid);
1172
1193
  }
1173
1194
 
1174
1195
  .mw-tree__tag--low {
1175
- background: rgba(216, 80, 74, 0.18);
1176
- border-bottom-color: #d8504a;
1196
+ background: var(--color-confidence-low-tint);
1197
+ border-bottom-color: var(--color-confidence-low);
1177
1198
  }
1178
1199
 
1179
1200
  /* #endregion */
@@ -1181,16 +1202,16 @@
1181
1202
  /* #region No-hit diagnostic (FailureDiagnostic) — a structured panel, tinted informational rather than red */
1182
1203
 
1183
1204
  .mw-failure {
1184
- margin-top: 1rem;
1185
- padding: 0.75rem 1rem;
1205
+ margin-top: var(--space-5);
1206
+ padding: var(--space-4) var(--space-5);
1186
1207
  background: var(--color-state-warning-background);
1187
1208
  border-left: 3px solid var(--color-state-warning);
1188
- border-radius: 4px;
1209
+ border-radius: var(--radius-tight);
1189
1210
  }
1190
1211
 
1191
1212
  .mw-failure h2 {
1192
1213
  font-size: 1rem;
1193
- margin: 0 0 0.5rem 0;
1214
+ margin: 0 0 var(--space-3) 0;
1194
1215
  text-transform: uppercase;
1195
1216
  letter-spacing: 0.05em;
1196
1217
  color: var(--color-state-warning);
@@ -1198,13 +1219,13 @@
1198
1219
 
1199
1220
  .mw-failure ul {
1200
1221
  margin: 0;
1201
- padding-left: 1.25rem;
1222
+ padding-left: var(--space-5);
1202
1223
  font-size: 0.875rem;
1203
1224
  color: var(--color-text-primary);
1204
1225
  }
1205
1226
 
1206
1227
  .mw-failure li + li {
1207
- margin-top: 0.35rem;
1228
+ margin-top: var(--space-2);
1208
1229
  }
1209
1230
 
1210
1231
  /* #endregion */
@@ -1212,9 +1233,9 @@
1212
1233
  /* #region About box (About) — the collapsible product explainer */
1213
1234
 
1214
1235
  .mw-about {
1215
- margin-bottom: 1rem;
1236
+ margin-bottom: var(--space-5);
1216
1237
  border: 1px solid var(--control-border);
1217
- border-radius: 8px;
1238
+ border-radius: var(--radius-control);
1218
1239
  background: var(--color-background-raised);
1219
1240
  font-size: 0.9rem;
1220
1241
  }
@@ -1224,14 +1245,14 @@
1224
1245
  }
1225
1246
 
1226
1247
  .mw-about__summary {
1227
- padding: 0.65rem 0.75rem;
1248
+ padding: var(--space-4) var(--space-4);
1228
1249
  cursor: pointer;
1229
1250
  user-select: none;
1230
1251
  font-weight: 600;
1231
1252
  display: flex;
1232
1253
  align-items: center;
1233
- gap: 0.35rem;
1234
- border-radius: 8px;
1254
+ gap: var(--space-2);
1255
+ border-radius: var(--radius-control);
1235
1256
  }
1236
1257
 
1237
1258
  .mw-about__summary:hover {
@@ -1244,11 +1265,11 @@
1244
1265
  }
1245
1266
 
1246
1267
  .mw-about__body {
1247
- padding: 0 0.75rem 0.75rem;
1268
+ padding: 0 var(--space-4) var(--space-4);
1248
1269
  }
1249
1270
 
1250
1271
  .mw-about__section {
1251
- margin-top: 0.75rem;
1272
+ margin-top: var(--space-4);
1252
1273
  }
1253
1274
 
1254
1275
  .mw-about__section:first-child {
@@ -1258,7 +1279,7 @@
1258
1279
  .mw-about__heading {
1259
1280
  font-size: 0.9rem;
1260
1281
  font-weight: 700;
1261
- margin: 0 0 0.3rem;
1282
+ margin: 0 0 var(--space-1);
1262
1283
  color: var(--color-text-primary);
1263
1284
  }
1264
1285
 
@@ -1270,44 +1291,44 @@
1270
1291
 
1271
1292
  .mw-about__section code {
1272
1293
  font-size: 0.85rem;
1273
- padding: 0.1rem 0.3rem;
1294
+ padding: var(--space-0) var(--space-1);
1274
1295
  background: var(--color-background-sunken);
1275
- border-radius: 3px;
1296
+ border-radius: var(--radius-tick);
1276
1297
  }
1277
1298
 
1278
1299
  .mw-about__legend {
1279
1300
  list-style: none;
1280
- margin: 0.5rem 0 0;
1301
+ margin: var(--space-3) 0 0;
1281
1302
  padding: 0;
1282
1303
  display: flex;
1283
1304
  flex-direction: column;
1284
- gap: 0.35rem;
1305
+ gap: var(--space-2);
1285
1306
  }
1286
1307
 
1287
1308
  .mw-about__item {
1288
1309
  display: flex;
1289
1310
  align-items: center;
1290
- gap: 0.4rem;
1311
+ gap: var(--space-2);
1291
1312
  font-size: 0.85rem;
1292
1313
  }
1293
1314
 
1294
1315
  .mw-about__swatch {
1295
1316
  flex-shrink: 0;
1296
- width: 10px;
1297
- height: 10px;
1298
- border-radius: 2px;
1317
+ width: 0.625rem;
1318
+ height: 0.625rem;
1319
+ border-radius: var(--radius-tick);
1299
1320
  }
1300
1321
 
1301
1322
  .mw-about__swatch--high {
1302
- background: #22c55e;
1323
+ background: var(--color-confidence-high);
1303
1324
  }
1304
1325
 
1305
1326
  .mw-about__swatch--mid {
1306
- background: #f59e0b;
1327
+ background: var(--color-confidence-mid);
1307
1328
  }
1308
1329
 
1309
1330
  .mw-about__swatch--low {
1310
- background: #ef4444;
1331
+ background: var(--color-confidence-low);
1311
1332
  }
1312
1333
 
1313
1334
  /* #endregion */
@@ -1319,8 +1340,8 @@
1319
1340
  * summary keep it legible without competing with the query, which is what the panel is for.
1320
1341
  */
1321
1342
  .mw-demo-developer {
1322
- margin-top: 1rem;
1323
- padding-top: 0.75rem;
1343
+ margin-top: var(--space-5);
1344
+ padding-top: var(--space-4);
1324
1345
  border-top: 1px solid var(--color-separator);
1325
1346
  }
1326
1347
 
@@ -1339,7 +1360,7 @@
1339
1360
  }
1340
1361
 
1341
1362
  .mw-demo-developer[open] > summary {
1342
- margin-bottom: 0.75rem;
1363
+ margin-bottom: var(--space-4);
1343
1364
  }
1344
1365
 
1345
1366
  /* #endregion */
@@ -1347,40 +1368,93 @@
1347
1368
  /* #region Chrome layout — where the floating pieces sit over a map */
1348
1369
 
1349
1370
  /*
1350
- * The search pill and the chips ride at the top, centred and width-capped rather than stretched: a search field
1351
- * the width of a desktop screen reads as a page header, not as a control over a map. The column clears the
1352
- * device's top and side safe-area insets because both apps install as PWAs.
1371
+ * the panel: search, examples and result on one surface.
1372
+ *
1373
+ * It replaces a floating pill plus a separate bottom sheet. Two surfaces meant the search field shared its row
1374
+ * with the control rail — which covered its right end at any width where the two met — and meant a phone could
1375
+ * open a result it had no way back from. One surface has one set of edges to reason about.
1376
+ *
1377
+ * Desktop: a column down the left over a full-bleed map, sized to its content rather than stretched to the
1378
+ * viewport, because with no result there is nothing to fill a full-height sidebar with.
1379
+ * Phone (below): a bottom drawer, the search riding at its top.
1353
1380
  */
1354
- .mw-map-chrome--top {
1381
+ .mw-map-panel {
1355
1382
  position: absolute;
1356
1383
  top: calc(1rem + var(--safe-area-top));
1357
1384
  left: calc(1rem + var(--safe-area-left));
1358
- right: calc(1rem + var(--safe-area-right));
1359
1385
  z-index: 3;
1360
1386
  display: grid;
1361
- gap: 0.5rem;
1362
- justify-items: stretch;
1363
- max-width: 34rem;
1364
- pointer-events: none;
1387
+ gap: var(--space-3);
1388
+ align-content: start;
1389
+ width: min(24rem, calc(100vw - 6rem));
1390
+ /* Stops short of the footer strip, so a long result never runs under the credits. */
1391
+ max-height: calc(100% - var(--map-footer-height) - var(--safe-area-top) - var(--safe-area-bottom) - 2rem);
1392
+ /* no TOP PADDING: the grip bar carries it, so the bar's paint can reach the panel's top edge. */
1393
+ padding: 0 var(--space-4) var(--space-4);
1394
+ border-radius: var(--radius-sheet);
1395
+ overflow: auto;
1396
+ overscroll-behavior: contain;
1397
+ /*
1398
+ * The MATERIAL is not stated here. It is composed once, with every other glass surface, in the material region
1399
+ * below — which is also the list the two fallbacks repeat. Written out at the component this panel had the
1400
+ * vendor pair the wrong way round (so Firefox lost the blur), a hardcoded `blur(20px)` with no saturation, and
1401
+ * no entry in either fallback, so a viewer asking for reduced transparency still got translucent glass. Only
1402
+ * the shadow is local, because the panel's is the sheet's rather than the pill's.
1403
+ */
1404
+ box-shadow: var(--material-glass-shadow);
1365
1405
  }
1366
1406
 
1367
- /* The container is click-through so the map stays draggable between the controls; each control takes its own. */
1368
- .mw-map-chrome--top > * {
1369
- pointer-events: auto;
1407
+ /*
1408
+ * The header: the grab bar and the search field as one sticky block.
1409
+ *
1410
+ * The field is in here rather than down in the scroll because scrolling a long result used to carry it off the
1411
+ * top of the panel, and the field is what a visitor reaches for next. The reference map apps pin exactly this
1412
+ * much and let everything under it move.
1413
+ *
1414
+ * It OWNS the panel's top gutter rather than sitting inside it: the panel carries no top padding, so the header's
1415
+ * paint reaches the panel's top edge. Opaque, because the panel's material is glass and a result read straight
1416
+ * through a translucent pinned header.
1417
+ *
1418
+ * no NEGATIVE TOP MARGIN to reach that edge. In a grid the track is sized from the margin box while the item is
1419
+ * laid out at the track's start, so a bar pulled up by 12px painted 12px past its own row, onto the field below.
1420
+ */
1421
+ .mw-map-panel__header {
1422
+ position: sticky;
1423
+ top: 0;
1424
+ z-index: 2;
1425
+ display: grid;
1426
+ gap: var(--space-3);
1427
+ margin-inline: calc(-1 * var(--space-4));
1428
+ padding: var(--space-4) var(--space-4) var(--space-3);
1429
+ background: var(--color-background-raised);
1430
+ border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
1431
+ /* A hairline under the pinned block, so a result scrolling beneath it has an edge to disappear at. */
1432
+ box-shadow: 0 1px 0 var(--color-separator);
1370
1433
  }
1371
1434
 
1372
- .mw-map-chrome__search {
1373
- margin: 0;
1435
+ /*
1436
+ * The grab bar's own row, inside the header.
1437
+ *
1438
+ * no MINIMUM on the desktop column: the row holds a handle that only the drawer offers and a close that only a
1439
+ * result offers, so on a desktop with nothing found it holds nothing — and a minimum drew that nothing as a band
1440
+ * of empty glass above the search field. Its height is whatever it is carrying; the drawer rule below puts a
1441
+ * minimum back, where the handle is the thing being reached for.
1442
+ */
1443
+ .mw-map-panel__grip {
1444
+ display: flex;
1445
+ align-items: center;
1446
+ justify-content: center;
1447
+ min-height: 0;
1374
1448
  }
1375
1449
 
1376
- .mw-map-searchbar__clear {
1377
- border: 0;
1378
- background: transparent;
1379
- color: inherit;
1380
- cursor: pointer;
1381
- font: inherit;
1382
- line-height: 1;
1383
- padding: 0 0.15rem;
1450
+ .mw-map-panel__result {
1451
+ display: grid;
1452
+ gap: var(--space-3);
1453
+ }
1454
+
1455
+ /* The form around the field carries no margin of its own; the header's grid sets the spacing. */
1456
+ .mw-map-panel__search {
1457
+ margin: 0;
1384
1458
  }
1385
1459
 
1386
1460
  /*
@@ -1400,16 +1474,6 @@
1400
1474
  overscroll-behavior: contain;
1401
1475
  }
1402
1476
 
1403
- .mw-map-sheet--bottom {
1404
- left: calc(1rem + var(--safe-area-left));
1405
- right: calc(1rem + var(--safe-area-right));
1406
- bottom: calc(2.5rem + var(--safe-area-bottom));
1407
- max-height: 52vh;
1408
- max-width: 34rem;
1409
- padding: 0.5rem 1rem 1rem;
1410
- border-radius: var(--radius-sheet);
1411
- }
1412
-
1413
1477
  /*
1414
1478
  * BESIDE the control column, not below it. Opening below meant the sheet's top depended on how many controls the
1415
1479
  * capsule held, and every app that added one covered the button that opened it. Beside, it clears the column
@@ -1424,10 +1488,14 @@
1424
1488
  * that scrolls, and a percentage there let the sheet run past the bottom of the screen.
1425
1489
  */
1426
1490
  max-height: calc(100dvh - 2rem - var(--map-footer-height) - var(--safe-area-top) - var(--safe-area-bottom));
1427
- padding: 1rem;
1491
+ padding: var(--space-5);
1428
1492
  border-radius: var(--radius-panel);
1429
- /* Above the result sheet: a panel is a different task, and it covers the answer rather than sharing an edge. */
1430
- z-index: 5;
1493
+ /*
1494
+ * the TOP OF the MAP'S LADDER: panel 3 (5 as a drawer), control rail 4, side sheet 6. A side sheet is a
1495
+ * different task and covers the answer rather than sharing an edge with it. It was 5 — a tie with the drawer,
1496
+ * resolved by nothing but the order the two happen to render in, and one JSX reorder from inverting.
1497
+ */
1498
+ z-index: 6;
1431
1499
  }
1432
1500
 
1433
1501
  /*
@@ -1445,9 +1513,9 @@
1445
1513
  display: flex;
1446
1514
  align-items: center;
1447
1515
  justify-content: space-between;
1448
- gap: 1rem;
1449
- margin: -1rem -1rem 0.75rem;
1450
- padding: 0.75rem 1rem;
1516
+ gap: var(--space-5);
1517
+ margin: calc(-1 * var(--space-5)) calc(-1 * var(--space-5)) var(--space-4);
1518
+ padding: var(--space-4) var(--space-5);
1451
1519
  background: var(--material-glass-fallback-background);
1452
1520
  border-bottom: 1px solid var(--color-separator);
1453
1521
  }
@@ -1486,10 +1554,27 @@
1486
1554
  outline-offset: 1px;
1487
1555
  }
1488
1556
 
1557
+ /*
1558
+ * The close sits at the right of the grip bar.
1559
+ *
1560
+ * IN FLOW on the desktop column, where the bar has no handle to center and therefore no height of its own. Taken
1561
+ * out of flow there it reserved nothing, and a 44px button hanging from a 0px bar came down across the right end
1562
+ * of the search field below it — the overlap this whole panel was meant to end. In flow it carries the bar, and
1563
+ * the field starts under it.
1564
+ *
1565
+ * The phone rule below puts it back to absolute, where the handle is the bar and has to stay centered on the sheet
1566
+ * rather than on the space the close leaves, and where the target grows to a full 44px because the drawer is the
1567
+ * whole panel and this is the only way out of it.
1568
+ */
1569
+ .mw-map-sheet__close--floating {
1570
+ margin-left: auto;
1571
+ right: 0.25rem;
1572
+ }
1573
+
1489
1574
  .mw-map-sheet__row {
1490
1575
  display: grid;
1491
- gap: 0.3rem;
1492
- padding: 0.7rem 0;
1576
+ gap: var(--space-1);
1577
+ padding: var(--space-4) 0;
1493
1578
  border-top: 1px solid var(--color-separator);
1494
1579
  }
1495
1580
 
@@ -1512,7 +1597,7 @@
1512
1597
 
1513
1598
  /* An intro paragraph is not a row, so it carries its own space before the first hairline. */
1514
1599
  .mw-map-sheet > .mw-map-sheet__hint {
1515
- margin-bottom: 0.75rem;
1600
+ margin-bottom: var(--space-4);
1516
1601
  }
1517
1602
 
1518
1603
  /* A value in a row reads at the row's size; the browser's default `code` is a step larger than the label above it. */
@@ -1526,7 +1611,7 @@
1526
1611
  .mw-map-sheet__check {
1527
1612
  display: flex;
1528
1613
  align-items: baseline;
1529
- gap: 0.5rem;
1614
+ gap: var(--space-3);
1530
1615
  cursor: pointer;
1531
1616
  font-size: var(--font-size-footnote);
1532
1617
  color: var(--color-text-primary);
@@ -1544,7 +1629,7 @@
1544
1629
  .mw-map-sheet input[type="search"] {
1545
1630
  width: 100%;
1546
1631
  box-sizing: border-box;
1547
- padding: 0.4rem 0.55rem;
1632
+ padding: var(--space-2) var(--space-3);
1548
1633
  font: inherit;
1549
1634
  font-size: var(--font-size-footnote);
1550
1635
  color: var(--control-foreground);
@@ -1559,17 +1644,56 @@
1559
1644
  outline-offset: 1px;
1560
1645
  }
1561
1646
 
1562
- /* The grab affordance the reference sheets carry. Decorative: the sheet scrolls, it does not drag. */
1647
+ /*
1648
+ * The grab affordance, and now a real control: drag to resize between two detents, drag down past the smaller one
1649
+ * to dismiss, tap or Enter to toggle. It was decorative, which is worse than absent — a handle that looks draggable
1650
+ * and is not reads as a broken sheet rather than a static one.
1651
+ *
1652
+ * The pill is drawn as a pseudo-element so the button itself can be a 44px-tall target without a 44px-tall pill.
1653
+ * `touch-action: none` stops the browser claiming the gesture as a scroll before the pointer handlers see it.
1654
+ */
1655
+ /* Desktop has no drawer to resize, so the handle is not offered there; the phone rule below restores it. */
1656
+ .mw-map-panel .mw-map-sheet__handle {
1657
+ display: none;
1658
+ }
1659
+
1563
1660
  .mw-map-sheet__handle {
1661
+ display: grid;
1662
+ place-items: center;
1663
+ width: 3rem;
1664
+ height: 2.5rem;
1665
+ padding: 0;
1666
+ border: 0;
1667
+ background: transparent;
1668
+ color: inherit;
1669
+ cursor: grab;
1670
+ touch-action: none;
1671
+ }
1672
+
1673
+ .mw-map-sheet__handle::before {
1674
+ content: "";
1564
1675
  width: 2.25rem;
1565
1676
  height: 0.25rem;
1566
- margin: 0 auto 0.6rem;
1567
1677
  border-radius: var(--radius-pill);
1568
1678
  background: var(--color-separator);
1569
1679
  }
1570
1680
 
1681
+ .mw-map-sheet__handle:hover::before {
1682
+ background: var(--color-text-tertiary);
1683
+ }
1684
+
1685
+ .mw-map-sheet__handle:active {
1686
+ cursor: grabbing;
1687
+ }
1688
+
1689
+ .mw-map-sheet__handle:focus-visible {
1690
+ outline: 2px solid var(--color-selection);
1691
+ outline-offset: -2px;
1692
+ border-radius: var(--radius-pill);
1693
+ }
1694
+
1571
1695
  .mw-map-sheet__actions {
1572
- margin-top: 0.75rem;
1696
+ margin-top: var(--space-4);
1573
1697
  display: flex;
1574
1698
  justify-content: flex-end;
1575
1699
  }
@@ -1594,21 +1718,68 @@
1594
1718
  * control plus its 1rem inset plus a 0.5rem gap. Without this the capsule sits on the search pill's clear
1595
1719
  * button, which is the one control at that end of the pill.
1596
1720
  */
1597
- .mw-map-chrome--top {
1598
- max-width: none;
1599
- right: calc(4rem + var(--safe-area-right));
1600
- }
1601
-
1602
- .mw-map-sheet--bottom {
1721
+ /*
1722
+ * The drawer. Anchored to the bottom edge above the footer, full width, and detented — the search rides at its
1723
+ * top so reaching it never means getting a result out of the way first.
1724
+ */
1725
+ .mw-map-panel {
1726
+ top: auto;
1603
1727
  left: 0;
1604
1728
  right: 0;
1605
1729
  bottom: calc(var(--map-footer-height) + var(--safe-area-bottom));
1606
- max-width: none;
1730
+ width: auto;
1731
+ /*
1732
+ * above the control rail (`z-index: 4`), which the desktop column never reaches. Pulled to its tall detent
1733
+ * the drawer's top edge crosses the rail's corner, and drawn under it the rail sat on the drawer's own
1734
+ * close. A sheet raised over a map covers what it covers; it does not share a corner with it.
1735
+ */
1736
+ z-index: 5;
1737
+ /*
1738
+ * `none`, not `contain`. A pull at the top of the scroll is a drag on the drawer here (see
1739
+ * `onPanelPointerMove`), and the browser's own rubber band fought it: the content bounced while the drawer
1740
+ * stayed put, which reads as the gesture being heard and refused.
1741
+ */
1742
+ overscroll-behavior: none;
1607
1743
  max-height: 55dvh;
1608
1744
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
1609
1745
  border-inline: 0;
1610
1746
  border-bottom: 0;
1611
- padding-bottom: 1rem;
1747
+ }
1748
+
1749
+ .mw-map-panel .mw-map-sheet__handle {
1750
+ display: grid;
1751
+ }
1752
+
1753
+ /* The header is the grab target, so the browser must not claim the gesture as a scroll before it is read. */
1754
+ .mw-map-panel__header {
1755
+ touch-action: none;
1756
+ }
1757
+
1758
+ /*
1759
+ * The control rail is hidden while a result is open. It shares the corner the drawer's tall detent reaches,
1760
+ * and a control stranded above an open drawer is out of reach of the thumb holding the phone. Closing the
1761
+ * result brings it back — which is the same gesture that gives the map back.
1762
+ */
1763
+ /* Doubled class: the base `.mw-map-control-stack` sets `display: flex` further down the sheet, and a single
1764
+ * class here loses to it on source order alone. */
1765
+ .mw-map-control-stack.mw-map-control-stack--drawer-open {
1766
+ display: none;
1767
+ }
1768
+
1769
+ /*
1770
+ * The drawer's bar is the grab target, so it keeps a full row — but only while it holds one. With no result the
1771
+ * bar is empty on a phone too, and an empty band over the search field is the gap this rule would otherwise put
1772
+ * back. `:has()` is the test; where it is unsupported the bar collapses, which is the harmless half.
1773
+ */
1774
+ .mw-map-panel__grip:has(button) {
1775
+ min-height: 2.25rem;
1776
+ }
1777
+
1778
+ .mw-map-sheet__close--floating {
1779
+ position: absolute;
1780
+ margin-left: 0;
1781
+ width: 2.75rem;
1782
+ height: 2.75rem;
1612
1783
  }
1613
1784
 
1614
1785
  .mw-map-sheet--side {
@@ -1621,7 +1792,7 @@
1621
1792
  max-height: none;
1622
1793
  border-radius: 0;
1623
1794
  border: 0;
1624
- padding: calc(1rem + var(--safe-area-top)) 1rem 1rem;
1795
+ padding: calc(var(--space-5) + var(--safe-area-top)) var(--space-5) var(--space-5);
1625
1796
  }
1626
1797
 
1627
1798
  /* The chips take the full width on a phone, so the fade has less to hide behind. */
@@ -1632,8 +1803,8 @@
1632
1803
 
1633
1804
  /* The header spans the panel's full width once the sheet loses its own inset. */
1634
1805
  .mw-map-sheet--side .mw-map-sheet__header {
1635
- margin: calc(-1rem - var(--safe-area-top)) -1rem 0.75rem;
1636
- padding-top: calc(0.75rem + var(--safe-area-top));
1806
+ margin: calc(-1 * (var(--space-5) + var(--safe-area-top))) calc(-1 * var(--space-5)) var(--space-4);
1807
+ padding-top: calc(var(--space-4) + var(--safe-area-top));
1637
1808
  }
1638
1809
  }
1639
1810
 
@@ -1648,7 +1819,7 @@
1648
1819
  */
1649
1820
 
1650
1821
  /*
1651
- * EVERY glass surface is listed here, and the two fallback blocks at the end of this region repeat exactly this
1822
+ * every glass surface is listed here, and the two fallback blocks at the end of this region repeat exactly this
1652
1823
  * list. Composing the material at each component instead left the sheets and the sources popover out of both
1653
1824
  * fallbacks, so a viewer who asked for reduced transparency still got a translucent panel.
1654
1825
  */
@@ -1657,11 +1828,12 @@
1657
1828
  .mw-map-control-group,
1658
1829
  .mw-map-footer,
1659
1830
  .mw-map-footer__popover,
1660
- .mw-map-sheet {
1831
+ .mw-map-sheet,
1832
+ .mw-map-panel {
1661
1833
  background: var(--material-glass-background);
1662
1834
  border: 1px solid var(--material-glass-border);
1663
1835
  /*
1664
- * PREFIXED FIRST, STANDARD LAST. The minifier collapses two declarations carrying the same value and keeps the
1836
+ * PREFIXED first, STANDARD last. The minifier collapses two declarations carrying the same value and keeps the
1665
1837
  * last one; written the other way round the shipped rule had `-webkit-backdrop-filter` alone, so every glass
1666
1838
  * surface lost its blur on Firefox, which implements the standard property and not the alias.
1667
1839
  */
@@ -1673,8 +1845,8 @@
1673
1845
  .mw-map-searchbar {
1674
1846
  display: flex;
1675
1847
  align-items: center;
1676
- gap: 0.5rem;
1677
- padding: 0.4rem 0.75rem;
1848
+ gap: var(--space-3);
1849
+ padding: var(--space-2) var(--space-4);
1678
1850
  border-radius: var(--radius-pill);
1679
1851
  box-shadow: var(--material-glass-shadow);
1680
1852
  }
@@ -1729,7 +1901,7 @@
1729
1901
  }
1730
1902
 
1731
1903
  /*
1732
- * The native clear button of `input[type="search"]`. Its COLOUR is the user agent's, decided by the document's
1904
+ * The native clear button of `input[type="search"]`. Its COLOR is the user agent's, decided by the document's
1733
1905
  * `color-scheme` — nothing here repaints it. Only the two things the scheme does not say are stated: that it is a
1734
1906
  * pointer target, and that it sits back until the field is under the pointer or holding focus.
1735
1907
  */
@@ -1751,7 +1923,7 @@
1751
1923
  background: transparent;
1752
1924
  color: inherit;
1753
1925
  font: inherit;
1754
- padding: 0.25rem 0;
1926
+ padding: var(--space-1) 0;
1755
1927
  }
1756
1928
 
1757
1929
  .mw-map-searchbar:focus-within {
@@ -1769,16 +1941,21 @@
1769
1941
  line-height: 1;
1770
1942
  }
1771
1943
 
1944
+ /* A drawn mark, not a typed one — see `SearchGlyph`. `block` keeps the line box off its baseline. */
1945
+ .mw-map-searchbar__glyph {
1946
+ display: block;
1947
+ }
1948
+
1772
1949
  /*
1773
1950
  * One line that scrolls, never a wrap. The scrollbar is hidden because the row sits over a map where a track
1774
1951
  * would read as chrome; the row stays reachable by keyboard through its buttons.
1775
1952
  */
1776
1953
  .mw-map-chiprow {
1777
1954
  display: flex;
1778
- gap: 0.4rem;
1955
+ gap: var(--space-2);
1779
1956
  overflow-x: auto;
1780
1957
  scrollbar-width: none;
1781
- padding: 0.15rem;
1958
+ padding: var(--space-0);
1782
1959
  scroll-padding-inline: 0.15rem;
1783
1960
  /* With the track hidden, a chip clipped at the edge reads as broken; the fade is what says the row scrolls. */
1784
1961
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 2rem), transparent);
@@ -1793,8 +1970,8 @@
1793
1970
  flex: 0 0 auto;
1794
1971
  display: inline-flex;
1795
1972
  align-items: center;
1796
- gap: 0.35rem;
1797
- padding: 0.35rem 0.7rem;
1973
+ gap: var(--space-2);
1974
+ padding: var(--space-2) var(--space-4);
1798
1975
  border-radius: var(--radius-pill);
1799
1976
  font-size: var(--font-size-footnote);
1800
1977
  font-weight: var(--font-weight-medium);
@@ -1834,7 +2011,7 @@
1834
2011
  top: calc(1rem + var(--safe-area-top));
1835
2012
  display: flex;
1836
2013
  flex-direction: column;
1837
- gap: 0.6rem;
2014
+ gap: var(--space-3);
1838
2015
  z-index: 4;
1839
2016
  }
1840
2017
 
@@ -1875,8 +2052,10 @@
1875
2052
  display: flex;
1876
2053
  align-items: center;
1877
2054
  justify-content: center;
1878
- width: 2.5rem;
1879
- height: 2.5rem;
2055
+ /* 2.5rem = 40px, under the 44px minimum for a touch target, and these three are the only way into the about,
2056
+ layers and developer sheets. */
2057
+ width: 2.75rem;
2058
+ height: 2.75rem;
1880
2059
  border: 0;
1881
2060
  background: transparent;
1882
2061
  color: var(--color-text-primary);
@@ -1884,6 +2063,17 @@
1884
2063
  cursor: pointer;
1885
2064
  }
1886
2065
 
2066
+ /*
2067
+ * This rail was the one control group in the app with no focus ring — every sibling has one (.mw-map-chip,
2068
+ * .mw-map-compass, .mw-map-sheet__close, .mw-map-footer__attribution-button). An `outline` alone would not have
2069
+ * shown anyway: the parent capsule clips with `overflow: hidden`, which hides an outline drawn outside the button's
2070
+ * box. An inset ring is drawn inside it, so the capsule cannot clip it.
2071
+ */
2072
+ .mw-map-control:focus-visible {
2073
+ outline: none;
2074
+ box-shadow: inset 0 0 0 2px var(--color-selection);
2075
+ }
2076
+
1887
2077
  .mw-map-control:hover:not(:disabled) {
1888
2078
  background: var(--control-background);
1889
2079
  }
@@ -1906,7 +2096,7 @@
1906
2096
  * `visibility` rather than `display` is what lets the opacity transition run at all.
1907
2097
  */
1908
2098
  /*
1909
- * The compass sits INSIDE a control capsule like the other controls, so it carries no material of its own — the
2099
+ * The compass sits inside a control capsule like the other controls, so it carries no material of its own — the
1910
2100
  * capsule supplies the glass, and a second background here would read as a button on a button.
1911
2101
  */
1912
2102
  .mw-map-compass {
@@ -1974,7 +2164,7 @@
1974
2164
  * take height from the thing a visitor asked for. Long credits scroll instead.
1975
2165
  */
1976
2166
  /*
1977
- * THE STRIP ITSELF DOES NOT CLIP. A non-visible overflow on one axis makes the other clip as well, so an
2167
+ * the STRIP ITSELF does not CLIP. A non-visible overflow on one axis makes the other clip as well, so an
1978
2168
  * `overflow-x` here erased the sources popover outright — it is positioned above the strip, entirely outside the
1979
2169
  * box that would have been doing the clipping. The scroll belongs to the identity region, which is the part
1980
2170
  * carrying text long enough to need one.
@@ -1983,12 +2173,12 @@
1983
2173
  display: flex;
1984
2174
  align-items: center;
1985
2175
  justify-content: space-between;
1986
- gap: 1rem;
2176
+ gap: var(--space-5);
1987
2177
  flex-wrap: nowrap;
1988
2178
  white-space: nowrap;
1989
2179
  box-sizing: content-box;
1990
2180
  height: var(--map-footer-height);
1991
- padding: 0 0.75rem;
2181
+ padding: 0 var(--space-4);
1992
2182
  padding-bottom: var(--safe-area-bottom);
1993
2183
  border-radius: 0;
1994
2184
  border-inline: 0;
@@ -1997,13 +2187,13 @@
1997
2187
  color: var(--color-text-secondary);
1998
2188
  }
1999
2189
 
2000
- /* Identity, then whatever is loading. The status is where the loader says WHAT; the bar on top says how far. */
2190
+ /* Identity, then whatever is loading. The status is where the loader says what; the bar on top says how far. */
2001
2191
  .mw-map-footer__identity {
2002
2192
  flex: 1 1 auto;
2003
2193
  min-width: 0;
2004
2194
  display: flex;
2005
2195
  align-items: baseline;
2006
- gap: 0.6rem;
2196
+ gap: var(--space-3);
2007
2197
  overflow-x: auto;
2008
2198
  scrollbar-width: none;
2009
2199
  }
@@ -2025,7 +2215,7 @@
2025
2215
  }
2026
2216
 
2027
2217
  .mw-map-footer__attribution-button {
2028
- padding: 0.1rem 0.5rem;
2218
+ padding: var(--space-0) var(--space-3);
2029
2219
  font: inherit;
2030
2220
  color: var(--color-text-secondary);
2031
2221
  background: transparent;
@@ -2046,6 +2236,30 @@
2046
2236
  outline-offset: 1px;
2047
2237
  }
2048
2238
 
2239
+ /*
2240
+ * One credit line. `MapFooter` has always rendered this class and `styles.css` never defined it, so the credits
2241
+ * inherited whatever the popover gave them — which was fine while they were bare strings and not once they became
2242
+ * links that have to look like links.
2243
+ */
2244
+ .mw-map-footer__credit {
2245
+ line-height: 1.5;
2246
+ }
2247
+
2248
+ .mw-map-footer__credit a {
2249
+ color: inherit;
2250
+ text-decoration: underline;
2251
+ text-underline-offset: 2px;
2252
+ }
2253
+
2254
+ .mw-map-footer__credit a:hover {
2255
+ color: var(--color-text-primary);
2256
+ }
2257
+
2258
+ .mw-map-footer__credit a:focus-visible {
2259
+ outline: 2px solid var(--color-selection);
2260
+ outline-offset: 2px;
2261
+ }
2262
+
2049
2263
  /* The credits open UPWARD from the strip, because the strip is already against the bottom of the viewport. */
2050
2264
  .mw-map-footer__popover {
2051
2265
  position: absolute;
@@ -2053,10 +2267,10 @@
2053
2267
  bottom: calc(100% + 0.4rem);
2054
2268
  z-index: 1;
2055
2269
  display: grid;
2056
- gap: 0.25rem;
2270
+ gap: var(--space-1);
2057
2271
  min-width: max-content;
2058
2272
  max-width: min(22rem, calc(100vw - 2rem));
2059
- padding: 0.6rem 0.8rem;
2273
+ padding: var(--space-3) var(--space-4);
2060
2274
  white-space: normal;
2061
2275
  text-align: right;
2062
2276
  box-shadow: var(--material-glass-shadow);
@@ -2133,7 +2347,8 @@
2133
2347
  .mw-map-control-group,
2134
2348
  .mw-map-footer,
2135
2349
  .mw-map-footer__popover,
2136
- .mw-map-sheet {
2350
+ .mw-map-sheet,
2351
+ .mw-map-panel {
2137
2352
  background: var(--material-glass-fallback-background);
2138
2353
  }
2139
2354
  }
@@ -2144,7 +2359,8 @@
2144
2359
  .mw-map-control-group,
2145
2360
  .mw-map-footer,
2146
2361
  .mw-map-footer__popover,
2147
- .mw-map-sheet {
2362
+ .mw-map-sheet,
2363
+ .mw-map-panel {
2148
2364
  background: var(--material-glass-fallback-background);
2149
2365
  -webkit-backdrop-filter: none;
2150
2366
  backdrop-filter: none;