@mailwoman/react 9.4.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.
- package/lib/common/About.tsx +87 -71
- package/lib/common/index.ts +22 -0
- package/lib/index.ts +4 -99
- package/lib/map/BackendControl.tsx +7 -3
- package/lib/map/CompareToggle.tsx +3 -2
- package/lib/map/Geocoder.tsx +48 -28
- package/lib/map/GeocoderControls.tsx +258 -99
- package/lib/map/MapChipRow.tsx +77 -0
- package/lib/map/MapCompass.tsx +77 -0
- package/lib/map/MapControlStack.tsx +98 -0
- package/lib/map/MapFooter.tsx +115 -0
- package/lib/map/MapProgressBar.tsx +58 -0
- package/lib/map/MapSearchBar.tsx +68 -0
- package/lib/map/MapSheet.tsx +62 -0
- package/lib/map/index.ts +19 -0
- package/lib/map/types.ts +18 -4
- package/lib/map/useMapBearing.ts +56 -0
- package/lib/map/useMapLabelPick.ts +123 -0
- package/lib/pipeline/index.ts +36 -0
- package/lib/pipeline/useParsePipeline.ts +29 -18
- package/lib/poi/index.ts +39 -0
- package/lib/runtime/index.ts +16 -0
- package/out/common/About.d.ts +13 -4
- package/out/common/About.d.ts.map +1 -1
- package/out/common/About.js +5 -2
- package/out/common/About.js.map +1 -1
- package/out/common/index.d.ts +22 -0
- package/out/common/index.d.ts.map +1 -0
- package/out/common/index.js +15 -0
- package/out/common/index.js.map +1 -0
- package/out/index.d.ts +4 -59
- package/out/index.d.ts.map +1 -1
- package/out/index.js +4 -36
- package/out/index.js.map +1 -1
- package/out/map/BackendControl.d.ts.map +1 -1
- package/out/map/BackendControl.js +1 -1
- package/out/map/BackendControl.js.map +1 -1
- package/out/map/CompareToggle.d.ts.map +1 -1
- package/out/map/CompareToggle.js +1 -1
- package/out/map/CompareToggle.js.map +1 -1
- package/out/map/Geocoder.d.ts +11 -1
- package/out/map/Geocoder.d.ts.map +1 -1
- package/out/map/Geocoder.js +26 -26
- package/out/map/Geocoder.js.map +1 -1
- package/out/map/GeocoderControls.d.ts +29 -11
- package/out/map/GeocoderControls.d.ts.map +1 -1
- package/out/map/GeocoderControls.js +65 -16
- package/out/map/GeocoderControls.js.map +1 -1
- package/out/map/MapChipRow.d.ts +47 -0
- package/out/map/MapChipRow.d.ts.map +1 -0
- package/out/map/MapChipRow.js +12 -0
- package/out/map/MapChipRow.js.map +1 -0
- package/out/map/MapCompass.d.ts +42 -0
- package/out/map/MapCompass.d.ts.map +1 -0
- package/out/map/MapCompass.js +11 -0
- package/out/map/MapCompass.js.map +1 -0
- package/out/map/MapControlStack.d.ts +57 -0
- package/out/map/MapControlStack.d.ts.map +1 -0
- package/out/map/MapControlStack.js +15 -0
- package/out/map/MapControlStack.js.map +1 -0
- package/out/map/MapFooter.d.ts +40 -0
- package/out/map/MapFooter.d.ts.map +1 -0
- package/out/map/MapFooter.js +51 -0
- package/out/map/MapFooter.js.map +1 -0
- package/out/map/MapProgressBar.d.ts +34 -0
- package/out/map/MapProgressBar.d.ts.map +1 -0
- package/out/map/MapProgressBar.js +8 -0
- package/out/map/MapProgressBar.js.map +1 -0
- package/out/map/MapSearchBar.d.ts +49 -0
- package/out/map/MapSearchBar.d.ts.map +1 -0
- package/out/map/MapSearchBar.js +6 -0
- package/out/map/MapSearchBar.js.map +1 -0
- package/out/map/MapSheet.d.ts +32 -0
- package/out/map/MapSheet.d.ts.map +1 -0
- package/out/map/MapSheet.js +33 -0
- package/out/map/MapSheet.js.map +1 -0
- package/out/map/OverlayLayers.js +1 -1
- package/out/map/ResolvedPlaceLayers.js +1 -1
- package/out/map/ResultPanel.js +1 -1
- package/out/map/fake-runtime.js.map +1 -1
- package/out/map/index.d.ts +17 -0
- package/out/map/index.d.ts.map +1 -1
- package/out/map/index.js +10 -0
- package/out/map/index.js.map +1 -1
- package/out/map/map-debug.d.ts.map +1 -1
- package/out/map/map-debug.js.map +1 -1
- package/out/map/types.d.ts +20 -4
- package/out/map/types.d.ts.map +1 -1
- package/out/map/useMapBearing.d.ts +28 -0
- package/out/map/useMapBearing.d.ts.map +1 -0
- package/out/map/useMapBearing.js +35 -0
- package/out/map/useMapBearing.js.map +1 -0
- package/out/map/useMapLabelPick.d.ts +23 -0
- package/out/map/useMapLabelPick.d.ts.map +1 -0
- package/out/map/useMapLabelPick.js +104 -0
- package/out/map/useMapLabelPick.js.map +1 -0
- package/out/pipeline/CandidatePicker.js +1 -1
- package/out/pipeline/PipelineExplorer.js +1 -1
- package/out/pipeline/QueryForm.js +1 -1
- package/out/pipeline/ResolvedPlace.js +1 -1
- package/out/pipeline/TimingPanel.js +1 -1
- package/out/pipeline/index.d.ts +33 -0
- package/out/pipeline/index.d.ts.map +1 -0
- package/out/pipeline/index.js +21 -0
- package/out/pipeline/index.js.map +1 -0
- package/out/pipeline/useParsePipeline.d.ts +5 -2
- package/out/pipeline/useParsePipeline.d.ts.map +1 -1
- package/out/pipeline/useParsePipeline.js +6 -2
- package/out/pipeline/useParsePipeline.js.map +1 -1
- package/out/poi/LiveResultsBlock.js +1 -1
- package/out/poi/POIExplorer.js +1 -1
- package/out/poi/SubjectPanel.js +1 -1
- package/out/poi/index.d.ts +23 -0
- package/out/poi/index.d.ts.map +1 -0
- package/out/poi/index.js +15 -0
- package/out/poi/index.js.map +1 -0
- package/out/poi/runtime.d.ts.map +1 -1
- package/out/runtime/index.d.ts +9 -0
- package/out/runtime/index.d.ts.map +1 -0
- package/out/runtime/index.js +8 -0
- package/out/runtime/index.js.map +1 -0
- package/package.json +87 -6
- package/styleframe.config.ts +9 -1
- package/styles.css +948 -26
- package/tokens/index.css +2 -1
- package/tokens/tokens.json +7 -0
- package/tokens/tokens.resolver.json +1 -1
package/styles.css
CHANGED
|
@@ -29,7 +29,39 @@
|
|
|
29
29
|
*/
|
|
30
30
|
@import url("./tokens/index.css") layer(tokens);
|
|
31
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
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
32
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
|
+
}
|
|
60
|
+
|
|
61
|
+
:root[data-theme="light"] {
|
|
62
|
+
color-scheme: light;
|
|
63
|
+
}
|
|
64
|
+
|
|
33
65
|
/*
|
|
34
66
|
* Form controls do not inherit the document's font. Left alone, a `<button>` renders in the user agent's default
|
|
35
67
|
* — measured as Arial on the deployed Earth app, beside a body in system-ui and labels in ui-monospace, which is
|
|
@@ -43,6 +75,27 @@
|
|
|
43
75
|
font-size: inherit;
|
|
44
76
|
line-height: inherit;
|
|
45
77
|
}
|
|
78
|
+
|
|
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
|
+
}
|
|
87
|
+
|
|
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
|
+
}
|
|
46
99
|
}
|
|
47
100
|
|
|
48
101
|
@layer components {
|
|
@@ -101,12 +154,33 @@
|
|
|
101
154
|
|
|
102
155
|
/* #region Preset chips */
|
|
103
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
|
+
*/
|
|
104
163
|
.mw-presets {
|
|
105
164
|
margin-top: 0.75rem;
|
|
106
165
|
display: flex;
|
|
107
|
-
flex-wrap:
|
|
166
|
+
flex-wrap: nowrap;
|
|
167
|
+
overflow-x: auto;
|
|
168
|
+
scrollbar-width: none;
|
|
108
169
|
gap: 0.4rem;
|
|
109
170
|
align-items: baseline;
|
|
171
|
+
padding-bottom: 0.15rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.mw-presets::-webkit-scrollbar {
|
|
175
|
+
display: none;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.mw-presets > * {
|
|
179
|
+
flex: 0 0 auto;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.mw-chip {
|
|
183
|
+
white-space: nowrap;
|
|
110
184
|
}
|
|
111
185
|
|
|
112
186
|
.mw-presets__label {
|
|
@@ -503,21 +577,33 @@
|
|
|
503
577
|
text-align: left;
|
|
504
578
|
padding: 0.4rem 0.6rem;
|
|
505
579
|
border: 1px solid var(--color-separator);
|
|
506
|
-
border-radius:
|
|
507
|
-
background:
|
|
580
|
+
border-radius: var(--radius-control);
|
|
581
|
+
background: var(--control-background);
|
|
582
|
+
color: var(--color-text-primary);
|
|
508
583
|
cursor: pointer;
|
|
509
584
|
font: inherit;
|
|
510
585
|
}
|
|
511
586
|
|
|
587
|
+
.mw-candidates__btn:hover:not(:disabled) {
|
|
588
|
+
background: var(--control-background-pressed);
|
|
589
|
+
border-color: var(--control-border);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.mw-candidates__btn:focus-visible {
|
|
593
|
+
outline: 2px solid var(--color-selection);
|
|
594
|
+
outline-offset: 1px;
|
|
595
|
+
}
|
|
596
|
+
|
|
512
597
|
.mw-candidates__btn--active {
|
|
513
598
|
border-color: var(--color-accent);
|
|
514
599
|
background: var(--color-accent-background);
|
|
515
600
|
}
|
|
516
601
|
|
|
602
|
+
/* Tertiary, not translucent: an opacity here also fades the text under it toward the pane behind the sheet. */
|
|
517
603
|
.mw-candidates__rank {
|
|
518
604
|
font-family: var(--font-family-code);
|
|
519
|
-
font-size:
|
|
520
|
-
|
|
605
|
+
font-size: var(--font-size-caption);
|
|
606
|
+
color: var(--color-text-tertiary);
|
|
521
607
|
}
|
|
522
608
|
|
|
523
609
|
.mw-candidates__name {
|
|
@@ -771,14 +857,16 @@
|
|
|
771
857
|
/* #region Demo control field (version / compare-version selects) */
|
|
772
858
|
|
|
773
859
|
.mw-demo-control {
|
|
774
|
-
|
|
860
|
+
display: grid;
|
|
861
|
+
gap: 0.3rem;
|
|
862
|
+
width: 100%;
|
|
775
863
|
}
|
|
776
864
|
|
|
777
865
|
.mw-demo-control__label {
|
|
778
866
|
display: block;
|
|
779
|
-
|
|
780
|
-
font-
|
|
781
|
-
|
|
867
|
+
font-weight: var(--font-weight-medium);
|
|
868
|
+
font-size: var(--font-size-footnote);
|
|
869
|
+
color: var(--color-text-secondary);
|
|
782
870
|
}
|
|
783
871
|
|
|
784
872
|
.mw-demo-control__select {
|
|
@@ -799,35 +887,26 @@
|
|
|
799
887
|
|
|
800
888
|
/* #region Backend indicator + WASM toggle / compare toggle */
|
|
801
889
|
|
|
890
|
+
/* Stacked, because both controls now sit in a sheet row where a label sits over its control, not beside it. */
|
|
802
891
|
.mw-demo-backend,
|
|
803
892
|
.mw-demo-compare {
|
|
804
|
-
display:
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
margin-bottom: 0.75rem;
|
|
809
|
-
font-size: 0.85rem;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
.mw-demo-compare {
|
|
813
|
-
display: block;
|
|
893
|
+
display: grid;
|
|
894
|
+
gap: 0.35rem;
|
|
895
|
+
justify-items: start;
|
|
896
|
+
font-size: var(--font-size-footnote);
|
|
814
897
|
}
|
|
815
898
|
|
|
816
899
|
.mw-demo-backend__active {
|
|
817
|
-
|
|
900
|
+
color: var(--color-text-tertiary);
|
|
901
|
+
font-size: var(--font-size-caption);
|
|
818
902
|
}
|
|
819
903
|
|
|
820
904
|
.mw-demo-backend__toggle,
|
|
821
905
|
.mw-demo-compare__toggle {
|
|
822
906
|
display: inline-flex;
|
|
823
907
|
align-items: center;
|
|
824
|
-
gap: 0.
|
|
908
|
+
gap: 0.5rem;
|
|
825
909
|
cursor: pointer;
|
|
826
|
-
opacity: 0.8;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
.mw-demo-compare__toggle {
|
|
830
|
-
margin-bottom: 0.5rem;
|
|
831
910
|
}
|
|
832
911
|
|
|
833
912
|
.mw-demo-compare__status {
|
|
@@ -1230,4 +1309,847 @@
|
|
|
1230
1309
|
.mw-about__swatch--low {
|
|
1231
1310
|
background: #ef4444;
|
|
1232
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
|
+
}
|
|
2153
|
+
|
|
2154
|
+
/* #endregion */
|
|
1233
2155
|
}
|