Colors
Puppertino ships with the full macOS 27 color system. Every color has a light and dark mode variant, every fill level adapts to its surface, and the text hierarchy gives six tiers of emphasis instead of four.
The colors live in colors.css. The legacy palettes from earlier versions of Puppertino remain available for backwards compatibility.
System accents
Thirteen accent colors form the base palette. Each color has a light mode and dark mode variant, and the dark variant is slightly more saturated to maintain visual impact against dark backgrounds.
How to use them
Apply system colors with the utility classes or the CSS variables directly.
<div class="p-sys-blue">Background blue</div>
<p class="p-sys-red-color">Red text</p>
.my-button {
background: var(--p-sys-blue);
color: white;
}
Control accent
Blue is also the accent for every tinted control: filled buttons, switches, sliders, progress bars, and the selected segment. It is the same blue as text links and selection, #0088FF in light mode and #0091FF in dark mode.
| Token | Light | Dark | What it is |
|---|---|---|---|
--p-control-accent | #0088FF | #0091FF | The default control fill |
--p-color-current | Follows --p-sys-blue | Follows --p-sys-blue | The tint a control actually uses |
--p-focus-ring | 3.5px band outside plus 1px inside, rgba(0,136,255,0.5) | Same, rgba(0,145,255,0.5) | Keyboard focus on fields and controls |
--p-control-accent-text | #0078F0 | #0091FF | Accent as text on a material, such as a borderless button label inside a vibrant surface |
Every color class also sets --p-color-current, so a class on a control retints it. The tint stays on that element and does not spread to its children, so a colored card does not retint the buttons inside it.
<button class="p-button p-button-colored">Blue in light, brighter blue in dark</button>
<button class="p-button p-button-colored p-sys-green">Green</button>
Use the focus ring as a box shadow on your own controls.
.my-field:focus-visible {
outline: none;
box-shadow: var(--p-focus-ring);
}
Vibrant accents
Color that sits on a material (a menu, a popover, an alert, a sidebar) is vibrant: instead of painting a flat color, it blends with the glass behind it. There are twelve vibrant accents, one for each system accent except gray.
Each vibrant color is a layer, not a finished color. In light mode it composites with mix-blend-mode: plus-darker, which adds the layer to the backdrop and subtracts white: over white you see the color exactly, over gray glass it darkens by the gray. In dark mode it uses plus-lighter, which adds the two: over black you see the color, over dark glass it brightens. --p-vibrant-blend holds the right mode for the current appearance.
.my-badge::before {
background: var(--p-vibrant-red);
mix-blend-mode: var(--p-vibrant-blend);
}
Where a blend isn’t possible, such as a text color, use the resolved token. It is the same recipe worked out over the standard overlay glass (#EBEBEB in light mode, #1A1A1A in dark).
| Color | Layer (light) | Layer (dark) | -resolved (light) | -resolved (dark) |
|---|---|---|---|---|
| Red | #F52F32 | #FF4747 | #E11B1E | #FF6161 |
| Orange | #F58625 | #FF9E33 | #E17211 | #FFB84D |
| Yellow | #F5C200 | #FFE014 | #E1AE00 | #FFFA2E |
| Green | #26BF4D | #3BDB63 | #12AB39 | #55F57D |
| Mint | #00BDA9 | #2DE0CD | #00A995 | #47FAE7 |
| Teal | #00B3BF | #2DD7E0 | #009FAB | #47F1FA |
| Cyan | #00ABCF | #47D8FC | #0097BB | #61F2FF |
| Blue | #0078F0 | #0A99FF | #0064DC | #24B3FF |
| Indigo | #5C50E6 | #7163FF | #483CD2 | #8B7DFF |
| Purple | #B72BC9 | #E647FC | #A317B5 | #FF61FF |
| Pink | #F5234B | #FF4169 | #E10F37 | #FF5B83 |
| Brown | #9E7354 | #C29672 | #8A5F40 | #DCB08C |
Safari supports plus-darker. Chrome and Firefox don’t, so there --p-vibrant-blend resolves to multiply in light mode, which matches over white and lands a few levels lighter over light glass. plus-lighter works in every current browser.
Buttons pick these up on their own inside vibrant surfaces. See Buttons.
Text hierarchy
Six levels of text emphasis. Primary is for body content, secondary for supporting copy, and the lower tiers are for placeholders and decorative text. Apple expanded this from four levels to six with Liquid Glass to give designers more room for ultra-subtle text.
Notice that primary text is not pure black. Apple uses 85% opacity so the surface behind shows through subtly. This is part of the Liquid Glass aesthetic.
<p class="p-text-primary">Body content sits here.</p>
<p class="p-text-secondary">Supporting text uses the secondary level.</p>
<p class="p-text-tertiary">Placeholder text and timestamps use tertiary.</p>
Fills
Five fill tiers for subtle background tints. Use them for buttons, segmented control backgrounds, search bars, or any element that needs a quiet container without competing with the surface.
The macOS fills use pure black (light mode) or pure white (dark mode) at low opacity. Apple replaced the older tinted-gray fills with this approach with Liquid Glass; it composites better over translucent surfaces.
Backgrounds
Three background tiers for layered surfaces, plus three more for grouped table-style content. Apple’s pattern: when you elevate a surface in dark mode, it gets lighter, not darker. The depth comes from the contrast against the layer below.
Use the grouped variants (--p-bg-grouped-primary, --p-bg-grouped-secondary, --p-bg-grouped-tertiary) when building list-style content like settings screens.
Elevated backgrounds
Sheets, popovers, and modal cards sit on the elevated tiers. In light mode they equal the base tiers. In dark mode each one is a step lighter, so a sheet reads as a separate layer without a heavy shadow.
| Token | Light | Dark |
|---|---|---|
--p-bg-elevated-primary | #FFFFFF | #1C1C1E |
--p-bg-elevated-secondary | #F2F2F7 | #2C2C2E |
--p-bg-elevated-tertiary | #FFFFFF | #3A3A3C |
--p-bg-grouped-elevated-primary | #F2F2F7 | #1C1C1E |
--p-bg-grouped-elevated-secondary | #FFFFFF | #2C2C2E |
--p-bg-grouped-elevated-tertiary | #F2F2F7 | #3A3A3C |
Each token has a matching utility class, such as .p-bg-elevated-secondary.
iOS colors
iOS shares the twelve accents with macOS. Its grays, labels, fills, and separator differ, so touch components use the --p-ios-* tokens. Desktop components keep the macOS tokens above.
Gray scale
On iOS, Gray stays #8E8E93 in dark mode. The macOS dark gray (--p-sys-gray) is #98989F.
Labels, fills, and separator
| Token | Light | Dark | Use it for |
|---|---|---|---|
--p-ios-label | #000000 | #FFFFFF | Primary text |
--p-ios-label-secondary | rgba(60,60,67,0.60) | rgba(235,235,245,0.70) | Subtitles, detail text |
--p-ios-label-tertiary | rgba(60,60,67,0.30) | rgba(235,235,245,0.30) | Placeholders, disabled text |
--p-ios-label-quaternary | rgba(60,60,67,0.18) | rgba(235,235,245,0.16) | Watermarks |
--p-ios-fill | rgba(120,120,128,0.20) | rgba(120,120,128,0.36) | Thin, small shapes like slider tracks |
--p-ios-fill-secondary | rgba(120,120,128,0.16) | rgba(120,120,128,0.32) | Search fields, selected sidebar rows |
--p-ios-fill-tertiary | rgba(118,118,128,0.12) | rgba(118,118,128,0.24) | Gray buttons |
--p-ios-fill-quaternary | rgba(116,116,128,0.08) | rgba(118,118,128,0.18) | Steppers, large quiet areas |
--p-ios-separator | rgba(0,0,0,0.12) | rgba(255,255,255,0.17) | Hairlines in lists and bars |
The iOS separator is lighter than the macOS one (--p-separator). Over white it lands at #E0E0E0, where the macOS value lands at #C6C6C8. The opaque separator, --p-separator-opaque, is the same on both platforms.
The label tokens have utility classes: .p-ios-label, .p-ios-label-secondary, .p-ios-label-tertiary, .p-ios-label-quaternary.
.my-list-row {
color: var(--p-ios-label);
box-shadow: inset 0 -0.5px 0 var(--p-ios-separator);
}
.my-list-row small {
color: var(--p-ios-label-secondary);
}
Dark mode
All color tokens flip automatically when the page enters dark mode. Two ways to opt in:
<!-- Manual: add the class -->
<body class="p-dark-mode">
<!-- Automatic: follow the system preference -->
<body class="p-auto-dark-mode">
The auto variant uses prefers-color-scheme and switches without any JavaScript.
Unofficial colors
A second palette ships alongside the system colors. These are not part of Apple’s HIG, they don’t flip in dark mode, and they don’t carry semantic meaning. They’re here because they look great, they have a full set of shades, and they make it easy to brand a Puppertino interface without leaving the framework.
Each color comes in five shades: 100 (lightest), 300, 500 (the base), 700, and 900 (darkest). Click any tile to copy its CSS variable.
Use them the same way as the system colors. The base name applies the 500 shade, or pick a specific step.
<div class="p-grape">Grape background</div>
<div class="p-grape-100">Lighter grape</div>
<p class="p-strawberry-700-color">Dark strawberry text</p>
Drop one of these classes on a button to retint it. The button picks up the new tint through the same --p-color-current mechanism the system colors use.
<button class="p-button p-button-colored p-grape">Save</button>
Accessibility
Apple’s system colors are tested for color blindness and meet WCAG AA contrast at the 4.5:1 ratio for body text. When using system accents over fills or materials, verify the contrast in both light and dark mode.
For people with prefers-contrast: more, consider adding stronger borders to elements that rely on fill colors alone for separation.