@frontpanel/css 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components.css +635 -2
- package/package.json +1 -1
- package/page.css +5 -0
- package/tailwind-page.css +5 -0
- package/tailwind.css +635 -2
package/tailwind.css
CHANGED
|
@@ -86,6 +86,19 @@
|
|
|
86
86
|
opacity: 1;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
/* A menu dropping open from its button: a short slide down as it fades in. */
|
|
91
|
+
@keyframes fp-menu-drop {
|
|
92
|
+
from {
|
|
93
|
+
opacity: 0;
|
|
94
|
+
translate: 0 -4px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
to {
|
|
98
|
+
opacity: 1;
|
|
99
|
+
translate: 0 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
/** Redraws an LCD line left to right in four steps, as when its value changes. */
|
|
@@ -150,6 +163,11 @@
|
|
|
150
163
|
overflow: clip;
|
|
151
164
|
border-radius: 26px;
|
|
152
165
|
}
|
|
166
|
+
|
|
167
|
+
/* Forced colours drop the chrome: an outline keeps the device's edge. */
|
|
168
|
+
@media (forced-colors: active) {
|
|
169
|
+
outline: 1px solid CanvasText;
|
|
170
|
+
}
|
|
153
171
|
}
|
|
154
172
|
|
|
155
173
|
/** Molded body plastic the modules sit on. */
|
|
@@ -254,6 +272,35 @@
|
|
|
254
272
|
&:disabled {
|
|
255
273
|
opacity: 0.45;
|
|
256
274
|
}
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* Forced colours drop the chrome and its shadows: an outline keeps the button's edge, the system's
|
|
278
|
+
* selected colours show it pressed, and GrayText, not a fade, shows it disabled.
|
|
279
|
+
*/
|
|
280
|
+
@media (forced-colors: active) {
|
|
281
|
+
outline: 1px solid ButtonText;
|
|
282
|
+
outline-offset: -1px;
|
|
283
|
+
|
|
284
|
+
&[aria-pressed="true"],
|
|
285
|
+
&[aria-expanded="true"],
|
|
286
|
+
&[aria-current="page"] {
|
|
287
|
+
forced-color-adjust: none;
|
|
288
|
+
background: SelectedItem;
|
|
289
|
+
box-shadow: none;
|
|
290
|
+
color: SelectedItemText;
|
|
291
|
+
|
|
292
|
+
/* Opted out, its focus ring would keep the skin's colour: the system's text colour shows on any ground. */
|
|
293
|
+
&:focus-visible {
|
|
294
|
+
outline-color: CanvasText;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
&:disabled {
|
|
299
|
+
opacity: 1;
|
|
300
|
+
color: GrayText;
|
|
301
|
+
outline-color: GrayText;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
257
304
|
}
|
|
258
305
|
|
|
259
306
|
/**
|
|
@@ -317,6 +364,46 @@
|
|
|
317
364
|
&:disabled {
|
|
318
365
|
opacity: 0.45;
|
|
319
366
|
}
|
|
367
|
+
|
|
368
|
+
/* Forced colours drop the gel and its shadows: an outline keeps its edge, and GrayText, not a fade, shows it disabled. */
|
|
369
|
+
@media (forced-colors: active) {
|
|
370
|
+
outline: 1px solid ButtonText;
|
|
371
|
+
outline-offset: -1px;
|
|
372
|
+
|
|
373
|
+
&:disabled {
|
|
374
|
+
opacity: 1;
|
|
375
|
+
color: GrayText;
|
|
376
|
+
outline-color: GrayText;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Chrome buttons joined side by side into one bezel, as on a transport row: fp-chrome-btn children
|
|
383
|
+
* share their seams, and only the outer corners stay round. Give it `role="group"` and a name.
|
|
384
|
+
*/
|
|
385
|
+
@utility fp-button-group {
|
|
386
|
+
display: inline-flex;
|
|
387
|
+
align-items: stretch;
|
|
388
|
+
|
|
389
|
+
/* The 1 px edge round each button falls in the gap, so neighbours share one seam. */
|
|
390
|
+
gap: 1px;
|
|
391
|
+
|
|
392
|
+
& > .fp-chrome-btn:not(:first-child) {
|
|
393
|
+
border-start-start-radius: 0;
|
|
394
|
+
border-end-start-radius: 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
& > .fp-chrome-btn:not(:last-child) {
|
|
398
|
+
border-start-end-radius: 0;
|
|
399
|
+
border-end-end-radius: 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/* A focused button's ring goes over its neighbours, not under them. */
|
|
403
|
+
& > .fp-chrome-btn:focus-visible {
|
|
404
|
+
position: relative;
|
|
405
|
+
z-index: 1;
|
|
406
|
+
}
|
|
320
407
|
}
|
|
321
408
|
|
|
322
409
|
/**
|
|
@@ -389,6 +476,34 @@
|
|
|
389
476
|
&:disabled {
|
|
390
477
|
opacity: 0.5;
|
|
391
478
|
}
|
|
479
|
+
|
|
480
|
+
/*
|
|
481
|
+
* Forced colours drop the plastic and its ring: an outline keeps the cap's edge, the system's
|
|
482
|
+
* selected colours show it selected, and GrayText, not a fade, shows it disabled.
|
|
483
|
+
*/
|
|
484
|
+
@media (forced-colors: active) {
|
|
485
|
+
outline: 1px solid ButtonText;
|
|
486
|
+
outline-offset: -1px;
|
|
487
|
+
|
|
488
|
+
&[aria-pressed="true"],
|
|
489
|
+
&[aria-checked="true"] {
|
|
490
|
+
forced-color-adjust: none;
|
|
491
|
+
background: SelectedItem;
|
|
492
|
+
box-shadow: none;
|
|
493
|
+
color: SelectedItemText;
|
|
494
|
+
|
|
495
|
+
/* Opted out, its focus ring would keep the skin's colour: the system's text colour shows on any ground. */
|
|
496
|
+
&:focus-visible {
|
|
497
|
+
outline-color: CanvasText;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
&:disabled {
|
|
502
|
+
opacity: 1;
|
|
503
|
+
color: GrayText;
|
|
504
|
+
outline-color: GrayText;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
392
507
|
}
|
|
393
508
|
|
|
394
509
|
/** Blue plastic for an fp-cap, with its own label colour. */
|
|
@@ -416,14 +531,21 @@
|
|
|
416
531
|
}
|
|
417
532
|
|
|
418
533
|
/**
|
|
419
|
-
* A control with its silkscreen label under it: a knob, fader or
|
|
420
|
-
*
|
|
534
|
+
* A control with its silkscreen label under it: a knob, fader, meter or switch and then an fp-silk.
|
|
535
|
+
* With `data-label-placement="start"` the label sits level with the control, before it in the
|
|
536
|
+
* line. A length set here, such as `--fp-fader-length`, reaches the control inside.
|
|
421
537
|
*/
|
|
422
538
|
@utility fp-unit {
|
|
423
539
|
display: inline-flex;
|
|
424
540
|
flex-direction: column;
|
|
425
541
|
align-items: center;
|
|
426
542
|
gap: 0.375rem;
|
|
543
|
+
|
|
544
|
+
/* Reversed, so the markup stays control then label either way. */
|
|
545
|
+
&[data-label-placement="start"] {
|
|
546
|
+
flex-direction: row-reverse;
|
|
547
|
+
gap: 0.5rem;
|
|
548
|
+
}
|
|
427
549
|
}
|
|
428
550
|
|
|
429
551
|
/**
|
|
@@ -482,6 +604,15 @@
|
|
|
482
604
|
opacity: 0.45;
|
|
483
605
|
cursor: not-allowed;
|
|
484
606
|
}
|
|
607
|
+
|
|
608
|
+
/* Forced colours drop the knurling, the dome and their shadows: outlines draw the skirt and the cap. */
|
|
609
|
+
@media (forced-colors: active) {
|
|
610
|
+
outline: 1px solid CanvasText;
|
|
611
|
+
|
|
612
|
+
&::before {
|
|
613
|
+
outline: 1px solid CanvasText;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
485
616
|
}
|
|
486
617
|
|
|
487
618
|
/** The pointer line on a knob's cap. Turn it with `rotate`: -135deg at the minimum, 135deg at the maximum. */
|
|
@@ -501,6 +632,14 @@
|
|
|
501
632
|
border-radius: 2px;
|
|
502
633
|
background-color: var(--fp-color-ink);
|
|
503
634
|
}
|
|
635
|
+
|
|
636
|
+
/* Forced colours would paint the line in the page colour, on the page colour. */
|
|
637
|
+
@media (forced-colors: active) {
|
|
638
|
+
&::after {
|
|
639
|
+
forced-color-adjust: none;
|
|
640
|
+
background-color: CanvasText;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
504
643
|
}
|
|
505
644
|
|
|
506
645
|
/**
|
|
@@ -557,6 +696,13 @@
|
|
|
557
696
|
height: 6px;
|
|
558
697
|
translate: 0 -50%;
|
|
559
698
|
}
|
|
699
|
+
|
|
700
|
+
/* Forced colours: the slot as a solid line, so the cap's travel shows. */
|
|
701
|
+
@media (forced-colors: active) {
|
|
702
|
+
forced-color-adjust: none;
|
|
703
|
+
background-color: CanvasText;
|
|
704
|
+
box-shadow: none;
|
|
705
|
+
}
|
|
560
706
|
}
|
|
561
707
|
|
|
562
708
|
/**
|
|
@@ -619,6 +765,344 @@
|
|
|
619
765
|
outline-offset: 2px;
|
|
620
766
|
filter: drop-shadow(0 0 3px var(--fp-color-focus));
|
|
621
767
|
}
|
|
768
|
+
|
|
769
|
+
/* Forced colours: a cap in the page colour hides the slot under it; an outline and the grip draw it. */
|
|
770
|
+
@media (forced-colors: active) {
|
|
771
|
+
background-color: Canvas;
|
|
772
|
+
outline: 1px solid CanvasText;
|
|
773
|
+
outline-offset: -1px;
|
|
774
|
+
|
|
775
|
+
&::after {
|
|
776
|
+
forced-color-adjust: none;
|
|
777
|
+
background-color: CanvasText;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Illuminated rocker switch: a lamp-lit paddle in a dark bezel, marked I at the top and O at the
|
|
784
|
+
* bottom. Off, the O half is pressed in; on, the I half is, and the lamp behind the lens lights.
|
|
785
|
+
* Put it on a button with `role="switch"` and `aria-checked`, holding an fp-switch-rocker. The
|
|
786
|
+
* lamp is red; colour it with fp-led-green or fp-led-amber. 44 x 56 px, 36 x 46 px with a mouse,
|
|
787
|
+
* trackpad or pen. With `data-orientation="horizontal"` it lies on its side, 56 x 44 px (46 x 36),
|
|
788
|
+
* O on the left and I on the right. After an illuminated rocker pen by ykadosh (CodePen, MIT), rebuilt on the kit's
|
|
789
|
+
* tokens.
|
|
790
|
+
*/
|
|
791
|
+
@utility fp-switch {
|
|
792
|
+
--fp-switch-lamp: var(--fp-led, var(--fp-color-led-red));
|
|
793
|
+
position: relative;
|
|
794
|
+
display: inline-block;
|
|
795
|
+
flex-shrink: 0;
|
|
796
|
+
width: 2.75rem;
|
|
797
|
+
height: 3.5rem;
|
|
798
|
+
padding: 5px;
|
|
799
|
+
border: 0;
|
|
800
|
+
border-radius: 4px;
|
|
801
|
+
background-color: color-mix(in srgb, var(--fp-color-housing) 40%, black);
|
|
802
|
+
box-shadow:
|
|
803
|
+
0 0 0 1px var(--fp-color-edge),
|
|
804
|
+
inset 1px 1px 0 rgb(255 255 255 / 0.25),
|
|
805
|
+
inset 0 0 1px 3px var(--fp-color-housing),
|
|
806
|
+
inset 0 0 1px 5px color-mix(in srgb, var(--fp-color-housing) 40%, black),
|
|
807
|
+
1px 2px 0 var(--fp-color-cast);
|
|
808
|
+
perspective: 216px;
|
|
809
|
+
cursor: pointer;
|
|
810
|
+
|
|
811
|
+
@media (pointer: fine) {
|
|
812
|
+
width: 2.25rem;
|
|
813
|
+
height: 2.875rem;
|
|
814
|
+
padding: 4px;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/* On: the I half goes in, the shine comes up, the shading goes, and the lamp lights as it lands. */
|
|
818
|
+
&[aria-checked="true"] .fp-switch-rocker {
|
|
819
|
+
transform: translateZ(6px) rotateX(25deg);
|
|
820
|
+
box-shadow: 0 -3px 6px var(--fp-switch-lamp);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
&[aria-checked="true"] .fp-switch-face::before {
|
|
824
|
+
opacity: 1;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
&[aria-checked="true"] .fp-switch-face::after {
|
|
828
|
+
opacity: 0;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
&[aria-checked="true"] .fp-switch-lamp {
|
|
832
|
+
opacity: 1;
|
|
833
|
+
transition-duration: 60ms;
|
|
834
|
+
transition-timing-function: linear;
|
|
835
|
+
transition-delay: 250ms;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/*
|
|
839
|
+
* On its side the paddle tips across instead, and the marks stay upright. With the light at the
|
|
840
|
+
* top left, the right end is now the one in shade that casts the shadow, and the left end is lit.
|
|
841
|
+
*/
|
|
842
|
+
&[data-orientation="horizontal"] {
|
|
843
|
+
width: 3.5rem;
|
|
844
|
+
height: 2.75rem;
|
|
845
|
+
|
|
846
|
+
@media (pointer: fine) {
|
|
847
|
+
width: 2.875rem;
|
|
848
|
+
height: 2.25rem;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
& .fp-switch-rocker {
|
|
852
|
+
transform: translateZ(6px) rotateY(-25deg);
|
|
853
|
+
background: linear-gradient(
|
|
854
|
+
90deg,
|
|
855
|
+
color-mix(in srgb, var(--fp-switch-lamp) 60%, black) 0%,
|
|
856
|
+
color-mix(in srgb, var(--fp-switch-lamp) 44%, black) 30%,
|
|
857
|
+
color-mix(in srgb, var(--fp-switch-lamp) 44%, black) 70%,
|
|
858
|
+
color-mix(in srgb, var(--fp-switch-lamp) 60%, black) 100%
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/* The right end, in shade, with the shadow the paddle casts into the bezel. */
|
|
863
|
+
& .fp-switch-rocker::before {
|
|
864
|
+
left: auto;
|
|
865
|
+
right: 0;
|
|
866
|
+
width: 15px;
|
|
867
|
+
height: 100%;
|
|
868
|
+
transform-origin: right;
|
|
869
|
+
transform: rotateY(-90deg);
|
|
870
|
+
background: linear-gradient(
|
|
871
|
+
270deg,
|
|
872
|
+
color-mix(in srgb, var(--fp-switch-lamp) 40%, black),
|
|
873
|
+
color-mix(in srgb, var(--fp-switch-lamp) 20%, black)
|
|
874
|
+
);
|
|
875
|
+
box-shadow:
|
|
876
|
+
-15px 0 3px 0 black,
|
|
877
|
+
-24px 0 6px 0 rgb(0 0 0 / 0.5);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/* The left end, lit from the left while it stands proud. */
|
|
881
|
+
& .fp-switch-rocker::after {
|
|
882
|
+
top: 0;
|
|
883
|
+
bottom: auto;
|
|
884
|
+
width: 15px;
|
|
885
|
+
height: 100%;
|
|
886
|
+
transform-origin: right;
|
|
887
|
+
transform: translateX(-15px) rotateY(-90deg);
|
|
888
|
+
background:
|
|
889
|
+
linear-gradient(
|
|
890
|
+
270deg,
|
|
891
|
+
rgb(255 255 255 / 0.8) 10%,
|
|
892
|
+
rgb(255 255 255 / 0.3) 30%,
|
|
893
|
+
color-mix(in srgb, var(--fp-switch-lamp) 40%, black) 75%,
|
|
894
|
+
color-mix(in srgb, var(--fp-switch-lamp) 20%, black)
|
|
895
|
+
)
|
|
896
|
+
50% 50% / 97% 97% no-repeat,
|
|
897
|
+
color-mix(in srgb, var(--fp-switch-lamp) 70%, black);
|
|
898
|
+
box-shadow: none;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
& .fp-switch-face {
|
|
902
|
+
background:
|
|
903
|
+
linear-gradient(#fff, #fff) 78% 50% / max(2px, 4%) 28% no-repeat,
|
|
904
|
+
radial-gradient(circle, transparent 50%, #fff 52%, #fff 70%, transparent 72%) 22% 50% / 25% 33% no-repeat,
|
|
905
|
+
radial-gradient(transparent 30%, color-mix(in srgb, color-mix(in srgb, var(--fp-switch-lamp) 40%, black) 70%, transparent) 70%) 0 0 / 3px 3px;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
& .fp-switch-face::before {
|
|
909
|
+
background:
|
|
910
|
+
linear-gradient(#fff, transparent 3%) 50% 50% / 97% 97% no-repeat,
|
|
911
|
+
linear-gradient(270deg, rgb(255 255 255 / 0.5), transparent 50%, transparent 80%, rgb(255 255 255 / 0.5)) 50% 50% / 97% 97% no-repeat;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
& .fp-switch-face::after {
|
|
915
|
+
background-image: linear-gradient(270deg, transparent 70%, rgb(0 0 0 / 0.8));
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
&[aria-checked="true"] .fp-switch-rocker {
|
|
919
|
+
transform: translateZ(6px) rotateY(25deg);
|
|
920
|
+
box-shadow: 3px 0 6px var(--fp-switch-lamp);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/* A solid ring with a glow outside it: the glow alone fails non-text contrast on light chrome. */
|
|
925
|
+
&:focus-visible {
|
|
926
|
+
outline: 2px solid var(--fp-color-focus-ring);
|
|
927
|
+
outline-offset: 2px;
|
|
928
|
+
filter: drop-shadow(0 0 3px var(--fp-color-focus));
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
&:disabled,
|
|
932
|
+
&[aria-disabled="true"] {
|
|
933
|
+
opacity: 0.45;
|
|
934
|
+
cursor: not-allowed;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/*
|
|
938
|
+
* Forced colours drop the paddle's paint: an outline keeps the bezel's edge, and the rocker fills
|
|
939
|
+
* when on, as a lit LED does, so the state reads by shape as well as by the tilt.
|
|
940
|
+
*/
|
|
941
|
+
@media (forced-colors: active) {
|
|
942
|
+
outline: 1px solid ButtonText;
|
|
943
|
+
|
|
944
|
+
&[data-orientation="horizontal"] .fp-switch-rocker {
|
|
945
|
+
background: Canvas;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
&[aria-checked="true"] .fp-switch-rocker,
|
|
949
|
+
&[data-orientation="horizontal"][aria-checked="true"] .fp-switch-rocker {
|
|
950
|
+
background: CanvasText;
|
|
951
|
+
box-shadow: none;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
&:disabled,
|
|
955
|
+
&[aria-disabled="true"] {
|
|
956
|
+
opacity: 1;
|
|
957
|
+
outline-color: GrayText;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* The paddle of an fp-switch, tilted in 3D. It holds an fp-switch-lamp and then an fp-switch-face;
|
|
964
|
+
* its top and bottom ends show as it tips.
|
|
965
|
+
*/
|
|
966
|
+
@utility fp-switch-rocker {
|
|
967
|
+
position: relative;
|
|
968
|
+
display: block;
|
|
969
|
+
width: 100%;
|
|
970
|
+
height: 100%;
|
|
971
|
+
transform-origin: 50% 50% -6px;
|
|
972
|
+
transform: translateZ(6px) rotateX(-25deg);
|
|
973
|
+
transform-style: preserve-3d;
|
|
974
|
+
background: linear-gradient(
|
|
975
|
+
color-mix(in srgb, var(--fp-switch-lamp) 60%, black) 0%,
|
|
976
|
+
color-mix(in srgb, var(--fp-switch-lamp) 44%, black) 30%,
|
|
977
|
+
color-mix(in srgb, var(--fp-switch-lamp) 44%, black) 70%,
|
|
978
|
+
color-mix(in srgb, var(--fp-switch-lamp) 60%, black) 100%
|
|
979
|
+
);
|
|
980
|
+
|
|
981
|
+
/* Snaps over at the end of its travel, as a rocker's spring does. */
|
|
982
|
+
transition: transform 300ms cubic-bezier(1, 0, 1, 1), box-shadow 300ms cubic-bezier(1, 0, 1, 1);
|
|
983
|
+
|
|
984
|
+
@media (prefers-reduced-motion: reduce) {
|
|
985
|
+
transition-duration: 0ms;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/* The top end, lit from above while it stands proud. */
|
|
989
|
+
&::before {
|
|
990
|
+
content: "";
|
|
991
|
+
position: absolute;
|
|
992
|
+
top: 0;
|
|
993
|
+
left: 0;
|
|
994
|
+
width: 100%;
|
|
995
|
+
height: 15px;
|
|
996
|
+
transform-origin: top;
|
|
997
|
+
transform: rotateX(-90deg);
|
|
998
|
+
background:
|
|
999
|
+
linear-gradient(
|
|
1000
|
+
rgb(255 255 255 / 0.8) 10%,
|
|
1001
|
+
rgb(255 255 255 / 0.3) 30%,
|
|
1002
|
+
color-mix(in srgb, var(--fp-switch-lamp) 40%, black) 75%,
|
|
1003
|
+
color-mix(in srgb, var(--fp-switch-lamp) 20%, black)
|
|
1004
|
+
)
|
|
1005
|
+
50% 50% / 97% 97% no-repeat,
|
|
1006
|
+
color-mix(in srgb, var(--fp-switch-lamp) 70%, black);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/* The bottom end, in shadow, with the shadow the paddle casts into the bezel. */
|
|
1010
|
+
&::after {
|
|
1011
|
+
content: "";
|
|
1012
|
+
position: absolute;
|
|
1013
|
+
bottom: 0;
|
|
1014
|
+
left: 0;
|
|
1015
|
+
width: 100%;
|
|
1016
|
+
height: 15px;
|
|
1017
|
+
transform-origin: top;
|
|
1018
|
+
transform: translateY(15px) rotateX(-90deg);
|
|
1019
|
+
background-image: linear-gradient(
|
|
1020
|
+
color-mix(in srgb, var(--fp-switch-lamp) 40%, black),
|
|
1021
|
+
color-mix(in srgb, var(--fp-switch-lamp) 20%, black)
|
|
1022
|
+
);
|
|
1023
|
+
box-shadow:
|
|
1024
|
+
0 15px 3px 0 black,
|
|
1025
|
+
0 24px 6px 0 rgb(0 0 0 / 0.5);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/* Forced colours: a plain paddle in the system's colours; fp-switch fills it when on. */
|
|
1029
|
+
@media (forced-colors: active) {
|
|
1030
|
+
forced-color-adjust: none;
|
|
1031
|
+
background: Canvas;
|
|
1032
|
+
outline: 1px solid CanvasText;
|
|
1033
|
+
outline-offset: -1px;
|
|
1034
|
+
|
|
1035
|
+
&::before,
|
|
1036
|
+
&::after {
|
|
1037
|
+
content: none;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/** The lamp behind an fp-switch's lens: lit when the switch is on, and slow to fade, like a filament cooling. */
|
|
1043
|
+
@utility fp-switch-lamp {
|
|
1044
|
+
position: absolute;
|
|
1045
|
+
inset: 0;
|
|
1046
|
+
opacity: 0;
|
|
1047
|
+
background-image: radial-gradient(
|
|
1048
|
+
color-mix(in srgb, var(--fp-switch-lamp) 35%, #fff2c8),
|
|
1049
|
+
var(--fp-switch-lamp) 40%,
|
|
1050
|
+
transparent 70%
|
|
1051
|
+
);
|
|
1052
|
+
transition: opacity 600ms ease-out;
|
|
1053
|
+
|
|
1054
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1055
|
+
transition-duration: 0ms;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/* Forced colours: the rocker's fill shows the state instead. */
|
|
1059
|
+
@media (forced-colors: active) {
|
|
1060
|
+
display: none;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* The front of an fp-switch's paddle: the dotted lens over the lamp, the I and O marks, and the
|
|
1066
|
+
* shine that comes up on the pressed-in half. Decorative; the switch says its state.
|
|
1067
|
+
*/
|
|
1068
|
+
@utility fp-switch-face {
|
|
1069
|
+
position: absolute;
|
|
1070
|
+
inset: 0;
|
|
1071
|
+
background:
|
|
1072
|
+
linear-gradient(#fff, #fff) 50% 20% / max(2px, 5%) 20% no-repeat,
|
|
1073
|
+
radial-gradient(circle, transparent 50%, #fff 52%, #fff 70%, transparent 72%) 50% 80% / 33% 25% no-repeat,
|
|
1074
|
+
radial-gradient(transparent 30%, color-mix(in srgb, color-mix(in srgb, var(--fp-switch-lamp) 40%, black) 70%, transparent) 70%) 0 0 / 3px 3px;
|
|
1075
|
+
|
|
1076
|
+
/* The shine: faint while the I half stands out, full once it is pressed in. */
|
|
1077
|
+
&::before,
|
|
1078
|
+
&::after {
|
|
1079
|
+
content: "";
|
|
1080
|
+
position: absolute;
|
|
1081
|
+
inset: 0;
|
|
1082
|
+
transition: opacity 300ms cubic-bezier(1, 0, 1, 1);
|
|
1083
|
+
|
|
1084
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1085
|
+
transition-duration: 0ms;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
&::before {
|
|
1090
|
+
opacity: 0.3;
|
|
1091
|
+
background:
|
|
1092
|
+
linear-gradient(#fff, transparent 3%) 50% 50% / 97% 97% no-repeat,
|
|
1093
|
+
linear-gradient(rgb(255 255 255 / 0.5), transparent 50%, transparent 80%, rgb(255 255 255 / 0.5)) 50% 50% / 97% 97% no-repeat;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/* The shading on the O half while it is pressed in. */
|
|
1097
|
+
&::after {
|
|
1098
|
+
opacity: 1;
|
|
1099
|
+
background-image: linear-gradient(transparent 70%, rgb(0 0 0 / 0.8));
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/* Forced colours: no lens or marks; the rocker's fill shows the state. */
|
|
1103
|
+
@media (forced-colors: active) {
|
|
1104
|
+
display: none;
|
|
1105
|
+
}
|
|
622
1106
|
}
|
|
623
1107
|
|
|
624
1108
|
/**
|
|
@@ -926,6 +1410,11 @@
|
|
|
926
1410
|
inset 1px 1px 0 var(--fp-color-bevel-hi),
|
|
927
1411
|
inset -1px -1px 0 var(--fp-color-bevel-lo),
|
|
928
1412
|
2px 3px 0 var(--fp-color-cast);
|
|
1413
|
+
|
|
1414
|
+
/* Forced colours drop the shadow that draws its edge: an outline keeps it. */
|
|
1415
|
+
@media (forced-colors: active) {
|
|
1416
|
+
outline: 1px solid CanvasText;
|
|
1417
|
+
}
|
|
929
1418
|
}
|
|
930
1419
|
|
|
931
1420
|
/** A module's own little title bar, in brushed chrome. */
|
|
@@ -980,6 +1469,130 @@
|
|
|
980
1469
|
padding: 0.75rem;
|
|
981
1470
|
}
|
|
982
1471
|
|
|
1472
|
+
/**
|
|
1473
|
+
* Faceplate menu: a small brushed-chrome plate that drops from the button that opens it, holding
|
|
1474
|
+
* fp-menu-item rows and fp-menu-separator grooves. Placing it is up to you, or to Reka's
|
|
1475
|
+
* DropdownMenu, which also sets the `data-state="open"` it drops in on.
|
|
1476
|
+
*/
|
|
1477
|
+
@utility fp-menu {
|
|
1478
|
+
color-scheme: var(--fp-scheme);
|
|
1479
|
+
z-index: 50;
|
|
1480
|
+
box-sizing: border-box;
|
|
1481
|
+
min-width: 10rem;
|
|
1482
|
+
overflow-y: auto;
|
|
1483
|
+
padding: 0.25rem;
|
|
1484
|
+
border-radius: 6px;
|
|
1485
|
+
color: var(--fp-color-ink);
|
|
1486
|
+
background-image: linear-gradient(
|
|
1487
|
+
180deg,
|
|
1488
|
+
color-mix(in srgb, var(--fp-color-chrome-hi) 60%, var(--fp-color-chrome-100)) 0%,
|
|
1489
|
+
var(--fp-color-chrome-100) 40%,
|
|
1490
|
+
var(--fp-color-chrome-300) 100%
|
|
1491
|
+
);
|
|
1492
|
+
box-shadow:
|
|
1493
|
+
0 0 0 1px var(--fp-color-edge),
|
|
1494
|
+
inset 1px 1px 0 var(--fp-color-bevel-hi),
|
|
1495
|
+
inset -1px -1px 0 var(--fp-color-bevel-lo),
|
|
1496
|
+
2px 3px 0 var(--fp-color-cast),
|
|
1497
|
+
0 12px 18px -8px var(--fp-color-cast);
|
|
1498
|
+
|
|
1499
|
+
/* The plate takes focus when a pointer opens it; its rows show where the keys are. */
|
|
1500
|
+
outline: none;
|
|
1501
|
+
|
|
1502
|
+
&[data-state="open"] {
|
|
1503
|
+
animation: fp-menu-drop 90ms ease-out;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1507
|
+
&[data-state="open"] {
|
|
1508
|
+
animation: none;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
/* Forced colours drop the chrome and its shadows: an outline keeps the plate's edge. */
|
|
1513
|
+
@media (forced-colors: active) {
|
|
1514
|
+
outline: 1px solid CanvasText;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
/**
|
|
1519
|
+
* A row on an fp-menu: a silkscreened label, with an fp-icon before it if you like. The highlighted
|
|
1520
|
+
* row presses into the plate; Reka sets `data-highlighted` on the row under the pointer or the
|
|
1521
|
+
* arrow keys, and `data-disabled` on one that can't be chosen. 44 px tall, 36 px with a mouse,
|
|
1522
|
+
* trackpad or pen.
|
|
1523
|
+
*/
|
|
1524
|
+
@utility fp-menu-item {
|
|
1525
|
+
display: flex;
|
|
1526
|
+
align-items: center;
|
|
1527
|
+
gap: 0.5rem;
|
|
1528
|
+
min-height: 2.75rem;
|
|
1529
|
+
padding-inline: 0.625rem;
|
|
1530
|
+
border-radius: 4px;
|
|
1531
|
+
color: var(--fp-color-ink);
|
|
1532
|
+
font-family: var(--fp-font-display);
|
|
1533
|
+
font-size: 11px;
|
|
1534
|
+
line-height: 1.3;
|
|
1535
|
+
letter-spacing: 0.08em;
|
|
1536
|
+
text-transform: uppercase;
|
|
1537
|
+
text-decoration: none;
|
|
1538
|
+
white-space: nowrap;
|
|
1539
|
+
cursor: default;
|
|
1540
|
+
user-select: none;
|
|
1541
|
+
outline: none;
|
|
1542
|
+
|
|
1543
|
+
@media (pointer: fine) {
|
|
1544
|
+
min-height: 2.25rem;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
&[data-highlighted] {
|
|
1548
|
+
background-color: var(--fp-color-chrome-300);
|
|
1549
|
+
box-shadow:
|
|
1550
|
+
inset 1px 1px 3px var(--fp-color-bevel-lo),
|
|
1551
|
+
inset -1px -1px 0 var(--fp-color-bevel-hi);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
/* The keyboard's row also gets the ring every focused control has, inside the row. */
|
|
1555
|
+
&:focus-visible {
|
|
1556
|
+
outline: 2px solid var(--fp-color-focus-ring);
|
|
1557
|
+
outline-offset: -2px;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
&[data-disabled] {
|
|
1561
|
+
opacity: 0.45;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/*
|
|
1565
|
+
* Forced colours drop the pressed-in shading: the system's highlight colours show the highlighted
|
|
1566
|
+
* row, and GrayText, not a fade, shows a disabled one.
|
|
1567
|
+
*/
|
|
1568
|
+
@media (forced-colors: active) {
|
|
1569
|
+
&[data-highlighted] {
|
|
1570
|
+
forced-color-adjust: none;
|
|
1571
|
+
background: Highlight;
|
|
1572
|
+
box-shadow: none;
|
|
1573
|
+
color: HighlightText;
|
|
1574
|
+
|
|
1575
|
+
/* Opted out, its focus ring would keep the skin's colour: the system's text colour shows on any ground. */
|
|
1576
|
+
&:focus-visible {
|
|
1577
|
+
outline-color: HighlightText;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
&[data-disabled] {
|
|
1582
|
+
opacity: 1;
|
|
1583
|
+
color: GrayText;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
/** A groove between groups of rows on an fp-menu, cut into the plate: shaded above, lit below. */
|
|
1589
|
+
@utility fp-menu-separator {
|
|
1590
|
+
height: 0;
|
|
1591
|
+
margin: 0.25rem 0.375rem;
|
|
1592
|
+
border-top: 1px solid var(--fp-color-bevel-lo);
|
|
1593
|
+
border-bottom: 1px solid var(--fp-color-bevel-hi);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
983
1596
|
/** Recessed well inside a matte panel, for secondary content or an empty slot. */
|
|
984
1597
|
@utility fp-well {
|
|
985
1598
|
color-scheme: var(--fp-scheme);
|
|
@@ -988,6 +1601,11 @@
|
|
|
988
1601
|
box-shadow:
|
|
989
1602
|
inset 1px 1px 2px var(--fp-color-bevel-lo),
|
|
990
1603
|
inset -1px -1px 0 var(--fp-color-bevel-hi);
|
|
1604
|
+
|
|
1605
|
+
/* Forced colours drop the shading that recesses it: an outline keeps an empty well in view. */
|
|
1606
|
+
@media (forced-colors: active) {
|
|
1607
|
+
outline: 1px solid CanvasText;
|
|
1608
|
+
}
|
|
991
1609
|
}
|
|
992
1610
|
|
|
993
1611
|
/** Silkscreened hardware label. */
|
|
@@ -1010,6 +1628,11 @@
|
|
|
1010
1628
|
0 0 0 2px var(--fp-color-chrome-800),
|
|
1011
1629
|
inset 2px 2px 4px rgb(0 0 0 / 0.35),
|
|
1012
1630
|
inset -1px -1px 0 rgb(255 255 255 / 0.2);
|
|
1631
|
+
|
|
1632
|
+
/* Forced colours drop the chrome bezel: an outline frames the glass. */
|
|
1633
|
+
@media (forced-colors: active) {
|
|
1634
|
+
outline: 2px solid CanvasText;
|
|
1635
|
+
}
|
|
1013
1636
|
}
|
|
1014
1637
|
|
|
1015
1638
|
/** One line of LCD text. Cells of fp-lcd-ghost stacked behind it show the unlit segments, as on real glass. */
|
|
@@ -1027,6 +1650,11 @@
|
|
|
1027
1650
|
/** The unlit segments behind an LCD line. Decorative: give it aria-hidden="true". */
|
|
1028
1651
|
@utility fp-lcd-ghost {
|
|
1029
1652
|
color: var(--fp-color-lcd-ghost);
|
|
1653
|
+
|
|
1654
|
+
/* Forced colours would draw the unlit segments as solid as the text over them. */
|
|
1655
|
+
@media (forced-colors: active) {
|
|
1656
|
+
visibility: hidden;
|
|
1657
|
+
}
|
|
1030
1658
|
}
|
|
1031
1659
|
|
|
1032
1660
|
/** Dark housing that LEDs and small readouts sit in. */
|
|
@@ -1043,6 +1671,11 @@
|
|
|
1043
1671
|
box-shadow:
|
|
1044
1672
|
inset 1px 1px 2px rgb(0 0 0 / 0.5),
|
|
1045
1673
|
0 1px 0 var(--fp-color-bevel-hi);
|
|
1674
|
+
|
|
1675
|
+
/* Forced colours turn the dark housing into the page colour: an outline keeps it in view. */
|
|
1676
|
+
@media (forced-colors: active) {
|
|
1677
|
+
outline: 1px solid CanvasText;
|
|
1678
|
+
}
|
|
1046
1679
|
}
|
|
1047
1680
|
|
|
1048
1681
|
/** An LED with its own dark bezel ring, so a lit one reads on light chrome too. Unlit by default. */
|