@mailwoman/react 9.3.0 → 10.0.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 (246) hide show
  1. package/fonts.css +59 -0
  2. package/lib/common/About.tsx +105 -0
  3. package/lib/common/KindBadge.tsx +2 -7
  4. package/lib/common/confidence-tiers.ts +50 -0
  5. package/lib/common/index.ts +22 -0
  6. package/lib/common/text-tokens.ts +88 -0
  7. package/lib/index.ts +10 -103
  8. package/lib/map/BackendControl.tsx +7 -3
  9. package/lib/map/CompareToggle.tsx +5 -4
  10. package/lib/map/{GeocoderDemo.tsx → Geocoder.tsx} +81 -61
  11. package/lib/map/GeocoderControls.tsx +352 -0
  12. package/lib/map/{DemoMap.tsx → MapCanvas.tsx} +15 -15
  13. package/lib/map/MapChipRow.tsx +77 -0
  14. package/lib/map/MapCompass.tsx +77 -0
  15. package/lib/map/MapControlStack.tsx +98 -0
  16. package/lib/map/MapFooter.tsx +115 -0
  17. package/lib/map/MapProgressBar.tsx +58 -0
  18. package/lib/map/MapSearchBar.tsx +68 -0
  19. package/lib/map/MapSheet.tsx +62 -0
  20. package/lib/map/PlaceMarker.tsx +1 -1
  21. package/lib/map/ResolvedPlaceLayers.tsx +3 -3
  22. package/lib/map/ResultCamera.tsx +1 -1
  23. package/lib/map/ResultPanel.tsx +2 -2
  24. package/lib/map/VersionPicker.tsx +3 -3
  25. package/lib/map/fake-runtime.ts +122 -0
  26. package/lib/map/index.ts +35 -16
  27. package/lib/map/map-debug.ts +51 -0
  28. package/lib/map/place-render.ts +3 -2
  29. package/lib/map/types.ts +58 -42
  30. package/lib/map/{useDemoGeocode.ts → useGeocode.ts} +8 -8
  31. package/lib/map/useMapBearing.ts +56 -0
  32. package/lib/map/useMapLabelPick.ts +123 -0
  33. package/lib/pipeline/CandidatePicker.tsx +1 -1
  34. package/lib/pipeline/ComponentTable.tsx +1 -2
  35. package/lib/pipeline/ConfidenceCell.tsx +7 -19
  36. package/lib/pipeline/FailureDiagnostic.tsx +56 -0
  37. package/lib/pipeline/ResolvedPlace.tsx +17 -4
  38. package/lib/pipeline/SpanHighlight.tsx +97 -0
  39. package/lib/pipeline/TimingPanel.tsx +65 -0
  40. package/lib/pipeline/TreeView.tsx +55 -0
  41. package/lib/pipeline/copy.ts +1 -1
  42. package/lib/pipeline/index.ts +36 -0
  43. package/lib/pipeline/types.ts +2 -75
  44. package/lib/pipeline/useParsePipeline.ts +31 -19
  45. package/lib/poi/index.ts +39 -0
  46. package/lib/poi/types.ts +2 -1
  47. package/lib/runtime/index.ts +16 -0
  48. package/lib/runtime/{useDemoRuntime.ts → useReleaseRuntime.ts} +22 -24
  49. package/out/common/About.d.ts +21 -0
  50. package/out/common/About.d.ts.map +1 -0
  51. package/out/common/About.js +8 -0
  52. package/out/common/About.js.map +1 -0
  53. package/out/common/KindBadge.d.ts +2 -9
  54. package/out/common/KindBadge.d.ts.map +1 -1
  55. package/out/common/KindBadge.js.map +1 -1
  56. package/out/common/confidence-tiers.d.ts +36 -0
  57. package/out/common/confidence-tiers.d.ts.map +1 -0
  58. package/out/common/confidence-tiers.js +42 -0
  59. package/out/common/confidence-tiers.js.map +1 -0
  60. package/out/common/index.d.ts +22 -0
  61. package/out/common/index.d.ts.map +1 -0
  62. package/out/common/index.js +15 -0
  63. package/out/common/index.js.map +1 -0
  64. package/out/common/text-tokens.d.ts +46 -0
  65. package/out/common/text-tokens.d.ts.map +1 -0
  66. package/out/common/text-tokens.js +52 -0
  67. package/out/common/text-tokens.js.map +1 -0
  68. package/out/index.d.ts +5 -51
  69. package/out/index.d.ts.map +1 -1
  70. package/out/index.js +4 -30
  71. package/out/index.js.map +1 -1
  72. package/out/map/BackendControl.d.ts.map +1 -1
  73. package/out/map/BackendControl.js +1 -1
  74. package/out/map/BackendControl.js.map +1 -1
  75. package/out/map/CompareToggle.d.ts +2 -2
  76. package/out/map/CompareToggle.d.ts.map +1 -1
  77. package/out/map/CompareToggle.js +1 -1
  78. package/out/map/CompareToggle.js.map +1 -1
  79. package/out/map/Geocoder.d.ts +67 -0
  80. package/out/map/Geocoder.d.ts.map +1 -0
  81. package/out/map/Geocoder.js +98 -0
  82. package/out/map/Geocoder.js.map +1 -0
  83. package/out/map/GeocoderControls.d.ts +81 -0
  84. package/out/map/GeocoderControls.d.ts.map +1 -0
  85. package/out/map/GeocoderControls.js +79 -0
  86. package/out/map/GeocoderControls.js.map +1 -0
  87. package/out/map/{DemoMap.d.ts → MapCanvas.d.ts} +15 -15
  88. package/out/map/MapCanvas.d.ts.map +1 -0
  89. package/out/map/{DemoMap.js → MapCanvas.js} +2 -2
  90. package/out/map/MapCanvas.js.map +1 -0
  91. package/out/map/MapChipRow.d.ts +47 -0
  92. package/out/map/MapChipRow.d.ts.map +1 -0
  93. package/out/map/MapChipRow.js +12 -0
  94. package/out/map/MapChipRow.js.map +1 -0
  95. package/out/map/MapCompass.d.ts +42 -0
  96. package/out/map/MapCompass.d.ts.map +1 -0
  97. package/out/map/MapCompass.js +11 -0
  98. package/out/map/MapCompass.js.map +1 -0
  99. package/out/map/MapControlStack.d.ts +57 -0
  100. package/out/map/MapControlStack.d.ts.map +1 -0
  101. package/out/map/MapControlStack.js +15 -0
  102. package/out/map/MapControlStack.js.map +1 -0
  103. package/out/map/MapFooter.d.ts +40 -0
  104. package/out/map/MapFooter.d.ts.map +1 -0
  105. package/out/map/MapFooter.js +51 -0
  106. package/out/map/MapFooter.js.map +1 -0
  107. package/out/map/MapProgressBar.d.ts +34 -0
  108. package/out/map/MapProgressBar.d.ts.map +1 -0
  109. package/out/map/MapProgressBar.js +8 -0
  110. package/out/map/MapProgressBar.js.map +1 -0
  111. package/out/map/MapSearchBar.d.ts +49 -0
  112. package/out/map/MapSearchBar.d.ts.map +1 -0
  113. package/out/map/MapSearchBar.js +6 -0
  114. package/out/map/MapSearchBar.js.map +1 -0
  115. package/out/map/MapSheet.d.ts +32 -0
  116. package/out/map/MapSheet.d.ts.map +1 -0
  117. package/out/map/MapSheet.js +33 -0
  118. package/out/map/MapSheet.js.map +1 -0
  119. package/out/map/OverlayLayers.js +1 -1
  120. package/out/map/PlaceMarker.d.ts +1 -1
  121. package/out/map/ResolvedPlaceLayers.d.ts +3 -3
  122. package/out/map/ResolvedPlaceLayers.js +1 -1
  123. package/out/map/ResultCamera.d.ts +1 -1
  124. package/out/map/ResultCamera.js +1 -1
  125. package/out/map/ResultPanel.d.ts +2 -2
  126. package/out/map/ResultPanel.d.ts.map +1 -1
  127. package/out/map/ResultPanel.js +1 -1
  128. package/out/map/ResultPanel.js.map +1 -1
  129. package/out/map/VersionPicker.d.ts +3 -3
  130. package/out/map/VersionPicker.d.ts.map +1 -1
  131. package/out/map/fake-runtime.d.ts +38 -0
  132. package/out/map/fake-runtime.d.ts.map +1 -0
  133. package/out/map/fake-runtime.js +107 -0
  134. package/out/map/fake-runtime.js.map +1 -0
  135. package/out/map/index.d.ts +27 -10
  136. package/out/map/index.d.ts.map +1 -1
  137. package/out/map/index.js +16 -6
  138. package/out/map/index.js.map +1 -1
  139. package/out/map/map-debug.d.ts +31 -0
  140. package/out/map/map-debug.d.ts.map +1 -0
  141. package/out/map/map-debug.js +31 -0
  142. package/out/map/map-debug.js.map +1 -0
  143. package/out/map/place-render.d.ts +2 -2
  144. package/out/map/place-render.d.ts.map +1 -1
  145. package/out/map/place-render.js +1 -1
  146. package/out/map/place-render.js.map +1 -1
  147. package/out/map/types.d.ts +60 -42
  148. package/out/map/types.d.ts.map +1 -1
  149. package/out/map/types.js +5 -5
  150. package/out/map/{useDemoGeocode.d.ts → useGeocode.d.ts} +9 -9
  151. package/out/map/useGeocode.d.ts.map +1 -0
  152. package/out/map/{useDemoGeocode.js → useGeocode.js} +4 -4
  153. package/out/map/useGeocode.js.map +1 -0
  154. package/out/map/useMapBearing.d.ts +28 -0
  155. package/out/map/useMapBearing.d.ts.map +1 -0
  156. package/out/map/useMapBearing.js +35 -0
  157. package/out/map/useMapBearing.js.map +1 -0
  158. package/out/map/useMapLabelPick.d.ts +23 -0
  159. package/out/map/useMapLabelPick.d.ts.map +1 -0
  160. package/out/map/useMapLabelPick.js +104 -0
  161. package/out/map/useMapLabelPick.js.map +1 -0
  162. package/out/pipeline/CandidatePicker.d.ts +1 -1
  163. package/out/pipeline/CandidatePicker.d.ts.map +1 -1
  164. package/out/pipeline/CandidatePicker.js +1 -1
  165. package/out/pipeline/CandidatePicker.js.map +1 -1
  166. package/out/pipeline/ComponentTable.d.ts +1 -1
  167. package/out/pipeline/ComponentTable.d.ts.map +1 -1
  168. package/out/pipeline/ComponentTable.js.map +1 -1
  169. package/out/pipeline/ConfidenceCell.d.ts +2 -2
  170. package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
  171. package/out/pipeline/ConfidenceCell.js +4 -16
  172. package/out/pipeline/ConfidenceCell.js.map +1 -1
  173. package/out/pipeline/FailureDiagnostic.d.ts +15 -0
  174. package/out/pipeline/FailureDiagnostic.d.ts.map +1 -0
  175. package/out/pipeline/FailureDiagnostic.js +21 -0
  176. package/out/pipeline/FailureDiagnostic.js.map +1 -0
  177. package/out/pipeline/PipelineExplorer.js +1 -1
  178. package/out/pipeline/QueryForm.js +1 -1
  179. package/out/pipeline/ResolvedPlace.d.ts +1 -1
  180. package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
  181. package/out/pipeline/ResolvedPlace.js +4 -10
  182. package/out/pipeline/ResolvedPlace.js.map +1 -1
  183. package/out/pipeline/SpanHighlight.d.ts +23 -0
  184. package/out/pipeline/SpanHighlight.d.ts.map +1 -0
  185. package/out/pipeline/SpanHighlight.js +31 -0
  186. package/out/pipeline/SpanHighlight.js.map +1 -0
  187. package/out/pipeline/TimingPanel.d.ts +16 -0
  188. package/out/pipeline/TimingPanel.d.ts.map +1 -0
  189. package/out/pipeline/TimingPanel.js +20 -0
  190. package/out/pipeline/TimingPanel.js.map +1 -0
  191. package/out/pipeline/TreeView.d.ts +17 -0
  192. package/out/pipeline/TreeView.d.ts.map +1 -0
  193. package/out/pipeline/TreeView.js +15 -0
  194. package/out/pipeline/TreeView.js.map +1 -0
  195. package/out/pipeline/copy.d.ts +1 -1
  196. package/out/pipeline/copy.d.ts.map +1 -1
  197. package/out/pipeline/index.d.ts +33 -0
  198. package/out/pipeline/index.d.ts.map +1 -0
  199. package/out/pipeline/index.js +21 -0
  200. package/out/pipeline/index.js.map +1 -0
  201. package/out/pipeline/types.d.ts +2 -68
  202. package/out/pipeline/types.d.ts.map +1 -1
  203. package/out/pipeline/types.js +1 -1
  204. package/out/pipeline/useParsePipeline.d.ts +7 -3
  205. package/out/pipeline/useParsePipeline.d.ts.map +1 -1
  206. package/out/pipeline/useParsePipeline.js +6 -2
  207. package/out/pipeline/useParsePipeline.js.map +1 -1
  208. package/out/poi/LiveResultsBlock.js +1 -1
  209. package/out/poi/POIExplorer.js +1 -1
  210. package/out/poi/SubjectPanel.js +1 -1
  211. package/out/poi/index.d.ts +23 -0
  212. package/out/poi/index.d.ts.map +1 -0
  213. package/out/poi/index.js +15 -0
  214. package/out/poi/index.js.map +1 -0
  215. package/out/poi/runtime.d.ts.map +1 -1
  216. package/out/poi/types.d.ts +2 -1
  217. package/out/poi/types.d.ts.map +1 -1
  218. package/out/runtime/index.d.ts +9 -0
  219. package/out/runtime/index.d.ts.map +1 -0
  220. package/out/runtime/index.js +8 -0
  221. package/out/runtime/index.js.map +1 -0
  222. package/out/runtime/{useDemoRuntime.d.ts → useReleaseRuntime.d.ts} +18 -20
  223. package/out/runtime/useReleaseRuntime.d.ts.map +1 -0
  224. package/out/runtime/{useDemoRuntime.js → useReleaseRuntime.js} +4 -4
  225. package/out/runtime/useReleaseRuntime.js.map +1 -0
  226. package/package.json +222 -31
  227. package/styleframe.config.ts +329 -0
  228. package/styles.css +1995 -663
  229. package/tokens/index.css +116 -0
  230. package/tokens/tokens.json +528 -0
  231. package/tokens/tokens.resolver.json +185 -0
  232. package/lib/map/DemoControls.tsx +0 -194
  233. package/out/map/DemoControls.d.ts +0 -64
  234. package/out/map/DemoControls.d.ts.map +0 -1
  235. package/out/map/DemoControls.js +0 -30
  236. package/out/map/DemoControls.js.map +0 -1
  237. package/out/map/DemoMap.d.ts.map +0 -1
  238. package/out/map/DemoMap.js.map +0 -1
  239. package/out/map/GeocoderDemo.d.ts +0 -57
  240. package/out/map/GeocoderDemo.d.ts.map +0 -1
  241. package/out/map/GeocoderDemo.js +0 -98
  242. package/out/map/GeocoderDemo.js.map +0 -1
  243. package/out/map/useDemoGeocode.d.ts.map +0 -1
  244. package/out/map/useDemoGeocode.js.map +0 -1
  245. package/out/runtime/useDemoRuntime.d.ts.map +0 -1
  246. package/out/runtime/useDemoRuntime.js.map +0 -1
package/styles.css CHANGED
@@ -1,823 +1,2155 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
  * @mailwoman/react — component styles.
3
3
  *
4
- * Plain, `mw-`-prefixed classes ported from the docs-site CSS modules. Every
5
- * Infima (`--ifm-*`) token carries an inline fallback, so the components render
6
- * correctly BOTH inside Docusaurus (where the real theme tokens win) and
7
- * standalone (Storybook, tests, any React app). No CSS module hashing — the
8
- * class names are stable and namespaced, and no component imports this file, so
9
- * the bare package import stays node-safe.
4
+ * Plain, `mw-`-prefixed classes. Every colour, family and radius here names a
5
+ * SEMANTIC token from `tokens.css`, which this file requires a host to load —
6
+ * `@mailwoman/react/tokens.css`, and `fonts.css` beside it for the brand face.
7
+ * There are no inline fallbacks, on purpose: a fallback is what let eight
8
+ * undefined names paint Infima's LIGHT values inside a dark app without
9
+ * anything failing. A token that is missing should look missing.
10
+ *
11
+ * A rule may read the semantic layer only. Reaching a primitive (`--neutral-*`,
12
+ * `--brand-*`) from here skips the layer that says what a value is FOR, which is
13
+ * how this stylesheet came to read a theme vocabulary it did not own.
14
+ *
15
+ * No CSS module hashing — the class names are stable and namespaced, and no
16
+ * component imports this file, so the bare package import stays node-safe.
10
17
  * --------------------------------------------------------------------------- */
11
18
 
12
- .mw-poi-explorer,
13
- .mw-pipeline-explorer {
14
- max-width: 720px;
15
- font-size: 0.95rem;
19
+ /*
20
+ * The layer order every consumer inherits. Naming the order here means a host's own rules can win by declaring a
21
+ * later layer rather than by out-specifying ours, which is what keeps this package embeddable in Docusaurus without
22
+ * either side fighting the other's selectors.
23
+ */
24
+ @layer reset, tokens, base, components, utilities, overrides;
25
+
26
+ /*
27
+ * The vocabulary these rules read, pulled in rather than left to the host to remember. A consumer that loaded the
28
+ * components and forgot the tokens is exactly the state that shipped: rules reading names nothing defined.
29
+ */
30
+ @import url("./tokens/index.css") layer(tokens);
31
+
32
+ @layer reset {
33
+ /*
34
+ * Every box is measured by its border. The default is `content-box`, where `width`, `height` and `max-height`
35
+ * describe the content ALONE and any padding and border stand outside them — so a sheet capped at 52% of the
36
+ * viewport shipped 34px taller than its cap and ran off the bottom of the screen, and every rule that pairs a size
37
+ * with padding is one edit away from the same defect.
38
+ *
39
+ * A rule that wants the other measure states `box-sizing: content-box` for itself; the footer strip does, because
40
+ * its height names one line of type and its safe-area padding has to sit outside that.
41
+ *
42
+ * It is in the `reset` layer, so a host's own rules and every layer below win over it without out-specifying it.
43
+ */
44
+ *,
45
+ *::before,
46
+ *::after {
47
+ box-sizing: border-box;
48
+ }
16
49
  }
17
50
 
18
- /* #region Field (label + input + button) */
51
+ @layer base {
52
+ /*
53
+ * The theme attribute has to reach the USER AGENT, not only our own rules. `color-scheme` is what paints a
54
+ * scrollbar, a focus ring, a `<select>` popup and — the one this app depends on — the native clear button inside
55
+ * `input[type="search"]`, which renders as a dark cross on a dark field until the document declares its scheme.
56
+ */
57
+ :root[data-theme="dark"] {
58
+ color-scheme: dark;
59
+ }
19
60
 
20
- .mw-field {
21
- display: flex;
22
- flex-direction: column;
23
- gap: 0.5rem;
24
- }
61
+ :root[data-theme="light"] {
62
+ color-scheme: light;
63
+ }
25
64
 
26
- .mw-field label {
27
- font-weight: 600;
28
- font-size: 0.9rem;
29
- }
65
+ /*
66
+ * Form controls do not inherit the document's font. Left alone, a `<button>` renders in the user agent's default
67
+ * — measured as Arial on the deployed Earth app, beside a body in system-ui and labels in ui-monospace, which is
68
+ * three families in one panel and none of them chosen.
69
+ */
70
+ button,
71
+ input,
72
+ select,
73
+ textarea {
74
+ font-family: inherit;
75
+ font-size: inherit;
76
+ line-height: inherit;
77
+ }
30
78
 
31
- .mw-field input {
32
- padding: 0.5rem 0.75rem;
33
- font: inherit;
34
- border: 1px solid var(--ifm-color-emphasis-300, #d1d5db);
35
- border-radius: 6px;
36
- background: var(--ifm-background-surface-color, #fff);
37
- color: var(--ifm-font-color-base, inherit);
38
- }
79
+ /*
80
+ * A button carries no color of its own: unset, it paints the user agent's `buttontext`, which is near-black and
81
+ * stays near-black inside a dark sheet. Every button in this stylesheet that sets a background but no color read
82
+ * that way the candidate list was the visible one.
83
+ */
84
+ button {
85
+ color: inherit;
86
+ }
39
87
 
40
- .mw-field input:disabled {
41
- opacity: 0.5;
88
+ /*
89
+ * A default face for a host that sets none. Wrapped in `:where()` so it carries ZERO specificity: Docusaurus's own
90
+ * `body` rule wins on the docs site and keeps that page's typography, while Storybook and a bare React host — which
91
+ * declare nothing — stop falling back to the user agent's serif.
92
+ */
93
+ :where(body) {
94
+ font-family: var(--font-family-text);
95
+ font-size: var(--font-size-body);
96
+ line-height: var(--line-height-body);
97
+ color: var(--color-text-primary);
98
+ }
42
99
  }
43
100
 
44
- .mw-field button[type="submit"] {
45
- padding: 0.5rem 0.75rem;
46
- background: var(--ifm-color-primary, #e0367c);
47
- color: #fff;
48
- border: 0;
49
- border-radius: 6px;
50
- font-weight: 600;
51
- cursor: pointer;
52
- display: inline-flex;
53
- align-items: center;
54
- gap: 0.4rem;
55
- align-self: flex-start;
56
- }
101
+ @layer components {
102
+ .mw-poi-explorer,
103
+ .mw-pipeline-explorer {
104
+ max-width: 720px;
105
+ font-size: 0.95rem;
106
+ }
57
107
 
58
- .mw-field button[type="submit"]:disabled {
59
- background: var(--ifm-color-emphasis-400, #b3b3b3);
60
- cursor: not-allowed;
61
- }
108
+ /* #region Field (label + input + button) */
62
109
 
63
- /* #endregion */
110
+ .mw-field {
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: 0.5rem;
114
+ }
64
115
 
65
- /* #region Preset chips */
116
+ .mw-field label {
117
+ font-weight: 600;
118
+ font-size: 0.9rem;
119
+ }
66
120
 
67
- .mw-presets {
68
- margin-top: 0.75rem;
69
- display: flex;
70
- flex-wrap: wrap;
71
- gap: 0.4rem;
72
- align-items: baseline;
73
- }
121
+ .mw-field input {
122
+ padding: 0.5rem 0.75rem;
123
+ font: inherit;
124
+ border: 1px solid var(--control-border);
125
+ border-radius: 6px;
126
+ background: var(--color-background-raised);
127
+ color: var(--color-text-primary);
128
+ }
74
129
 
75
- .mw-presets__label {
76
- font-size: 0.85rem;
77
- color: var(--ifm-color-emphasis-600, #6e6e6e);
78
- margin-right: 0.25rem;
79
- }
130
+ .mw-field input:disabled {
131
+ opacity: 0.5;
132
+ }
80
133
 
81
- .mw-chip {
82
- font-size: 0.8rem;
83
- padding: 0.25rem 0.55rem;
84
- background: var(--ifm-color-emphasis-100, #f5f6f7);
85
- color: var(--ifm-color-emphasis-800, #303846);
86
- border: 1px solid var(--ifm-color-emphasis-300, #d1d5db);
87
- border-radius: 4px;
88
- font-weight: 500;
89
- cursor: pointer;
90
- font-family: inherit;
91
- }
134
+ .mw-field button[type="submit"] {
135
+ padding: 0.5rem 0.75rem;
136
+ background: var(--color-accent);
137
+ color: var(--color-accent-contrast);
138
+ border: 0;
139
+ border-radius: 6px;
140
+ font-weight: 600;
141
+ cursor: pointer;
142
+ display: inline-flex;
143
+ align-items: center;
144
+ gap: 0.4rem;
145
+ align-self: flex-start;
146
+ }
92
147
 
93
- .mw-chip:hover:not(:disabled) {
94
- background: var(--ifm-color-emphasis-200, #ebedf0);
95
- border-color: var(--ifm-color-primary, #e0367c);
96
- }
148
+ .mw-field button[type="submit"]:disabled {
149
+ background: var(--color-text-tertiary);
150
+ cursor: not-allowed;
151
+ }
97
152
 
98
- .mw-chip:disabled {
99
- opacity: 0.5;
100
- cursor: not-allowed;
101
- }
153
+ /* #endregion */
154
+
155
+ /* #region Preset chips */
156
+
157
+ /*
158
+ * One line that scrolls, never a wrap. Twelve examples wrapped down five ragged rows (3/3/2/1/1/1) and took a
159
+ * third of the panel; a scrolling row costs a fixed height whatever the number of examples. The scrollbar is
160
+ * hidden because the row sits inside a floating panel where a track reads as chrome, and every chip stays
161
+ * reachable by keyboard.
162
+ */
163
+ .mw-presets {
164
+ margin-top: 0.75rem;
165
+ display: flex;
166
+ flex-wrap: nowrap;
167
+ overflow-x: auto;
168
+ scrollbar-width: none;
169
+ gap: 0.4rem;
170
+ align-items: baseline;
171
+ padding-bottom: 0.15rem;
172
+ }
102
173
 
103
- /* #endregion */
174
+ .mw-presets::-webkit-scrollbar {
175
+ display: none;
176
+ }
104
177
 
105
- /* #region Generic button (copy / search) */
178
+ .mw-presets > * {
179
+ flex: 0 0 auto;
180
+ }
106
181
 
107
- .mw-btn {
108
- font-size: 0.8rem;
109
- padding: 0.25rem 0.55rem;
110
- background: var(--ifm-color-emphasis-100, #f5f6f7);
111
- color: var(--ifm-color-emphasis-800, #303846);
112
- border: 1px solid var(--ifm-color-emphasis-300, #d1d5db);
113
- border-radius: 4px;
114
- cursor: pointer;
115
- font-family: inherit;
116
- }
182
+ .mw-chip {
183
+ white-space: nowrap;
184
+ }
117
185
 
118
- .mw-btn:hover:not(:disabled) {
119
- background: var(--ifm-color-emphasis-200, #ebedf0);
120
- }
186
+ .mw-presets__label {
187
+ font-size: 0.85rem;
188
+ color: var(--color-text-secondary);
189
+ margin-right: 0.25rem;
190
+ }
121
191
 
122
- .mw-btn:disabled {
123
- opacity: 0.5;
124
- cursor: not-allowed;
125
- }
192
+ .mw-chip {
193
+ font-size: 0.8rem;
194
+ padding: 0.25rem 0.55rem;
195
+ background: var(--control-background);
196
+ color: var(--color-text-primary);
197
+ border: 1px solid var(--control-border);
198
+ border-radius: 4px;
199
+ font-weight: 500;
200
+ cursor: pointer;
201
+ font-family: inherit;
202
+ }
126
203
 
127
- /* #endregion */
204
+ .mw-chip:hover:not(:disabled) {
205
+ background: var(--color-background-sunken);
206
+ border-color: var(--color-accent);
207
+ }
128
208
 
129
- /* #region Result panel + errors */
209
+ .mw-chip:disabled {
210
+ opacity: 0.5;
211
+ cursor: not-allowed;
212
+ }
130
213
 
131
- .mw-result {
132
- margin-top: 1.5rem;
133
- }
214
+ /* #endregion */
134
215
 
135
- .mw-result__header {
136
- display: flex;
137
- justify-content: space-between;
138
- align-items: center;
139
- margin-bottom: 0.75rem;
140
- }
216
+ /* #region Generic button (copy / search) */
141
217
 
142
- .mw-result__header h2 {
143
- margin: 0;
144
- font-size: 1.1rem;
145
- }
218
+ .mw-btn {
219
+ font-size: 0.8rem;
220
+ padding: 0.25rem 0.55rem;
221
+ background: var(--control-background);
222
+ color: var(--color-text-primary);
223
+ border: 1px solid var(--control-border);
224
+ border-radius: 4px;
225
+ cursor: pointer;
226
+ font-family: inherit;
227
+ }
146
228
 
147
- .mw-panel__header {
148
- display: flex;
149
- justify-content: space-between;
150
- align-items: center;
151
- margin-bottom: 0.4rem;
152
- }
229
+ .mw-btn:hover:not(:disabled) {
230
+ background: var(--color-background-sunken);
231
+ }
153
232
 
154
- .mw-panel__header h3 {
155
- margin: 0;
156
- font-size: 0.95rem;
157
- }
233
+ .mw-btn:disabled {
234
+ opacity: 0.5;
235
+ cursor: not-allowed;
236
+ }
158
237
 
159
- .mw-muted {
160
- font-style: italic;
161
- color: var(--ifm-color-emphasis-600, #6e6e6e);
162
- }
238
+ /* #endregion */
163
239
 
164
- .mw-error {
165
- color: var(--ifm-color-danger, #d9364c);
166
- font-family: var(--ifm-font-family-monospace, monospace);
167
- white-space: pre-wrap;
168
- }
240
+ /* #region Result panel + errors */
169
241
 
170
- /* #endregion */
242
+ .mw-result {
243
+ margin-top: 1.5rem;
244
+ }
171
245
 
172
- /* #region KindBadge */
246
+ .mw-result__header {
247
+ display: flex;
248
+ justify-content: space-between;
249
+ align-items: center;
250
+ margin-bottom: 0.75rem;
251
+ }
173
252
 
174
- .mw-kind {
175
- margin-bottom: 0.5rem;
176
- font-size: 0.9rem;
177
- }
253
+ .mw-result__header h2 {
254
+ margin: 0;
255
+ font-size: 1.1rem;
256
+ }
178
257
 
179
- .mw-kind__summary {
180
- cursor: pointer;
181
- user-select: none;
182
- }
258
+ .mw-panel__header {
259
+ display: flex;
260
+ justify-content: space-between;
261
+ align-items: center;
262
+ margin-bottom: 0.4rem;
263
+ }
183
264
 
184
- .mw-kind__confidence {
185
- opacity: 0.7;
186
- }
265
+ .mw-panel__header h3 {
266
+ margin: 0;
267
+ font-size: 0.95rem;
268
+ }
187
269
 
188
- .mw-kind__alternatives {
189
- margin: 0.25rem 0 0 1rem;
190
- padding: 0;
191
- list-style: disc;
192
- }
270
+ .mw-muted {
271
+ font-style: italic;
272
+ color: var(--color-text-secondary);
273
+ }
193
274
 
194
- /* #endregion */
275
+ .mw-error {
276
+ color: var(--color-state-danger);
277
+ font-family: var(--font-family-code);
278
+ white-space: pre-wrap;
279
+ }
195
280
 
196
- /* #region POI subject panel */
281
+ /* #endregion */
197
282
 
198
- .mw-subject__row {
199
- display: flex;
200
- align-items: center;
201
- gap: 0.5rem;
202
- margin-bottom: 0.5rem;
203
- }
283
+ /* #region KindBadge */
204
284
 
205
- .mw-subject__chip {
206
- display: inline-block;
207
- padding: 0.2rem 0.6rem;
208
- border-radius: 999px;
209
- background: var(--ifm-color-primary-contrast-background, rgba(224, 54, 124, 0.12));
210
- color: var(--ifm-color-primary, #e0367c);
211
- font-weight: 600;
212
- font-size: 0.85rem;
213
- }
285
+ .mw-kind {
286
+ margin-bottom: 0.5rem;
287
+ font-size: 0.9rem;
288
+ }
214
289
 
215
- .mw-subject__badge {
216
- display: inline-block;
217
- padding: 0.2rem 0.5rem;
218
- border-radius: 999px;
219
- background: var(--ifm-color-warning-contrast-background, rgba(245, 158, 11, 0.15));
220
- color: var(--ifm-color-warning-darkest, #92400e);
221
- font-size: 0.75rem;
222
- font-weight: 600;
223
- text-transform: uppercase;
224
- letter-spacing: 0.02em;
225
- }
290
+ .mw-kind__summary {
291
+ cursor: pointer;
292
+ user-select: none;
293
+ }
226
294
 
227
- .mw-subject__badge--brand {
228
- background: var(--ifm-color-info-contrast-background, rgba(84, 199, 236, 0.15));
229
- color: var(--ifm-color-info-darkest, #14657d);
230
- }
295
+ .mw-kind__confidence {
296
+ opacity: 0.7;
297
+ }
231
298
 
232
- .mw-subject__qid {
233
- display: inline-block;
234
- padding: 0.2rem 0.5rem;
235
- border-radius: 999px;
236
- background: var(--ifm-color-emphasis-200, #ebedf0);
237
- color: var(--ifm-color-emphasis-800, #303846);
238
- font-family: var(--ifm-font-family-monospace, monospace);
239
- font-size: 0.75rem;
240
- font-weight: 600;
241
- text-decoration: none;
242
- }
299
+ .mw-kind__alternatives {
300
+ margin: 0.25rem 0 0 1rem;
301
+ padding: 0;
302
+ list-style: disc;
303
+ }
243
304
 
244
- .mw-subject__qid:hover {
245
- text-decoration: underline;
246
- }
305
+ /* #endregion */
247
306
 
248
- .mw-subject__note {
249
- margin: 0 0 0.75rem;
250
- font-size: 0.85rem;
251
- opacity: 0.8;
252
- }
307
+ /* #region POI subject panel */
253
308
 
254
- .mw-subject__detail {
255
- display: grid;
256
- grid-template-columns: auto 1fr;
257
- gap: 0.25rem 0.75rem;
258
- margin: 0 0 0.75rem;
259
- font-size: 0.9rem;
260
- }
309
+ .mw-subject__row {
310
+ display: flex;
311
+ align-items: center;
312
+ gap: 0.5rem;
313
+ margin-bottom: 0.5rem;
314
+ }
261
315
 
262
- .mw-subject__detail dt {
263
- font-weight: 600;
264
- color: var(--ifm-color-emphasis-700, #4a5163);
265
- }
316
+ .mw-subject__chip {
317
+ display: inline-block;
318
+ padding: 0.2rem 0.6rem;
319
+ border-radius: 999px;
320
+ background: var(--color-accent-background);
321
+ color: var(--color-accent);
322
+ font-weight: 600;
323
+ font-size: 0.85rem;
324
+ }
266
325
 
267
- .mw-subject__detail dd {
268
- margin: 0;
269
- }
326
+ .mw-subject__badge {
327
+ display: inline-block;
328
+ padding: 0.2rem 0.5rem;
329
+ border-radius: 999px;
330
+ background: var(--color-state-warning-background);
331
+ color: var(--color-state-warning);
332
+ font-size: 0.75rem;
333
+ font-weight: 600;
334
+ text-transform: uppercase;
335
+ letter-spacing: 0.02em;
336
+ }
270
337
 
271
- /* #endregion */
338
+ .mw-subject__badge--brand {
339
+ background: var(--color-state-info-background);
340
+ color: var(--color-state-info);
341
+ }
272
342
 
273
- /* #region OverpassQL block */
343
+ .mw-subject__qid {
344
+ display: inline-block;
345
+ padding: 0.2rem 0.5rem;
346
+ border-radius: 999px;
347
+ background: var(--color-background-sunken);
348
+ color: var(--color-text-primary);
349
+ font-family: var(--font-family-code);
350
+ font-size: 0.75rem;
351
+ font-weight: 600;
352
+ text-decoration: none;
353
+ }
274
354
 
275
- .mw-overpass {
276
- margin-top: 0.75rem;
277
- }
355
+ .mw-subject__qid:hover {
356
+ text-decoration: underline;
357
+ }
278
358
 
279
- .mw-overpass__code {
280
- margin: 0;
281
- padding: 0.75rem;
282
- border-radius: 6px;
283
- background: var(--ifm-color-emphasis-100, #f5f6f7);
284
- font-family: var(--ifm-font-family-monospace, monospace);
285
- font-size: 0.85rem;
286
- white-space: pre-wrap;
287
- overflow-x: auto;
288
- }
359
+ .mw-subject__note {
360
+ margin: 0 0 0.75rem;
361
+ font-size: 0.85rem;
362
+ opacity: 0.8;
363
+ }
289
364
 
290
- /* #endregion */
365
+ .mw-subject__detail {
366
+ display: grid;
367
+ grid-template-columns: auto 1fr;
368
+ gap: 0.25rem 0.75rem;
369
+ margin: 0 0 0.75rem;
370
+ font-size: 0.9rem;
371
+ }
291
372
 
292
- /* #region Live results */
373
+ .mw-subject__detail dt {
374
+ font-weight: 600;
375
+ color: var(--color-text-secondary);
376
+ }
293
377
 
294
- .mw-live {
295
- margin-top: 1rem;
296
- }
378
+ .mw-subject__detail dd {
379
+ margin: 0;
380
+ }
297
381
 
298
- .mw-live__caption {
299
- margin: 0 0 0.4rem;
300
- font-size: 0.85rem;
301
- color: var(--ifm-color-emphasis-600, #6e6e6e);
302
- }
382
+ /* #endregion */
303
383
 
304
- .mw-live__results {
305
- list-style: none;
306
- margin: 0;
307
- padding: 0;
308
- display: flex;
309
- flex-direction: column;
310
- gap: 0.35rem;
311
- }
384
+ /* #region OverpassQL block */
312
385
 
313
- .mw-live__results li {
314
- display: flex;
315
- justify-content: space-between;
316
- align-items: baseline;
317
- gap: 0.75rem;
318
- padding: 0.4rem 0.6rem;
319
- border-radius: 6px;
320
- background: var(--ifm-color-emphasis-100, #f5f6f7);
321
- font-size: 0.9rem;
322
- }
386
+ .mw-overpass {
387
+ margin-top: 0.75rem;
388
+ }
323
389
 
324
- .mw-live__name {
325
- font-weight: 600;
326
- }
390
+ .mw-overpass__code {
391
+ margin: 0;
392
+ padding: 0.75rem;
393
+ border-radius: 6px;
394
+ background: var(--control-background);
395
+ font-family: var(--font-family-code);
396
+ font-size: 0.85rem;
397
+ white-space: pre-wrap;
398
+ overflow-x: auto;
399
+ }
327
400
 
328
- .mw-live__meta {
329
- color: var(--ifm-color-emphasis-600, #6e6e6e);
330
- font-size: 0.8rem;
331
- white-space: nowrap;
332
- }
401
+ /* #endregion */
333
402
 
334
- /* #endregion */
403
+ /* #region Live results */
335
404
 
336
- /* #region Component table */
405
+ .mw-live {
406
+ margin-top: 1rem;
407
+ }
337
408
 
338
- .mw-components {
339
- width: 100%;
340
- border-collapse: collapse;
341
- margin: 0.75rem 0;
342
- font-size: 0.9rem;
343
- }
409
+ .mw-live__caption {
410
+ margin: 0 0 0.4rem;
411
+ font-size: 0.85rem;
412
+ color: var(--color-text-secondary);
413
+ }
344
414
 
345
- .mw-components th,
346
- .mw-components td {
347
- padding: 0.4rem 0.6rem;
348
- text-align: left;
349
- border-bottom: 1px solid var(--ifm-color-emphasis-200, #ebedf0);
350
- }
415
+ .mw-live__results {
416
+ list-style: none;
417
+ margin: 0;
418
+ padding: 0;
419
+ display: flex;
420
+ flex-direction: column;
421
+ gap: 0.35rem;
422
+ }
351
423
 
352
- .mw-components th {
353
- font-weight: 600;
354
- color: var(--ifm-color-emphasis-600, #6e6e6e);
355
- font-size: 0.8rem;
356
- text-transform: uppercase;
357
- }
424
+ .mw-live__results li {
425
+ display: flex;
426
+ justify-content: space-between;
427
+ align-items: baseline;
428
+ gap: 0.75rem;
429
+ padding: 0.4rem 0.6rem;
430
+ border-radius: 6px;
431
+ background: var(--control-background);
432
+ font-size: 0.9rem;
433
+ }
358
434
 
359
- /* #endregion */
435
+ .mw-live__name {
436
+ font-weight: 600;
437
+ }
360
438
 
361
- /* #region Confidence cell */
439
+ .mw-live__meta {
440
+ color: var(--color-text-secondary);
441
+ font-size: 0.8rem;
442
+ white-space: nowrap;
443
+ }
362
444
 
363
- .mw-conf__dash {
364
- color: var(--ifm-color-emphasis-500, #8c8c8c);
365
- }
445
+ /* #endregion */
366
446
 
367
- .mw-conf {
368
- display: flex;
369
- align-items: center;
370
- gap: 0.35rem;
371
- min-width: 80px;
372
- }
447
+ /* #region Component table */
373
448
 
374
- .mw-conf__bar {
375
- height: 6px;
376
- border-radius: 3px;
377
- min-width: 4px;
378
- transition: width 0.2s ease;
379
- }
449
+ .mw-components {
450
+ width: 100%;
451
+ border-collapse: collapse;
452
+ margin: 0.75rem 0;
453
+ font-size: 0.9rem;
454
+ }
380
455
 
381
- .mw-conf__bar--high {
382
- background: #22c55e;
383
- }
456
+ .mw-components th,
457
+ .mw-components td {
458
+ padding: 0.4rem 0.6rem;
459
+ text-align: left;
460
+ border-bottom: 1px solid var(--color-separator);
461
+ }
384
462
 
385
- .mw-conf__bar--mid {
386
- background: #f59e0b;
387
- }
463
+ .mw-components th {
464
+ font-weight: 600;
465
+ color: var(--color-text-secondary);
466
+ font-size: 0.8rem;
467
+ text-transform: uppercase;
468
+ }
388
469
 
389
- .mw-conf__bar--low {
390
- background: #ef4444;
391
- }
470
+ /* #endregion */
392
471
 
393
- .mw-conf__value {
394
- font-family: var(--ifm-font-family-monospace, monospace);
395
- font-size: 0.8rem;
396
- }
472
+ /* #region Confidence cell */
397
473
 
398
- /* #endregion */
474
+ .mw-conf__dash {
475
+ color: var(--color-text-tertiary);
476
+ }
399
477
 
400
- /* #region Resolved place */
478
+ .mw-conf {
479
+ display: flex;
480
+ align-items: center;
481
+ gap: 0.35rem;
482
+ min-width: 80px;
483
+ }
401
484
 
402
- .mw-resolved {
403
- margin-top: 1rem;
404
- padding: 0.75rem;
405
- border: 1px solid var(--ifm-color-emphasis-200, #ebedf0);
406
- border-radius: 6px;
407
- background: var(--ifm-color-emphasis-0, #fff);
408
- }
485
+ .mw-conf__bar {
486
+ height: 6px;
487
+ border-radius: 3px;
488
+ min-width: 4px;
489
+ transition: width 0.2s ease;
490
+ }
409
491
 
410
- .mw-resolved h2 {
411
- margin: 0 0 0.5rem;
412
- font-size: 1rem;
413
- }
492
+ .mw-conf__bar--high {
493
+ background: #22c55e;
494
+ }
414
495
 
415
- .mw-resolved dl {
416
- display: grid;
417
- grid-template-columns: auto 1fr;
418
- gap: 0.25rem 0.75rem;
419
- margin: 0;
420
- }
496
+ .mw-conf__bar--mid {
497
+ background: #f59e0b;
498
+ }
421
499
 
422
- .mw-resolved dt {
423
- font-weight: 600;
424
- color: var(--ifm-color-emphasis-700, #4a5163);
425
- }
500
+ .mw-conf__bar--low {
501
+ background: #ef4444;
502
+ }
426
503
 
427
- .mw-resolved dd {
428
- margin: 0;
429
- }
504
+ .mw-conf__value {
505
+ font-family: var(--font-family-code);
506
+ font-size: 0.8rem;
507
+ }
430
508
 
431
- .mw-resolved__dual {
432
- margin: 0.5rem 0 0;
433
- padding: 0.4rem 0.6rem;
434
- border-radius: 6px;
435
- background: var(--ifm-color-info-contrast-background, rgba(54, 122, 246, 0.1));
436
- font-size: 0.9rem;
437
- }
509
+ /* #endregion */
438
510
 
439
- /* #endregion */
511
+ /* #region Resolved place */
440
512
 
441
- /* #region Candidate picker */
513
+ .mw-resolved {
514
+ margin-top: 1rem;
515
+ padding: 0.75rem;
516
+ border: 1px solid var(--color-separator);
517
+ border-radius: 6px;
518
+ background: var(--color-background-canvas);
519
+ }
442
520
 
443
- .mw-candidates {
444
- margin-top: 1rem;
445
- }
521
+ .mw-resolved h2 {
522
+ margin: 0 0 0.5rem;
523
+ font-size: 1rem;
524
+ }
446
525
 
447
- .mw-candidates h2 {
448
- font-size: 1rem;
449
- margin: 0 0 0.5rem;
450
- }
526
+ .mw-resolved dl {
527
+ display: grid;
528
+ grid-template-columns: auto 1fr;
529
+ gap: 0.25rem 0.75rem;
530
+ margin: 0;
531
+ }
451
532
 
452
- .mw-candidates__list {
453
- list-style: none;
454
- margin: 0;
455
- padding: 0;
456
- display: flex;
457
- flex-direction: column;
458
- gap: 0.35rem;
459
- }
533
+ .mw-resolved dt {
534
+ font-weight: 600;
535
+ color: var(--color-text-secondary);
536
+ }
460
537
 
461
- .mw-candidates__btn {
462
- display: flex;
463
- align-items: baseline;
464
- gap: 0.6rem;
465
- width: 100%;
466
- text-align: left;
467
- padding: 0.4rem 0.6rem;
468
- border: 1px solid var(--ifm-color-emphasis-200, #ebedf0);
469
- border-radius: 6px;
470
- background: transparent;
471
- cursor: pointer;
472
- font: inherit;
473
- }
538
+ .mw-resolved dd {
539
+ margin: 0;
540
+ }
474
541
 
475
- .mw-candidates__btn--active {
476
- border-color: var(--ifm-color-primary, #e0367c);
477
- background: var(--ifm-color-primary-contrast-background, rgba(224, 54, 124, 0.1));
478
- }
542
+ .mw-resolved__dual {
543
+ margin: 0.5rem 0 0;
544
+ padding: 0.4rem 0.6rem;
545
+ border-radius: 6px;
546
+ background: var(--color-state-info-background);
547
+ font-size: 0.9rem;
548
+ }
479
549
 
480
- .mw-candidates__rank {
481
- font-family: var(--ifm-font-family-monospace, monospace);
482
- font-size: 0.8rem;
483
- opacity: 0.6;
484
- }
550
+ /* #endregion */
485
551
 
486
- .mw-candidates__name {
487
- font-weight: 600;
488
- }
552
+ /* #region Candidate picker */
489
553
 
490
- .mw-candidates__meta {
491
- margin-left: auto;
492
- font-size: 0.8rem;
493
- color: var(--ifm-color-emphasis-600, #6e6e6e);
494
- }
554
+ .mw-candidates {
555
+ margin-top: 1rem;
556
+ }
495
557
 
496
- /* #endregion */
558
+ .mw-candidates h2 {
559
+ font-size: 1rem;
560
+ margin: 0 0 0.5rem;
561
+ }
497
562
 
498
- /* #region LoadingIndicator */
563
+ .mw-candidates__list {
564
+ list-style: none;
565
+ margin: 0;
566
+ padding: 0;
567
+ display: flex;
568
+ flex-direction: column;
569
+ gap: 0.35rem;
570
+ }
499
571
 
500
- .mw-loading {
501
- display: flex;
502
- flex-direction: column;
503
- align-items: center;
504
- justify-content: center;
505
- gap: 0.75rem;
506
- padding: 1.5rem;
507
- }
572
+ .mw-candidates__btn {
573
+ display: flex;
574
+ align-items: baseline;
575
+ gap: 0.6rem;
576
+ width: 100%;
577
+ text-align: left;
578
+ padding: 0.4rem 0.6rem;
579
+ border: 1px solid var(--color-separator);
580
+ border-radius: var(--radius-control);
581
+ background: var(--control-background);
582
+ color: var(--color-text-primary);
583
+ cursor: pointer;
584
+ font: inherit;
585
+ }
508
586
 
509
- .mw-loading__label {
510
- font-size: 0.85rem;
511
- color: var(--ifm-color-emphasis-600, #6e6e6e);
512
- font-family: var(--ifm-font-family-monospace, monospace);
513
- text-align: center;
514
- }
587
+ .mw-candidates__btn:hover:not(:disabled) {
588
+ background: var(--control-background-pressed);
589
+ border-color: var(--control-border);
590
+ }
515
591
 
516
- .mw-pulse {
517
- display: flex;
518
- flex-direction: column;
519
- gap: 0.5rem;
520
- width: 100%;
521
- max-width: 320px;
522
- }
592
+ .mw-candidates__btn:focus-visible {
593
+ outline: 2px solid var(--color-selection);
594
+ outline-offset: 1px;
595
+ }
523
596
 
524
- .mw-pulse__bar {
525
- height: 0.75rem;
526
- border-radius: 4px;
527
- background: var(--ifm-color-emphasis-200, #ebedf0);
528
- animation: mw-pulse-fade 1.4s ease-in-out infinite;
529
- }
597
+ .mw-candidates__btn--active {
598
+ border-color: var(--color-accent);
599
+ background: var(--color-accent-background);
600
+ }
530
601
 
531
- .mw-pulse__bar:nth-child(1) {
532
- animation-delay: 0s;
533
- }
534
- .mw-pulse__bar:nth-child(2) {
535
- animation-delay: 0.15s;
536
- }
537
- .mw-pulse__bar:nth-child(3) {
538
- animation-delay: 0.3s;
539
- }
540
- .mw-pulse__bar:nth-child(4) {
541
- animation-delay: 0.45s;
542
- }
543
- .mw-pulse__bar:nth-child(5) {
544
- animation-delay: 0.6s;
545
- }
546
- .mw-pulse__bar:nth-child(odd) {
547
- width: 100%;
548
- }
549
- .mw-pulse__bar:nth-child(even) {
550
- width: 72%;
551
- }
602
+ /* Tertiary, not translucent: an opacity here also fades the text under it toward the pane behind the sheet. */
603
+ .mw-candidates__rank {
604
+ font-family: var(--font-family-code);
605
+ font-size: var(--font-size-caption);
606
+ color: var(--color-text-tertiary);
607
+ }
552
608
 
553
- @keyframes mw-pulse-fade {
554
- 0%,
555
- 100% {
556
- opacity: 0.35;
609
+ .mw-candidates__name {
610
+ font-weight: 600;
557
611
  }
558
- 50% {
559
- opacity: 1;
612
+
613
+ .mw-candidates__meta {
614
+ margin-left: auto;
615
+ font-size: 0.8rem;
616
+ color: var(--color-text-secondary);
560
617
  }
561
- }
562
618
 
563
- .mw-spinner {
564
- width: 2rem;
565
- height: 2rem;
566
- border: 3px solid var(--ifm-color-emphasis-200, #ebedf0);
567
- border-top-color: var(--ifm-color-primary, #e0367c);
568
- border-radius: 50%;
569
- animation: mw-spin 0.7s linear infinite;
570
- }
619
+ /* #endregion */
571
620
 
572
- .mw-spinner--small {
573
- width: 1.25rem;
574
- height: 1.25rem;
575
- border-width: 2px;
576
- }
621
+ /* #region LoadingIndicator */
577
622
 
578
- .mw-spinner--large {
579
- width: 3rem;
580
- height: 3rem;
581
- border-width: 4px;
582
- }
623
+ .mw-loading {
624
+ display: flex;
625
+ flex-direction: column;
626
+ align-items: center;
627
+ justify-content: center;
628
+ gap: 0.75rem;
629
+ padding: 1.5rem;
630
+ }
583
631
 
584
- @keyframes mw-spin {
585
- to {
586
- transform: rotate(360deg);
632
+ .mw-loading__label {
633
+ font-size: 0.85rem;
634
+ color: var(--color-text-secondary);
635
+ font-family: var(--font-family-code);
636
+ text-align: center;
587
637
  }
588
- }
589
638
 
590
- .mw-staged {
591
- display: flex;
592
- flex-direction: column;
593
- gap: 0.5rem;
594
- width: 100%;
595
- max-width: 360px;
596
- list-style: none;
597
- margin: 0;
598
- padding: 0;
599
- }
639
+ .mw-pulse {
640
+ display: flex;
641
+ flex-direction: column;
642
+ gap: 0.5rem;
643
+ width: 100%;
644
+ max-width: 320px;
645
+ }
600
646
 
601
- .mw-staged__step {
602
- display: flex;
603
- align-items: center;
604
- gap: 0.6rem;
605
- padding: 0.4rem 0.6rem;
606
- border-radius: 4px;
607
- font-size: 0.85rem;
608
- transition:
609
- background 0.3s,
610
- color 0.3s;
611
- }
647
+ .mw-pulse__bar {
648
+ height: 0.75rem;
649
+ border-radius: 4px;
650
+ background: var(--color-background-sunken);
651
+ animation: mw-pulse-fade 1.4s ease-in-out infinite;
652
+ }
612
653
 
613
- .mw-staged__step--pending {
614
- color: var(--ifm-color-emphasis-500, #8c8c8c);
615
- }
654
+ .mw-pulse__bar:nth-child(1) {
655
+ animation-delay: 0s;
656
+ }
657
+ .mw-pulse__bar:nth-child(2) {
658
+ animation-delay: 0.15s;
659
+ }
660
+ .mw-pulse__bar:nth-child(3) {
661
+ animation-delay: 0.3s;
662
+ }
663
+ .mw-pulse__bar:nth-child(4) {
664
+ animation-delay: 0.45s;
665
+ }
666
+ .mw-pulse__bar:nth-child(5) {
667
+ animation-delay: 0.6s;
668
+ }
669
+ .mw-pulse__bar:nth-child(odd) {
670
+ width: 100%;
671
+ }
672
+ .mw-pulse__bar:nth-child(even) {
673
+ width: 72%;
674
+ }
616
675
 
617
- .mw-staged__step--active {
618
- color: var(--ifm-color-primary, #e0367c);
619
- background: color-mix(in srgb, var(--ifm-color-primary, #e0367c) 8%, transparent);
620
- font-weight: 600;
621
- }
676
+ @keyframes mw-pulse-fade {
677
+ 0%,
678
+ 100% {
679
+ opacity: 0.35;
680
+ }
681
+ 50% {
682
+ opacity: 1;
683
+ }
684
+ }
622
685
 
623
- .mw-staged__step--complete {
624
- color: var(--ifm-color-success, #1aa84d);
625
- }
686
+ .mw-spinner {
687
+ width: 2rem;
688
+ height: 2rem;
689
+ border: 3px solid var(--color-separator);
690
+ border-top-color: var(--color-accent);
691
+ border-radius: 50%;
692
+ animation: mw-spin 0.7s linear infinite;
693
+ }
626
694
 
627
- .mw-staged__icon {
628
- display: flex;
629
- align-items: center;
630
- justify-content: center;
631
- width: 1.25rem;
632
- height: 1.25rem;
633
- flex-shrink: 0;
634
- }
695
+ .mw-spinner--small {
696
+ width: 1.25rem;
697
+ height: 1.25rem;
698
+ border-width: 2px;
699
+ }
635
700
 
636
- .mw-staged__dot {
637
- width: 0.55rem;
638
- height: 0.55rem;
639
- border-radius: 50%;
640
- background: var(--ifm-color-primary, #e0367c);
641
- animation: mw-pulse-dot 1s ease-in-out infinite;
642
- }
701
+ .mw-spinner--large {
702
+ width: 3rem;
703
+ height: 3rem;
704
+ border-width: 4px;
705
+ }
643
706
 
644
- @keyframes mw-pulse-dot {
645
- 0%,
646
- 100% {
647
- opacity: 0.3;
648
- transform: scale(0.8);
707
+ @keyframes mw-spin {
708
+ to {
709
+ transform: rotate(360deg);
710
+ }
649
711
  }
650
- 50% {
651
- opacity: 1;
652
- transform: scale(1.2);
712
+
713
+ .mw-staged {
714
+ display: flex;
715
+ flex-direction: column;
716
+ gap: 0.5rem;
717
+ width: 100%;
718
+ max-width: 360px;
719
+ list-style: none;
720
+ margin: 0;
721
+ padding: 0;
653
722
  }
654
- }
655
723
 
656
- .mw-staged__check {
657
- width: 1rem;
658
- height: 1rem;
659
- position: relative;
660
- }
724
+ .mw-staged__step {
725
+ display: flex;
726
+ align-items: center;
727
+ gap: 0.6rem;
728
+ padding: 0.4rem 0.6rem;
729
+ border-radius: 4px;
730
+ font-size: 0.85rem;
731
+ transition:
732
+ background 0.3s,
733
+ color 0.3s;
734
+ }
661
735
 
662
- .mw-staged__check::before {
663
- content: "";
664
- position: absolute;
665
- top: 50%;
666
- left: 25%;
667
- width: 0.35rem;
668
- height: 0.65rem;
669
- border: solid var(--ifm-color-success, #1aa84d);
670
- border-width: 0 2px 2px 0;
671
- transform: translateY(-60%) rotate(45deg);
672
- }
736
+ .mw-staged__step--pending {
737
+ color: var(--color-text-tertiary);
738
+ }
673
739
 
674
- /* #endregion */
740
+ .mw-staged__step--active {
741
+ color: var(--color-accent);
742
+ background: color-mix(in srgb, var(--color-accent) 8%, transparent);
743
+ font-weight: 600;
744
+ }
675
745
 
676
- /* #region Demo map (react-map-gl/maplibre shell) */
746
+ .mw-staged__step--complete {
747
+ color: var(--color-state-success);
748
+ }
677
749
 
678
- /*
679
- * The <DemoMap> wrapper. Sizing is the host's call (pass `style`/`className`), but a min-height keeps
750
+ .mw-staged__icon {
751
+ display: flex;
752
+ align-items: center;
753
+ justify-content: center;
754
+ width: 1.25rem;
755
+ height: 1.25rem;
756
+ flex-shrink: 0;
757
+ }
758
+
759
+ .mw-staged__dot {
760
+ width: 0.55rem;
761
+ height: 0.55rem;
762
+ border-radius: 50%;
763
+ background: var(--color-accent);
764
+ animation: mw-pulse-dot 1s ease-in-out infinite;
765
+ }
766
+
767
+ @keyframes mw-pulse-dot {
768
+ 0%,
769
+ 100% {
770
+ opacity: 0.3;
771
+ transform: scale(0.8);
772
+ }
773
+ 50% {
774
+ opacity: 1;
775
+ transform: scale(1.2);
776
+ }
777
+ }
778
+
779
+ .mw-staged__check {
780
+ width: 1rem;
781
+ height: 1rem;
782
+ position: relative;
783
+ }
784
+
785
+ .mw-staged__check::before {
786
+ content: "";
787
+ position: absolute;
788
+ top: 50%;
789
+ left: 25%;
790
+ width: 0.35rem;
791
+ height: 0.65rem;
792
+ border: solid var(--color-state-success);
793
+ border-width: 0 2px 2px 0;
794
+ transform: translateY(-60%) rotate(45deg);
795
+ }
796
+
797
+ /* #endregion */
798
+
799
+ /* #region Demo map (react-map-gl/maplibre shell) */
800
+
801
+ /*
802
+ * The <MapCanvas> wrapper. Sizing is the host's call (pass `style`/`className`), but a min-height keeps
680
803
  * the map from collapsing to zero when a consumer forgets. The inner <Map> fills 100% of this box.
681
804
  * The host must ALSO import `maplibre-gl/dist/maplibre-gl.css` for the map's own control/canvas styles.
682
805
  */
683
- .mw-demo-map {
684
- position: relative;
685
- width: 100%;
686
- min-height: 320px;
687
- overflow: hidden;
688
- }
806
+ .mw-demo-map {
807
+ position: relative;
808
+ width: 100%;
809
+ min-height: 320px;
810
+ overflow: hidden;
811
+ }
689
812
 
690
- /*
813
+ /*
691
814
  * The demo fills its positioning context; the host sizes it (a full-viewport wrapper in docs). The map is the
692
815
  * background layer, the control panel floats over the top-left (bottom on narrow screens). A host that wants a
693
816
  * different layout can restyle these classes without touching the components.
694
817
  */
695
- .mw-geocoder-demo {
696
- position: relative;
697
- width: 100%;
698
- height: 100%;
699
- min-height: 480px;
700
- }
701
-
702
- .mw-geocoder-demo__map {
703
- position: absolute;
704
- inset: 0;
705
- }
818
+ .mw-geocoder-demo {
819
+ position: relative;
820
+ width: 100%;
821
+ height: 100%;
822
+ min-height: 480px;
823
+ }
706
824
 
707
- .mw-demo-controls {
708
- position: absolute;
709
- top: 1rem;
710
- left: 1rem;
711
- z-index: 2;
712
- width: min(360px, calc(100% - 2rem));
713
- max-height: calc(100% - 2rem);
714
- overflow-y: auto;
715
- padding: 1rem;
716
- border-radius: 10px;
717
- background: color-mix(in srgb, var(--ifm-background-surface-color, #fff) 92%, transparent);
718
- box-shadow: 0 2px 16px rgba(0, 0, 0, 0.18);
719
- font-size: 0.95rem;
720
- }
825
+ .mw-geocoder-demo__map {
826
+ position: absolute;
827
+ inset: 0;
828
+ }
721
829
 
722
- @media (max-width: 600px) {
723
830
  .mw-demo-controls {
724
- top: auto;
725
- bottom: 1rem;
831
+ position: absolute;
832
+ top: 1rem;
726
833
  left: 1rem;
727
- right: 1rem;
728
- width: auto;
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;
729
843
  }
730
- }
731
844
 
732
- /* #endregion */
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
+ }
733
854
 
734
- /* #region Demo control field (version / compare-version selects) */
855
+ /* #endregion */
735
856
 
736
- .mw-demo-control {
737
- margin-bottom: 0.75rem;
738
- }
857
+ /* #region Demo control field (version / compare-version selects) */
739
858
 
740
- .mw-demo-control__label {
741
- display: block;
742
- margin-bottom: 0.25rem;
743
- font-weight: 600;
744
- font-size: 0.9rem;
745
- }
859
+ .mw-demo-control {
860
+ display: grid;
861
+ gap: 0.3rem;
862
+ width: 100%;
863
+ }
746
864
 
747
- .mw-demo-control__select {
748
- width: 100%;
749
- padding: 0.4rem;
750
- font: inherit;
751
- border: 1px solid var(--ifm-color-emphasis-300, #d1d5db);
752
- border-radius: 6px;
753
- background: var(--ifm-background-surface-color, #fff);
754
- color: var(--ifm-font-color-base, inherit);
755
- }
865
+ .mw-demo-control__label {
866
+ display: block;
867
+ font-weight: var(--font-weight-medium);
868
+ font-size: var(--font-size-footnote);
869
+ color: var(--color-text-secondary);
870
+ }
756
871
 
757
- .mw-demo-control__select:disabled {
758
- opacity: 0.5;
759
- }
872
+ .mw-demo-control__select {
873
+ width: 100%;
874
+ padding: 0.4rem;
875
+ font: inherit;
876
+ border: 1px solid var(--control-border);
877
+ border-radius: 6px;
878
+ background: var(--color-background-raised);
879
+ color: var(--color-text-primary);
880
+ }
760
881
 
761
- /* #endregion */
882
+ .mw-demo-control__select:disabled {
883
+ opacity: 0.5;
884
+ }
762
885
 
763
- /* #region Backend indicator + WASM toggle / compare toggle */
886
+ /* #endregion */
764
887
 
765
- .mw-demo-backend,
766
- .mw-demo-compare {
767
- display: flex;
768
- align-items: center;
769
- gap: 0.75rem;
770
- flex-wrap: wrap;
771
- margin-bottom: 0.75rem;
772
- font-size: 0.85rem;
773
- }
888
+ /* #region Backend indicator + WASM toggle / compare toggle */
774
889
 
775
- .mw-demo-compare {
776
- display: block;
777
- }
890
+ /* Stacked, because both controls now sit in a sheet row where a label sits over its control, not beside it. */
891
+ .mw-demo-backend,
892
+ .mw-demo-compare {
893
+ display: grid;
894
+ gap: 0.35rem;
895
+ justify-items: start;
896
+ font-size: var(--font-size-footnote);
897
+ }
778
898
 
779
- .mw-demo-backend__active {
780
- opacity: 0.7;
781
- }
899
+ .mw-demo-backend__active {
900
+ color: var(--color-text-tertiary);
901
+ font-size: var(--font-size-caption);
902
+ }
782
903
 
783
- .mw-demo-backend__toggle,
784
- .mw-demo-compare__toggle {
785
- display: inline-flex;
786
- align-items: center;
787
- gap: 0.25rem;
788
- cursor: pointer;
789
- opacity: 0.8;
790
- }
904
+ .mw-demo-backend__toggle,
905
+ .mw-demo-compare__toggle {
906
+ display: inline-flex;
907
+ align-items: center;
908
+ gap: 0.5rem;
909
+ cursor: pointer;
910
+ }
791
911
 
792
- .mw-demo-compare__toggle {
793
- margin-bottom: 0.5rem;
794
- }
912
+ .mw-demo-compare__status {
913
+ margin: 0.25rem 0 0;
914
+ font-size: 0.8rem;
915
+ color: var(--color-text-secondary);
916
+ }
795
917
 
796
- .mw-demo-compare__status {
797
- margin: 0.25rem 0 0;
798
- font-size: 0.8rem;
799
- color: var(--ifm-color-emphasis-600, #6e6e6e);
800
- }
918
+ /* #endregion */
801
919
 
802
- /* #endregion */
920
+ /* #region Place autocomplete listbox (reuses .mw-chip) */
803
921
 
804
- /* #region Place autocomplete listbox (reuses .mw-chip) */
922
+ .mw-demo-suggest {
923
+ margin-top: 0.75rem;
924
+ display: flex;
925
+ flex-wrap: wrap;
926
+ gap: 0.4rem;
927
+ align-items: baseline;
928
+ }
805
929
 
806
- .mw-demo-suggest {
807
- margin-top: 0.75rem;
808
- display: flex;
809
- flex-wrap: wrap;
810
- gap: 0.4rem;
811
- align-items: baseline;
812
- }
930
+ .mw-demo-suggest__label {
931
+ font-size: 0.85rem;
932
+ color: var(--color-text-secondary);
933
+ margin-right: 0.25rem;
934
+ }
813
935
 
814
- .mw-demo-suggest__label {
815
- font-size: 0.85rem;
816
- color: var(--ifm-color-emphasis-600, #6e6e6e);
817
- margin-right: 0.25rem;
818
- }
936
+ .mw-chip--active {
937
+ outline: 2px solid var(--color-accent);
938
+ outline-offset: 1px;
939
+ }
940
+
941
+ /* #endregion */
942
+
943
+ /* #region Span ribbon (SpanHighlight) — each tagged span is a column: the text on top, tinted by tier, the tag beneath */
944
+
945
+ .mw-spans {
946
+ margin: 0.5rem 0 1rem 0;
947
+ }
948
+
949
+ .mw-spans__legend {
950
+ display: flex;
951
+ align-items: center;
952
+ gap: 0.35rem;
953
+ font-size: 0.7rem;
954
+ text-transform: uppercase;
955
+ letter-spacing: 0.04em;
956
+ color: var(--color-text-secondary);
957
+ margin-bottom: 0.5rem;
958
+ }
959
+
960
+ .mw-spans__swatch {
961
+ display: inline-block;
962
+ width: 0.8rem;
963
+ height: 0.8rem;
964
+ border-radius: 2px;
965
+ margin-left: 0.4rem;
966
+ }
967
+
968
+ .mw-spans__track {
969
+ display: flex;
970
+ flex-wrap: wrap;
971
+ align-items: flex-end;
972
+ row-gap: 1.5rem;
973
+ padding: 0.5rem 0.6rem;
974
+ border: 1px solid var(--color-separator);
975
+ border-radius: 6px;
976
+ background: var(--color-background-raised);
977
+ font-family: var(--font-family-code);
978
+ font-size: 0.9rem;
979
+ line-height: 1.4;
980
+ }
981
+
982
+ .mw-spans__seg {
983
+ display: inline-flex;
984
+ flex-direction: column;
985
+ align-items: stretch;
986
+ }
987
+
988
+ .mw-spans__text {
989
+ padding: 0.05rem 0.1rem;
990
+ border-bottom: 2px solid transparent;
991
+ white-space: pre;
992
+ }
993
+
994
+ .mw-spans__tag {
995
+ margin-top: 0.15rem;
996
+ font-size: 0.6rem;
997
+ line-height: 1;
998
+ text-align: center;
999
+ letter-spacing: 0.02em;
1000
+ color: var(--color-text-secondary);
1001
+ white-space: nowrap;
1002
+ }
1003
+
1004
+ .mw-spans__gap {
1005
+ display: inline-flex;
1006
+ align-items: flex-start;
1007
+ white-space: pre;
1008
+ color: var(--color-text-tertiary);
1009
+ }
1010
+
1011
+ /* The tier tints match .mw-conf__bar--high/--mid/--low. */
1012
+ .mw-spans__seg--high .mw-spans__text {
1013
+ background: rgba(26, 168, 77, 0.18);
1014
+ border-bottom-color: #1aa84d;
1015
+ }
1016
+
1017
+ .mw-spans__seg--mid .mw-spans__text {
1018
+ background: rgba(230, 168, 0, 0.18);
1019
+ border-bottom-color: #e6a800;
1020
+ }
1021
+
1022
+ .mw-spans__seg--low .mw-spans__text {
1023
+ background: rgba(216, 80, 74, 0.18);
1024
+ border-bottom-color: #d8504a;
1025
+ }
1026
+
1027
+ .mw-spans__swatch--high {
1028
+ background: #1aa84d;
1029
+ }
1030
+
1031
+ .mw-spans__swatch--mid {
1032
+ background: #e6a800;
1033
+ }
1034
+
1035
+ .mw-spans__swatch--low {
1036
+ background: #d8504a;
1037
+ }
1038
+
1039
+ /* #endregion */
1040
+
1041
+ /* #region Stage timing (TimingPanel) — a stacked bar by wall-clock, stage hues, never the confidence colours */
1042
+
1043
+ .mw-timing {
1044
+ margin: 1rem 0;
1045
+ font-size: 0.8rem;
1046
+ }
1047
+
1048
+ .mw-timing__heading {
1049
+ display: flex;
1050
+ align-items: baseline;
1051
+ justify-content: space-between;
1052
+ text-transform: uppercase;
1053
+ letter-spacing: 0.05em;
1054
+ color: var(--color-text-secondary);
1055
+ margin-bottom: 0.35rem;
1056
+ }
1057
+
1058
+ .mw-timing__total {
1059
+ font-family: var(--font-family-code);
1060
+ text-transform: none;
1061
+ letter-spacing: 0;
1062
+ color: var(--color-text-secondary);
1063
+ }
1064
+
1065
+ .mw-timing__bar {
1066
+ display: flex;
1067
+ width: 100%;
1068
+ height: 0.7rem;
1069
+ border-radius: 4px;
1070
+ overflow: hidden;
1071
+ background: var(--color-background-sunken);
1072
+ }
1073
+
1074
+ .mw-timing__seg {
1075
+ height: 100%;
1076
+ }
1077
+
1078
+ .mw-timing__legend {
1079
+ display: flex;
1080
+ flex-wrap: wrap;
1081
+ gap: 0.25rem 1rem;
1082
+ margin-top: 0.4rem;
1083
+ color: var(--color-text-secondary);
1084
+ }
1085
+
1086
+ .mw-timing__item {
1087
+ display: inline-flex;
1088
+ align-items: center;
1089
+ gap: 0.35rem;
1090
+ }
1091
+
1092
+ .mw-timing__ms {
1093
+ font-family: var(--font-family-code);
1094
+ color: var(--color-text-secondary);
1095
+ }
1096
+
1097
+ .mw-timing__swatch {
1098
+ display: inline-block;
1099
+ width: 0.7rem;
1100
+ height: 0.7rem;
1101
+ border-radius: 2px;
1102
+ }
1103
+
1104
+ .mw-timing__seg--shape {
1105
+ background: #3578e5;
1106
+ }
1107
+
1108
+ .mw-timing__seg--classify {
1109
+ background: #8b5cf6;
1110
+ }
1111
+
1112
+ .mw-timing__seg--resolve {
1113
+ background: #14b8a6;
1114
+ }
1115
+
1116
+ /* #endregion */
1117
+
1118
+ /* #region Containment tree (TreeView) — nested lists with a guide rail per level */
1119
+
1120
+ .mw-tree {
1121
+ margin: 0.5rem 0 0 0;
1122
+ }
1123
+
1124
+ .mw-tree__children {
1125
+ list-style: none;
1126
+ margin: 0;
1127
+ padding-left: 1.1rem;
1128
+ }
1129
+
1130
+ /* Nested levels get a guide rail; the outermost list sits flush. */
1131
+ .mw-tree__children .mw-tree__children {
1132
+ border-left: 1px solid var(--control-border);
1133
+ margin-left: 0.3rem;
1134
+ }
1135
+
1136
+ .mw-tree__node {
1137
+ margin: 0.15rem 0;
1138
+ }
1139
+
1140
+ .mw-tree__row {
1141
+ display: inline-flex;
1142
+ align-items: baseline;
1143
+ gap: 0.5rem;
1144
+ font-size: 0.85rem;
1145
+ }
1146
+
1147
+ .mw-tree__tag {
1148
+ font-weight: 600;
1149
+ padding: 0 0.3rem;
1150
+ border-radius: 3px;
1151
+ border-bottom: 2px solid transparent;
1152
+ }
1153
+
1154
+ .mw-tree__value {
1155
+ font-family: var(--font-family-code);
1156
+ }
1157
+
1158
+ .mw-tree__conf {
1159
+ font-family: var(--font-family-code);
1160
+ font-size: 0.75rem;
1161
+ color: var(--color-text-secondary);
1162
+ }
1163
+
1164
+ .mw-tree__tag--high {
1165
+ background: rgba(26, 168, 77, 0.18);
1166
+ border-bottom-color: #1aa84d;
1167
+ }
1168
+
1169
+ .mw-tree__tag--mid {
1170
+ background: rgba(230, 168, 0, 0.18);
1171
+ border-bottom-color: #e6a800;
1172
+ }
1173
+
1174
+ .mw-tree__tag--low {
1175
+ background: rgba(216, 80, 74, 0.18);
1176
+ border-bottom-color: #d8504a;
1177
+ }
1178
+
1179
+ /* #endregion */
1180
+
1181
+ /* #region No-hit diagnostic (FailureDiagnostic) — a structured panel, tinted informational rather than red */
1182
+
1183
+ .mw-failure {
1184
+ margin-top: 1rem;
1185
+ padding: 0.75rem 1rem;
1186
+ background: var(--color-state-warning-background);
1187
+ border-left: 3px solid var(--color-state-warning);
1188
+ border-radius: 4px;
1189
+ }
1190
+
1191
+ .mw-failure h2 {
1192
+ font-size: 1rem;
1193
+ margin: 0 0 0.5rem 0;
1194
+ text-transform: uppercase;
1195
+ letter-spacing: 0.05em;
1196
+ color: var(--color-state-warning);
1197
+ }
1198
+
1199
+ .mw-failure ul {
1200
+ margin: 0;
1201
+ padding-left: 1.25rem;
1202
+ font-size: 0.875rem;
1203
+ color: var(--color-text-primary);
1204
+ }
1205
+
1206
+ .mw-failure li + li {
1207
+ margin-top: 0.35rem;
1208
+ }
1209
+
1210
+ /* #endregion */
1211
+
1212
+ /* #region About box (About) — the collapsible product explainer */
1213
+
1214
+ .mw-about {
1215
+ margin-bottom: 1rem;
1216
+ border: 1px solid var(--control-border);
1217
+ border-radius: 8px;
1218
+ background: var(--color-background-raised);
1219
+ font-size: 0.9rem;
1220
+ }
1221
+
1222
+ .mw-about[open] {
1223
+ background: var(--color-background-canvas);
1224
+ }
1225
+
1226
+ .mw-about__summary {
1227
+ padding: 0.65rem 0.75rem;
1228
+ cursor: pointer;
1229
+ user-select: none;
1230
+ font-weight: 600;
1231
+ display: flex;
1232
+ align-items: center;
1233
+ gap: 0.35rem;
1234
+ border-radius: 8px;
1235
+ }
1236
+
1237
+ .mw-about__summary:hover {
1238
+ background: var(--control-background);
1239
+ }
1240
+
1241
+ .mw-about__icon {
1242
+ font-size: 1.1rem;
1243
+ opacity: 0.7;
1244
+ }
1245
+
1246
+ .mw-about__body {
1247
+ padding: 0 0.75rem 0.75rem;
1248
+ }
1249
+
1250
+ .mw-about__section {
1251
+ margin-top: 0.75rem;
1252
+ }
1253
+
1254
+ .mw-about__section:first-child {
1255
+ margin-top: 0;
1256
+ }
1257
+
1258
+ .mw-about__heading {
1259
+ font-size: 0.9rem;
1260
+ font-weight: 700;
1261
+ margin: 0 0 0.3rem;
1262
+ color: var(--color-text-primary);
1263
+ }
1264
+
1265
+ .mw-about__section p {
1266
+ margin: 0;
1267
+ line-height: 1.6;
1268
+ color: var(--color-text-secondary);
1269
+ }
1270
+
1271
+ .mw-about__section code {
1272
+ font-size: 0.85rem;
1273
+ padding: 0.1rem 0.3rem;
1274
+ background: var(--color-background-sunken);
1275
+ border-radius: 3px;
1276
+ }
1277
+
1278
+ .mw-about__legend {
1279
+ list-style: none;
1280
+ margin: 0.5rem 0 0;
1281
+ padding: 0;
1282
+ display: flex;
1283
+ flex-direction: column;
1284
+ gap: 0.35rem;
1285
+ }
1286
+
1287
+ .mw-about__item {
1288
+ display: flex;
1289
+ align-items: center;
1290
+ gap: 0.4rem;
1291
+ font-size: 0.85rem;
1292
+ }
1293
+
1294
+ .mw-about__swatch {
1295
+ flex-shrink: 0;
1296
+ width: 10px;
1297
+ height: 10px;
1298
+ border-radius: 2px;
1299
+ }
1300
+
1301
+ .mw-about__swatch--high {
1302
+ background: #22c55e;
1303
+ }
1304
+
1305
+ .mw-about__swatch--mid {
1306
+ background: #f59e0b;
1307
+ }
1308
+
1309
+ .mw-about__swatch--low {
1310
+ background: #ef4444;
1311
+ }
1312
+
1313
+ /* #endregion */
1314
+
1315
+ /* #region Developer disclosure */
1316
+
1317
+ /*
1318
+ * The expert set lives here, below the result rather than above the address field. A hairline and a quieter
1319
+ * summary keep it legible without competing with the query, which is what the panel is for.
1320
+ */
1321
+ .mw-demo-developer {
1322
+ margin-top: 1rem;
1323
+ padding-top: 0.75rem;
1324
+ border-top: 1px solid var(--color-separator);
1325
+ }
1326
+
1327
+ .mw-demo-developer > summary {
1328
+ cursor: pointer;
1329
+ user-select: none;
1330
+ font-size: var(--font-size-footnote);
1331
+ font-weight: var(--font-weight-medium);
1332
+ color: var(--color-text-secondary);
1333
+ letter-spacing: 0.02em;
1334
+ text-transform: uppercase;
1335
+ }
1336
+
1337
+ .mw-demo-developer > summary:hover {
1338
+ color: var(--color-text-primary);
1339
+ }
1340
+
1341
+ .mw-demo-developer[open] > summary {
1342
+ margin-bottom: 0.75rem;
1343
+ }
1344
+
1345
+ /* #endregion */
1346
+
1347
+ /* #region Chrome layout — where the floating pieces sit over a map */
1348
+
1349
+ /*
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.
1353
+ */
1354
+ .mw-map-chrome--top {
1355
+ position: absolute;
1356
+ top: calc(1rem + var(--safe-area-top));
1357
+ left: calc(1rem + var(--safe-area-left));
1358
+ right: calc(1rem + var(--safe-area-right));
1359
+ z-index: 3;
1360
+ display: grid;
1361
+ gap: 0.5rem;
1362
+ justify-items: stretch;
1363
+ max-width: 34rem;
1364
+ pointer-events: none;
1365
+ }
1366
+
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;
1370
+ }
1371
+
1372
+ .mw-map-chrome__search {
1373
+ margin: 0;
1374
+ }
1375
+
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;
1384
+ }
1385
+
1386
+ /*
1387
+ * A sheet: the glass surface a result or a panel arrives on. The bottom one rises over the map's lower edge with
1388
+ * a drag handle, the side one sits under the control column it belongs to.
1389
+ */
1390
+ .mw-map-sheet {
1391
+ position: absolute;
1392
+ z-index: 3;
1393
+ /*
1394
+ * `max-height` measures the CONTENT box by default, so a sheet with 1rem of padding stood 34px taller than its
1395
+ * cap and ran past the bottom of the screen. Every height here is meant as the whole box.
1396
+ */
1397
+ box-sizing: border-box;
1398
+ box-shadow: var(--material-glass-shadow);
1399
+ overflow: auto;
1400
+ overscroll-behavior: contain;
1401
+ }
1402
+
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
+ /*
1414
+ * BESIDE the control column, not below it. Opening below meant the sheet's top depended on how many controls the
1415
+ * capsule held, and every app that added one covered the button that opened it. Beside, it clears the column
1416
+ * whatever it holds: 2.5rem of control plus its inset and a gap.
1417
+ */
1418
+ .mw-map-sheet--side {
1419
+ top: calc(1rem + var(--safe-area-top));
1420
+ right: calc(4rem + var(--safe-area-right));
1421
+ width: min(24rem, calc(100vw - 6rem));
1422
+ /*
1423
+ * Measured against the VIEWPORT, not the containing block: the map wrapper is taller than the window on a page
1424
+ * that scrolls, and a percentage there let the sheet run past the bottom of the screen.
1425
+ */
1426
+ max-height: calc(100dvh - 2rem - var(--map-footer-height) - var(--safe-area-top) - var(--safe-area-bottom));
1427
+ padding: 1rem;
1428
+ 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;
1431
+ }
1432
+
1433
+ /*
1434
+ * A sheet's own furniture: a title, then rows separated by hairlines, then the small print. Without these a sheet
1435
+ * is a stack of raw form controls behind glass, which reads as a debug panel rather than as part of the app.
1436
+ */
1437
+ /*
1438
+ * The title and its close button ride together and stay put while the body scrolls. The close is not decoration:
1439
+ * on a phone the sheet is the whole panel and covers the control that opened it, so this is the only way out.
1440
+ */
1441
+ .mw-map-sheet__header {
1442
+ position: sticky;
1443
+ top: 0;
1444
+ z-index: 1;
1445
+ display: flex;
1446
+ align-items: center;
1447
+ justify-content: space-between;
1448
+ gap: 1rem;
1449
+ margin: -1rem -1rem 0.75rem;
1450
+ padding: 0.75rem 1rem;
1451
+ background: var(--material-glass-fallback-background);
1452
+ border-bottom: 1px solid var(--color-separator);
1453
+ }
1454
+
1455
+ .mw-map-sheet__title {
1456
+ margin: 0;
1457
+ font-family: var(--font-family-display);
1458
+ font-size: var(--font-size-headline);
1459
+ font-weight: var(--font-weight-semibold);
1460
+ color: var(--color-text-primary);
1461
+ }
1462
+
1463
+ .mw-map-sheet__close {
1464
+ display: flex;
1465
+ align-items: center;
1466
+ justify-content: center;
1467
+ flex: 0 0 auto;
1468
+ width: 1.75rem;
1469
+ height: 1.75rem;
1470
+ font-size: 1.15rem;
1471
+ line-height: 1;
1472
+ color: var(--color-text-secondary);
1473
+ background: transparent;
1474
+ border: 0;
1475
+ border-radius: var(--radius-pill);
1476
+ cursor: pointer;
1477
+ }
1478
+
1479
+ .mw-map-sheet__close:hover {
1480
+ color: var(--color-text-primary);
1481
+ background: var(--control-background);
1482
+ }
1483
+
1484
+ .mw-map-sheet__close:focus-visible {
1485
+ outline: 2px solid var(--color-selection);
1486
+ outline-offset: 1px;
1487
+ }
1488
+
1489
+ .mw-map-sheet__row {
1490
+ display: grid;
1491
+ gap: 0.3rem;
1492
+ padding: 0.7rem 0;
1493
+ border-top: 1px solid var(--color-separator);
1494
+ }
1495
+
1496
+ .mw-map-sheet__row:first-of-type {
1497
+ border-top: 0;
1498
+ padding-top: 0;
1499
+ }
1500
+
1501
+ .mw-map-sheet__label {
1502
+ font-size: var(--font-size-footnote);
1503
+ font-weight: var(--font-weight-medium);
1504
+ color: var(--color-text-secondary);
1505
+ }
1506
+
1507
+ .mw-map-sheet__hint {
1508
+ margin: 0;
1509
+ font-size: var(--font-size-caption);
1510
+ color: var(--color-text-tertiary);
1511
+ }
1512
+
1513
+ /* An intro paragraph is not a row, so it carries its own space before the first hairline. */
1514
+ .mw-map-sheet > .mw-map-sheet__hint {
1515
+ margin-bottom: 0.75rem;
1516
+ }
1517
+
1518
+ /* 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. */
1519
+ .mw-map-sheet__row code {
1520
+ font-family: var(--font-family-code);
1521
+ font-size: var(--font-size-footnote);
1522
+ color: var(--color-text-primary);
1523
+ }
1524
+
1525
+ /* A checkbox and its words are one target, and the words sit beside the box rather than under it. */
1526
+ .mw-map-sheet__check {
1527
+ display: flex;
1528
+ align-items: baseline;
1529
+ gap: 0.5rem;
1530
+ cursor: pointer;
1531
+ font-size: var(--font-size-footnote);
1532
+ color: var(--color-text-primary);
1533
+ }
1534
+
1535
+ .mw-map-sheet__check input[type="checkbox"] {
1536
+ margin: 0;
1537
+ accent-color: var(--color-accent);
1538
+ cursor: pointer;
1539
+ }
1540
+
1541
+ /* Every form control in a sheet takes the app's type and the control palette, never the browser's defaults. */
1542
+ .mw-map-sheet select,
1543
+ .mw-map-sheet input[type="text"],
1544
+ .mw-map-sheet input[type="search"] {
1545
+ width: 100%;
1546
+ box-sizing: border-box;
1547
+ padding: 0.4rem 0.55rem;
1548
+ font: inherit;
1549
+ font-size: var(--font-size-footnote);
1550
+ color: var(--control-foreground);
1551
+ background: var(--control-background);
1552
+ border: 1px solid var(--control-border);
1553
+ border-radius: var(--radius-control);
1554
+ }
1555
+
1556
+ .mw-map-sheet select:focus-visible,
1557
+ .mw-map-sheet input:focus-visible {
1558
+ outline: 2px solid var(--color-selection);
1559
+ outline-offset: 1px;
1560
+ }
1561
+
1562
+ /* The grab affordance the reference sheets carry. Decorative: the sheet scrolls, it does not drag. */
1563
+ .mw-map-sheet__handle {
1564
+ width: 2.25rem;
1565
+ height: 0.25rem;
1566
+ margin: 0 auto 0.6rem;
1567
+ border-radius: var(--radius-pill);
1568
+ background: var(--color-separator);
1569
+ }
1570
+
1571
+ .mw-map-sheet__actions {
1572
+ margin-top: 0.75rem;
1573
+ display: flex;
1574
+ justify-content: flex-end;
1575
+ }
1576
+
1577
+ /*
1578
+ * On a phone the chrome spans the width and the sheet becomes a true bottom sheet against the edge, which is what
1579
+ * leaves the map its full height.
1580
+ */
1581
+ /*
1582
+ * The phone layout. The map keeps the whole screen and every floating piece is measured against the footer strip,
1583
+ * whose height is `--map-footer-height` plus the safe-area inset: a sheet that ends at the screen's edge hides its
1584
+ * own last rows behind the credits.
1585
+ *
1586
+ * A RESULT is a bottom sheet, because it answers the query in the field above it and both stay in view. A SIDE
1587
+ * sheet is the whole panel, because it is a different task — layers, settings, the explainer — and a phone has no
1588
+ * room to hold it beside anything. That also settles the overlap: the panel covers the result rather than sharing
1589
+ * an edge with it.
1590
+ */
1591
+ @media (max-width: 600px) {
1592
+ /*
1593
+ * The column spans the width, so it has to stop short of the control capsule in the same corner — 2.5rem of
1594
+ * control plus its 1rem inset plus a 0.5rem gap. Without this the capsule sits on the search pill's clear
1595
+ * button, which is the one control at that end of the pill.
1596
+ */
1597
+ .mw-map-chrome--top {
1598
+ max-width: none;
1599
+ right: calc(4rem + var(--safe-area-right));
1600
+ }
1601
+
1602
+ .mw-map-sheet--bottom {
1603
+ left: 0;
1604
+ right: 0;
1605
+ bottom: calc(var(--map-footer-height) + var(--safe-area-bottom));
1606
+ max-width: none;
1607
+ max-height: 55dvh;
1608
+ border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
1609
+ border-inline: 0;
1610
+ border-bottom: 0;
1611
+ padding-bottom: 1rem;
1612
+ }
1613
+
1614
+ .mw-map-sheet--side {
1615
+ top: 0;
1616
+ left: 0;
1617
+ right: 0;
1618
+ bottom: calc(var(--map-footer-height) + var(--safe-area-bottom));
1619
+ width: auto;
1620
+ max-width: none;
1621
+ max-height: none;
1622
+ border-radius: 0;
1623
+ border: 0;
1624
+ padding: calc(1rem + var(--safe-area-top)) 1rem 1rem;
1625
+ }
1626
+
1627
+ /* The chips take the full width on a phone, so the fade has less to hide behind. */
1628
+ .mw-map-chiprow {
1629
+ -webkit-mask-image: linear-gradient(to right, black calc(100% - 1.25rem), transparent);
1630
+ mask-image: linear-gradient(to right, black calc(100% - 1.25rem), transparent);
1631
+ }
1632
+
1633
+ /* The header spans the panel's full width once the sheet loses its own inset. */
1634
+ .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));
1637
+ }
1638
+ }
1639
+
1640
+ /* #endregion */
1641
+
1642
+ /* #region Map chrome */
1643
+
1644
+ /*
1645
+ * The floating controls over a map: a search pill on top, example chips beneath it, a control column down one
1646
+ * edge, a footer along the bottom. Each is a glass material composed from tokens, and each carries the opaque
1647
+ * fallback below — no control depends on `backdrop-filter` to stay readable.
1648
+ */
1649
+
1650
+ /*
1651
+ * EVERY glass surface is listed here, and the two fallback blocks at the end of this region repeat exactly this
1652
+ * list. Composing the material at each component instead left the sheets and the sources popover out of both
1653
+ * fallbacks, so a viewer who asked for reduced transparency still got a translucent panel.
1654
+ */
1655
+ .mw-map-searchbar,
1656
+ .mw-map-chip,
1657
+ .mw-map-control-group,
1658
+ .mw-map-footer,
1659
+ .mw-map-footer__popover,
1660
+ .mw-map-sheet {
1661
+ background: var(--material-glass-background);
1662
+ border: 1px solid var(--material-glass-border);
1663
+ /*
1664
+ * PREFIXED FIRST, STANDARD LAST. The minifier collapses two declarations carrying the same value and keeps the
1665
+ * last one; written the other way round the shipped rule had `-webkit-backdrop-filter` alone, so every glass
1666
+ * surface lost its blur on Firefox, which implements the standard property and not the alias.
1667
+ */
1668
+ -webkit-backdrop-filter: blur(var(--material-glass-blur)) saturate(var(--material-glass-saturation));
1669
+ backdrop-filter: blur(var(--material-glass-blur)) saturate(var(--material-glass-saturation));
1670
+ color: var(--color-text-primary);
1671
+ }
1672
+
1673
+ .mw-map-searchbar {
1674
+ display: flex;
1675
+ align-items: center;
1676
+ gap: 0.5rem;
1677
+ padding: 0.4rem 0.75rem;
1678
+ border-radius: var(--radius-pill);
1679
+ box-shadow: var(--material-glass-shadow);
1680
+ }
1681
+
1682
+ .mw-map-searchbar__field {
1683
+ flex: 1;
1684
+ min-width: 0;
1685
+ }
1686
+
1687
+ /*
1688
+ * Busy is a hairline along the pill's lower edge, inside its radius. It is drawn on a pseudo-element so it costs
1689
+ * no layout — a spinner in a slot changed the pill's height on every submit, which moved the field under the
1690
+ * pointer.
1691
+ */
1692
+ .mw-map-searchbar {
1693
+ position: relative;
1694
+ overflow: hidden;
1695
+ }
1696
+
1697
+ .mw-map-searchbar--busy::after {
1698
+ content: "";
1699
+ position: absolute;
1700
+ left: 0;
1701
+ right: 0;
1702
+ bottom: 0;
1703
+ height: 2px;
1704
+ background: var(--color-accent);
1705
+ transform-origin: left center;
1706
+ animation: mw-map-searchbar-sweep 1.1s var(--easing-standard) infinite;
1707
+ }
1708
+
1709
+ @keyframes mw-map-searchbar-sweep {
1710
+ 0% {
1711
+ transform: scaleX(0);
1712
+ transform-origin: left center;
1713
+ }
1714
+
1715
+ 50% {
1716
+ transform: scaleX(1);
1717
+ transform-origin: left center;
1718
+ }
1719
+
1720
+ 51% {
1721
+ transform: scaleX(1);
1722
+ transform-origin: right center;
1723
+ }
1724
+
1725
+ 100% {
1726
+ transform: scaleX(0);
1727
+ transform-origin: right center;
1728
+ }
1729
+ }
1730
+
1731
+ /*
1732
+ * The native clear button of `input[type="search"]`. Its COLOUR is the user agent's, decided by the document's
1733
+ * `color-scheme` — nothing here repaints it. Only the two things the scheme does not say are stated: that it is a
1734
+ * pointer target, and that it sits back until the field is under the pointer or holding focus.
1735
+ */
1736
+ .mw-map-searchbar input[type="search"]::-webkit-search-cancel-button {
1737
+ cursor: pointer;
1738
+ opacity: 0.55;
1739
+ }
1740
+
1741
+ .mw-map-searchbar input[type="search"]:hover::-webkit-search-cancel-button,
1742
+ .mw-map-searchbar input[type="search"]:focus::-webkit-search-cancel-button {
1743
+ opacity: 1;
1744
+ }
1745
+
1746
+ /* The host's input carries no chrome of its own — the pill is the chrome. */
1747
+ .mw-map-searchbar__field input {
1748
+ width: 100%;
1749
+ border: 0;
1750
+ outline: 0;
1751
+ background: transparent;
1752
+ color: inherit;
1753
+ font: inherit;
1754
+ padding: 0.25rem 0;
1755
+ }
1756
+
1757
+ .mw-map-searchbar:focus-within {
1758
+ outline: 2px solid var(--color-selection);
1759
+ outline-offset: 2px;
1760
+ }
1761
+
1762
+ /* The glyph face draws its control marks small, so a leading or trailing mark is sized up to the field's own weight. */
1763
+ .mw-map-searchbar__slot {
1764
+ display: inline-flex;
1765
+ align-items: center;
1766
+ color: var(--color-text-secondary);
1767
+ font-family: var(--font-family-glyph);
1768
+ font-size: 1.15rem;
1769
+ line-height: 1;
1770
+ }
1771
+
1772
+ /*
1773
+ * One line that scrolls, never a wrap. The scrollbar is hidden because the row sits over a map where a track
1774
+ * would read as chrome; the row stays reachable by keyboard through its buttons.
1775
+ */
1776
+ .mw-map-chiprow {
1777
+ display: flex;
1778
+ gap: 0.4rem;
1779
+ overflow-x: auto;
1780
+ scrollbar-width: none;
1781
+ padding: 0.15rem;
1782
+ scroll-padding-inline: 0.15rem;
1783
+ /* With the track hidden, a chip clipped at the edge reads as broken; the fade is what says the row scrolls. */
1784
+ -webkit-mask-image: linear-gradient(to right, black calc(100% - 2rem), transparent);
1785
+ mask-image: linear-gradient(to right, black calc(100% - 2rem), transparent);
1786
+ }
1787
+
1788
+ .mw-map-chiprow::-webkit-scrollbar {
1789
+ display: none;
1790
+ }
1791
+
1792
+ .mw-map-chip {
1793
+ flex: 0 0 auto;
1794
+ display: inline-flex;
1795
+ align-items: center;
1796
+ gap: 0.35rem;
1797
+ padding: 0.35rem 0.7rem;
1798
+ border-radius: var(--radius-pill);
1799
+ font-size: var(--font-size-footnote);
1800
+ font-weight: var(--font-weight-medium);
1801
+ white-space: nowrap;
1802
+ cursor: pointer;
1803
+ }
1804
+
1805
+ .mw-map-chip:hover:not(:disabled) {
1806
+ background: var(--material-glass-fallback-background);
1807
+ border-color: var(--control-border);
1808
+ }
1809
+
1810
+ .mw-map-chip:focus-visible {
1811
+ outline: 2px solid var(--color-selection);
1812
+ outline-offset: 1px;
1813
+ }
1814
+
1815
+ /* A chip that carries a state reports it through `aria-pressed`, so the accent follows the attribute, not a class. */
1816
+ .mw-map-chip--active,
1817
+ .mw-map-chip[aria-pressed="true"] {
1818
+ border-color: var(--color-accent);
1819
+ color: var(--color-accent);
1820
+ }
1821
+
1822
+ .mw-map-chip:disabled {
1823
+ opacity: 0.5;
1824
+ cursor: not-allowed;
1825
+ }
1826
+
1827
+ .mw-map-chip__icon {
1828
+ display: inline-flex;
1829
+ font-family: var(--font-family-glyph);
1830
+ }
1831
+
1832
+ .mw-map-control-stack {
1833
+ position: absolute;
1834
+ top: calc(1rem + var(--safe-area-top));
1835
+ display: flex;
1836
+ flex-direction: column;
1837
+ gap: 0.6rem;
1838
+ z-index: 4;
1839
+ }
1840
+
1841
+ /*
1842
+ * The compass capsule collapses to nothing while the compass is hidden, so the capsules below it do not sit under
1843
+ * a gap the map shows through. `visibility` alone kept the box.
1844
+ */
1845
+ .mw-map-control-group--compass:has(.mw-map-compass--north) {
1846
+ box-shadow: none;
1847
+ border-color: transparent;
1848
+ background: transparent;
1849
+ -webkit-backdrop-filter: none;
1850
+ backdrop-filter: none;
1851
+ }
1852
+
1853
+ .mw-map-control-stack--right {
1854
+ right: calc(1rem + var(--safe-area-right));
1855
+ }
1856
+
1857
+ .mw-map-control-stack--left {
1858
+ left: calc(1rem + var(--safe-area-left));
1859
+ }
1860
+
1861
+ /* A capsule: related controls read as one object, divided by hairlines rather than gaps. */
1862
+ .mw-map-control-group {
1863
+ display: flex;
1864
+ flex-direction: column;
1865
+ border-radius: var(--radius-control);
1866
+ overflow: hidden;
1867
+ box-shadow: var(--material-glass-shadow);
1868
+ }
1869
+
1870
+ .mw-map-control-group > * + * {
1871
+ border-top: 1px solid var(--material-glass-border);
1872
+ }
1873
+
1874
+ .mw-map-control {
1875
+ display: flex;
1876
+ align-items: center;
1877
+ justify-content: center;
1878
+ width: 2.5rem;
1879
+ height: 2.5rem;
1880
+ border: 0;
1881
+ background: transparent;
1882
+ color: var(--color-text-primary);
1883
+ font-family: var(--font-family-glyph);
1884
+ cursor: pointer;
1885
+ }
1886
+
1887
+ .mw-map-control:hover:not(:disabled) {
1888
+ background: var(--control-background);
1889
+ }
1890
+
1891
+ .mw-map-control:active:not(:disabled) {
1892
+ background: var(--control-background-pressed);
1893
+ }
1894
+
1895
+ .mw-map-control--active {
1896
+ color: var(--color-accent);
1897
+ }
1898
+
1899
+ .mw-map-control:disabled {
1900
+ opacity: 0.4;
1901
+ cursor: not-allowed;
1902
+ }
1903
+
1904
+ /*
1905
+ * The compass keeps its box while invisible so the capsules above it do not shift as the map rotates.
1906
+ * `visibility` rather than `display` is what lets the opacity transition run at all.
1907
+ */
1908
+ /*
1909
+ * The compass sits INSIDE a control capsule like the other controls, so it carries no material of its own — the
1910
+ * capsule supplies the glass, and a second background here would read as a button on a button.
1911
+ */
1912
+ .mw-map-compass {
1913
+ display: flex;
1914
+ align-items: center;
1915
+ justify-content: center;
1916
+ width: 2.5rem;
1917
+ height: 2.5rem;
1918
+ border: 0;
1919
+ background: transparent;
1920
+ color: var(--color-text-primary);
1921
+ cursor: pointer;
1922
+ opacity: 1;
1923
+ visibility: visible;
1924
+ transition:
1925
+ opacity var(--duration-standard) var(--easing-standard),
1926
+ visibility 0s linear 0s;
1927
+ }
1928
+
1929
+ .mw-map-compass:hover:not(:disabled) {
1930
+ background: var(--control-background);
1931
+ }
1932
+
1933
+ .mw-map-compass:active:not(:disabled) {
1934
+ background: var(--control-background-pressed);
1935
+ }
1936
+
1937
+ .mw-map-compass:focus-visible {
1938
+ outline: 2px solid var(--color-selection);
1939
+ outline-offset: -2px;
1940
+ }
1941
+
1942
+ /* The dial: a ring, not a disc — the map has to stay readable through the middle of the control. */
1943
+ .mw-map-compass__dial {
1944
+ fill: none;
1945
+ stroke: var(--color-separator);
1946
+ stroke-width: 1.5;
1947
+ }
1948
+
1949
+ /* Red north, pale south. Two tones are what say which end points north without the reader knowing a convention. */
1950
+ .mw-map-compass__north {
1951
+ fill: var(--color-state-danger);
1952
+ }
1953
+
1954
+ .mw-map-compass__south {
1955
+ fill: var(--color-text-tertiary);
1956
+ }
1957
+
1958
+ /*
1959
+ * Invisible, and out of the way: `visibility: hidden` keeps the element in flow, so without the pointer rule a
1960
+ * compass nobody can see still swallows every click on the map beneath it.
1961
+ */
1962
+ .mw-map-compass--north {
1963
+ opacity: 0;
1964
+ visibility: hidden;
1965
+ pointer-events: none;
1966
+ transition:
1967
+ opacity var(--duration-standard) var(--easing-standard),
1968
+ visibility 0s linear var(--duration-standard);
1969
+ }
1970
+
1971
+ /*
1972
+ * One line, always. Wrapping was the alternative and it grew the strip to three lines on a phone, where it then
1973
+ * covered the bottom sheet's last rows — the credits are the least important thing on the screen and must never
1974
+ * take height from the thing a visitor asked for. Long credits scroll instead.
1975
+ */
1976
+ /*
1977
+ * THE STRIP ITSELF DOES NOT CLIP. A non-visible overflow on one axis makes the other clip as well, so an
1978
+ * `overflow-x` here erased the sources popover outright — it is positioned above the strip, entirely outside the
1979
+ * box that would have been doing the clipping. The scroll belongs to the identity region, which is the part
1980
+ * carrying text long enough to need one.
1981
+ */
1982
+ .mw-map-footer {
1983
+ display: flex;
1984
+ align-items: center;
1985
+ justify-content: space-between;
1986
+ gap: 1rem;
1987
+ flex-wrap: nowrap;
1988
+ white-space: nowrap;
1989
+ box-sizing: content-box;
1990
+ height: var(--map-footer-height);
1991
+ padding: 0 0.75rem;
1992
+ padding-bottom: var(--safe-area-bottom);
1993
+ border-radius: 0;
1994
+ border-inline: 0;
1995
+ border-bottom: 0;
1996
+ font-size: var(--font-size-caption);
1997
+ color: var(--color-text-secondary);
1998
+ }
1999
+
2000
+ /* Identity, then whatever is loading. The status is where the loader says WHAT; the bar on top says how far. */
2001
+ .mw-map-footer__identity {
2002
+ flex: 1 1 auto;
2003
+ min-width: 0;
2004
+ display: flex;
2005
+ align-items: baseline;
2006
+ gap: 0.6rem;
2007
+ overflow-x: auto;
2008
+ scrollbar-width: none;
2009
+ }
2010
+
2011
+ .mw-map-footer__identity::-webkit-scrollbar {
2012
+ display: none;
2013
+ }
2014
+
2015
+ .mw-map-footer__status {
2016
+ min-width: 0;
2017
+ overflow: hidden;
2018
+ text-overflow: ellipsis;
2019
+ color: var(--color-text-tertiary);
2020
+ }
2021
+
2022
+ .mw-map-footer__sources {
2023
+ position: relative;
2024
+ flex: 0 0 auto;
2025
+ }
2026
+
2027
+ .mw-map-footer__attribution-button {
2028
+ padding: 0.1rem 0.5rem;
2029
+ font: inherit;
2030
+ color: var(--color-text-secondary);
2031
+ background: transparent;
2032
+ border: 1px solid transparent;
2033
+ border-radius: var(--radius-pill);
2034
+ cursor: pointer;
2035
+ }
2036
+
2037
+ .mw-map-footer__attribution-button:hover,
2038
+ .mw-map-footer__attribution-button[aria-expanded="true"] {
2039
+ color: var(--color-text-primary);
2040
+ background: var(--control-background);
2041
+ border-color: var(--control-border);
2042
+ }
2043
+
2044
+ .mw-map-footer__attribution-button:focus-visible {
2045
+ outline: 2px solid var(--color-selection);
2046
+ outline-offset: 1px;
2047
+ }
2048
+
2049
+ /* The credits open UPWARD from the strip, because the strip is already against the bottom of the viewport. */
2050
+ .mw-map-footer__popover {
2051
+ position: absolute;
2052
+ right: 0;
2053
+ bottom: calc(100% + 0.4rem);
2054
+ z-index: 1;
2055
+ display: grid;
2056
+ gap: 0.25rem;
2057
+ min-width: max-content;
2058
+ max-width: min(22rem, calc(100vw - 2rem));
2059
+ padding: 0.6rem 0.8rem;
2060
+ white-space: normal;
2061
+ text-align: right;
2062
+ box-shadow: var(--material-glass-shadow);
2063
+ border-radius: var(--radius-panel);
2064
+ color: var(--color-text-secondary);
2065
+ }
2066
+
2067
+ /* #region Loading */
2068
+
2069
+ /*
2070
+ * The bundle-load bar, pinned across the top of the viewport. It reports at the page's edge because loading the
2071
+ * model is a page-level event: in the search field it resized the control being typed into, and in the result
2072
+ * sheet it held open a panel that had no answer in it yet.
2073
+ */
2074
+ .mw-map-progress {
2075
+ position: fixed;
2076
+ top: 0;
2077
+ left: 0;
2078
+ right: 0;
2079
+ z-index: 10;
2080
+ height: 3px;
2081
+ overflow: hidden;
2082
+ background: var(--control-background);
2083
+ opacity: 1;
2084
+ transition: opacity var(--duration-standard) var(--easing-standard);
2085
+ }
2086
+
2087
+ .mw-map-progress--idle {
2088
+ opacity: 0;
2089
+ pointer-events: none;
2090
+ }
2091
+
2092
+ .mw-map-progress__fill {
2093
+ height: 100%;
2094
+ background: var(--color-accent);
2095
+ transform: scaleX(0);
2096
+ transform-origin: left center;
2097
+ transition: transform var(--duration-standard) var(--easing-decelerate);
2098
+ }
2099
+
2100
+ /* Work whose length is unknown sweeps rather than filling, so the bar never invents a percentage. */
2101
+ .mw-map-progress__fill--indeterminate {
2102
+ width: 35%;
2103
+ transform: none;
2104
+ animation: mw-map-progress-sweep 1.4s var(--easing-standard) infinite;
2105
+ }
2106
+
2107
+ @keyframes mw-map-progress-sweep {
2108
+ from {
2109
+ margin-left: -35%;
2110
+ }
2111
+
2112
+ to {
2113
+ margin-left: 100%;
2114
+ }
2115
+ }
2116
+
2117
+ /* #endregion */
2118
+
2119
+ @media (prefers-reduced-motion: reduce) {
2120
+ .mw-map-compass,
2121
+ .mw-map-compass--north {
2122
+ transition: none;
2123
+ }
2124
+ }
2125
+
2126
+ /*
2127
+ * Where the blur cannot run, or the viewer has asked for less transparency, every material becomes opaque.
2128
+ * Text contrast holds in all three states; the glass is never what makes a control legible.
2129
+ */
2130
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
2131
+ .mw-map-searchbar,
2132
+ .mw-map-chip,
2133
+ .mw-map-control-group,
2134
+ .mw-map-footer,
2135
+ .mw-map-footer__popover,
2136
+ .mw-map-sheet {
2137
+ background: var(--material-glass-fallback-background);
2138
+ }
2139
+ }
2140
+
2141
+ @media (prefers-reduced-transparency: reduce) {
2142
+ .mw-map-searchbar,
2143
+ .mw-map-chip,
2144
+ .mw-map-control-group,
2145
+ .mw-map-footer,
2146
+ .mw-map-footer__popover,
2147
+ .mw-map-sheet {
2148
+ background: var(--material-glass-fallback-background);
2149
+ -webkit-backdrop-filter: none;
2150
+ backdrop-filter: none;
2151
+ }
2152
+ }
819
2153
 
820
- .mw-chip--active {
821
- outline: 2px solid var(--ifm-color-primary, #e0367c);
822
- outline-offset: 1px;
2154
+ /* #endregion */
823
2155
  }