@junoput01/junoui 0.2.0 → 0.4.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/CHANGELOG.md +251 -0
- package/README.md +23 -19
- package/dist/css/juno-custom-media.css +32 -0
- package/dist/css/juno.css +1355 -40
- package/dist/icons/inline.js +22 -0
- package/docs/accessibility.md +188 -0
- package/docs/boot-shell.md +295 -0
- package/docs/components/README.md +71 -0
- package/docs/components/accordion.md +49 -0
- package/docs/components/alert.md +46 -0
- package/docs/components/avatar.md +45 -0
- package/docs/components/badge.md +35 -0
- package/docs/components/breadcrumb.md +31 -0
- package/docs/components/button.md +32 -0
- package/docs/components/card.md +41 -0
- package/docs/components/checkbox.md +41 -0
- package/docs/components/chip.md +44 -0
- package/docs/components/divider.md +32 -0
- package/docs/components/dock.md +215 -0
- package/docs/components/drawer.md +100 -0
- package/docs/components/field.md +44 -0
- package/docs/components/fold-slot.md +31 -0
- package/docs/components/gauge.md +48 -0
- package/docs/components/icon-loader.md +122 -0
- package/docs/components/icon.md +70 -0
- package/docs/components/input.md +45 -0
- package/docs/components/list.md +76 -0
- package/docs/components/load-state.md +131 -0
- package/docs/components/loader.md +88 -0
- package/docs/components/menu.md +54 -0
- package/docs/components/modal.md +52 -0
- package/docs/components/navbar.md +53 -0
- package/docs/components/pagination.md +42 -0
- package/docs/components/pillbar.md +211 -0
- package/docs/components/popover.md +43 -0
- package/docs/components/rail.md +54 -0
- package/docs/components/readout.md +39 -0
- package/docs/components/reload.md +41 -0
- package/docs/components/segmented.md +46 -0
- package/docs/components/select.md +33 -0
- package/docs/components/skeleton.md +45 -0
- package/docs/components/slider.md +48 -0
- package/docs/components/spark.md +51 -0
- package/docs/components/status.md +30 -0
- package/docs/components/stepper.md +46 -0
- package/docs/components/switch.md +38 -0
- package/docs/components/table.md +126 -0
- package/docs/components/tabs.md +61 -0
- package/docs/components/thumb.md +81 -0
- package/docs/components/toast.md +48 -0
- package/docs/components/toggle-button.md +40 -0
- package/docs/components/tooltip.md +63 -0
- package/docs/design-guidelines.md +173 -0
- package/docs/flutter.md +42 -0
- package/docs/getting-started.md +93 -0
- package/docs/integration.md +95 -0
- package/docs/ios-conformance.md +224 -0
- package/docs/layout.md +271 -0
- package/docs/native.md +52 -0
- package/docs/roadmap.md +106 -0
- package/docs/tokens-reference.md +223 -0
- package/docs/web.md +95 -0
- package/package.json +7 -3
- package/src/css/base.css +171 -1
- package/src/css/components/dock.css +335 -0
- package/src/css/components/drawer.css +40 -3
- package/src/css/components/fold-slot.css +44 -0
- package/src/css/components/icon-loader.css +67 -0
- package/src/css/components/icon.css +6 -4
- package/src/css/components/load-state.css +136 -0
- package/src/css/components/loader.css +6 -0
- package/src/css/components/menu.css +4 -0
- package/src/css/components/modal.css +24 -3
- package/src/css/components/navbar.css +5 -1
- package/src/css/components/pillbar.css +222 -7
- package/src/css/components/rail.css +8 -0
- package/src/css/components/reload.css +48 -0
- package/src/css/components/skeleton.css +41 -13
- package/src/css/components/tabs.css +5 -0
- package/src/css/components/thumb.css +63 -1
- package/src/css/components/toast.css +5 -1
- package/src/css/density.css +22 -0
- package/src/css/layout.css +95 -5
- package/src/css/utilities.css +4 -1
package/docs/web.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Web (CSS / SCSS / JS)
|
|
2
|
+
|
|
3
|
+
## CSS — the fast path
|
|
4
|
+
|
|
5
|
+
Import the full stylesheet (tokens + base + utilities + components):
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import '@junoput01/junoui/css'; // bundler
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
@import '@junoput01/junoui/css'; /* plain CSS */
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Set the theme with two attributes on `<html>`:
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<html data-juno-palette="standard" data-juno-mode="dark"></html>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Both are optional. **Omit `data-juno-mode` and the theme follows the OS**
|
|
22
|
+
(`prefers-color-scheme`, live — no JS): dark systems get dark, light systems
|
|
23
|
+
light, in whichever palette is set (default `standard`). The base layer also
|
|
24
|
+
sets `color-scheme` so scrollbars and native form chrome match. An explicit
|
|
25
|
+
`data-juno-mode` pins the mode and ignores the OS.
|
|
26
|
+
|
|
27
|
+
Other system preferences honored out of the box: `prefers-reduced-motion`
|
|
28
|
+
(animations collapse), `prefers-contrast: more` (hairlines step up to the
|
|
29
|
+
strong border), `prefers-reduced-transparency` (translucent surfaces go
|
|
30
|
+
solid), `forced-colors` (system palette). Language is the app's job — junoui
|
|
31
|
+
ships no strings and is RTL-safe via logical properties; set `lang`/`dir` and
|
|
32
|
+
the layout follows.
|
|
33
|
+
|
|
34
|
+
Switch at runtime:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
document.documentElement.dataset.junoPalette = 'colorblind';
|
|
38
|
+
document.documentElement.dataset.junoMode = 'light';
|
|
39
|
+
delete document.documentElement.dataset.junoMode; // back to following the OS
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use semantic variables and component classes:
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<span class="juno-badge juno--warning">WARNING</span>
|
|
46
|
+
|
|
47
|
+
<div style="color: var(--juno-nominal); padding: var(--juno-space-16);">…</div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Want variables only (bring your own components)? Import `@junoput01/junoui/css/tokens`.
|
|
51
|
+
|
|
52
|
+
## SCSS
|
|
53
|
+
|
|
54
|
+
```scss
|
|
55
|
+
@use '@junoput01/junoui/scss' as juno; // $juno-color-standard-dark-nominal, $juno-space-16, …
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
All variables are `!default`, so you can override before `@use` if you fork values.
|
|
59
|
+
|
|
60
|
+
## JS / TS
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { TOKENS, CORE, getTokens } from '@junoput01/junoui';
|
|
64
|
+
|
|
65
|
+
getTokens('colorblind', 'light').warning; // "#BA4300"
|
|
66
|
+
TOKENS.standard.dark.nominal; // "oklch(73% 0.22 148)"
|
|
67
|
+
CORE.space['16']; // "16px"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Types ship with the package (`JunoPalette`, `JunoMode`, `JunoRole`, `JunoTheme`).
|
|
71
|
+
|
|
72
|
+
## Semantic vs explicit variables
|
|
73
|
+
|
|
74
|
+
- **Semantic** `--juno-nominal` … resolve to the _current_ theme. Use these in components.
|
|
75
|
+
- **Explicit** values for a specific theme live in SCSS/JS as
|
|
76
|
+
`…-standard-dark-nominal`. Use only when you need a fixed theme regardless of context.
|
|
77
|
+
|
|
78
|
+
## Fonts
|
|
79
|
+
|
|
80
|
+
junoui **never fetches fonts** (a cross-origin `@import` would break a strict CSP and
|
|
81
|
+
phone home). `base.css` names B612 / B612 Mono via `--juno-font-family-*` but doesn't
|
|
82
|
+
load them. Two options:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
import '@junoput01/junoui/fonts.css'; // opt-in: self-hosted B612 woff2, no network (CSP-safe)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
…or bring your own B612 (e.g. `@fontsource/b612`). Without either, the UI falls back to
|
|
89
|
+
system sans/mono. See [integration.md](./integration.md#2-fonts-opt-in-csp-safe).
|
|
90
|
+
|
|
91
|
+
## Boot performance
|
|
92
|
+
|
|
93
|
+
An app that wants chrome on screen at the first HTML parse — before `juno.css`
|
|
94
|
+
or any bundle arrives — and everything else loaded in the background follows
|
|
95
|
+
the boot-shell ladder: [boot-shell.md](./boot-shell.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@junoput01/junoui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "junoui — a token-driven design system. Color carries semantic meaning, never decoration: every hue has one assigned role (NOMINAL / ACTIVE / TARGET / CAUTION / WARNING). Ships multi-platform tokens (CSS, SCSS, JS/TS, JSON, Android, iOS, Flutter) plus a framework-agnostic CSS component layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "git
|
|
14
|
+
"url": "git+https://github.com/junoput/junoui.git"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"design-system",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"module": "./dist/js/tokens.js",
|
|
30
30
|
"types": "./dist/js/tokens.d.ts",
|
|
31
31
|
"sideEffects": [
|
|
32
|
-
"**/*.css"
|
|
32
|
+
"**/*.css",
|
|
33
|
+
"./dist/icons/inline.js"
|
|
33
34
|
],
|
|
34
35
|
"exports": {
|
|
35
36
|
".": {
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
},
|
|
40
41
|
"./css": "./dist/css/juno.css",
|
|
41
42
|
"./css/tokens": "./dist/css/juno-tokens.css",
|
|
43
|
+
"./css/custom-media": "./dist/css/juno-custom-media.css",
|
|
42
44
|
"./fonts.css": "./dist/css/juno-fonts.css",
|
|
43
45
|
"./scss": "./dist/scss/_juno-tokens.scss",
|
|
44
46
|
"./tokens.json": "./dist/json/tokens.json",
|
|
@@ -47,6 +49,7 @@
|
|
|
47
49
|
"./ios": "./dist/ios/JunoTokens.swift",
|
|
48
50
|
"./flutter": "./dist/flutter/juno_tokens.dart",
|
|
49
51
|
"./icons": "./dist/icons/juno-icons.svg",
|
|
52
|
+
"./icons/inline": "./dist/icons/inline.js",
|
|
50
53
|
"./package.json": "./package.json"
|
|
51
54
|
},
|
|
52
55
|
"files": [
|
|
@@ -54,6 +57,7 @@
|
|
|
54
57
|
"src/css",
|
|
55
58
|
"src/icons",
|
|
56
59
|
"src/fonts",
|
|
60
|
+
"docs",
|
|
57
61
|
"README.md",
|
|
58
62
|
"CHANGELOG.md"
|
|
59
63
|
],
|
package/src/css/base.css
CHANGED
|
@@ -13,7 +13,37 @@
|
|
|
13
13
|
/* System color scheme. Without data-juno-mode the theme follows the OS
|
|
14
14
|
(`prefers-color-scheme`; see juno-tokens.css) — `dark light` here lets the
|
|
15
15
|
UA pick matching scrollbars/form chrome. An explicit mode pins both. */
|
|
16
|
-
:root {
|
|
16
|
+
:root {
|
|
17
|
+
color-scheme: dark light;
|
|
18
|
+
|
|
19
|
+
/* Floating-nav scroll clearance — a page/scroller that a fixed dock or
|
|
20
|
+
pillbar floats over reserves this much room at its foot so the last row
|
|
21
|
+
clears the overlay. Consumers write `padding-block-end:
|
|
22
|
+
var(--juno-dock-clearance)` and stay correct when the dock geometry
|
|
23
|
+
changes — no hand-rolled calc() per app. Web-only (they carry env()), so
|
|
24
|
+
they live in the CSS layer, not the cross-platform token set.
|
|
25
|
+
--juno-dock-clearance ≈ pill height + bottom margin + breathing room;
|
|
26
|
+
--juno-pillbar-clearance suits the shorter centered pill. */
|
|
27
|
+
--juno-dock-clearance: calc(var(--juno-space-72) + var(--juno-space-20) + env(safe-area-inset-bottom, 0px));
|
|
28
|
+
--juno-pillbar-clearance: calc(var(--juno-space-72) + env(safe-area-inset-bottom, 0px));
|
|
29
|
+
|
|
30
|
+
/* JS-readable motion contract. CSS-only `prefers-reduced-motion` never reaches
|
|
31
|
+
imperative JS (scrollTo/scrollIntoView smooth behavior, rAF-driven transforms,
|
|
32
|
+
an "animate or not" branch) — so the preference is also exposed as a custom
|
|
33
|
+
property script can read with one getComputedStyle call, no matchMedia
|
|
34
|
+
listener required for a one-shot check:
|
|
35
|
+
getComputedStyle(document.documentElement)
|
|
36
|
+
.getPropertyValue('--juno-motion').trim() !== 'none'
|
|
37
|
+
A component MAY author its durations through the scale rather than a raw
|
|
38
|
+
duration token — `calc(var(--juno-motion-duration-base) * var(--juno-motion-scale))`
|
|
39
|
+
— so the reduced-motion override below collapses them to 0 without its own
|
|
40
|
+
per-component media query. Web-only DOM contract, so it lives
|
|
41
|
+
here rather than in the cross-platform token set (see --juno-dock-clearance
|
|
42
|
+
above for the same reasoning). */
|
|
43
|
+
--juno-motion: auto;
|
|
44
|
+
--juno-motion-scale: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
17
47
|
:root[data-juno-mode='dark'] { color-scheme: dark; }
|
|
18
48
|
|
|
19
49
|
/* Control surfaces. On dark panels the hairline border (~23% L) disappears, so
|
|
@@ -89,11 +119,103 @@ code, kbd, samp, pre { font-family: var(--juno-font-family-mono); }
|
|
|
89
119
|
the contract; a phone just reads the bigger one. */
|
|
90
120
|
@media (pointer: coarse) {
|
|
91
121
|
:root { --juno-size-tap-min: var(--juno-size-tap-comfortable); }
|
|
122
|
+
|
|
123
|
+
/* iOS Safari is widely observed to zoom the page onto a focused text field
|
|
124
|
+
whose font-size is under 16px. NOTE: no primary WebKit/Apple source states
|
|
125
|
+
this — it is empirical behavior, not published spec, so don't cite it as
|
|
126
|
+
one (see docs/ios-conformance.md and ticket 20260803-032). The mitigation
|
|
127
|
+
is harmless either way: hold text-entry controls (.juno-input covers input,
|
|
128
|
+
textarea and the select's inner control) at a 16px floor on touch. max()
|
|
129
|
+
keeps the floor even under a scaled-down --juno-font-scale, and still grows
|
|
130
|
+
when scaled up. */
|
|
131
|
+
.juno-input { font-size: max(16px, var(--juno-font-size-16)); }
|
|
132
|
+
|
|
133
|
+
/* Kill the UA tap-highlight square on the interactive surfaces so it never
|
|
134
|
+
flashes past a rounded control on tap. Consumers were adding this by hand
|
|
135
|
+
per component; make it a first-class touch default. See 20260802-020. */
|
|
136
|
+
:where(
|
|
137
|
+
.juno-btn,
|
|
138
|
+
.juno-dock__item,
|
|
139
|
+
.juno-pillbar__item,
|
|
140
|
+
.juno-tabs__tab,
|
|
141
|
+
.juno-list__item,
|
|
142
|
+
.juno-menu__item
|
|
143
|
+
) {
|
|
144
|
+
-webkit-tap-highlight-color: transparent;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Tappable primitives opt out of double-tap-to-zoom. A browser that still
|
|
149
|
+
recognises that gesture has to WAIT after the first tap to see whether a
|
|
150
|
+
second one is coming, which reads as a late, mushy tap on exactly the
|
|
151
|
+
surfaces a phone UI is built from. `manipulation` keeps panning and
|
|
152
|
+
pinch-zoom (so the page stays zoomable — never `none` here, that would be an
|
|
153
|
+
a11y regression) and drops only the double-tap.
|
|
154
|
+
NOT inside the pointer:coarse block above: a hybrid device (touch laptop,
|
|
155
|
+
iPad with a trackpad) reports a fine primary pointer while still taking
|
|
156
|
+
touch input, and the property is inert on a mouse anyway.
|
|
157
|
+
Community convention — no primary Apple/WebKit source names it; see
|
|
158
|
+
docs/ios-conformance.md. Named components only, so a consumer's own elements
|
|
159
|
+
are untouched. See 20260803-038. */
|
|
160
|
+
:where(
|
|
161
|
+
.juno-btn,
|
|
162
|
+
.juno-dock__item,
|
|
163
|
+
.juno-pillbar__item,
|
|
164
|
+
.juno-pillbar__overflow,
|
|
165
|
+
.juno-tabs__tab,
|
|
166
|
+
.juno-list__item,
|
|
167
|
+
.juno-menu__item,
|
|
168
|
+
.juno-seg__option,
|
|
169
|
+
.juno-chip,
|
|
170
|
+
.juno-toggle-btn
|
|
171
|
+
) {
|
|
172
|
+
touch-action: manipulation;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Gesture-owned surfaces — for an element whose pointer events are fully
|
|
176
|
+
driven by app JS (drag-pan, pinch-zoom, swipe classification: a state
|
|
177
|
+
machine, not a native scroller). The UA must get out of the way: no
|
|
178
|
+
scroll/zoom gesture recognition, no callout menu on long-press, no text
|
|
179
|
+
selection, no tap-highlight flash. Community convention — no primary
|
|
180
|
+
Apple/WebKit source names any of these four properties for iOS, see
|
|
181
|
+
docs/ios-conformance.md; do not attribute them to Apple. Opt-in utility
|
|
182
|
+
class (unlike the pointer:coarse reset above, which targets junoui's own
|
|
183
|
+
named components), so it isn't gated behind a pointer-type query — apply
|
|
184
|
+
it only to elements a gesture handler actually owns.
|
|
185
|
+
--juno-touch-action narrows the axis without overriding the rest of the
|
|
186
|
+
block; default `none` hands every axis to JS. */
|
|
187
|
+
.juno-gesture-surface {
|
|
188
|
+
touch-action: var(--juno-touch-action, none);
|
|
189
|
+
-webkit-touch-callout: none;
|
|
190
|
+
user-select: none;
|
|
191
|
+
-webkit-tap-highlight-color: transparent;
|
|
92
192
|
}
|
|
93
193
|
|
|
194
|
+
/* Single-axis escape hatches: the UA keeps native scrolling on one axis
|
|
195
|
+
while JS reads gestures on the other (e.g. a vertical list row that also
|
|
196
|
+
supports horizontal swipe-to-reveal). Equivalent to
|
|
197
|
+
`--juno-touch-action: pan-x|pan-y` on .juno-gesture-surface, offered as
|
|
198
|
+
standalone classes for elements that only need the axis lock and none of
|
|
199
|
+
the callout/selection/tap-highlight resets. */
|
|
200
|
+
.juno-pan-x { touch-action: pan-x; }
|
|
201
|
+
.juno-pan-y { touch-action: pan-y; }
|
|
202
|
+
|
|
94
203
|
@keyframes juno-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
|
95
204
|
|
|
205
|
+
/* Softer opacity pulse — a "working / refreshing" cadence that dims rather
|
|
206
|
+
than fully blinks out (used by the reload indicator and any live dot that
|
|
207
|
+
wants a gentler beat than juno-blink). */
|
|
208
|
+
@keyframes juno-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
|
|
209
|
+
|
|
96
210
|
@media (prefers-reduced-motion: reduce) {
|
|
211
|
+
/* Flip the JS-readable contract declared at the top of this file. Without
|
|
212
|
+
this the property would always report `auto` and script could never see
|
|
213
|
+
the preference — the whole point of exposing it. */
|
|
214
|
+
:root {
|
|
215
|
+
--juno-motion: none;
|
|
216
|
+
--juno-motion-scale: 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
97
219
|
*, *::before, *::after {
|
|
98
220
|
animation-duration: 0.01ms !important;
|
|
99
221
|
animation-iteration-count: 1 !important;
|
|
@@ -118,3 +240,51 @@ code, kbd, samp, pre { font-family: var(--juno-font-family-mono); }
|
|
|
118
240
|
.juno-readout { border: 1px solid CanvasText; }
|
|
119
241
|
.juno-badge { forced-color-adjust: none; } /* keep status fill meaningful */
|
|
120
242
|
}
|
|
243
|
+
|
|
244
|
+
/* ── iOS standalone letterbox unlock ─────────────────────────────────────────
|
|
245
|
+
iOS WebKit (observed through 26.6, iPhone 16 Pro, iOS 18.7) sizes a
|
|
246
|
+
Home-Screen standalone window whose DOCUMENT cannot scroll as if a
|
|
247
|
+
retractable browser toolbar existed: `screen.height − status bar`, pinned to
|
|
248
|
+
the top. The reserved strip — exactly env(safe-area-inset-top) — surfaces at
|
|
249
|
+
the BOTTOM of the glass, outside the window, painting black on every screen.
|
|
250
|
+
The same install with a scrollable document gets the whole screen.
|
|
251
|
+
|
|
252
|
+
Established by measurement, not inference (nexora 20260812-006): 201 device
|
|
253
|
+
readings; a four-structure A/B on one install where doc-scroll = full screen
|
|
254
|
+
and fixed-shell = letterboxed on every cold launch; and this exact mechanism
|
|
255
|
+
— the shell kept, the document left scrollable behind it by an invisible
|
|
256
|
+
in-flow spacer — verified full-screen on the device before landing here.
|
|
257
|
+
Transient scrollability is NOT enough (seven timed interventions, five
|
|
258
|
+
controlled runs, all negative): iOS samples the resting structure.
|
|
259
|
+
|
|
260
|
+
So: keep the document scrollable behind the app. The spacer is body::after
|
|
261
|
+
(a consumer that needs body::after for itself overrides this at the same
|
|
262
|
+
gate — none of ours do), invisible, 1px wide, and taller than the LARGE
|
|
263
|
+
viewport so the document always overflows whatever window iOS grants.
|
|
264
|
+
`overscroll-behavior: none` keeps the ghost scroller from rubber-banding;
|
|
265
|
+
apps put `overscroll-behavior: contain` on their real scrollers so an
|
|
266
|
+
inner fling never chains into it.
|
|
267
|
+
|
|
268
|
+
Gate, all three required:
|
|
269
|
+
display-mode: standalone only installed apps are letterboxed
|
|
270
|
+
pointer: coarse touch devices — keeps macOS Dock apps out
|
|
271
|
+
-webkit-touch-callout support iOS/iPadOS WebKit only
|
|
272
|
+
Selectors carry `html:root` (0,1,2) on purpose: app resets commonly declare
|
|
273
|
+
`body { overflow: hidden }` at (0,0,1) AFTER this sheet, and the unlock must
|
|
274
|
+
win the cascade without !important. */
|
|
275
|
+
@media (display-mode: standalone) and (pointer: coarse) {
|
|
276
|
+
@supports (-webkit-touch-callout: none) {
|
|
277
|
+
html:root,
|
|
278
|
+
html:root body { overflow: visible; }
|
|
279
|
+
html:root body { overscroll-behavior: none; }
|
|
280
|
+
|
|
281
|
+
html:root body::after {
|
|
282
|
+
content: '';
|
|
283
|
+
display: block;
|
|
284
|
+
width: 1px;
|
|
285
|
+
height: calc(100lvh + 80px);
|
|
286
|
+
visibility: hidden;
|
|
287
|
+
pointer-events: none;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|