Skip to content
Hey AlbertBrand and design system
As MarkdownDeutschDE

Foundations

Colour

Warm paper, ink, a pink accent and one sticky note per person. Every colour is a role with a fixed meaning, light and dark from one source.

Hey Albert looks like a notebook (Notizbuch). The background is warm paper, the type is ink. Every person has their own sticky note. A marker highlights what matters now. The sidebar is black, the accent is pink.

Colour comes from the cards, not from the background. The background stays calm: no gradients, no textures, no patterns.

Roles, never ladders

Every colour has a name that says what it is for. We say “card” (--karte), not “Beige 200”. A component names only the role, never the value. That is how dark mode switches without any component knowing about it.

The values live in exactly one place: packages/design-system/tokens/quelle/. CSS, Tailwind and Swift are generated from there. Everything on this page is read from there at build time.

/* right: the role */
.termin { background: var(--flaeche-karte); color: var(--text-koerper); border-radius: var(--radius-karte); }

/* wrong: the value. In dark mode the card stays light. */
.termin { background: #EEE8DD; }
// right: the role from AlbertFarbe, it carries light and dark
Text("Schwimmen mit Lena")
    .foregroundStyle(AlbertFarbe.textKoerper)
    .padding(AlbertRaum.karteInnen)
    .background(AlbertFarbe.flaecheKarte, in: .rect(cornerRadius: AlbertForm.radiusKarte))

// wrong: an ad-hoc colour or a switch on the colour scheme
// Color(hex: 0xEEE8DD) · if colorScheme == .dark { … }

Base colours

The base colours are the material. Most components do not use them directly but through the semantic roles further down.

#F8F2E7#14110DSeitenhintergrund, warmes Creme
#EEE8DD#2A2620Standardkarte (Termin), beige
#FBF7EE#201C17Tagesreiter, Menüs, Badges auf Karten, Suchfeld
#EDE6D8#322D26Segment-Regler inaktiv, sekundäre Knöpfe
#171717#0B0A08Leiste, primäre Knöpfe, heutiger Tag, aktive Auswahl
#2C2C2CSchwarz unter dem Zeiger (Knopf, Kreis, heutiger Reiter)
#3A3A3ASchwarz beim Drücken
#1A1A1A#F4EFE6Fließtext, Titel
#6E6A63#A9A297Zweittext, Zeiten, Beschriftungen
#D8D0BF#3D372EHaarlinien 1 px, Ränder von Feldern und Kreisen
#F3B8DFAkzent: Plus, Jetzt-Zeit, aktiver Ort, Zähler, Lupe
#F7CDE8Zustands-Pillen, Tageskreis mit Offenem
#F5D95CFamilie und Rituale, Alberts Vorschlag (iPhone), Zahlen
#E4C63AFormen auf gelben Karten
#BFD9A6Bewertung: gut (HQ)
#F5D95C→ gelbBewertung: Potenzial (HQ)
#EBA7A0Bewertung: schwach (HQ)
#2B2A25
#BFCDF0Fahrten
#9DB1E3Formen auf blauen Karten
#B8467F#F09CC6nur gestrichelter Rand für „ohne Zuständigen“
#4A4530Zweittext auf gelben Flächen
#F4EFE6Text und Zeichen auf Schwarz
#C9A0BD#B98CADgedämpftes Rosa-Grau für den Sonntag
  • --grund is the paper. Every surface lies on it.
  • --karte is the recessed surface, the standard card for appointments.
  • --hell is what floats: day tabs, menus, the search field, badges on cards.
  • --schwarz carries the sidebar, the primary button and today’s date.
  • --tinte is body text and titles. --grau is secondary text: times, places, labels.
  • --linie draws the hairlines.

Meanings that are never swapped

Four colours carry a meaning. It holds everywhere: in the app, on the website, on social media, in the yearbook.

#F3B8DF→ rosaAkzent und „jetzt“ – nie Fehler
#F7CDE8→ rosa-hell
#B8467F#F09CC6→ offen
#BFCDF0→ blau
#9DB1E3→ blau-dunkel
#F5D95C→ gelb
#E4C63A→ gelb-dunkel
#EEE8DD#2A2620→ karte
ColourMeansExamples
Pink (--akzent, --rosa)accent and nowplus, the current time, the active place, counters, the magnifier
Light pink (--rosa-hell)a state that needs attentionthe pill “Kein Fahrer” (no driver), a day circle with open items
Yellow (--bedeutung-familie)family and ritualthe Sunday round (Sonntagsrunde), lunch at Oma Grete’s, large numbers, Albert’s suggestion on iPhone
Blue (--bedeutung-fahrt)drivepick-up, ride home, drive pills
Open-pink (--offen)no one responsibleonly as a dashed outline, never as a fill
Dashed grey (--rand-vorschlag)suggestion from Albertdashed outline without its own fill

Pink never means “error”. An error has no alarm colour with us. It says what happened and what you can do.

Yellow is never a text colour. On the paper it is barely legible. Yellow is always a surface; text on it uses --text-auf-gelb.

Semantic roles

Components use these roles. Each points to a base colour and may point to a different one in dark mode.

Surfaces

#F8F2E7#14110D→ grund
#FBF7EE#201C17→ hellwas schwebt: Menü, Reiter, Feld
#EEE8DD#2A2620→ karteTermin
#BFCDF0→ blauFahrt
#F5D95C→ gelbFamilie und Ritual
transparentVorschlag: gestrichelt, ohne Füllung
#171717#0B0A08→ schwarz
rgba(26, 26, 26, 0.32)rgba(0, 0, 0, 0.56)dämpft, was dahinter liegt
rgba(244, 239, 230, 0.08)Ort in der Leiste unter dem Zeiger
rgba(244, 239, 230, 0.14)aktiver Ort in der Leiste unter dem Zeiger

--flaeche-schleier is the only translucent colour. The veil dims whatever lies behind a dialog, a menu or the scanner. There is no frosted glass and no blur.

Text

#1A1A1A#F4EFE6→ tinte
#1A1A1A#F4EFE6→ tinte
#6E6A63#A9A297→ grau
#F4EFE6→ leistentext
#9A948B#8C857A
#4A4530→ auf-gelb
#1A1A1A→ tinte
#4A4F63Zweittext auf blauen Flächen (Fahrt)
#1A1A1A→ tinte
#A29B8F#7A7469gerechnet, keine Deckkraft

Text on yellow, blue and pink has its own roles: --text-auf-gelb, --text-auf-blau, --text-auf-rosa. They stay dark in dark mode because the surface stays light. Use --tinte there and you write cream on light at night.

--text-inaktiv is a computed colour. Disabled never means “half opacity” here.

Lines and outlines

#D8D0BF#3D372E→ linie
#C2B8A2#524A3DKontur 1,5 px statt 1 px
#E4DDCE#2B2620gerechnet, keine Deckkraft
#1A1A1A#F4EFE6→ tintegestrichelte Jetzt-Achse
#6E6A63#A9A297→ graugestrichelt grau: Vorschlag von Albert
#B8467F#F09CC6→ offengestrichelt: ohne Zuständigen
#B8467F#F09CC6→ offen:focus-visible Ring
#171717#F4EFE6→ schwarz
#2C2C2C#E2DACD→ schwarz-zeigerDruck macht die Fläche nicht dunkler, sondern die Schrift ruhiger
#3A3A3A#CFC6B7→ schwarz-druck
#F4EFE6#171717→ leistentext
#EDE6D8#322D26→ knopf-zweit
#1A1A1A#F4EFE6→ tinte
#E9E2D4#2B2620
#A29B8F#7A7469→ text-inaktiv

The primary button gets lighter on hover and press, not darker. On paper, lightening feels calmer. In dark mode it flips: light surface, dark text.

Person colours

Every person in the household has a slot and with it a colour. There are eight slots. The Sonntag family fills five: Anna, Tobias, Felix, Lena and Sofia. The grandparents are guests.

A
Anna--person-1#D5F5C2
T
Tobias--person-2#A8E5E5
F
Felix--person-3#F6D0FF
L
Lena--person-4#FFD6A5
S
Sofia--person-5#AEBAFF
G
Oma Grete--person-6#C7EFD0
W
Opa Werner--person-7#FFC9C9
H
Oma Hilde--person-8#E3DCA8

Every slot has two faces:

  • The note (--person-1 to --person-8) is a light surface: avatar, sticky note, personal lane. Text on it is always --person-text, which is ink. The note stays light in dark mode too, because a sticky note is a light scrap of paper at night as well.
  • The line (--person-linie-1 to --person-linie-8) is the stronger step for dots, outlines and lanes. In dark mode it becomes stronger still, otherwise it would disappear.

Three rules always apply:

  1. Colour is never the only carrier. Every person colour comes with an initial or a name. On the paper the person lines only reach 1.7:1 to 2.9:1. The system promises no contrast there, so initial and name carry the meaning.
  2. One person, one colour, everywhere. Lena is peach on iPhone, on the Mac and in the campaign. Anyone who knows Anna recognises her colour.
  3. Guests are outlined, household and helpers are filled. Oma Grete appears as a ring, Sofia as a filled note.

Children design their own space, within contrast guardrails (principle 4).

Dark mode

Dark mode is not a second design. It redefines the same roles under :root[data-modus="dunkel"]. In SwiftUI every role carries both values and decides at runtime.

  • --grund becomes a deep black-brown, --karte a dark beige-grey.
  • --tinte becomes cream.
  • Pink, yellow and blue stay light surfaces. Text on them stays dark.
  • The person notes stay light, their lines get stronger.
  • --offen gets a stronger step so the dashed outline still reads at night.

The swatches on this page switch along. The button at the top right changes the mode.

Contrast

Body text and controls need at least 4.5:1. Surfaces and outlines need at least 3:1. The table computes both modes from the tokens on every build.

PairLightDark
Aatinte on grund15.62:1 · AAA16.43:1 · AAA
Aatinte on karte14.27:1 · AAA13.13:1 · AAA
Aagrau on grund4.83:1 · AA7.44:1 · AAA
Aagrau on karte4.41:1 · 3:15.94:1 · AA
Aatext-inaktiv on grund2.47:1 · zu schwach4.06:1 · 3:1
Aatinte on rosa10.55:1 · AAA1.44:1 · zu schwach
Aatinte on gelb12.40:1 · AAA1.23:1 · zu schwach
Aatinte on blau10.94:1 · AAA1.39:1 · zu schwach
Aatinte on person-114.64:1 · AAA1.04:1 · zu schwach
Aatinte on person-59.34:1 · AAA1.63:1 · zu schwach
Aahell on schwarz16.77:1 · AAA1.17:1 · zu schwach
Aaoffen on grund4.47:1 · 3:19.21:1 · AAA
Aalinie on grund1.38:1 · zu schwach1.60:1 · zu schwach

For information, not as a promise: pink, blue and yellow as surfaces on the paper sit at 1.3:1 to 1.5:1. These surfaces separate through their hairline and their content, not through colour distance.

HQ-only colours

--ampel-gruen, --ampel-gelb, --ampel-rot and --text-auf-ampel exist only in the internal HQ. There they rate figures: good, potential, weak. They never appear in the family app. A child never sees a red score.

In short