@frontpanel/css 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +100 -2
- package/base.css +49 -0
- package/components.css +547 -0
- package/fonts/OFL-michroma.txt +93 -0
- package/fonts/OFL-vt323.txt +93 -0
- package/fonts/michroma-latin-400.woff2 +0 -0
- package/fonts/vt323-latin-400.woff2 +0 -0
- package/fonts.css +24 -0
- package/index.css +3 -0
- package/package.json +59 -3
- package/page.css +101 -0
- package/tailwind-base.css +49 -0
- package/tailwind-page.css +101 -0
- package/tailwind.css +605 -0
- package/tokens.css +132 -0
package/tailwind.css
ADDED
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
/* Generated by scripts/build.ts from src/. Do not edit; edit the source and run `pnpm build`. */
|
|
2
|
+
@import "./tokens.css" layer(theme);
|
|
3
|
+
|
|
4
|
+
@theme inline {
|
|
5
|
+
--color-fp-chrome-hi: var(--fp-color-chrome-hi);
|
|
6
|
+
--color-fp-chrome-100: var(--fp-color-chrome-100);
|
|
7
|
+
--color-fp-chrome-300: var(--fp-color-chrome-300);
|
|
8
|
+
--color-fp-chrome-500: var(--fp-color-chrome-500);
|
|
9
|
+
--color-fp-chrome-800: var(--fp-color-chrome-800);
|
|
10
|
+
--color-fp-chrome-tint: var(--fp-color-chrome-tint);
|
|
11
|
+
--color-fp-scroll-thumb: var(--fp-color-scroll-thumb);
|
|
12
|
+
--color-fp-shell: var(--fp-color-shell);
|
|
13
|
+
--color-fp-shell-hi: var(--fp-color-shell-hi);
|
|
14
|
+
--color-fp-shell-matte: var(--fp-color-shell-matte);
|
|
15
|
+
--color-fp-well: var(--fp-color-well);
|
|
16
|
+
--color-fp-field: var(--fp-color-field);
|
|
17
|
+
--color-fp-ink: var(--fp-color-ink);
|
|
18
|
+
--color-fp-ink-soft: var(--fp-color-ink-soft);
|
|
19
|
+
--color-fp-ink-dim: var(--fp-color-ink-dim);
|
|
20
|
+
--color-fp-bevel-hi: var(--fp-color-bevel-hi);
|
|
21
|
+
--color-fp-bevel-lo: var(--fp-color-bevel-lo);
|
|
22
|
+
--color-fp-edge: var(--fp-color-edge);
|
|
23
|
+
--color-fp-edge-strong: var(--fp-color-edge-strong);
|
|
24
|
+
--color-fp-cast: var(--fp-color-cast);
|
|
25
|
+
--color-fp-grid: var(--fp-color-grid);
|
|
26
|
+
--color-fp-lcd-bg: var(--fp-color-lcd-bg);
|
|
27
|
+
--color-fp-lcd-ink: var(--fp-color-lcd-ink);
|
|
28
|
+
--color-fp-lcd-ghost: var(--fp-color-lcd-ghost);
|
|
29
|
+
--color-fp-housing: var(--fp-color-housing);
|
|
30
|
+
--color-fp-housing-ink: var(--fp-color-housing-ink);
|
|
31
|
+
--color-fp-led-on: var(--fp-color-led-on);
|
|
32
|
+
--color-fp-led-amber: var(--fp-color-led-amber);
|
|
33
|
+
--color-fp-led-red: var(--fp-color-led-red);
|
|
34
|
+
--color-fp-led-off: var(--fp-color-led-off);
|
|
35
|
+
--color-fp-cap: var(--fp-color-cap);
|
|
36
|
+
--color-fp-cap-ink: var(--fp-color-cap-ink);
|
|
37
|
+
--color-fp-cap-blue: var(--fp-color-cap-blue);
|
|
38
|
+
--color-fp-cap-blue-ink: var(--fp-color-cap-blue-ink);
|
|
39
|
+
--color-fp-cap-amber: var(--fp-color-cap-amber);
|
|
40
|
+
--color-fp-cap-amber-ink: var(--fp-color-cap-amber-ink);
|
|
41
|
+
--color-fp-cap-graphite: var(--fp-color-cap-graphite);
|
|
42
|
+
--color-fp-cap-graphite-ink: var(--fp-color-cap-graphite-ink);
|
|
43
|
+
--color-fp-cap-berry: var(--fp-color-cap-berry);
|
|
44
|
+
--color-fp-cap-berry-ink: var(--fp-color-cap-berry-ink);
|
|
45
|
+
--color-fp-gel: var(--fp-color-gel);
|
|
46
|
+
--color-fp-gel-hi: var(--fp-color-gel-hi);
|
|
47
|
+
--color-fp-gel-lo: var(--fp-color-gel-lo);
|
|
48
|
+
--color-fp-gel-ink: var(--fp-color-gel-ink);
|
|
49
|
+
--color-fp-focus: var(--fp-color-focus);
|
|
50
|
+
--color-fp-focus-ring: var(--fp-color-focus-ring);
|
|
51
|
+
--color-fp-select: var(--fp-color-select);
|
|
52
|
+
--color-fp-error-text: var(--fp-color-error-text);
|
|
53
|
+
--color-fp-backdrop: var(--fp-color-backdrop);
|
|
54
|
+
--color-fp-backdrop-hi: var(--fp-color-backdrop-hi);
|
|
55
|
+
--font-fp-display: var(--fp-font-display);
|
|
56
|
+
--font-fp-lcd: var(--fp-font-lcd);
|
|
57
|
+
--font-fp-ui: var(--fp-font-ui);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@layer components {
|
|
61
|
+
/* An LCD line redrawing left to right; the fp-lcd-redraw class steps through it. */
|
|
62
|
+
@keyframes fp-lcd-redraw {
|
|
63
|
+
from {
|
|
64
|
+
clip-path: inset(0 100% 0 0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
to {
|
|
68
|
+
clip-path: inset(0 0 0 0);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Two blinks 400 ms apart, then steady. Nothing on the device blinks for longer. */
|
|
73
|
+
@keyframes fp-blink-twice {
|
|
74
|
+
0%,
|
|
75
|
+
100% {
|
|
76
|
+
opacity: 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
12.5%,
|
|
80
|
+
37.5% {
|
|
81
|
+
opacity: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
25%,
|
|
85
|
+
50% {
|
|
86
|
+
opacity: 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Redraws an LCD line left to right in four steps, as when its value changes. */
|
|
92
|
+
@utility fp-lcd-redraw {
|
|
93
|
+
animation: fp-lcd-redraw 160ms steps(4, end);
|
|
94
|
+
|
|
95
|
+
@media (prefers-reduced-motion: reduce) {
|
|
96
|
+
animation: none;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Blinks twice, then holds: an LED confirming an action. */
|
|
101
|
+
@utility fp-blink-twice {
|
|
102
|
+
animation: fp-blink-twice 1.6s steps(1, end) 1;
|
|
103
|
+
|
|
104
|
+
@media (prefers-reduced-motion: reduce) {
|
|
105
|
+
animation: none;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The page behind the device: quiet blue-grey with a faint Y2K grid. */
|
|
110
|
+
@utility fp-device-backdrop {
|
|
111
|
+
background-color: var(--fp-color-backdrop);
|
|
112
|
+
background-image:
|
|
113
|
+
linear-gradient(var(--fp-color-grid) 1px, transparent 1px),
|
|
114
|
+
linear-gradient(90deg, var(--fp-color-grid) 1px, transparent 1px),
|
|
115
|
+
radial-gradient(ellipse 80% 60% at 20% 0%, var(--fp-color-backdrop-hi), transparent 70%),
|
|
116
|
+
linear-gradient(180deg, var(--fp-color-backdrop-hi), var(--fp-color-backdrop));
|
|
117
|
+
background-size:
|
|
118
|
+
32px 32px,
|
|
119
|
+
32px 32px,
|
|
120
|
+
auto,
|
|
121
|
+
auto;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Liquid-chrome ring around the device body. Diagonal so the reflection band crosses the corners. */
|
|
125
|
+
@utility fp-device-rim {
|
|
126
|
+
border-radius: 36px;
|
|
127
|
+
padding: 10px;
|
|
128
|
+
background-image: linear-gradient(
|
|
129
|
+
160deg,
|
|
130
|
+
var(--fp-color-chrome-hi) 0%,
|
|
131
|
+
var(--fp-color-chrome-100) 14%,
|
|
132
|
+
var(--fp-color-chrome-tint) 38%,
|
|
133
|
+
var(--fp-color-chrome-500) 50%,
|
|
134
|
+
var(--fp-color-chrome-300) 70%,
|
|
135
|
+
var(--fp-color-chrome-100) 100%
|
|
136
|
+
);
|
|
137
|
+
box-shadow:
|
|
138
|
+
0 0 0 1px var(--fp-color-chrome-800),
|
|
139
|
+
inset 0 1px 0 var(--fp-color-chrome-hi),
|
|
140
|
+
0 4px 0 var(--fp-color-cast),
|
|
141
|
+
0 14px 18px -10px var(--fp-color-cast);
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* A body set in the rim follows its curve (the rim's radius less its padding) and clips to it.
|
|
145
|
+
* No specificity, so a rim sized another way can give its body a matching radius with a class.
|
|
146
|
+
*/
|
|
147
|
+
:where(& > .fp-device-body) {
|
|
148
|
+
overflow: clip;
|
|
149
|
+
border-radius: 26px;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Molded body plastic the modules sit on. */
|
|
154
|
+
@utility fp-device-body {
|
|
155
|
+
background-image: linear-gradient(180deg, var(--fp-color-shell-hi), var(--fp-color-shell) 240px);
|
|
156
|
+
box-shadow:
|
|
157
|
+
inset 1px 1px 0 var(--fp-color-bevel-hi),
|
|
158
|
+
inset -1px -1px 0 var(--fp-color-bevel-lo);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Liquid chrome with a hard horizon, for title bars and other frames. Never behind text. */
|
|
162
|
+
@utility fp-chrome {
|
|
163
|
+
background-image: linear-gradient(
|
|
164
|
+
180deg,
|
|
165
|
+
var(--fp-color-chrome-hi) 0%,
|
|
166
|
+
var(--fp-color-chrome-100) 18%,
|
|
167
|
+
var(--fp-color-chrome-tint) 45%,
|
|
168
|
+
var(--fp-color-chrome-500) 52%,
|
|
169
|
+
var(--fp-color-chrome-300) 75%,
|
|
170
|
+
var(--fp-color-chrome-100) 100%
|
|
171
|
+
);
|
|
172
|
+
box-shadow:
|
|
173
|
+
inset 0 1px 0 var(--fp-color-chrome-hi),
|
|
174
|
+
inset 0 -1px 0 var(--fp-color-edge);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Brushed chrome without the horizon, calm enough to print a label in the middle of it. */
|
|
178
|
+
@utility fp-chrome-soft {
|
|
179
|
+
background-image: linear-gradient(
|
|
180
|
+
180deg,
|
|
181
|
+
color-mix(in srgb, var(--fp-color-chrome-hi) 60%, var(--fp-color-chrome-100)) 0%,
|
|
182
|
+
var(--fp-color-chrome-100) 40%,
|
|
183
|
+
var(--fp-color-chrome-300) 100%
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Small hardware push button in brushed chrome. 44 px tall, 36 px with a mouse, trackpad or pen. */
|
|
188
|
+
@utility fp-chrome-btn {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
gap: 0.375rem;
|
|
193
|
+
min-height: 2.75rem;
|
|
194
|
+
min-width: 2.75rem;
|
|
195
|
+
padding-inline: 0.625rem;
|
|
196
|
+
border-radius: 6px;
|
|
197
|
+
color: var(--fp-color-ink);
|
|
198
|
+
font-size: 13px;
|
|
199
|
+
font-weight: 700;
|
|
200
|
+
background-image: linear-gradient(
|
|
201
|
+
180deg,
|
|
202
|
+
color-mix(in srgb, var(--fp-color-chrome-hi) 60%, var(--fp-color-chrome-100)) 0%,
|
|
203
|
+
var(--fp-color-chrome-100) 40%,
|
|
204
|
+
var(--fp-color-chrome-300) 100%
|
|
205
|
+
);
|
|
206
|
+
box-shadow:
|
|
207
|
+
0 0 0 1px var(--fp-color-edge),
|
|
208
|
+
inset 1px 1px 0 var(--fp-color-bevel-hi),
|
|
209
|
+
inset -1px -1px 0 var(--fp-color-bevel-lo),
|
|
210
|
+
1px 2px 0 var(--fp-color-cast);
|
|
211
|
+
transition-property: translate, box-shadow, filter;
|
|
212
|
+
transition-duration: 70ms;
|
|
213
|
+
transition-timing-function: linear;
|
|
214
|
+
|
|
215
|
+
@media (prefers-reduced-motion: reduce) {
|
|
216
|
+
transition-duration: 0ms;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@media (pointer: fine) {
|
|
220
|
+
min-height: 2.25rem;
|
|
221
|
+
min-width: 2.25rem;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
&:hover:not(:disabled) {
|
|
225
|
+
filter: brightness(1.05);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&:active:not(:disabled),
|
|
229
|
+
&[aria-pressed="true"],
|
|
230
|
+
&[aria-expanded="true"],
|
|
231
|
+
&[aria-current="page"] {
|
|
232
|
+
translate: 0 1px;
|
|
233
|
+
box-shadow:
|
|
234
|
+
0 0 0 1px var(--fp-color-edge),
|
|
235
|
+
inset 1px 1px 3px var(--fp-color-bevel-lo),
|
|
236
|
+
inset -1px -1px 0 var(--fp-color-bevel-hi);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* A solid ring with a glow outside it: the glow alone fails non-text contrast on light chrome. */
|
|
240
|
+
&:focus-visible {
|
|
241
|
+
outline: 2px solid var(--fp-color-focus-ring);
|
|
242
|
+
outline-offset: 2px;
|
|
243
|
+
filter: drop-shadow(0 0 3px var(--fp-color-focus));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* The hover filter outranks the focus rule, so a hovered control keeps its glow here. */
|
|
247
|
+
&:focus-visible:hover:not(:disabled) {
|
|
248
|
+
filter: brightness(1.05) drop-shadow(0 0 3px var(--fp-color-focus));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
&:disabled {
|
|
252
|
+
opacity: 0.45;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Glossy gel pill for primary actions. Its white label sits on the base colour at mid-height,
|
|
258
|
+
* where the highlight ellipse has already faded out (7:1).
|
|
259
|
+
*/
|
|
260
|
+
@utility fp-gel {
|
|
261
|
+
display: inline-flex;
|
|
262
|
+
align-items: center;
|
|
263
|
+
justify-content: center;
|
|
264
|
+
gap: 0.5rem;
|
|
265
|
+
min-height: 2.75rem;
|
|
266
|
+
padding-inline: 1rem;
|
|
267
|
+
border-radius: 9999px;
|
|
268
|
+
color: var(--fp-color-gel-ink);
|
|
269
|
+
font-size: 14px;
|
|
270
|
+
font-weight: 700;
|
|
271
|
+
text-shadow: 0 -1px 0 rgb(0 0 0 / 0.35);
|
|
272
|
+
background-image:
|
|
273
|
+
radial-gradient(ellipse 80% 45% at 50% 0%, rgb(255 255 255 / 0.7), rgb(255 255 255 / 0.08) 90%, transparent 100%),
|
|
274
|
+
linear-gradient(180deg, var(--fp-color-gel-hi) 0%, var(--fp-color-gel) 48%, var(--fp-color-gel-lo) 100%);
|
|
275
|
+
box-shadow:
|
|
276
|
+
0 0 0 1px var(--fp-color-gel-lo),
|
|
277
|
+
inset 0 -3px 5px rgb(140 200 255 / 0.4),
|
|
278
|
+
1px 2px 0 var(--fp-color-cast);
|
|
279
|
+
transition-property: translate, box-shadow, filter;
|
|
280
|
+
transition-duration: 70ms;
|
|
281
|
+
transition-timing-function: linear;
|
|
282
|
+
|
|
283
|
+
@media (prefers-reduced-motion: reduce) {
|
|
284
|
+
transition-duration: 0ms;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@media (pointer: fine) {
|
|
288
|
+
min-height: 2.5rem;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
&:hover:not(:disabled) {
|
|
292
|
+
filter: brightness(1.08);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
&:active:not(:disabled) {
|
|
296
|
+
translate: 0 1px;
|
|
297
|
+
box-shadow:
|
|
298
|
+
0 0 0 1px var(--fp-color-gel-lo),
|
|
299
|
+
inset 0 2px 4px rgb(0 0 0 / 0.35);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* A solid ring with a glow outside it: the glow alone fails non-text contrast on light chrome. */
|
|
303
|
+
&:focus-visible {
|
|
304
|
+
outline: 2px solid var(--fp-color-focus-ring);
|
|
305
|
+
outline-offset: 2px;
|
|
306
|
+
filter: drop-shadow(0 0 3px var(--fp-color-focus));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* The hover filter outranks the focus rule, so a hovered control keeps its glow here. */
|
|
310
|
+
&:focus-visible:hover:not(:disabled) {
|
|
311
|
+
filter: brightness(1.08) drop-shadow(0 0 3px var(--fp-color-focus));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
&:disabled {
|
|
315
|
+
opacity: 0.45;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Molded-plastic cap. The cap colour and its label colour come from the fp-cap-* classes
|
|
321
|
+
* (`--fp-cap`, `--fp-cap-ink`); a bare `fp-cap` is white plastic with a dark label. Selected caps
|
|
322
|
+
* stay pressed in and get a ring, so selection never depends on colour.
|
|
323
|
+
*/
|
|
324
|
+
@utility fp-cap {
|
|
325
|
+
position: relative;
|
|
326
|
+
display: inline-flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
justify-content: center;
|
|
329
|
+
min-height: 2.75rem;
|
|
330
|
+
padding-inline: 0.5rem;
|
|
331
|
+
border-radius: 6px;
|
|
332
|
+
color: var(--fp-cap-ink, var(--fp-color-cap-ink));
|
|
333
|
+
font-weight: 700;
|
|
334
|
+
background-color: var(--fp-cap, var(--fp-color-cap));
|
|
335
|
+
background-image: radial-gradient(ellipse 110% 80% at 30% 10%, rgb(255 255 255 / 0.28), transparent 65%);
|
|
336
|
+
box-shadow:
|
|
337
|
+
0 0 0 1px var(--fp-color-edge),
|
|
338
|
+
inset 0 2px 0 rgb(255 255 255 / 0.45),
|
|
339
|
+
inset 0 -2px 0 rgb(0 0 0 / 0.25),
|
|
340
|
+
1px 2px 1px var(--fp-color-cast);
|
|
341
|
+
transition-property: translate, box-shadow, filter;
|
|
342
|
+
transition-duration: 70ms;
|
|
343
|
+
transition-timing-function: linear;
|
|
344
|
+
|
|
345
|
+
@media (prefers-reduced-motion: reduce) {
|
|
346
|
+
transition-duration: 0ms;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
@media (pointer: fine) {
|
|
350
|
+
min-height: 2.25rem;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
&:hover:not(:disabled) {
|
|
354
|
+
filter: brightness(1.05);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
&:active:not(:disabled) {
|
|
358
|
+
translate: 0 1px;
|
|
359
|
+
box-shadow:
|
|
360
|
+
0 0 0 1px var(--fp-color-edge),
|
|
361
|
+
inset 0 2px 3px rgb(0 0 0 / 0.35),
|
|
362
|
+
inset 0 -1px 0 rgb(255 255 255 / 0.3);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
&[aria-pressed="true"],
|
|
366
|
+
&[aria-checked="true"] {
|
|
367
|
+
translate: 0 1px;
|
|
368
|
+
box-shadow:
|
|
369
|
+
0 0 0 2px var(--fp-color-select),
|
|
370
|
+
inset 0 2px 3px rgb(0 0 0 / 0.35),
|
|
371
|
+
inset 0 -1px 0 rgb(255 255 255 / 0.3);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* A solid ring with a glow outside it: the glow alone fails non-text contrast on light chrome. */
|
|
375
|
+
&:focus-visible {
|
|
376
|
+
outline: 2px solid var(--fp-color-focus-ring);
|
|
377
|
+
outline-offset: 2px;
|
|
378
|
+
filter: drop-shadow(0 0 3px var(--fp-color-focus));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* The hover filter outranks the focus rule, so a hovered control keeps its glow here. */
|
|
382
|
+
&:focus-visible:hover:not(:disabled) {
|
|
383
|
+
filter: brightness(1.05) drop-shadow(0 0 3px var(--fp-color-focus));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
&:disabled {
|
|
387
|
+
opacity: 0.5;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Blue plastic for an fp-cap, with its own label colour. */
|
|
392
|
+
@utility fp-cap-blue {
|
|
393
|
+
--fp-cap: var(--fp-color-cap-blue);
|
|
394
|
+
--fp-cap-ink: var(--fp-color-cap-blue-ink);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** Amber plastic for an fp-cap, with its own label colour. */
|
|
398
|
+
@utility fp-cap-amber {
|
|
399
|
+
--fp-cap: var(--fp-color-cap-amber);
|
|
400
|
+
--fp-cap-ink: var(--fp-color-cap-amber-ink);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** Graphite plastic for an fp-cap, with its own label colour. */
|
|
404
|
+
@utility fp-cap-graphite {
|
|
405
|
+
--fp-cap: var(--fp-color-cap-graphite);
|
|
406
|
+
--fp-cap-ink: var(--fp-color-cap-graphite-ink);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** Berry plastic for an fp-cap, with its own label colour. */
|
|
410
|
+
@utility fp-cap-berry {
|
|
411
|
+
--fp-cap: var(--fp-color-cap-berry);
|
|
412
|
+
--fp-cap-ink: var(--fp-color-cap-berry-ink);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Matte content panel. This is where reading happens: no gloss, a 1 px bevel and a short hard shadow. */
|
|
416
|
+
@utility fp-module {
|
|
417
|
+
border-radius: 10px;
|
|
418
|
+
background-color: var(--fp-color-shell-matte);
|
|
419
|
+
box-shadow:
|
|
420
|
+
0 0 0 1px var(--fp-color-edge),
|
|
421
|
+
inset 1px 1px 0 var(--fp-color-bevel-hi),
|
|
422
|
+
inset -1px -1px 0 var(--fp-color-bevel-lo),
|
|
423
|
+
2px 3px 0 var(--fp-color-cast);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** A module's own little title bar, in brushed chrome. */
|
|
427
|
+
@utility fp-module-title {
|
|
428
|
+
display: flex;
|
|
429
|
+
align-items: center;
|
|
430
|
+
gap: 0.5rem;
|
|
431
|
+
min-height: 1.875rem;
|
|
432
|
+
padding: 0.25rem 0.625rem;
|
|
433
|
+
border-radius: 10px 10px 0 0;
|
|
434
|
+
border-bottom: 1px solid var(--fp-color-edge);
|
|
435
|
+
background-image: linear-gradient(
|
|
436
|
+
180deg,
|
|
437
|
+
color-mix(in srgb, var(--fp-color-chrome-hi) 60%, var(--fp-color-chrome-100)) 0%,
|
|
438
|
+
var(--fp-color-chrome-100) 40%,
|
|
439
|
+
var(--fp-color-chrome-300) 100%
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* A window: a module (or, in the page extra, a sheet panel) whose fp-module-title stays in view
|
|
445
|
+
* while its body scrolls under it.
|
|
446
|
+
*/
|
|
447
|
+
@utility fp-window {
|
|
448
|
+
/* Its top corners follow the window's, which differ between a module and a sheet. */
|
|
449
|
+
& > .fp-module-title {
|
|
450
|
+
position: sticky;
|
|
451
|
+
top: 0;
|
|
452
|
+
z-index: 1;
|
|
453
|
+
border-start-start-radius: inherit;
|
|
454
|
+
border-start-end-radius: inherit;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/* Title-bar buttons stay small with a precise pointer; touch keeps the 44 px target. */
|
|
458
|
+
@media (pointer: fine) {
|
|
459
|
+
& > .fp-module-title .fp-chrome-btn {
|
|
460
|
+
min-height: 1.75rem;
|
|
461
|
+
min-width: 1.75rem;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** A window's name in its title bar. Pair it with fp-silk; it pushes the title-bar buttons to the far end. */
|
|
467
|
+
@utility fp-window-title {
|
|
468
|
+
margin: 0;
|
|
469
|
+
margin-inline-end: auto;
|
|
470
|
+
font-weight: 400;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** The padded body under a window's title bar. */
|
|
474
|
+
@utility fp-window-body {
|
|
475
|
+
padding: 0.75rem;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Recessed well inside a matte panel, for secondary content or an empty slot. */
|
|
479
|
+
@utility fp-well {
|
|
480
|
+
border-radius: 6px;
|
|
481
|
+
background-color: var(--fp-color-well);
|
|
482
|
+
box-shadow:
|
|
483
|
+
inset 1px 1px 2px var(--fp-color-bevel-lo),
|
|
484
|
+
inset -1px -1px 0 var(--fp-color-bevel-hi);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** Silkscreened hardware label. */
|
|
488
|
+
@utility fp-silk {
|
|
489
|
+
font-family: var(--fp-font-display);
|
|
490
|
+
font-size: 11px;
|
|
491
|
+
line-height: 1.3;
|
|
492
|
+
letter-spacing: 0.08em;
|
|
493
|
+
text-transform: uppercase;
|
|
494
|
+
color: var(--fp-color-ink-soft);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** LCD glass, recessed into the chrome. Text on it uses `--fp-font-lcd`; drawings use `--fp-color-lcd-ink`. */
|
|
498
|
+
@utility fp-lcd {
|
|
499
|
+
border-radius: 8px;
|
|
500
|
+
color: var(--fp-color-lcd-ink);
|
|
501
|
+
background-color: var(--fp-color-lcd-bg);
|
|
502
|
+
background-image: repeating-linear-gradient(0deg, rgb(0 0 0 / 0.04) 0 1px, transparent 1px 3px);
|
|
503
|
+
box-shadow:
|
|
504
|
+
0 0 0 2px var(--fp-color-chrome-800),
|
|
505
|
+
inset 2px 2px 4px rgb(0 0 0 / 0.35),
|
|
506
|
+
inset -1px -1px 0 rgb(255 255 255 / 0.2);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/** One line of LCD text. Cells of fp-lcd-ghost stacked behind it show the unlit segments, as on real glass. */
|
|
510
|
+
@utility fp-lcd-line {
|
|
511
|
+
display: grid;
|
|
512
|
+
margin: 0;
|
|
513
|
+
font-family: var(--fp-font-lcd);
|
|
514
|
+
white-space: pre;
|
|
515
|
+
|
|
516
|
+
& > * {
|
|
517
|
+
grid-area: 1 / 1;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** The unlit segments behind an LCD line. Decorative: give it aria-hidden="true". */
|
|
522
|
+
@utility fp-lcd-ghost {
|
|
523
|
+
color: var(--fp-color-lcd-ghost);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/** Dark housing that LEDs and small readouts sit in. */
|
|
527
|
+
@utility fp-housing {
|
|
528
|
+
display: inline-flex;
|
|
529
|
+
align-items: center;
|
|
530
|
+
gap: 0.375rem;
|
|
531
|
+
border-radius: 9999px;
|
|
532
|
+
padding: 0.125rem 0.5rem;
|
|
533
|
+
color: var(--fp-color-housing-ink);
|
|
534
|
+
font-size: 12px;
|
|
535
|
+
font-weight: 700;
|
|
536
|
+
background-color: var(--fp-color-housing);
|
|
537
|
+
box-shadow:
|
|
538
|
+
inset 1px 1px 2px rgb(0 0 0 / 0.5),
|
|
539
|
+
0 1px 0 var(--fp-color-bevel-hi);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** An LED with its own dark bezel ring, so a lit one reads on light chrome too. Unlit by default. */
|
|
543
|
+
@utility fp-led {
|
|
544
|
+
display: inline-block;
|
|
545
|
+
flex-shrink: 0;
|
|
546
|
+
width: 0.5rem;
|
|
547
|
+
height: 0.5rem;
|
|
548
|
+
border-radius: 9999px;
|
|
549
|
+
background-color: var(--fp-color-led-off);
|
|
550
|
+
box-shadow:
|
|
551
|
+
0 0 0 2px var(--fp-color-housing),
|
|
552
|
+
inset 0 -1px 1px rgb(0 0 0 / 0.45);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Green for an fp-led, the default. */
|
|
556
|
+
@utility fp-led-green {
|
|
557
|
+
--fp-led: var(--fp-color-led-on);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** Amber for an fp-led. */
|
|
561
|
+
@utility fp-led-amber {
|
|
562
|
+
--fp-led: var(--fp-color-led-amber);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Red for an fp-led. */
|
|
566
|
+
@utility fp-led-red {
|
|
567
|
+
--fp-led: var(--fp-color-led-red);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/** Lights an fp-led in its colour, with a glow. Say what it means in text nearby, never by colour alone. */
|
|
571
|
+
@utility fp-led-lit {
|
|
572
|
+
background-color: var(--fp-led, var(--fp-color-led-on));
|
|
573
|
+
box-shadow:
|
|
574
|
+
0 0 0 2px var(--fp-color-housing),
|
|
575
|
+
0 0 7px 2px color-mix(in srgb, var(--fp-led, var(--fp-color-led-on)) 65%, transparent),
|
|
576
|
+
inset 0 -1px 1px rgb(0 0 0 / 0.2);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** Decorative screw head. Give it aria-hidden="true". */
|
|
580
|
+
@utility fp-screw {
|
|
581
|
+
display: inline-block;
|
|
582
|
+
flex-shrink: 0;
|
|
583
|
+
width: 10px;
|
|
584
|
+
height: 10px;
|
|
585
|
+
border-radius: 9999px;
|
|
586
|
+
background-image:
|
|
587
|
+
linear-gradient(135deg, transparent 44%, var(--fp-color-chrome-800) 44% 56%, transparent 56%),
|
|
588
|
+
radial-gradient(circle at 35% 30%, var(--fp-color-chrome-hi), var(--fp-color-chrome-300) 60%, var(--fp-color-chrome-500));
|
|
589
|
+
box-shadow: 0 0 0 1px var(--fp-color-edge);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** A scrolling panel, such as a list window, with a thin scrollbar that never pushes the layout. */
|
|
593
|
+
@utility fp-scroll-thin {
|
|
594
|
+
scrollbar-width: thin;
|
|
595
|
+
scrollbar-color: var(--fp-color-scroll-thumb) transparent;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** A 16 px pixel icon. Size it in whole multiples of 16 px so its pixels stay crisp. */
|
|
599
|
+
@utility fp-icon {
|
|
600
|
+
flex-shrink: 0;
|
|
601
|
+
width: 16px;
|
|
602
|
+
height: 16px;
|
|
603
|
+
fill: currentColor;
|
|
604
|
+
shape-rendering: crispEdges;
|
|
605
|
+
}
|