Classes
Every .fp-* class, read from the CSS source at build time. In plain CSS they live in components.css (or page.css), inside @layer frontpanel; in Tailwind they are utilities, so lg:fp-module and the like work. Each interactive class carries its own focus ring and handles reduced motion.
"Responds to" lists the states a class styles: aria-pressed, hover and focus, and the input and motion queries. Use the ARIA attributes the class expects, and the right look follows.
Every core class on one device, built from plain classes alone, in both skins:
NOW PLAYING 02:41
CHROME HORIZONMixer
- 01 Intro
- 02 Chrome Horizon
- 03 Gel Pressure
- 04 Silkscreen
- 05 Backlight
- 06 Two Blinks
- 07 Rim Light
- 08 Outro
NOW PLAYING 02:41
CHROME HORIZONMixer
- 01 Intro
- 02 Chrome Horizon
- 03 Gel Pressure
- 04 Silkscreen
- 05 Backlight
- 06 Two Blinks
- 07 Rim Light
- 08 Outro
Core
index.css, components.css, tailwind.css.
.fp-lcd-redraw
Redraws an LCD line left to right in four steps, as when its value changes.
Responds to
@media (prefers-reduced-motion: reduce)
.fp-blink-twice
Blinks twice, then holds: an LED confirming an action.
Responds to
@media (prefers-reduced-motion: reduce)
.fp-device-backdrop
The page behind the device: quiet blue-grey with a faint Y2K grid.
.fp-device-rim
Liquid-chrome ring around the device body. Diagonal so the reflection band crosses the corners.
Responds to
:where(.fp-device-rim > .fp-device-body)@media (forced-colors: active)
.fp-device-body
Molded body plastic the modules sit on.
.fp-chrome
Liquid chrome with a hard horizon, for title bars and other frames. Never behind text.
.fp-chrome-soft
Brushed chrome without the horizon, calm enough to print a label in the middle of it.
.fp-chrome-btn
Small hardware push button in brushed chrome. 44 px tall, 36 px with a mouse, trackpad or pen.
Responds to
@media (prefers-reduced-motion: reduce)@media (pointer: fine).fp-chrome-btn:hover:not(:disabled).fp-chrome-btn:active:not(:disabled), .fp-chrome-btn[aria-pressed="true"], .fp-chrome-btn[aria-expanded="true"], .fp-chrome-btn[aria-current="page"].fp-chrome-btn:focus-visible.fp-chrome-btn:focus-visible:hover:not(:disabled).fp-chrome-btn:disabled@media (forced-colors: active).fp-chrome-btn[aria-pressed="true"], .fp-chrome-btn[aria-expanded="true"], .fp-chrome-btn[aria-current="page"]
.fp-gel
Glossy gel pill for primary actions. Its white label sits on the base colour at mid-height, where the highlight ellipse has already faded out (7:1).
Responds to
@media (prefers-reduced-motion: reduce)@media (pointer: fine).fp-gel:hover:not(:disabled).fp-gel:active:not(:disabled).fp-gel:focus-visible.fp-gel:focus-visible:hover:not(:disabled).fp-gel:disabled@media (forced-colors: active)
.fp-cap
Molded-plastic cap. The cap colour and its label colour come from the fp-cap-* classes
(--fp-cap, --fp-cap-ink); a bare fp-cap is white plastic with a dark label. Selected caps
stay pressed in and get a ring, so selection never depends on colour.
Responds to
@media (prefers-reduced-motion: reduce)@media (pointer: fine).fp-cap:hover:not(:disabled).fp-cap:active:not(:disabled).fp-cap[aria-pressed="true"], .fp-cap[aria-checked="true"].fp-cap:focus-visible.fp-cap:focus-visible:hover:not(:disabled).fp-cap:disabled@media (forced-colors: active)
.fp-cap-blue
Blue plastic for an fp-cap, with its own label colour.
.fp-cap-amber
Amber plastic for an fp-cap, with its own label colour.
.fp-cap-graphite
Graphite plastic for an fp-cap, with its own label colour.
.fp-cap-berry
Berry plastic for an fp-cap, with its own label colour.
.fp-unit
A control with its silkscreen label under it: a knob, fader, meter or switch and then an fp-silk.
With data-label-placement="start" the label sits level with the control, before it in the
line. A length set here, such as --fp-fader-length, reaches the control inside.
Responds to
.fp-unit[data-label-placement="start"]
.fp-knob
Rotary knob: a knurled chrome skirt round a domed cap. The cap is lit from the top left and stays
still; only its fp-knob-mark turns, by rotate, through 270 degrees. 48 px, 40 px with a mouse,
trackpad or pen.
Responds to
@media (pointer: fine).fp-knob::before.fp-knob:focus-visible.fp-knob[aria-disabled="true"]@media (forced-colors: active)
.fp-knob-mark
The pointer line on a knob's cap. Turn it with rotate: -135deg at the minimum, 135deg at the maximum.
Responds to
.fp-knob-mark::after@media (forced-colors: active)
.fp-fader
Fader: a chrome cap on a recessed slot. It stands up by default and lies on its side with
data-orientation="horizontal"; --fp-fader-length sets how far it travels (8rem). 44 px
across, 36 px with a mouse, trackpad or pen. Pressing the slot moves the cap there.
Responds to
@media (pointer: fine).fp-fader[data-orientation="horizontal"].fp-fader[data-disabled]
.fp-fader-slot
The slot a fader's cap rides in, cut into the panel: shaded on its top and left inside edges.
Responds to
.fp-fader-slot[data-orientation="horizontal"]@media (forced-colors: active)
.fp-fader-cap
A fader's cap: brushed chrome lit from the top left, with an ink grip line that marks the value.
Place it along the slot with bottom (or left on its side, with data-orientation="horizontal"
on the slot and cap as well as the fader).
Responds to
@media (pointer: fine).fp-fader-cap::after.fp-fader-cap[data-orientation="horizontal"].fp-fader-cap:focus-visible@media (forced-colors: active)
.fp-switch
Illuminated rocker switch: a lamp-lit paddle in a dark bezel, marked I at the top and O at the
bottom. Off, the O half is pressed in; on, the I half is, and the lamp behind the lens lights.
Put it on a button with role="switch" and aria-checked, holding an fp-switch-rocker. The
lamp is red; colour it with fp-led-green or fp-led-amber. 44 x 56 px, 36 x 46 px with a mouse,
trackpad or pen. With data-orientation="horizontal" it lies on its side, 56 x 44 px (46 x 36),
O on the left and I on the right. After an illuminated rocker pen by ykadosh (CodePen, MIT), rebuilt on the kit's
tokens.
Responds to
@media (pointer: fine).fp-switch[aria-checked="true"] .fp-switch-rocker.fp-switch[aria-checked="true"] .fp-switch-face::before.fp-switch[aria-checked="true"] .fp-switch-face::after.fp-switch[aria-checked="true"] .fp-switch-lamp.fp-switch[data-orientation="horizontal"].fp-switch .fp-switch-rocker.fp-switch .fp-switch-rocker::before.fp-switch .fp-switch-rocker::after.fp-switch .fp-switch-face.fp-switch .fp-switch-face::before.fp-switch .fp-switch-face::after.fp-switch:focus-visible.fp-switch:disabled, .fp-switch[aria-disabled="true"]@media (forced-colors: active).fp-switch[data-orientation="horizontal"] .fp-switch-rocker.fp-switch[aria-checked="true"] .fp-switch-rocker, .fp-switch[data-orientation="horizontal"][aria-checked="true"] .fp-switch-rocker
.fp-switch-rocker
The paddle of an fp-switch, tilted in 3D. It holds an fp-switch-lamp and then an fp-switch-face; its top and bottom ends show as it tips.
Responds to
@media (prefers-reduced-motion: reduce).fp-switch-rocker::before.fp-switch-rocker::after@media (forced-colors: active).fp-switch-rocker::before, .fp-switch-rocker::after
.fp-switch-lamp
The lamp behind an fp-switch's lens: lit when the switch is on, and slow to fade, like a filament cooling.
Responds to
@media (prefers-reduced-motion: reduce)@media (forced-colors: active)
.fp-switch-face
The front of an fp-switch's paddle: the dotted lens over the lamp, the I and O marks, and the shine that comes up on the pressed-in half. Decorative; the switch says its state.
Responds to
.fp-switch-face::before, .fp-switch-face::after@media (prefers-reduced-motion: reduce).fp-switch-face::before.fp-switch-face::after@media (forced-colors: active)
.fp-meter
Level meter: a strip of LED segments in a dark housing, lit green, then amber, then red. Set
--fp-meter-level (0 to 1, in whole segments), --fp-meter-segments (12), and where amber and
red begin, --fp-meter-amber (8/12) and --fp-meter-red (11/12), as shares of the strip on
segment edges, or a segment lights in two colours. It stands
up by default and lies on its side with data-orientation="horizontal"; --fp-meter-length
sets how long it is (8rem). Give it role="meter" and its values, or aria-hidden beside a
readout that says the same.
Responds to
.fp-meter::before, .fp-meter::after.fp-meter::before.fp-meter::after@media (forced-colors: active).fp-meter[data-orientation="horizontal"]
.fp-readout
Seven-segment readout: LED digits on a near-black face, set in the housing. Each character is an fp-readout-cell, and the value is said in an fp-readout-text inside. Green by default; colour it with fp-led-amber or fp-led-red. Lit digits pass as text on the face at any size.
.fp-readout-cell
One character of an fp-readout, leaning a little like a real display. It shows its unlit
segments itself, a figure eight and a point, faintly in the lit colour; put the lit ones in an
fp-readout-lit inside. With data-colon it is a narrow colon cell. --fp-readout-height sets
its height (2rem). Give it aria-hidden="true".
Responds to
.fp-readout-cell::before.fp-readout-cell[data-colon]@media (forced-colors: active)
.fp-readout-lit
The lit segments of an fp-readout-cell: an element for each, named by data-segment, a to g
(top, then clockwise, then the middle), dp, or a colon's colon-upper and colon-lower. Each
is brightest over its chip, in the middle, and they glow onto the face, both by the lens.
Responds to
.fp-readout-lit > [data-segment].fp-readout-lit > [data-segment="a"], .fp-readout-lit > [data-segment="d"], .fp-readout-lit > [data-segment="g"].fp-readout-lit > [data-segment="b"], .fp-readout-lit > [data-segment="c"], .fp-readout-lit > [data-segment="e"], .fp-readout-lit > [data-segment="f"].fp-readout-lit > [data-segment="a"].fp-readout-lit > [data-segment="g"].fp-readout-lit > [data-segment="d"].fp-readout-lit > [data-segment="b"], .fp-readout-lit > [data-segment="c"].fp-readout-lit > [data-segment="e"], .fp-readout-lit > [data-segment="f"].fp-readout-lit > [data-segment="b"], .fp-readout-lit > [data-segment="f"].fp-readout-lit > [data-segment="c"], .fp-readout-lit > [data-segment="e"].fp-readout-lit > [data-segment="dp"], .fp-readout-lit > [data-segment="colon-upper"], .fp-readout-lit > [data-segment="colon-lower"].fp-readout-lit > [data-segment="dp"].fp-readout-lit > [data-segment="colon-upper"], .fp-readout-lit > [data-segment="colon-lower"].fp-readout-lit > [data-segment="colon-upper"].fp-readout-lit > [data-segment="colon-lower"]@media (forced-colors: active)
.fp-readout-text
An fp-readout's value as text, for screen readers: hidden from view, read in place of the digits.
.fp-module
Matte content panel. This is where reading happens: no gloss, a 1 px bevel and a short hard shadow.
Responds to
@media (forced-colors: active)
.fp-module-title
A module's own little title bar, in brushed chrome.
.fp-window
A window: a module (or, in the page extra, a sheet panel) whose fp-module-title stays in view while its body scrolls under it.
Responds to
.fp-window > .fp-module-title@media (pointer: fine).fp-window > .fp-module-title .fp-chrome-btn
.fp-window-title
A window's name in its title bar. Pair it with fp-silk; it pushes the title-bar buttons to the far end.
.fp-window-body
The padded body under a window's title bar.
.fp-well
Recessed well inside a matte panel, for secondary content or an empty slot.
Responds to
@media (forced-colors: active)
.fp-silk
Silkscreened hardware label.
.fp-lcd
LCD glass, recessed into the chrome. Text on it uses --fp-font-lcd; drawings use --fp-color-lcd-ink.
Responds to
@media (forced-colors: active)
.fp-lcd-line
One line of LCD text. Cells of fp-lcd-ghost stacked behind it show the unlit segments, as on real glass.
Responds to
.fp-lcd-line > *
.fp-lcd-ghost
The unlit segments behind an LCD line. Decorative: give it aria-hidden="true".
Responds to
@media (forced-colors: active)
.fp-housing
Dark housing that LEDs and small readouts sit in.
Responds to
@media (forced-colors: active)
.fp-led
An LED with its own dark bezel ring, so a lit one reads on light chrome too. Unlit by default.
Responds to
@media (forced-colors: active)
.fp-led-green
Green for an fp-led or fp-readout, the default.
.fp-led-amber
Amber for an fp-led or fp-readout.
.fp-led-red
Red for an fp-led or fp-readout.
.fp-led-lit
Lights an fp-led in its colour, brightest over the chip in its middle, with a glow. The lens sets how strong both are. Say what it means in text nearby, never by colour alone.
Responds to
@media (forced-colors: active)
.fp-lens-flat
LED lens, flat: an even fill with no hot spot. A lens class works on an fp-led, fp-meter or fp-readout, or on any element around them, such as a device body, to set every one inside.
.fp-lens-diffused
LED lens, diffused, the default: like most real displays, each LED is a little brighter over its chip, in the middle, with a soft glow.
.fp-lens-clear
LED lens, clear: a bright, pale core over each chip and a wider glow, like a water-clear lens.
.fp-screw
Decorative screw head. Give it aria-hidden="true".
.fp-scroll-thin
A scrolling panel, such as a list window, with a thin scrollbar that never pushes the layout.
.fp-icon
A 16 px pixel icon. Size it in whole multiples of 16 px so its pixels stay crisp.
Page extra
page.css, tailwind-page.css: pieces for a website around a device.
.fp-sheet-panel
A matte panel lifted over the device as a bottom sheet on phones; dock it as an fp-module on wide screens.
Responds to
@media (forced-colors: active)
.fp-field
Inset text field or select on a matte panel. Its border keeps 3:1 against the panel in both skins.
Responds to
@media (pointer: fine).fp-field:focus-visible.fp-field:disabled