Skip to content

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:

Chrome Silver

NOW PLAYING 02:41

CHROME HORIZON
PWR REC CLIP 12:05

Mixer

Playlist
  1. 01 Intro
  2. 02 Chrome Horizon
  3. 03 Gel Pressure
  4. 04 Silkscreen
  5. 05 Backlight
  6. 06 Two Blinks
  7. 07 Rim Light
  8. 08 Outro
Brushed chrome
Gunmetal Night

NOW PLAYING 02:41

CHROME HORIZON
PWR REC CLIP 12:05

Mixer

Playlist
  1. 01 Intro
  2. 02 Chrome Horizon
  3. 03 Gel Pressure
  4. 04 Silkscreen
  5. 05 Backlight
  6. 06 Two Blinks
  7. 07 Rim Light
  8. 08 Outro
Brushed chrome

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)

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