@telepath-computer/television 0.1.216 → 1.3.2
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/dist/THIRD-PARTY-NOTICES.txt +336 -0
- package/dist/canonical/v1/frozen.json +6 -0
- package/dist/canonical/v1/styles.css +7 -2
- package/dist/canonical/v2/components.js +1 -0
- package/dist/canonical/v2/fonts/Hind-Variable.933e9900.woff2 +0 -0
- package/dist/canonical/v2/styles.css +1153 -0
- package/dist/cli.cjs +1763 -761
- package/dist/onboarding/README.md +16 -14
- package/dist/onboarding/business-ops/about.html +4 -3
- package/dist/onboarding/business-ops/retention-vs-releases.html +25 -32
- package/dist/onboarding/business-ops/revenue-vs-goals.html +26 -31
- package/dist/onboarding/productivity/about.html +4 -3
- package/dist/onboarding/productivity/company-todos/THIRD-PARTY-NOTICES.txt +29 -0
- package/dist/onboarding/productivity/company-todos/index.html +20 -20
- package/dist/onboarding/productivity/company-todos/task.css +4 -5
- package/dist/onboarding/productivity/company-todos/task.js +1 -1
- package/dist/onboarding/productivity/meeting-prep.html +12 -12
- package/dist/onboarding/productivity/priorities-today.html +10 -10
- package/dist/onboarding/productivity/todays-calendar/calendar.css +1 -1
- package/dist/onboarding/productivity/todays-calendar/index.html +12 -14
- package/dist/onboarding/research/about.html +4 -3
- package/dist/onboarding/research/open-model-research.html +35 -35
- package/dist/onboarding/research/todays-news.html +72 -72
- package/dist/onboarding/tv-guide/welcome.html +178 -0
- package/dist/skills/television/SKILL.md +122 -67
- package/dist/skills/television/theming.md +1087 -0
- package/dist/skills/tv-calendar/SKILL.md +3 -1
- package/dist/skills/tv-calendar/calendar.css +1 -1
- package/dist/skills/tv-table/SKILL.md +5 -2
- package/dist/skills/tv-tasks/SKILL.md +19 -15
- package/dist/skills/tv-tasks/task.css +4 -26
- package/dist/skills/tv-tasks/task.js +1 -1
- package/dist/themes/README.md +5 -0
- package/dist/themes/aquarium/README.md +48 -0
- package/dist/themes/aquarium/iframe-background.js +137 -0
- package/dist/themes/aquarium/manifest.json +7 -0
- package/dist/themes/aquarium/theme.css +46 -0
- package/dist/themes/blueprint/README.md +31 -0
- package/dist/themes/blueprint/manifest.json +6 -0
- package/dist/themes/blueprint/theme.css +115 -0
- package/dist/themes/clouds/README.md +15 -0
- package/dist/themes/clouds/THIRD-PARTY-NOTICES.txt +81 -0
- package/dist/themes/clouds/manifest.json +6 -0
- package/dist/themes/clouds/theme.css +62 -0
- package/dist/themes/clouds/wallpaper-dark.webp +0 -0
- package/dist/themes/clouds/wallpaper.webp +0 -0
- package/dist/themes/crt-phosphor/README.md +31 -0
- package/dist/themes/crt-phosphor/manifest.json +6 -0
- package/dist/themes/crt-phosphor/theme.css +105 -0
- package/dist/themes/nord/README.md +9 -0
- package/dist/themes/nord/THIRD-PARTY-NOTICES.txt +29 -0
- package/dist/themes/nord/manifest.json +5 -0
- package/dist/themes/nord/theme.css +28 -0
- package/dist/themes/swiss/README.md +5 -0
- package/dist/themes/swiss/manifest.json +5 -0
- package/dist/themes/swiss/theme.css +34 -0
- package/dist/themes/tokyo-night/README.md +17 -0
- package/dist/themes/tokyo-night/THIRD-PARTY-NOTICES.txt +235 -0
- package/dist/themes/tokyo-night/manifest.json +5 -0
- package/dist/themes/tokyo-night/theme.css +31 -0
- package/dist/themes/tokyo-night/wallpaper.webp +0 -0
- package/dist/views/artifact-missing/index.html +40 -68
- package/dist/views/markdown/THIRD-PARTY-NOTICES.txt +26 -0
- package/dist/views/markdown/index.html +49 -23
- package/dist/web/THIRD-PARTY-NOTICES.txt +26 -0
- package/dist/web/assets/artifact-bridge-BEUWXKq7.js +1 -0
- package/dist/web/assets/{artifactMissing-BiK_l3Ts.js → artifactMissing-CUs1ZwDx.js} +1 -1
- package/dist/web/assets/main-3UimTRLK.css +1 -0
- package/dist/web/assets/main-CSSzbG7q.js +704 -0
- package/dist/web/assets/{urlUnsupported-RGIrhMDe.js → urlUnsupported-powR79PT.js} +1 -1
- package/dist/web/index.html +40 -5
- package/dist/web/views/artifact-missing/index.html +40 -68
- package/dist/web/views/url-unsupported/index.html +40 -68
- package/package.json +1 -1
- package/dist/onboarding/tv-guide/welcome/assets/television.svg +0 -71
- package/dist/onboarding/tv-guide/welcome/index.html +0 -203
- package/dist/skills/tv-theme/SKILL.md +0 -449
- package/dist/web/assets/artifact-bridge-3Trk-B2L.js +0 -1
- package/dist/web/assets/clouds-CAYIArXj.jpg +0 -0
- package/dist/web/assets/main-Blg8fuaV.css +0 -1
- package/dist/web/assets/main-V14r9Psb.js +0 -596
|
@@ -0,0 +1,1153 @@
|
|
|
1
|
+
/* Foundation styling carries no specificity: every selector that can be is
|
|
2
|
+
wrapped in `:where()`, so later sheets — the element sheets, surfaces,
|
|
3
|
+
themes — override any of this with a plain rule. The universal box-sizing
|
|
4
|
+
rule stays bare only because pseudo-elements cannot appear inside
|
|
5
|
+
`:where()`; its selectors carry no specificity anyway. */
|
|
6
|
+
*,
|
|
7
|
+
*::before,
|
|
8
|
+
*::after {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:where(html, body) {
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* The document's base typography, stated once at the root: surfaces inherit
|
|
18
|
+
rather than restate, and the form controls below inherit it in turn. */
|
|
19
|
+
:where(body) {
|
|
20
|
+
font-family: var(--font-sans);
|
|
21
|
+
font-size: var(--text-md);
|
|
22
|
+
font-weight: var(--font-weight-normal);
|
|
23
|
+
line-height: normal;
|
|
24
|
+
color: var(--color-text);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:where(h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, pre, hr) {
|
|
28
|
+
margin: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:where(button, input, select, textarea) {
|
|
32
|
+
font: inherit;
|
|
33
|
+
color: inherit;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Floating elements arrive with UA chrome — a solid border and padding on
|
|
37
|
+
dialog and on popover hosts. Zeroed here so the panel styling states only
|
|
38
|
+
what a panel looks like. The UA margin stays: it centers a modal dialog. */
|
|
39
|
+
:where(dialog, [popover]) {
|
|
40
|
+
border: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Hind — the committed variable cut, weights 300–700. */
|
|
45
|
+
@font-face {
|
|
46
|
+
font-family: "Hind";
|
|
47
|
+
src: url(/canonical/v2/fonts/Hind-Variable.933e9900.woff2) format("woff2-variations");
|
|
48
|
+
font-weight: 300 700;
|
|
49
|
+
font-display: block;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:where(:root) { /* The faces above, named; weights as material plus the body role. */
|
|
53
|
+
--font-sans: "Hind", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
54
|
+
--font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
|
|
55
|
+
--font-weight-normal: 400;
|
|
56
|
+
--font-weight-medium: 500;
|
|
57
|
+
--font-weight-semibold: 600;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Palette seeds and derived scales adapted from Tailwind CSS.
|
|
61
|
+
https://github.com/tailwindlabs/tailwindcss
|
|
62
|
+
Copyright (c) Tailwind Labs, Inc.
|
|
63
|
+
MIT License; see THIRD-PARTY-NOTICES.txt. */
|
|
64
|
+
|
|
65
|
+
/* Both tables sit at zero specificity — ambient styling is the weakest
|
|
66
|
+
thing in the cascade, tokens included. A theme states a token with a
|
|
67
|
+
plain `:root` and out-cascades both tables at once — one statement, both
|
|
68
|
+
modes — or writes its own `[data-theme="dark"]` block to retune dark
|
|
69
|
+
alone. Between the tables themselves, source order decides: the dark
|
|
70
|
+
table follows the light one, so it wins where the attribute matches. */
|
|
71
|
+
:where(:root) {
|
|
72
|
+
/* A surface's inner edge moves toward its light pole; its outer line moves
|
|
73
|
+
toward its dark pole. Both follow the surface rather than appearance. */
|
|
74
|
+
--surface-border-color: color-mix(in oklch, var(--color-surface), oklch(from var(--color-surface) 1 0 h) var(--alpha-15));
|
|
75
|
+
--surface-outline-color: color-mix(in oklch, var(--color-surface), oklch(from var(--color-surface) 0 0 h) var(--alpha-10));
|
|
76
|
+
--surface-outline-width: 1px;
|
|
77
|
+
--surface-outline: var(--surface-outline-width) solid var(--surface-outline-color);
|
|
78
|
+
|
|
79
|
+
/* Panels: popovers, menus, selects and dialogs. */
|
|
80
|
+
--panel-background: var(--color-surface);
|
|
81
|
+
--panel-text-color: var(--color-text);
|
|
82
|
+
--panel-border-color: var(--surface-border-color);
|
|
83
|
+
--panel-border-width: 1px;
|
|
84
|
+
--panel-border: var(--panel-border-width) solid var(--panel-border-color);
|
|
85
|
+
--panel-outline: var(--surface-outline);
|
|
86
|
+
|
|
87
|
+
/* Options: menu items and select options. */
|
|
88
|
+
--option-background-highlighted: color-mix(in oklch, transparent, var(--option-background-active) var(--hover-mix));
|
|
89
|
+
--option-background-active: var(--tint-active);
|
|
90
|
+
|
|
91
|
+
/* Checked checklist marker fill and border. */
|
|
92
|
+
--checkbox-color: var(--color-primary);
|
|
93
|
+
|
|
94
|
+
/* Controls share these defaults in app and artifact documents. */
|
|
95
|
+
--control-text-color: var(--color-text);
|
|
96
|
+
--control-border-color: var(--color-border);
|
|
97
|
+
--control-border-width: 1px;
|
|
98
|
+
--control-border: var(--control-border-width) solid var(--control-border-color);
|
|
99
|
+
--input-placeholder-text-color: var(--color-text-muted);
|
|
100
|
+
|
|
101
|
+
/* Slots — the theme's raw material, each stated at its own 500 step: the
|
|
102
|
+
hue's mid, the brand weight. A theme restates any of them and the scale
|
|
103
|
+
below it regenerates. The neutral is genuinely neutral; give it a chroma
|
|
104
|
+
and hue and the whole grey world takes the undertone. */
|
|
105
|
+
--neutral: oklch(0.556 0 0);
|
|
106
|
+
--red: oklch(0.637 0.237 25.331);
|
|
107
|
+
--orange: oklch(0.705 0.213 47.604);
|
|
108
|
+
--yellow: oklch(0.852 0.199 91.936);
|
|
109
|
+
--green: oklch(0.723 0.219 149.579);
|
|
110
|
+
--cyan: oklch(0.715 0.143 215.221);
|
|
111
|
+
--blue: oklch(0.623 0.214 259.815);
|
|
112
|
+
--purple: oklch(0.627 0.265 303.9);
|
|
113
|
+
--pink: oklch(0.656 0.241 354.308);
|
|
114
|
+
/* The one tunable identity — any color a theme or picker supplies; used
|
|
115
|
+
raw as the accent fill, and everything accent-flavored derives from it. */
|
|
116
|
+
--accent: var(--blue);
|
|
117
|
+
|
|
118
|
+
/* Scales. Every step is generated around its slot: pale steps climb a
|
|
119
|
+
fraction of the headroom from the slot's lightness to white, deep steps
|
|
120
|
+
climb toward black, and every step keeps a fraction of the slot's chroma.
|
|
121
|
+
The numbers sit inline, per scale, per step — tuning is editing the line.
|
|
122
|
+
Cluster scales carry the curve measured off the hand-tuned red ramp;
|
|
123
|
+
yellow carries its own numbers, including chroma fractions above 1 and
|
|
124
|
+
per-step hue rotation (dark yellow at constant hue is olive).
|
|
125
|
+
|
|
126
|
+
The neutral scale is a lightness ladder with chroma carried unchanged:
|
|
127
|
+
dose arithmetic cannot hold an undertone at the pale end, and the
|
|
128
|
+
interface's contrast skeleton wants stated lightnesses. */
|
|
129
|
+
--neutral-50: oklch(from var(--neutral) 0.985 c h);
|
|
130
|
+
--neutral-100: oklch(from var(--neutral) 0.97 c h);
|
|
131
|
+
--neutral-200: oklch(from var(--neutral) 0.922 c h);
|
|
132
|
+
--neutral-300: oklch(from var(--neutral) 0.87 c h);
|
|
133
|
+
--neutral-400: oklch(from var(--neutral) 0.708 c h);
|
|
134
|
+
--neutral-500: var(--neutral);
|
|
135
|
+
--neutral-600: oklch(from var(--neutral) 0.439 c h);
|
|
136
|
+
--neutral-700: oklch(from var(--neutral) 0.371 c h);
|
|
137
|
+
--neutral-800: oklch(from var(--neutral) 0.269 c h);
|
|
138
|
+
--neutral-900: oklch(from var(--neutral) 0.205 c h);
|
|
139
|
+
--neutral-950: oklch(from var(--neutral) 0.145 c h);
|
|
140
|
+
|
|
141
|
+
--red-50: oklch(from var(--red) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
142
|
+
--red-100: oklch(from var(--red) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
143
|
+
--red-200: oklch(from var(--red) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
144
|
+
--red-300: oklch(from var(--red) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
145
|
+
--red-400: oklch(from var(--red) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
146
|
+
--red-500: var(--red);
|
|
147
|
+
--red-600: oklch(from var(--red) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
148
|
+
--red-700: oklch(from var(--red) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
149
|
+
--red-800: oklch(from var(--red) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
150
|
+
--red-900: oklch(from var(--red) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
151
|
+
--red-950: oklch(from var(--red) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
152
|
+
|
|
153
|
+
--orange-50: oklch(from var(--orange) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
154
|
+
--orange-100: oklch(from var(--orange) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
155
|
+
--orange-200: oklch(from var(--orange) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
156
|
+
--orange-300: oklch(from var(--orange) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
157
|
+
--orange-400: oklch(from var(--orange) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
158
|
+
--orange-500: var(--orange);
|
|
159
|
+
--orange-600: oklch(from var(--orange) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
160
|
+
--orange-700: oklch(from var(--orange) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
161
|
+
--orange-800: oklch(from var(--orange) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
162
|
+
--orange-900: oklch(from var(--orange) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
163
|
+
--orange-950: oklch(from var(--orange) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
164
|
+
|
|
165
|
+
--yellow-50: oklch(from var(--yellow) calc(l + (1 - l) * 0.937) calc(c * 0.141) calc(h + 10));
|
|
166
|
+
--yellow-100: oklch(from var(--yellow) calc(l + (1 - l) * 0.868) calc(c * 0.386) calc(h + 11));
|
|
167
|
+
--yellow-200: oklch(from var(--yellow) calc(l + (1 - l) * 0.732) calc(c * 0.701) calc(h + 10));
|
|
168
|
+
--yellow-300: oklch(from var(--yellow) calc(l + (1 - l) * 0.537) calc(c * 0.989) calc(h + 6));
|
|
169
|
+
--yellow-400: oklch(from var(--yellow) calc(l + (1 - l) * 0.278) calc(c * 1.082) calc(h + 3));
|
|
170
|
+
--yellow-500: var(--yellow);
|
|
171
|
+
--yellow-600: oklch(from var(--yellow) calc(l * (1 - 0.08)) calc(c * 0.95) calc(h - 6));
|
|
172
|
+
--yellow-700: oklch(from var(--yellow) calc(l * (1 - 0.19)) calc(c * 0.8) calc(h - 14));
|
|
173
|
+
--yellow-800: oklch(from var(--yellow) calc(l * (1 - 0.33)) calc(c * 0.65) calc(h - 26));
|
|
174
|
+
--yellow-900: oklch(from var(--yellow) calc(l * (1 - 0.46)) calc(c * 0.52) calc(h - 32));
|
|
175
|
+
--yellow-950: oklch(from var(--yellow) calc(l * (1 - 0.64)) calc(c * 0.359) calc(h - 38));
|
|
176
|
+
|
|
177
|
+
--green-50: oklch(from var(--green) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
178
|
+
--green-100: oklch(from var(--green) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
179
|
+
--green-200: oklch(from var(--green) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
180
|
+
--green-300: oklch(from var(--green) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
181
|
+
--green-400: oklch(from var(--green) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
182
|
+
--green-500: var(--green);
|
|
183
|
+
--green-600: oklch(from var(--green) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
184
|
+
--green-700: oklch(from var(--green) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
185
|
+
--green-800: oklch(from var(--green) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
186
|
+
--green-900: oklch(from var(--green) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
187
|
+
--green-950: oklch(from var(--green) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
188
|
+
|
|
189
|
+
--cyan-50: oklch(from var(--cyan) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
190
|
+
--cyan-100: oklch(from var(--cyan) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
191
|
+
--cyan-200: oklch(from var(--cyan) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
192
|
+
--cyan-300: oklch(from var(--cyan) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
193
|
+
--cyan-400: oklch(from var(--cyan) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
194
|
+
--cyan-500: var(--cyan);
|
|
195
|
+
--cyan-600: oklch(from var(--cyan) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
196
|
+
--cyan-700: oklch(from var(--cyan) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
197
|
+
--cyan-800: oklch(from var(--cyan) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
198
|
+
--cyan-900: oklch(from var(--cyan) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
199
|
+
--cyan-950: oklch(from var(--cyan) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
200
|
+
|
|
201
|
+
--blue-50: oklch(from var(--blue) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
202
|
+
--blue-100: oklch(from var(--blue) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
203
|
+
--blue-200: oklch(from var(--blue) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
204
|
+
--blue-300: oklch(from var(--blue) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
205
|
+
--blue-400: oklch(from var(--blue) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
206
|
+
--blue-500: var(--blue);
|
|
207
|
+
--blue-600: oklch(from var(--blue) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
208
|
+
--blue-700: oklch(from var(--blue) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
209
|
+
--blue-800: oklch(from var(--blue) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
210
|
+
--blue-900: oklch(from var(--blue) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
211
|
+
--blue-950: oklch(from var(--blue) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
212
|
+
|
|
213
|
+
--purple-50: oklch(from var(--purple) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
214
|
+
--purple-100: oklch(from var(--purple) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
215
|
+
--purple-200: oklch(from var(--purple) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
216
|
+
--purple-300: oklch(from var(--purple) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
217
|
+
--purple-400: oklch(from var(--purple) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
218
|
+
--purple-500: var(--purple);
|
|
219
|
+
--purple-600: oklch(from var(--purple) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
220
|
+
--purple-700: oklch(from var(--purple) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
221
|
+
--purple-800: oklch(from var(--purple) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
222
|
+
--purple-900: oklch(from var(--purple) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
223
|
+
--purple-950: oklch(from var(--purple) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
224
|
+
|
|
225
|
+
--pink-50: oklch(from var(--pink) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
226
|
+
--pink-100: oklch(from var(--pink) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
227
|
+
--pink-200: oklch(from var(--pink) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
228
|
+
--pink-300: oklch(from var(--pink) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
229
|
+
--pink-400: oklch(from var(--pink) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
230
|
+
--pink-500: var(--pink);
|
|
231
|
+
--pink-600: oklch(from var(--pink) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
232
|
+
--pink-700: oklch(from var(--pink) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
233
|
+
--pink-800: oklch(from var(--pink) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
234
|
+
--pink-900: oklch(from var(--pink) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
235
|
+
--pink-950: oklch(from var(--pink) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
236
|
+
|
|
237
|
+
--accent-50: oklch(from var(--accent) calc(l + (1 - l) * 0.92) calc(c * 0.055) h);
|
|
238
|
+
--accent-100: oklch(from var(--accent) calc(l + (1 - l) * 0.824) calc(c * 0.135) h);
|
|
239
|
+
--accent-200: oklch(from var(--accent) calc(l + (1 - l) * 0.683) calc(c * 0.262) h);
|
|
240
|
+
--accent-300: oklch(from var(--accent) calc(l + (1 - l) * 0.471) calc(c * 0.481) h);
|
|
241
|
+
--accent-400: oklch(from var(--accent) calc(l + (1 - l) * 0.185) calc(c * 0.806) h);
|
|
242
|
+
--accent-500: var(--accent);
|
|
243
|
+
--accent-600: oklch(from var(--accent) calc(l * (1 - 0.094)) calc(c * 1.034) h);
|
|
244
|
+
--accent-700: oklch(from var(--accent) calc(l * (1 - 0.207)) calc(c * 0.899) h);
|
|
245
|
+
--accent-800: oklch(from var(--accent) calc(l * (1 - 0.303)) calc(c * 0.747) h);
|
|
246
|
+
--accent-900: oklch(from var(--accent) calc(l * (1 - 0.378)) calc(c * 0.595) h);
|
|
247
|
+
--accent-950: oklch(from var(--accent) calc(l * (1 - 0.595)) calc(c * 0.435) h);
|
|
248
|
+
|
|
249
|
+
/* Alpha scales — each color slot at a ladder of opacities, compositing on
|
|
250
|
+
whatever is beneath: restate the slot and its alphas follow. Used for
|
|
251
|
+
tinted backgrounds and translucent content. */
|
|
252
|
+
--neutral-alpha-5: oklch(from var(--neutral) l c h / var(--alpha-5)); --neutral-alpha-10: oklch(from var(--neutral) l c h / var(--alpha-10)); --neutral-alpha-15: oklch(from var(--neutral) l c h / var(--alpha-15));
|
|
253
|
+
--neutral-alpha-25: oklch(from var(--neutral) l c h / var(--alpha-25)); --neutral-alpha-50: oklch(from var(--neutral) l c h / var(--alpha-50)); --neutral-alpha-75: oklch(from var(--neutral) l c h / var(--alpha-75));
|
|
254
|
+
--red-alpha-5: oklch(from var(--red) l c h / var(--alpha-5)); --red-alpha-10: oklch(from var(--red) l c h / var(--alpha-10)); --red-alpha-15: oklch(from var(--red) l c h / var(--alpha-15));
|
|
255
|
+
--red-alpha-25: oklch(from var(--red) l c h / var(--alpha-25)); --red-alpha-50: oklch(from var(--red) l c h / var(--alpha-50)); --red-alpha-75: oklch(from var(--red) l c h / var(--alpha-75));
|
|
256
|
+
--orange-alpha-5: oklch(from var(--orange) l c h / var(--alpha-5)); --orange-alpha-10: oklch(from var(--orange) l c h / var(--alpha-10)); --orange-alpha-15: oklch(from var(--orange) l c h / var(--alpha-15));
|
|
257
|
+
--orange-alpha-25: oklch(from var(--orange) l c h / var(--alpha-25)); --orange-alpha-50: oklch(from var(--orange) l c h / var(--alpha-50)); --orange-alpha-75: oklch(from var(--orange) l c h / var(--alpha-75));
|
|
258
|
+
--yellow-alpha-5: oklch(from var(--yellow) l c h / var(--alpha-5)); --yellow-alpha-10: oklch(from var(--yellow) l c h / var(--alpha-10)); --yellow-alpha-15: oklch(from var(--yellow) l c h / var(--alpha-15));
|
|
259
|
+
--yellow-alpha-25: oklch(from var(--yellow) l c h / var(--alpha-25)); --yellow-alpha-50: oklch(from var(--yellow) l c h / var(--alpha-50)); --yellow-alpha-75: oklch(from var(--yellow) l c h / var(--alpha-75));
|
|
260
|
+
--green-alpha-5: oklch(from var(--green) l c h / var(--alpha-5)); --green-alpha-10: oklch(from var(--green) l c h / var(--alpha-10)); --green-alpha-15: oklch(from var(--green) l c h / var(--alpha-15));
|
|
261
|
+
--green-alpha-25: oklch(from var(--green) l c h / var(--alpha-25)); --green-alpha-50: oklch(from var(--green) l c h / var(--alpha-50)); --green-alpha-75: oklch(from var(--green) l c h / var(--alpha-75));
|
|
262
|
+
--cyan-alpha-5: oklch(from var(--cyan) l c h / var(--alpha-5)); --cyan-alpha-10: oklch(from var(--cyan) l c h / var(--alpha-10)); --cyan-alpha-15: oklch(from var(--cyan) l c h / var(--alpha-15));
|
|
263
|
+
--cyan-alpha-25: oklch(from var(--cyan) l c h / var(--alpha-25)); --cyan-alpha-50: oklch(from var(--cyan) l c h / var(--alpha-50)); --cyan-alpha-75: oklch(from var(--cyan) l c h / var(--alpha-75));
|
|
264
|
+
--blue-alpha-5: oklch(from var(--blue) l c h / var(--alpha-5)); --blue-alpha-10: oklch(from var(--blue) l c h / var(--alpha-10)); --blue-alpha-15: oklch(from var(--blue) l c h / var(--alpha-15));
|
|
265
|
+
--blue-alpha-25: oklch(from var(--blue) l c h / var(--alpha-25)); --blue-alpha-50: oklch(from var(--blue) l c h / var(--alpha-50)); --blue-alpha-75: oklch(from var(--blue) l c h / var(--alpha-75));
|
|
266
|
+
--purple-alpha-5: oklch(from var(--purple) l c h / var(--alpha-5)); --purple-alpha-10: oklch(from var(--purple) l c h / var(--alpha-10)); --purple-alpha-15: oklch(from var(--purple) l c h / var(--alpha-15));
|
|
267
|
+
--purple-alpha-25: oklch(from var(--purple) l c h / var(--alpha-25)); --purple-alpha-50: oklch(from var(--purple) l c h / var(--alpha-50)); --purple-alpha-75: oklch(from var(--purple) l c h / var(--alpha-75));
|
|
268
|
+
--pink-alpha-5: oklch(from var(--pink) l c h / var(--alpha-5)); --pink-alpha-10: oklch(from var(--pink) l c h / var(--alpha-10)); --pink-alpha-15: oklch(from var(--pink) l c h / var(--alpha-15));
|
|
269
|
+
--pink-alpha-25: oklch(from var(--pink) l c h / var(--alpha-25)); --pink-alpha-50: oklch(from var(--pink) l c h / var(--alpha-50)); --pink-alpha-75: oklch(from var(--pink) l c h / var(--alpha-75));
|
|
270
|
+
--accent-alpha-5: oklch(from var(--accent) l c h / var(--alpha-5)); --accent-alpha-10: oklch(from var(--accent) l c h / var(--alpha-10)); --accent-alpha-15: oklch(from var(--accent) l c h / var(--alpha-15));
|
|
271
|
+
--accent-alpha-25: oklch(from var(--accent) l c h / var(--alpha-25)); --accent-alpha-50: oklch(from var(--accent) l c h / var(--alpha-50)); --accent-alpha-75: oklch(from var(--accent) l c h / var(--alpha-75));
|
|
272
|
+
|
|
273
|
+
/* The alpha ladder the alpha scales read — nominal percent, values tunable
|
|
274
|
+
within a few points of their names. */
|
|
275
|
+
--alpha-3: 3%; --alpha-5: 5%; --alpha-10: 10%; --alpha-15: 15%; --alpha-20: 20%;
|
|
276
|
+
--alpha-25: 25%; --alpha-40: 40%; --alpha-50: 50%; --alpha-75: 75%;
|
|
277
|
+
|
|
278
|
+
/* Active strength and hover position are independent. Hover moves this
|
|
279
|
+
fraction of the way from resting to the resolved active color. The
|
|
280
|
+
default is halfway in both appearances. */
|
|
281
|
+
--hover-mix: 50%;
|
|
282
|
+
--alpha-active: 8%;
|
|
283
|
+
|
|
284
|
+
/* Ghost controls use their text pigment at active strength. Hover blends
|
|
285
|
+
transparent with that resolved endpoint, including theme overrides. */
|
|
286
|
+
--tint-hover: color-mix(in oklch, transparent, var(--tint-active) var(--hover-mix));
|
|
287
|
+
--tint-active: oklch(from currentColor l c h / var(--alpha-active));
|
|
288
|
+
|
|
289
|
+
/* Stencil icons: a drawing from the glyph vocabulary, packaged as a mask
|
|
290
|
+
for the places a rule must draw it — a pseudo-element can hold no
|
|
291
|
+
element, so the checklist's done mark and the select's selected mark
|
|
292
|
+
paint through this stencil instead of composing tv-icon. */
|
|
293
|
+
--icon-check: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path d="M10.2 3.1 5.1 8.2 2.4 5.5" fill="none" stroke="black" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>');
|
|
294
|
+
|
|
295
|
+
/* Neutral roles — the interface's jobs, pointed at the material. Sheets
|
|
296
|
+
read roles and scales, never a value of their own. */
|
|
297
|
+
/* Pure white, stated: the surface is a frame for user content, and
|
|
298
|
+
white-backgrounded artifacts and images must composite seamlessly. */
|
|
299
|
+
--color-surface: white;
|
|
300
|
+
--color-surface-muted: var(--neutral-100);
|
|
301
|
+
--color-text: var(--neutral-900);
|
|
302
|
+
--color-text-muted: var(--neutral-500);
|
|
303
|
+
/* Reversed type — the text knocked out of a solid fill. One token: fills
|
|
304
|
+
share the readable band by construction (meanings sit at fill weight),
|
|
305
|
+
and a variant whose fill is too light for reversed type wears
|
|
306
|
+
--color-text instead. */
|
|
307
|
+
--color-text-reversed: white;
|
|
308
|
+
/* Borders are tints of the text role, not stated steps: a translucent
|
|
309
|
+
edge always separates from whatever ground it sits on — an opaque
|
|
310
|
+
step vanishes the day a region paints that same step. Dark appearance
|
|
311
|
+
uses stronger tints to keep the edges visible. */
|
|
312
|
+
--color-border: oklch(from var(--color-text) l c h / 12%);
|
|
313
|
+
/* Translucent surface fills; backdrop blur is applied by the component. */
|
|
314
|
+
--tint-surface: oklch(from var(--color-surface) l c h / var(--alpha-50));
|
|
315
|
+
--tint-surface-muted: oklch(from var(--color-surface-muted) l c h / var(--alpha-50));
|
|
316
|
+
/* A control is a small surface, lifted by its border. */
|
|
317
|
+
--control-background: var(--color-surface);
|
|
318
|
+
/* Situations — danger, alert, success, primary. Each is one pointer at
|
|
319
|
+
the hue's 500; its tints and state fills derive from it, so repointing
|
|
320
|
+
the situation moves everything that wears it. */
|
|
321
|
+
--color-danger: var(--red-500);
|
|
322
|
+
--tint-danger: oklch(from var(--color-danger) l c h / var(--alpha-10));
|
|
323
|
+
--tint-danger-hover: color-mix(in oklch, transparent, var(--tint-danger-active) var(--hover-mix));
|
|
324
|
+
--tint-danger-active: oklch(from var(--color-danger) l c h / var(--alpha-active));
|
|
325
|
+
|
|
326
|
+
--color-alert: var(--yellow-500);
|
|
327
|
+
--tint-alert: oklch(from var(--color-alert) l c h / var(--alpha-10));
|
|
328
|
+
--tint-alert-hover: color-mix(in oklch, transparent, var(--tint-alert-active) var(--hover-mix));
|
|
329
|
+
--tint-alert-active: oklch(from var(--color-alert) l c h / var(--alpha-active));
|
|
330
|
+
|
|
331
|
+
--color-success: var(--green-500);
|
|
332
|
+
--tint-success: oklch(from var(--color-success) l c h / var(--alpha-10));
|
|
333
|
+
|
|
334
|
+
/* The primary action — the accent worn as a situation: the default
|
|
335
|
+
button, the current sidebar row. Selection wears it too; a selected
|
|
336
|
+
role returns the day selection and primary want different colors. */
|
|
337
|
+
--color-primary: var(--accent-500);
|
|
338
|
+
--tint-primary: oklch(from var(--color-primary) l c h / var(--alpha-10));
|
|
339
|
+
--tint-primary-hover: color-mix(in oklch, transparent, var(--tint-primary-active) var(--hover-mix));
|
|
340
|
+
--tint-primary-active: oklch(from var(--color-primary) l c h / var(--alpha-active));
|
|
341
|
+
/* The text on the primary fill, computed against it: dark ink above the
|
|
342
|
+
contrast flip, near-white below — so any accent, light gold included,
|
|
343
|
+
keeps a legible label wherever the fill appears. */
|
|
344
|
+
--color-primary-text: oklch(from var(--color-primary) clamp(0.2, (var(--contrast-flip) - l) * 1e6, 0.98) 0 h);
|
|
345
|
+
/* The keyboard's ring: one stroke wherever focus lands — width and
|
|
346
|
+
pigment here, the offset each control's own. */
|
|
347
|
+
--outline-focus: 2px solid var(--color-primary);
|
|
348
|
+
|
|
349
|
+
/* Filled active colors move toward black or white according to state-flip.
|
|
350
|
+
Hover follows the resolved active endpoint. Ordinary buttons consume
|
|
351
|
+
only resting and active fills; their hover appearance stays unchanged.
|
|
352
|
+
Derived states accept colors. Supply explicit states for gradients. */
|
|
353
|
+
--control-background-hover: color-mix(in oklch, var(--control-background), var(--control-background-active) var(--hover-mix));
|
|
354
|
+
--control-background-active: color-mix(in oklch, var(--control-background), oklch(from var(--control-background) clamp(0, (var(--state-flip) - l) * 1e6, 1) 0 h) var(--alpha-active));
|
|
355
|
+
--color-primary-hover: color-mix(in oklch, var(--color-primary), var(--color-primary-active) var(--hover-mix));
|
|
356
|
+
--color-primary-active: color-mix(in oklch, var(--color-primary), oklch(from var(--color-primary) clamp(0, (var(--state-flip) - l) * 1e6, 1) 0 h) var(--alpha-active));
|
|
357
|
+
--color-danger-hover: color-mix(in oklch, var(--color-danger), var(--color-danger-active) var(--hover-mix));
|
|
358
|
+
--color-danger-active: color-mix(in oklch, var(--color-danger), oklch(from var(--color-danger) clamp(0, (var(--state-flip) - l) * 1e6, 1) 0 h) var(--alpha-active));
|
|
359
|
+
--color-alert-hover: color-mix(in oklch, var(--color-alert), var(--color-alert-active) var(--hover-mix));
|
|
360
|
+
--color-alert-active: color-mix(in oklch, var(--color-alert), oklch(from var(--color-alert) clamp(0, (var(--state-flip) - l) * 1e6, 1) 0 h) var(--alpha-active));
|
|
361
|
+
|
|
362
|
+
/* A link follows its surrounding text unless a theme gives it an accent.
|
|
363
|
+
currentColor, not inherit: it means the ambient ink in any property it
|
|
364
|
+
lands in, and CSS-wide keywords substitute brittly through var(). */
|
|
365
|
+
--color-link: currentColor;
|
|
366
|
+
/* The dialog backdrop: near-black at the overlay opacity, dimming the
|
|
367
|
+
page; deriving from the neutral keeps the theme's undertone. */
|
|
368
|
+
--color-overlay: oklch(from var(--neutral-950) l c h / var(--alpha-40));
|
|
369
|
+
|
|
370
|
+
/* Two thresholds read a fill's own lightness and pick between two
|
|
371
|
+
outcomes. --state-flip steers the fill's motion in its states: a fill
|
|
372
|
+
lighter than it darkens on hover and press, a darker one lightens —
|
|
373
|
+
a genuinely dark fill has nowhere darker to go. --contrast-flip
|
|
374
|
+
steers the ink on the fill: a fill lighter than it wears dark text,
|
|
375
|
+
a darker one wears reversed type. Different questions flip at
|
|
376
|
+
different points — a red of 0.6 lightness wants reversed text yet
|
|
377
|
+
still darkens on press. */
|
|
378
|
+
--state-flip: 0.35;
|
|
379
|
+
--contrast-flip: 0.66;
|
|
380
|
+
|
|
381
|
+
color-scheme: light;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* The dark table changes the role pointers. Scales are not restated as
|
|
385
|
+
scales; the hue slots take slightly lighter values (saturated mids vibrate
|
|
386
|
+
on near-black), and every derived step follows. The neutral slot does not
|
|
387
|
+
move — the roles flip which steps they take. */
|
|
388
|
+
:where([data-theme="dark"]) {
|
|
389
|
+
--alpha-active: 12%;
|
|
390
|
+
--red: oklch(0.704 0.191 22.216);
|
|
391
|
+
--orange: oklch(0.75 0.183 55.934);
|
|
392
|
+
--yellow: oklch(0.879 0.169 91.5);
|
|
393
|
+
--green: oklch(0.792 0.209 151.711);
|
|
394
|
+
--cyan: oklch(0.789 0.154 211.53);
|
|
395
|
+
--blue: oklch(0.707 0.165 254.624);
|
|
396
|
+
--purple: oklch(0.714 0.203 305.504);
|
|
397
|
+
--pink: oklch(0.718 0.202 349.761);
|
|
398
|
+
|
|
399
|
+
--color-surface: var(--neutral-900);
|
|
400
|
+
--color-surface-muted: var(--neutral-800);
|
|
401
|
+
--color-text: var(--neutral-100);
|
|
402
|
+
--color-text-muted: var(--neutral-400);
|
|
403
|
+
--color-border: oklch(from var(--color-text) l c h / 18%);
|
|
404
|
+
|
|
405
|
+
color-scheme: dark;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
:where(:root) {
|
|
409
|
+
/* Controls follow the standard UI text size by default. */
|
|
410
|
+
--control-font-size: var(--text-md);
|
|
411
|
+
|
|
412
|
+
/* Type — one seed; each size a stated multiple, written as its tuned pixel
|
|
413
|
+
over the default base: retune --text-base and every size follows (at the
|
|
414
|
+
root — the var chain resolves there, not per subtree); read the fraction
|
|
415
|
+
and you see the pixels it lands on at 14. */
|
|
416
|
+
--text-base: 14px;
|
|
417
|
+
--text-sm: round(calc(var(--text-base) * 12 / 14), 1px);
|
|
418
|
+
--text-md: var(--text-base);
|
|
419
|
+
--text-lg: round(calc(var(--text-base) * 16 / 14), 1px);
|
|
420
|
+
--text-xl: round(calc(var(--text-base) * 18 / 14), 1px);
|
|
421
|
+
--text-2xl: round(calc(var(--text-base) * 20 / 14), 1px);
|
|
422
|
+
--text-3xl: round(calc(var(--text-base) * 24 / 14), 1px);
|
|
423
|
+
--text-4xl: round(calc(var(--text-base) * 30 / 14), 1px);
|
|
424
|
+
|
|
425
|
+
/* The control lines: the line-height a control's label uses, and the one
|
|
426
|
+
input its height derives from — the line, plus the space-2 padding step
|
|
427
|
+
top and bottom, plus a 1px border each side, gives every control the
|
|
428
|
+
same height: 18 + 4 + 2 = 24px (14 + 4 + 2 = 20px at the small step).
|
|
429
|
+
Stated in pixels, not a ratio: a control's cell is tighter than prose,
|
|
430
|
+
immune to the leading around it, and lands on even pixels in any font. */
|
|
431
|
+
--line-control: 18px;
|
|
432
|
+
--line-control-sm: 14px;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
:where(:root) {
|
|
436
|
+
/* Ordinary buttons and text fields share control padding. */
|
|
437
|
+
--control-padding: var(--space-2) var(--space-16);
|
|
438
|
+
|
|
439
|
+
/* Spacing — the thirteen legal distances. The ladder is a constraint, not a
|
|
440
|
+
theming surface: names state their fixed pixel values, and an off-ladder
|
|
441
|
+
length in a sheet is a visible smell. A density mode, if ever real,
|
|
442
|
+
swaps the ladder wholesale rather than lying under these names. */
|
|
443
|
+
--space-2: 2px;
|
|
444
|
+
--space-3: 3px;
|
|
445
|
+
--space-4: 4px;
|
|
446
|
+
--space-6: 6px;
|
|
447
|
+
--space-8: 8px;
|
|
448
|
+
--space-10: 10px;
|
|
449
|
+
--space-12: 12px;
|
|
450
|
+
--space-16: 16px;
|
|
451
|
+
--space-20: 20px;
|
|
452
|
+
--space-24: 24px;
|
|
453
|
+
--space-32: 32px;
|
|
454
|
+
--space-48: 48px;
|
|
455
|
+
--space-64: 64px;
|
|
456
|
+
|
|
457
|
+
/* Radius roles — jobs, themable. A numbered ladder would be value-names a
|
|
458
|
+
theme cannot restate without lying. */
|
|
459
|
+
--control-radius: 6px; /* buttons, inputs, menu items, small insets */
|
|
460
|
+
--radius-pill: 9999px; /* fully rounded ends at any element size */
|
|
461
|
+
|
|
462
|
+
/* Shared panel corners. */
|
|
463
|
+
--panel-radius: 8px;
|
|
464
|
+
|
|
465
|
+
/* The clearance a placed panel keeps on every side — off the trigger and
|
|
466
|
+
off every window edge ([[ui/foundation/popover/index.md]], Placement).
|
|
467
|
+
The element reads it from computed style, so a theme override reaches
|
|
468
|
+
the placement algorithm. Foundation, not app chrome: the popover family
|
|
469
|
+
ships to artifact documents, so its clearance must travel with it. */
|
|
470
|
+
--popover-distance: var(--space-4);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
:where(:root) {
|
|
474
|
+
/* Reusable elevations, from a close contact to a broad floating shadow. */
|
|
475
|
+
--shadow-sm: 0 1px 4px oklch(from var(--neutral-950) l c h / var(--alpha-15));
|
|
476
|
+
--shadow-md: 0 4px 12px oklch(from var(--neutral-950) l c h / var(--alpha-15));
|
|
477
|
+
--shadow-lg:
|
|
478
|
+
0 8px 24px oklch(from var(--neutral-950) l c h / var(--alpha-10)),
|
|
479
|
+
0 2px 8px oklch(from var(--neutral-950) l c h / var(--alpha-5));
|
|
480
|
+
|
|
481
|
+
/* Broad window elevation for artifact frames. */
|
|
482
|
+
--shadow-xl:
|
|
483
|
+
0 24px 48px oklch(from var(--neutral-950) l c h / var(--alpha-15)),
|
|
484
|
+
0 4px 12px oklch(from var(--neutral-950) l c h / 7.5%);
|
|
485
|
+
|
|
486
|
+
/* Popovers, including menus and selects, sit closer than dialogs. */
|
|
487
|
+
--popover-shadow: var(--shadow-md);
|
|
488
|
+
--dialog-shadow: var(--shadow-lg);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/* Dark surfaces need stronger shadows with the same neutral pigment. */
|
|
492
|
+
:where([data-theme="dark"]) {
|
|
493
|
+
--shadow-sm: 0 1px 4px oklch(from var(--neutral-950) l c h / var(--alpha-40));
|
|
494
|
+
--shadow-md: 0 4px 12px oklch(from var(--neutral-950) l c h / var(--alpha-40));
|
|
495
|
+
--shadow-lg:
|
|
496
|
+
0 8px 24px oklch(from var(--neutral-950) l c h / var(--alpha-40)),
|
|
497
|
+
0 2px 8px oklch(from var(--neutral-950) l c h / var(--alpha-25));
|
|
498
|
+
--shadow-xl:
|
|
499
|
+
0 24px 48px oklch(from var(--neutral-950) l c h / 30%),
|
|
500
|
+
0 4px 12px oklch(from var(--neutral-950) l c h / 18.75%);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/* The app-level paint order ([[ui/foundation/index.md]], Layers): every
|
|
504
|
+
z-index either places an element on one of these or lifts above siblings
|
|
505
|
+
with a calculation on one. Zero specificity like every token table — a
|
|
506
|
+
plain `:root` rule from a theme beats it. */
|
|
507
|
+
:where(:root) {
|
|
508
|
+
/* The base plane the document lays out. Nothing is placed on it; lifts on
|
|
509
|
+
the base plane calculate from it. */
|
|
510
|
+
--layer-ground: 0;
|
|
511
|
+
/* Floating panels opened from a surface: menus, the top-bar popovers. */
|
|
512
|
+
--layer-panel: 100;
|
|
513
|
+
/* The interruption: the dialog overlay and its backdrop. */
|
|
514
|
+
--layer-overlay: 200;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* The prose treatment ([[ui/foundation/index.md]], Prose): document
|
|
518
|
+
typography for plain semantic HTML, applying inside any region marked
|
|
519
|
+
text-display="prose". Zero specificity like every foundation rule; a
|
|
520
|
+
document's own styling outranks all of it. */
|
|
521
|
+
|
|
522
|
+
:where([text-display="prose"]) {
|
|
523
|
+
font-size: var(--text-md);
|
|
524
|
+
font-weight: var(--font-weight-medium);
|
|
525
|
+
line-height: 1.5;
|
|
526
|
+
-webkit-font-smoothing: antialiased;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/* The heading scale. */
|
|
530
|
+
:where([text-display="prose"] h1) {
|
|
531
|
+
font-size: var(--text-3xl);
|
|
532
|
+
font-weight: var(--font-weight-semibold);
|
|
533
|
+
line-height: 1.25;
|
|
534
|
+
margin: 0 0 var(--space-12);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
:where([text-display="prose"] h2) {
|
|
538
|
+
font-size: var(--text-xl);
|
|
539
|
+
font-weight: var(--font-weight-semibold);
|
|
540
|
+
line-height: 1.3;
|
|
541
|
+
margin: var(--space-24) 0 var(--space-8);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
:where([text-display="prose"] h3, [text-display="prose"] h4, [text-display="prose"] h5, [text-display="prose"] h6) {
|
|
545
|
+
font-size: var(--text-lg);
|
|
546
|
+
font-weight: var(--font-weight-semibold);
|
|
547
|
+
margin: var(--space-16) 0 var(--space-4);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* Block rhythm. */
|
|
551
|
+
:where([text-display="prose"] p, [text-display="prose"] ul, [text-display="prose"] ol, [text-display="prose"] blockquote, [text-display="prose"] pre, [text-display="prose"] hr, [text-display="prose"] table, [text-display="prose"] figure) {
|
|
552
|
+
margin: 0 0 var(--space-12);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
:where([text-display="prose"] > :last-child) {
|
|
556
|
+
margin-bottom: 0;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
:where([text-display="prose"] a) {
|
|
560
|
+
color: var(--color-link);
|
|
561
|
+
text-decoration: underline;
|
|
562
|
+
text-underline-offset: 2px;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
:where([text-display="prose"] ul, [text-display="prose"] ol) {
|
|
566
|
+
padding-left: var(--space-24);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
:where([text-display="prose"] li + li) {
|
|
570
|
+
margin-top: var(--space-4);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
:where([text-display="prose"] blockquote) {
|
|
574
|
+
border-left: 2px solid var(--color-border);
|
|
575
|
+
padding-left: var(--space-12);
|
|
576
|
+
color: var(--color-text-muted);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
:where([text-display="prose"] code, [text-display="prose"] kbd, [text-display="prose"] samp) {
|
|
580
|
+
font-family: var(--font-mono);
|
|
581
|
+
font-size: var(--text-sm);
|
|
582
|
+
background: var(--color-surface-muted);
|
|
583
|
+
border-radius: var(--control-radius);
|
|
584
|
+
padding: 1px var(--space-4);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
:where([text-display="prose"] pre) {
|
|
588
|
+
font-family: var(--font-mono);
|
|
589
|
+
font-size: var(--text-sm);
|
|
590
|
+
background: var(--color-surface-muted);
|
|
591
|
+
border: 1px solid var(--color-border);
|
|
592
|
+
border-radius: var(--control-radius);
|
|
593
|
+
padding: var(--space-12);
|
|
594
|
+
overflow-x: auto;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/* A block's code cell. */
|
|
598
|
+
:where([text-display="prose"] pre code) {
|
|
599
|
+
background: none;
|
|
600
|
+
border-radius: 0;
|
|
601
|
+
padding: 0;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
:where([text-display="prose"] hr) {
|
|
605
|
+
border: 0;
|
|
606
|
+
border-top: 1px solid var(--color-border);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
:where([text-display="prose"] table) {
|
|
610
|
+
border-collapse: collapse;
|
|
611
|
+
width: 100%;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
:where([text-display="prose"] th) {
|
|
615
|
+
text-align: left;
|
|
616
|
+
font-weight: var(--font-weight-semibold);
|
|
617
|
+
background: var(--color-surface-muted);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
:where([text-display="prose"] th, [text-display="prose"] td) {
|
|
621
|
+
padding: var(--space-4) var(--space-12) var(--space-4) 0;
|
|
622
|
+
border-bottom: 1px solid var(--color-border);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
:where([text-display="prose"] img) {
|
|
626
|
+
max-width: 100%;
|
|
627
|
+
height: auto;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/* The header idiom. */
|
|
631
|
+
:where([text-display="prose"] header p) {
|
|
632
|
+
color: var(--color-text-muted);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/* The heading's own bottom margin would collapse with the subtitle's; the
|
|
636
|
+
pair states its gap once. */
|
|
637
|
+
:where(header :is(h1, h2, h3, h4, h5, h6):has(+ p)) {
|
|
638
|
+
margin-bottom: 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
:where(header :is(h1, h2, h3, h4, h5, h6) + p) {
|
|
642
|
+
margin-top: var(--space-4);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/* Every rule in this sheet is wrapped in `:where()`, which contributes
|
|
646
|
+
nothing to specificity — foundation styling is the weakest thing in the
|
|
647
|
+
cascade, and a component placing a button overrides any of it with a plain
|
|
648
|
+
selector instead of contriving one that outranks it. Without this,
|
|
649
|
+
`button:hover:not(:disabled)` beats a component's own `:hover` rule, and
|
|
650
|
+
the component has to mirror the `:not()` to win — a workaround that reads
|
|
651
|
+
like an accident and gets tidied away. Within the sheet, source order does
|
|
652
|
+
the layering: intents beat the bare element, sizes beat the intents. */
|
|
653
|
+
:where(button) {
|
|
654
|
+
display: inline-flex;
|
|
655
|
+
align-items: center;
|
|
656
|
+
justify-content: center;
|
|
657
|
+
gap: var(--space-6);
|
|
658
|
+
padding: var(--control-padding);
|
|
659
|
+
border: var(--control-border);
|
|
660
|
+
border-radius: var(--control-radius);
|
|
661
|
+
/* A button is a surface of its own, lifted off whatever it sits on, rather
|
|
662
|
+
than a bordered hole in it. The fill is the kind's situation role, and
|
|
663
|
+
hover and press are that role's derived state fills in the token table
|
|
664
|
+
([[ui/foundation/tokens/colors.css]]) — the state rules below point at
|
|
665
|
+
them per kind, so a theme that restates a fill gets its states for
|
|
666
|
+
free, and one with an exact opinion overrides a state token. */
|
|
667
|
+
background: var(--control-background);
|
|
668
|
+
color: var(--control-text-color);
|
|
669
|
+
/* A button is a target, not text to select through. */
|
|
670
|
+
cursor: default;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/* A colored intent is a fill declaration; its states follow below. The
|
|
674
|
+
label is reversed type with the contrast clamp layered over it per kind,
|
|
675
|
+
so a theme's repointed situation keeps a legible label — the clamp
|
|
676
|
+
answers dark text on the alert gold (a clamp line drops at parse time in
|
|
677
|
+
engines without relative color, leaving the reversed role). */
|
|
678
|
+
:where(button[intent]) {
|
|
679
|
+
border-color: transparent;
|
|
680
|
+
color: var(--color-text-reversed);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/* The primary intent is the default action — the one Return fires; the
|
|
684
|
+
accent worn as a fill, macOS-style. */
|
|
685
|
+
:where(button[intent="primary"]) {
|
|
686
|
+
background: var(--color-primary);
|
|
687
|
+
color: var(--color-primary-text);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
:where(button[intent="danger"]) {
|
|
691
|
+
background: var(--color-danger);
|
|
692
|
+
color: oklch(from var(--color-danger) clamp(0.2, (var(--contrast-flip) - l) * 1e6, 0.98) 0 h);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
:where(button[intent="alert"]) {
|
|
696
|
+
background: var(--color-alert);
|
|
697
|
+
color: oklch(from var(--color-alert) clamp(0.2, (var(--contrast-flip) - l) * 1e6, 0.98) 0 h);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/* Buttons retain their resting appearance on hover. Pressed fills follow
|
|
701
|
+
the base fills so source order lets the state win. */
|
|
702
|
+
:where(button:active:not(:disabled)) {
|
|
703
|
+
background: var(--control-background-active);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
:where(button[intent="primary"]:active:not(:disabled)) {
|
|
707
|
+
background: var(--color-primary-active);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
:where(button[intent="danger"]:active:not(:disabled)) {
|
|
711
|
+
background: var(--color-danger-active);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
:where(button[intent="alert"]:active:not(:disabled)) {
|
|
715
|
+
background: var(--color-alert-active);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/* Keyboard focus only — a ring on every click would be noise. */
|
|
719
|
+
:where(button:focus-visible) {
|
|
720
|
+
outline: var(--outline-focus);
|
|
721
|
+
outline-offset: 1px;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/* Faded rather than restyled, so a disabled button keeps its shape and stays
|
|
725
|
+
recognisable as the control it is. */
|
|
726
|
+
:where(button:disabled) {
|
|
727
|
+
opacity: 0.4;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/* A button whose whole content is an icon: a square line-sized cell, the
|
|
731
|
+
glyph centred. Geometry only — the quiet treatment is `ghost`, stated
|
|
732
|
+
separately. */
|
|
733
|
+
:where(button[icon]) {
|
|
734
|
+
padding: var(--space-2);
|
|
735
|
+
display: inline-grid;
|
|
736
|
+
place-items: center;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/* The expanded state: the button holds the panel it opened (the element
|
|
740
|
+
maintains `aria-expanded`).
|
|
741
|
+
Source order puts it after the ghost and pointer-state rules. A filled
|
|
742
|
+
button holds the press-step fill; the ghost's tint treatment below is
|
|
743
|
+
guarded out of every kind. */
|
|
744
|
+
:where(button[aria-expanded="true"]:not(:disabled):not([variant="ghost"])) {
|
|
745
|
+
background: var(--control-background-active);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
:where(button[intent="primary"][aria-expanded="true"]:not(:disabled):not([variant="ghost"])) {
|
|
749
|
+
background: var(--color-primary-active);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
:where(button[intent="danger"][aria-expanded="true"]:not(:disabled):not([variant="ghost"])) {
|
|
753
|
+
background: var(--color-danger-active);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
:where(button[intent="alert"][aria-expanded="true"]:not(:disabled):not([variant="ghost"])) {
|
|
757
|
+
background: var(--color-alert-active);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* Ghost buttons inherit their containing text color. Intent colors
|
|
761
|
+
remain explicit; hover gives way to pressed and expanded states. */
|
|
762
|
+
:where(button[variant="ghost"]) {
|
|
763
|
+
border-color: transparent;
|
|
764
|
+
background: transparent;
|
|
765
|
+
color: inherit;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
:where(button[variant="ghost"][intent="primary"]) { color: var(--color-primary); }
|
|
769
|
+
:where(button[variant="ghost"][intent="danger"]) { color: var(--color-danger); }
|
|
770
|
+
:where(button[variant="ghost"][intent="alert"]) { color: var(--color-alert); }
|
|
771
|
+
|
|
772
|
+
:where(button[variant="ghost"]:hover:not(:disabled)) {
|
|
773
|
+
background: var(--tint-hover);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
:where(button[variant="ghost"]:is(:active, [aria-expanded="true"]):not(:disabled)) {
|
|
777
|
+
background: var(--tint-active);
|
|
778
|
+
background-clip: border-box;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
:where(button[variant="ghost"][intent="primary"]:hover:not(:disabled)) {
|
|
782
|
+
background: var(--tint-primary-hover);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
:where(button[variant="ghost"][intent="primary"]:is(:active, [aria-expanded="true"]):not(:disabled)) {
|
|
786
|
+
background: var(--tint-primary-active);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
:where(button[variant="ghost"][intent="danger"]:hover:not(:disabled)) {
|
|
790
|
+
background: var(--tint-danger-hover);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
:where(button[variant="ghost"][intent="danger"]:is(:active, [aria-expanded="true"]):not(:disabled)) {
|
|
794
|
+
background: var(--tint-danger-active);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
:where(button[variant="ghost"][intent="alert"]:hover:not(:disabled)) {
|
|
798
|
+
background: var(--tint-alert-hover);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
:where(button[variant="ghost"][intent="alert"]:is(:active, [aria-expanded="true"]):not(:disabled)) {
|
|
802
|
+
background: var(--tint-alert-active);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
:where(button[icon])::before {
|
|
806
|
+
content: "";
|
|
807
|
+
inline-size: 1lh;
|
|
808
|
+
block-size: 1lh;
|
|
809
|
+
grid-area: 1 / 1;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
:where(button[icon] > *) {
|
|
813
|
+
grid-area: 1 / 1;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/* Sizes. A size pairs a text step — the line a control's cell follows —
|
|
817
|
+
with a padding step, so a size means the same thing wherever it appears
|
|
818
|
+
and mixed rows line up. The control lines are shared vocabulary
|
|
819
|
+
([[ui/foundation/tokens/text.css]]): non-button controls — the tab, the
|
|
820
|
+
sidebar channel — state the same line from their own sheets.
|
|
821
|
+
|
|
822
|
+
Placed after the attribute rules above: at equal (zero) specificity,
|
|
823
|
+
source order lets a size outrank them (`size="sm"` padding beats
|
|
824
|
+
`icon`). */
|
|
825
|
+
|
|
826
|
+
/* The default size, stated: a control's line is the control's, not its
|
|
827
|
+
context's — without this, height follows whatever leading the surroundings
|
|
828
|
+
happen to have. Stated in pixels, not the prose leading: a control's cell
|
|
829
|
+
is tighter than a paragraph's. A control's height is derived, never
|
|
830
|
+
declared: the control line, plus the space-2 padding step top and
|
|
831
|
+
bottom, plus a 1px border each side (transparent where no border
|
|
832
|
+
shows) — 24px, with the line as the only input
|
|
833
|
+
([[ui/foundation/tokens/text.css]]). A control that visually contains
|
|
834
|
+
another holds it as an overlaid sibling. */
|
|
835
|
+
:where(button) {
|
|
836
|
+
font-size: var(--control-font-size);
|
|
837
|
+
line-height: var(--line-control);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
:where(button[size="sm"]) {
|
|
841
|
+
font-size: var(--text-sm);
|
|
842
|
+
/* Stated in pixels, not a ratio: a compact control's cell hugs its content,
|
|
843
|
+
and the default's prose leading would leave it mostly air. */
|
|
844
|
+
line-height: var(--line-control-sm);
|
|
845
|
+
padding: var(--space-2) var(--space-8);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
:where(button[size="sm"][icon]) {
|
|
849
|
+
padding: var(--space-2);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/* A sized control sizes the icon it holds: whatever size the composer put on
|
|
853
|
+
the icon, the control's own wins — `tv-icon[size]` names a fixed pixel
|
|
854
|
+
size, so left alone the icon would ignore the control shrinking around it.
|
|
855
|
+
12px is the even-pixel step below the sm line, the same seat the default
|
|
856
|
+
button gives its glyph. */
|
|
857
|
+
:where(button[size="sm"] tv-icon) {
|
|
858
|
+
font-size: 12px;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
:where(:is(input:not([type]), input[type=""], input[type="text"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], textarea)) {
|
|
862
|
+
box-sizing: border-box;
|
|
863
|
+
font-family: var(--font-sans);
|
|
864
|
+
font-size: var(--control-font-size);
|
|
865
|
+
line-height: var(--line-control);
|
|
866
|
+
color: var(--control-text-color);
|
|
867
|
+
background: var(--control-background);
|
|
868
|
+
border: var(--control-border);
|
|
869
|
+
border-radius: var(--control-radius);
|
|
870
|
+
padding: var(--control-padding);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
:where(:is(input:not([type]), input[type=""], input[type="text"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], textarea))::placeholder {
|
|
874
|
+
color: var(--input-placeholder-text-color);
|
|
875
|
+
opacity: 1;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
:where(:is(input:not([type]), input[type=""], input[type="text"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], textarea):focus-visible) {
|
|
879
|
+
outline: var(--outline-focus);
|
|
880
|
+
outline-offset: 0;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
:where(:is(input:not([type]), input[type=""], input[type="text"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], textarea)[aria-invalid="true"]) {
|
|
884
|
+
border-color: var(--color-danger);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
:where(:is(input:not([type]), input[type=""], input[type="text"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], textarea):disabled) {
|
|
888
|
+
background: var(--color-surface-muted);
|
|
889
|
+
opacity: 0.4;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
:where(textarea) {
|
|
893
|
+
line-height: 1.5;
|
|
894
|
+
resize: vertical;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/* Shared error-message styling; validation and announcement belong to the surface. */
|
|
898
|
+
:where(.tv-error) {
|
|
899
|
+
margin: 0;
|
|
900
|
+
color: var(--color-danger);
|
|
901
|
+
font-size: var(--text-sm);
|
|
902
|
+
line-height: 1.5;
|
|
903
|
+
overflow-wrap: anywhere;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/* The popover: the panel that floats over the page while the page stays
|
|
907
|
+
live, anchored to the trigger that opened it
|
|
908
|
+
([[ui/foundation/popover/index.md]]). This sheet states the box and the
|
|
909
|
+
open state; the contents belong to the composing surface, and where the
|
|
910
|
+
panel sits is stated by the placement algorithm in the spec. */
|
|
911
|
+
|
|
912
|
+
/* The box: the panel and the background, nothing inward. Sized to the
|
|
913
|
+
contents, not the page. tv-menu ([[ui/foundation/menu/index.md]]) and
|
|
914
|
+
tv-select ([[ui/foundation/select/index.md]]) are popover
|
|
915
|
+
specializations and wear the same box. */
|
|
916
|
+
:where(tv-popover, tv-menu, tv-select) {
|
|
917
|
+
width: max-content;
|
|
918
|
+
background: var(--panel-background);
|
|
919
|
+
background-clip: border-box;
|
|
920
|
+
/* Its own surface, its own ink and face: a panel floats over arbitrary
|
|
921
|
+
context and never inherits the color or font treatment around it —
|
|
922
|
+
the way a native menu renders as a system panel wherever it opens.
|
|
923
|
+
Weight and leading are the document base's and inherit unrepeated. */
|
|
924
|
+
color: var(--panel-text-color);
|
|
925
|
+
font-family: var(--font-sans);
|
|
926
|
+
/* The shared panel border keeps the existing hairline geometry. */
|
|
927
|
+
border: var(--panel-border);
|
|
928
|
+
outline: var(--panel-outline);
|
|
929
|
+
outline-offset: 0;
|
|
930
|
+
border-radius: var(--panel-radius);
|
|
931
|
+
box-shadow: var(--popover-shadow);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/* The `open` attribute is the open state ([[ui/foundation/popover/index.md]],
|
|
935
|
+
Markup). The closed rule is deliberately not `:where()`-wrapped: an
|
|
936
|
+
interior sheet stating its own open display (a flex panel) must not
|
|
937
|
+
accidentally out-cascade closedness. */
|
|
938
|
+
tv-popover:not([open]),
|
|
939
|
+
tv-menu:not([open]),
|
|
940
|
+
tv-select:not([open]) {
|
|
941
|
+
display: none;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
:where(tv-popover[open], tv-menu[open], tv-select[open]) {
|
|
945
|
+
display: block;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/* The expanded trigger's treatment is the button's
|
|
949
|
+
([[ui/foundation/button/index.md]]): the element maintains
|
|
950
|
+
`aria-expanded`, and the button sheet paints the state. */
|
|
951
|
+
|
|
952
|
+
/* The menu interior ([[ui/foundation/menu/index.md]]): the panel is the
|
|
953
|
+
popover's box ([[ui/foundation/popover/styles.css]]); these rules state
|
|
954
|
+
what a menu holds inside it. */
|
|
955
|
+
:where(tv-menu) {
|
|
956
|
+
min-width: 180px;
|
|
957
|
+
padding: var(--space-4);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
:where(tv-menu-item) {
|
|
961
|
+
display: flex;
|
|
962
|
+
align-items: center;
|
|
963
|
+
/* The control line, stated as the button states it — a menu row is a
|
|
964
|
+
control, not prose, and inherits prose leading without this. */
|
|
965
|
+
font-size: var(--text-md);
|
|
966
|
+
line-height: var(--line-control);
|
|
967
|
+
/* A deeper inset than a control's row padding, and no border at all —
|
|
968
|
+
menu rows read as one list, and sit denser than controls standing
|
|
969
|
+
alone. */
|
|
970
|
+
padding: var(--space-3) var(--space-10);
|
|
971
|
+
/* The panel's radius less its padding, so the two curves sit concentric. */
|
|
972
|
+
border-radius: calc(var(--panel-radius) - var(--space-4));
|
|
973
|
+
cursor: default;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/* One highlight: the hover tint stands down while the keyboard holds the
|
|
977
|
+
highlight (a script focus from pointing shows no :focus-visible, so the
|
|
978
|
+
pointer path keeps its tint); the mouse moving again takes it back. */
|
|
979
|
+
:where(tv-menu:not(:has(:focus-visible)) tv-menu-item:hover),
|
|
980
|
+
:where(tv-menu-item:focus-visible) {
|
|
981
|
+
background: var(--option-background-highlighted);
|
|
982
|
+
outline: none;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
:where(tv-menu-item:active) {
|
|
986
|
+
background: var(--option-background-active);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/* The destructive treatment: the danger situation as text, and the
|
|
990
|
+
situation's own tints, stated explicitly so a theme
|
|
991
|
+
overrides the pigment through the role. */
|
|
992
|
+
:where(tv-menu-item[intent="danger"]) {
|
|
993
|
+
color: var(--color-danger);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
:where(tv-menu:not(:has(:focus-visible)) tv-menu-item[intent="danger"]:hover),
|
|
997
|
+
:where(tv-menu-item[intent="danger"]:focus-visible) {
|
|
998
|
+
background: var(--tint-danger-hover);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
:where(tv-menu-item[intent="danger"]:active) {
|
|
1002
|
+
background: var(--tint-danger-active);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
:where(tv-menu hr) {
|
|
1006
|
+
border: 0;
|
|
1007
|
+
border-top: 1px solid var(--color-border);
|
|
1008
|
+
margin: var(--space-4) calc(-1 * var(--space-4));
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/* The select interior ([[ui/foundation/select/index.md]]): the panel is
|
|
1012
|
+
the popover's box ([[ui/foundation/popover/styles.css]]); these rules state
|
|
1013
|
+
what a select holds inside it. The row sits as the menu's does
|
|
1014
|
+
([[ui/foundation/menu/styles.css]]), with a leading gutter carrying the
|
|
1015
|
+
selected mark. */
|
|
1016
|
+
/* The trigger: the choice reads from the leading edge and the caret sits
|
|
1017
|
+
pinned at the trailing edge — the native pop-up arrangement, visible
|
|
1018
|
+
whenever the widest-option width leaves room. The hook is the combobox
|
|
1019
|
+
semantics the element writes on the trigger ([[arch/ui/elements.md]]);
|
|
1020
|
+
the button's own inline-flex row ([[ui/foundation/button/button.css]])
|
|
1021
|
+
supplies the rest. */
|
|
1022
|
+
:where(button[aria-haspopup="listbox"]) {
|
|
1023
|
+
justify-content: space-between;
|
|
1024
|
+
text-align: left;
|
|
1025
|
+
/* Tighter than the standalone button's inset: the panel opens over this
|
|
1026
|
+
control at its width, so the trigger sits closer to its list rows than
|
|
1027
|
+
to freestanding buttons. Tighter still on the trailing side — the caret
|
|
1028
|
+
hugs the right edge, since the label holds the left. */
|
|
1029
|
+
padding-inline: var(--space-8) var(--space-4);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/* No minimum of its own: the panel is at least as wide as its trigger
|
|
1033
|
+
([[ui/foundation/select/index.md]], Placement), and no wider than its
|
|
1034
|
+
options ask. */
|
|
1035
|
+
:where(tv-select) {
|
|
1036
|
+
padding: var(--space-4);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
:where(tv-option) {
|
|
1040
|
+
position: relative;
|
|
1041
|
+
display: flex;
|
|
1042
|
+
align-items: center;
|
|
1043
|
+
/* The control line, stated as the button states it — an option row is a
|
|
1044
|
+
control, not prose, and inherits prose leading without this. */
|
|
1045
|
+
font-size: var(--text-md);
|
|
1046
|
+
line-height: var(--line-control);
|
|
1047
|
+
/* A near-even inset: the leading edge holds the mark's gutter, and the
|
|
1048
|
+
trailing edge carries enough of it back that the row reads balanced. */
|
|
1049
|
+
padding: var(--space-3) var(--space-12) var(--space-3) var(--space-20);
|
|
1050
|
+
/* The panel's radius less its padding, so the two curves sit concentric. */
|
|
1051
|
+
border-radius: calc(var(--panel-radius) - var(--space-4));
|
|
1052
|
+
cursor: default;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/* One highlight, element-managed ([[ui/foundation/select/index.md]],
|
|
1056
|
+
Keyboard) — pointer and keyboard share the tint by construction, so no
|
|
1057
|
+
hover rule exists to fight it. */
|
|
1058
|
+
:where(tv-option[highlighted]) {
|
|
1059
|
+
background: var(--option-background-highlighted);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
:where(tv-option:active) {
|
|
1063
|
+
background: var(--option-background-active);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/* The selected mark: a check in the leading gutter, drawn as a mask (the
|
|
1067
|
+
checklist's technique, [[ui/foundation/checkbox-list/styles.css]]) so the
|
|
1068
|
+
authored option carries no icon markup. currentColor keeps it true on the
|
|
1069
|
+
highlight tint. */
|
|
1070
|
+
:where(tv-option[selected])::before {
|
|
1071
|
+
content: "";
|
|
1072
|
+
position: absolute;
|
|
1073
|
+
left: var(--space-4);
|
|
1074
|
+
top: 50%;
|
|
1075
|
+
translate: 0 -50%;
|
|
1076
|
+
width: 1em;
|
|
1077
|
+
height: 1em;
|
|
1078
|
+
background: currentColor;
|
|
1079
|
+
mask: var(--icon-check) center / 80% no-repeat;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/* The checklist's looks ([[ui/foundation/checkbox-list/index.md]]): the list's
|
|
1083
|
+
stack, the row's marker-and-content grid, and the done treatment.
|
|
1084
|
+
The checked marker consumes the shared `--checkbox-color` token. */
|
|
1085
|
+
checkbox-list {
|
|
1086
|
+
display: grid;
|
|
1087
|
+
gap: var(--space-6);
|
|
1088
|
+
margin: var(--space-12) 0;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
checkbox-item {
|
|
1092
|
+
position: relative;
|
|
1093
|
+
display: grid;
|
|
1094
|
+
grid-template-columns: 1em minmax(0, 1fr);
|
|
1095
|
+
gap: var(--space-8);
|
|
1096
|
+
align-items: baseline;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/* The marker box, seated on the first line's text. */
|
|
1100
|
+
checkbox-item::before {
|
|
1101
|
+
content: "";
|
|
1102
|
+
width: 1em;
|
|
1103
|
+
height: 1em;
|
|
1104
|
+
align-self: start;
|
|
1105
|
+
translate: 0 0.12em;
|
|
1106
|
+
background: transparent;
|
|
1107
|
+
border: var(--control-border);
|
|
1108
|
+
border-radius: var(--control-radius);
|
|
1109
|
+
box-sizing: border-box;
|
|
1110
|
+
cursor: not-allowed;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
checkbox-item[checked]::before {
|
|
1114
|
+
background: var(--checkbox-color);
|
|
1115
|
+
border-color: var(--checkbox-color);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/* The check, drawn as a mask over the marker's cell. */
|
|
1119
|
+
checkbox-item[checked]::after {
|
|
1120
|
+
content: "";
|
|
1121
|
+
position: absolute;
|
|
1122
|
+
left: 0;
|
|
1123
|
+
top: 0.12em;
|
|
1124
|
+
width: 1em;
|
|
1125
|
+
height: 1em;
|
|
1126
|
+
background: var(--color-surface);
|
|
1127
|
+
mask: var(--icon-check) center / 80% no-repeat;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
checkbox-item[checked] {
|
|
1131
|
+
color: var(--color-text-muted);
|
|
1132
|
+
text-decoration: line-through;
|
|
1133
|
+
text-decoration-thickness: 0.08em;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
tv-icon:not(:defined) {
|
|
1137
|
+
display: inline-flex;
|
|
1138
|
+
flex: none;
|
|
1139
|
+
width: 1em;
|
|
1140
|
+
height: 1em;
|
|
1141
|
+
/* Glyphs are drawn on a square canvas whose visual weight sits below the
|
|
1142
|
+
cap height of the text beside them; nudging down aligns their centre with
|
|
1143
|
+
the text's rather than with its baseline box. */
|
|
1144
|
+
vertical-align: -0.125em;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
tv-icon:not(:defined)[size="sm"] { font-size: 16px; }
|
|
1148
|
+
|
|
1149
|
+
tv-icon:not(:defined)[size="md"] { font-size: 20px; }
|
|
1150
|
+
|
|
1151
|
+
tv-icon:not(:defined)[size="lg"] { font-size: 24px; }
|
|
1152
|
+
|
|
1153
|
+
tv-icon:not(:defined)[size="xl"] { font-size: 32px; }
|