Design Language · Version 3.0
Design Language.
Every surface — the app, the website, a Nachtrag PDF, a slide in a Vergabegespräch, a film — is built from the rules on this page.
01Foundation
Derived,
not decorated.
German construction runs on documents that have to be exactly right. This system's job is to make BauLynq look like the software that gets them right.
Three principles
Derived, not decorated
Chart colours come from a colour-blindness simulation. Spacing comes from a 4 pt unit. Type sizes come from one ratio. Nothing is here because it looked nice.
Hairlines and air
Structure comes from 1 px rules and space, not heavy boxes or fills. A page should read like a well-set technical drawing.
One red
Oxblood, once per view — the primary action, money, a decision, a blockage. Spread it and it stops meaning anything.
The numbers are the product
A Leistungsverzeichnis is thousands of rows of money. Money is set in Plus Jakarta with tabular figures and no cents in a list — cents only where a document reconciles, like an invoice total. Identifiers are the only thing set in Geist Mono. Status is a tone from the ring, always with its word.
| Nr. | Bezeichnung | Zeitraum | Netto | Status |
|---|---|---|---|---|
| AR-11 | Abschlagsrechnung | 01.06.–30.06.2026 | 317.854 € | In Prüfung |
| AR-10 | Abschlagsrechnung | 01.05.–31.05.2026 | 289.410 € | Freigegeben |
| NT-07 | Nachtrag | — | 17.760 € | Überfällig |
| AR-09 | Abschlagsrechnung | 01.04.–30.04.2026 | 244.176 € | Bezahlt |
02Logo
One mark.
No lockup.
The mark is a B — two interlocking links, 0.867 as wide as it is tall (277.28 × 320). Size it by its height. It stands alone, on no tile, and the name never stands beside it.
The mark — this is the logo
One file, filled with currentColor: ink #16181A on a light surface, paper #F7F7F5 on a dark one. Set the colour once on a parent and both themes are correct. Minimum 20 px high — below that the counters close up. Clear space is half the mark's width on every side.
The badge — only where the background is not yours
The mark reversed inside a rounded square: corner radius 23.5 % of the side, mark inset 22 % so it is 56 % of the tile's height. It exists for the three places the surface behind the logo cannot be controlled — favicons and app icons, avatars, and placement over photography. Anywhere else, use the bare mark. Minimum 18 px.
color is correct on every canvas, and the mark can never disappear into its own tile.The name
Ordinary typography — Plus Jakarta Sans, two weights by size. Nothing ties its weight to the mark's stroke any more.
| Size | Weight | Tracking | Where |
|---|---|---|---|
| 28 px and up | 800 | -0.030 em | Covers, slide titles, the website hero. |
| Below 28 px | 700 | -0.012 em | App headers, footers, captions. |
Placement — opposite ends
The mark anchors one end of a bar or surface; the name sits at the far end, or on another edge entirely. Minimum separation is 8 × the mark's width, or the full width of the surface. Where the far end is taken — a CTA, a toolbar — the name moves to the next quiet anchor, usually the footer. It does not move next to the mark.
App header — mark far left, page title beside it, name far right.
Slide — mark top-left, name top-right.
Rules
Do
- Use the bare mark. It is the logo.
- Set
coloronce and let one file serve both themes. - Size it by its height and let the width follow.
- Put the name at the far end, or leave it off — the mark carries the brand.
- Below 20 px high, use the badge (minimum 18 px).
Don't
- Build a lockup. Not horizontal, not stacked, not "just this once".
- Force the mark into a square box, or stretch, crop, recolour or redraw it.
- Put the name beside, under or over the mark.
- Put a badge on a surface you control — that is what the bare mark is for.
- Put more than one mark on a surface.
03Typography
Two faces,
one job each.
Plus Jakarta Sans carries the voice and every figure. Geist Mono carries identifiers — and nothing else. Both SIL OFL: free to use, embed and ship.
Which face carries what
Aa 4.284.900 €
Plus Jakarta Sans
Headlines, text, UI — and money and quantities: tabular-nums wherever figures stack, no decimals in a list, a Kennzahlkarte or a headline.
AR-2026-005
01.02.0030
Geist Mono
Identifiers only: record numbers, OZ, routes, hashes. Never a price, never a label, never a kicker.
The scale
display-1800 · -0.045em · 0.94display-2800 · -0.04em · 0.98h1700 · -0.032em · 1.06h2700 · -0.026em · 1.12h3600 · -0.02em · 1.2h4600 · -0.014em · 1.3body-lg400 · -0.006em · 1.6body400 · 0 · 1.6body-sm400 · 0 · 1.55caption500 · 0.005em · 1.45kickerJakarta 600 · 0.06em · 11 pxfigureJakarta 650 · tabularidGeist Mono 500German typesetting
Do
- Quotes are „low-high" —
„Ein Projekt." - Thousands a dot, decimal a comma: 1.234.567,89 € — and no cents where nothing reconciles: 1.234.568 €.
- Non-breaking space before
€,%,§. - Dates 27.09.2026, two-digit day and month in tables.
tnumanywhere numbers stack vertically.
Don't
- Set long compounds in all caps — ABSCHLAGSRECHNUNG is unreadable.
- Hyphenate a headline. Rewrite it shorter.
- Use tabular figures for a big standalone number — it goes gappy.
- Letterspace lowercase. Only the uppercase kicker gets tracking.
- Set a price or a label in mono.
04Colour
Paper, two inks
and one red.
Three surfaces, two ink tiers and oxblood carry almost everything. Eight ramps, stepped in OKLCH so lightness moves evenly to the eye, sit behind them.
Papier, Blatt, Linie
The app stands on three surfaces: Papier is the canvas, Blatt the cards, rail and header, Linie every edge. They are cool greys on purpose — warm greys read as a second hue next to oxblood. Print, the website and the films stand on the brand paper #F7F7F5, the Beton 50 of this page.
#F6F7F9#FFFFFF#E6E8EBTwo inks — and no third grey
#16181A · 16.6 : 1 — headings, body, figures.#53575B · 6.8 : 1 — secondary text, labels, kickers.#707478 is 4.39 : 1 on paper — under AA. Quietness comes from size and weight, never from more grey, and never from a text opacity below 70 %.The status ring
Six tones, one meaning each. A tone appears as a 3 px tick at the left of a row and, where a column reports it, as a pill on its tint. The word always travels with it.
| Tone | Means | Pill | Printed in |
|---|---|---|---|
| gruen | Freigegeben, bezahlt | Freigegeben | #006133 |
| bernstein | In Prüfung, Frist läuft | In Prüfung | #985E00 |
| rot | Überfällig, abgelehnt | Überfällig | #B83B36 |
| beton | Entwurf — no status yet | Entwurf | #53575B — the tick grey is too light to print |
| ox | Money, decision, blockage | Freigabe offen | #8E2222 |
| ink | A plain fact with no state | Info | #16181A |
#B83B36 sits two steps off #8E2222, so an error can never be mistaken for a primary action.Ramps
Rot
The brand. German industrial red pulled toward Bordeaux so it reads as engineering, not alarm.
Beton
The neutral. The brand paper, the hairlines and both ink tiers.
Stahl
Steel blue. Data slot 4, and the focus ring — the only blue in the system.
Grün
Freigegeben, bezahlt, geprüft. Data slot 3.
Bernstein
In Prüfung, Frist läuft. Data slot 5.
Violett
Data slot 2 only. Never a status, never a UI colour.
Türkis
Reserve, for module tints when a module needs its own.
Gold
An ordinary ramp. The flag gold #F6C500 is not in it — that one is reserved for the flag rule.
#AA8300 is gold 500, an ordinary ramp step. #F6C500 is not in any ramp: it is the Schwarz-Rot-Gold flag gold, and it appears in exactly one place — the flag rule.Semantic tokens
Never reference a ramp step in a component — reference the semantic token, and both themes take care of themselves. Contrast is measured against each theme's canvas.
| Token | Light | Dark | Contrast L / D | Use |
|---|---|---|---|---|
--bl-bg | #F7F7F5 | #07080A | — | Brand paper — web, print, film |
--bl-surface | #FFFFFF | #121418 | — | Sheets — cards, tables, charts |
--bl-ink | #16181A | #F2F4F6 | 16.6 / 18.2 | Headings, body, figures |
--bl-ink-2 | #53575B | #9AA0A6 | 6.8 / 7.6 | Secondary text — the last tier |
--bl-line | #E2E3E0 | rgba(255,255,255,.08) | — | Hairlines. 1 px, always |
--bl-accent | #8E2222 | #D8574D | 8.2 / 5.1 | Oxblood — the primary action, money, decision |
--bl-focus | #286CBE | #5FA4FC | 4.9 / 7.8 | Focus ring. Deliberately not red |
05Data visualisation
Validated,
not picked.
Charts answer „wo stehen wir?". The palette was optimised, then validated against colour-blindness simulation.
Categorical — fixed order, never cycled
#A22626#D8574D#A09BFF#5E54BA#007A4B#19A572#60A6FF#1962B6#9B6000#C57E00#DE75B4#A5417F| Check | Light | Dark | Gate |
|---|---|---|---|
| Adjacent CVD ΔE | 20.7 | 20.8 | Target ≥ 8. Comfortably clear. |
| Normal-vision ΔE | 24.0 | 23.1 | Hard floor ≥ 15. |
| Lightness band, chroma floor | pass | pass | All six in band, all above the floor. |
| Contrast vs surface | 3 of 6 < 3:1 | all ≥ 3:1 | Slots 2, 4, 6 on white need labels or the table view. |
In practice
Abrechnungsstand je Gewerk
Abgerechnet und offen, in Tausend Euro
Kumulierte Abrechnung
Februar bis Juni 2026, in Tausend Euro
Sequential and diverging
Sequential — one hue, light to dark. Magnitude only.
Diverging — Stahl to Rot, neutral grey middle. Polarity only.
Marks
Do
- Bars ≤ 24 px thick, 4 px rounded at the data end, square at the baseline.
- 2 px lines; markers ≥ 8 px with a 2 px surface-colour ring.
- A 2 px surface gap between stacked segments — never a stroke.
- Hairline solid gridlines. Label the endpoint or the extreme, not every point.
- A legend whenever there are two or more series.
Don't
- Two y-axes. Ever. Split into two charts or index to a base.
- Colour bars by their value — bar length already says that.
- Use a status colour as „Serie 4".
- Colour label text with the series colour. Marks carry colour; text wears ink.
- Dashed gridlines, 3-D, gradients, or a border around the plot.
06Layout & space
Hairlines
and air.
One 4 pt unit, a 1200 px content maximum, two radii, and one surface per page.
Space
Base unit 4 px. Section padding 96 / 56 px, content maximum 1200 px, gutter clamp(20px, 4vw, 48px).
Radii
10 px on every control, 12 px on every card — the app's two radii. Pills for chips and status; 18 px only for the website's large sheets. Print uses none.
One surface per page
A page is one Blatt on the Papier with a 1 px Linie edge. Sections inside it are separated by hairlines — never by boxes that each bring their own radius and padding, which reads as four unrelated widgets. Elevation is for what genuinely floats: menus, dialogs, a toast.
07Components
A small kit,
built from tokens.
If something is not here, build it from the tokens rather than inventing a value.
Buttons and modules
One primary per view, in oxblood — it is that view's red. A creation action is always a button, never a ghost link. 10 px radius. The focus ring is Stahl blue, never red.
Module names: Jakarta, hairline outline, no fill. Capital X, no space, no hyphen.
Rows and status
Status pills read the ring — tinted ground, tone-coloured word; the 3 px tick marks the row. The word is mandatory: a coloured row means nothing to a colour-blind Bauleiter without Überfällig beside it.
Kennzahlen
Kicker label, ink figure in Jakarta — tabular, no cents, no icon. Oxblood only on the figure that is money held up, never as the default figure colour. Figures appear; they never count up.
08Motion
Motion explains
a change.
Motion explains a relationship or a change of state. If it explains nothing, it is decoration, and it does not ship.
Four durations — try them
One scale, defined once as tokens, never a bare duration at a call site. Easings say what the thing is doing: --bl-ease-out arriving, --bl-ease-in leaving, --bl-ease-move travelling.
--bl-dur-tap 90 msPressed and hover — must read as instant.--bl-dur-ui 160 msControl state, tint, tick, badge.--bl-dur-enter 220 msSomething arrives. Exits mostly do not animate.--bl-dur-move 300 msSomething travels: sheet, drawer, reorder.Rules
Do
- Animate only
transformandopacity— composited, never layout. - Animate entrances. Let exits happen at once; the backdrop is the exception.
- Stagger on first paint only, capped at six rows.
- Collapse every duration to 1 ms under
prefers-reduced-motion— once, at the token layer. - Gate pointer effects by
pointer: fine.
Don't
- Animate height, width or top.
- Count a figure up. Money and status appear.
- Re-stagger a list on every refetch — that is noise.
- Write a bare
0.22sat a call site: it silently opts out of the guard. - Bounce.
09Motion & film
One world.
One red thread.
The films are one continuous world a camera travels through — the paper, guides and type of this page — with every picture placed on the spoken word.
The frame, reduced
Der rote Faden
Ein Bauprojekt.
Ein Datensatz.
01.02.0030The camera creeps, words light on their spoken word, the thread draws station by station — and yields when the flag rule lands, so there is only ever one red. Captions keep their own band.
The rules
01One world, one camera
Scenes are places in one world, not slides. The camera glides on the spoken word, creeps 2–3 % over a hold and drifts 2–3 px, so nothing is ever pixel-still. Tilt at most 0.5°.
No fade to black: the next shot overlaps the last by 50–100 ms — a morph, a continuity cut, the UI moving the camera.
02Words light as they are said
Every word starts dim and lights on its timestamp. A title's last clause keeps the dim-to-lit contrast — the website's headline, in motion.
03The red thread
One line in oxblood (#D8574D on dark) links the stations of one LV position — LV, Aufmaß, Prüfung, Abnahme, Rechnung, XRechnung. It draws as the narration names each step, runs in its own lane and never crosses text or UI.
It is the only red in the frame. When the app's own red is on screen — a primary button, the Freigabe stamp — the thread yields.
04Gold once
#F6C500 appears only in the flag rule on the end card, its black band in ink so it survives on dark. The end card is the film's own world pulled back: mark top-left, the name at the far end, never a lockup.
05Sound under the picture
A synthesised kit, no stock audio: pencil for the Maßkette, stamp for the Freigabe, tick per validated position, chime for „XRechnung valide", paper, whoosh on every camera travel. Sound leads the cut by 0.1–0.2 s.
A quiet music bed, ducked under the voice (about –32 LUFS); the master is –14 LUFS.
06Captions keep their band
Phrases of two to five words, never bouncing word by word, timed from the word timestamps. A boxed pill that never sits on a figure, a button or a headline — marked content pushes it away. On by default on the website.
07The app stays the app
Screens are the shipped product in its light theme, with real German data and one hero record through the whole film. A counter never shows a value that was never true.
Eases by role
| Role | Curve | Use |
|---|---|---|
| enter | cubic-bezier(.23,1,.32,1) | Arrivals. The brand --bl-ease is this curve. |
| exit | cubic-bezier(.55,0,.9,.4) | Leaving, at 0.65 × the enter duration. |
| move | cubic-bezier(.77,0,.175,1) | Panes, sheets, reorders. |
| camera | cubic-bezier(.65,0,.35,1) | Every camera glide — the brand --bl-ease-io. |
| swift | cubic-bezier(.2,0,0,1) | Presses and toggles. |
10Voice
Write like
a Bauleiter.
German, direct, technically literate. Short sentences, exact nouns, no adjective doing a number's job.
Tone
Do
- „Von der Ausschreibung bis zur Übergabe geht nichts verloren."
- Name the artefact: Leistungsverzeichnis, Aufmaß, Nachtrag, Abschlagsrechnung.
- Cite the rule where it earns trust: VOB/B § 16.
- Headlines of one or two clauses. Sub-copy of one sentence.
- Use „Sie". Address a Bauleiter, not a persona.
Don't
- „Revolutionäre KI-gestützte Cloud-Lösung."
- Anglicisms where a German word exists — Abrechnung, not Billing.
- Exclamation marks. Ever.
- Claims without a figure behind them.
- Emoji, in any surface.
Naming
BauLynq — one word, capital B and L, everywhere. Modules are InrX, PlanX, ProcureX, LedgerX, ReportsX — capital X, no space, no hyphen. Messages the app sends a person are written in German and English at the place they are raised; records stay German.
11Documents
Same tokens,
on paper.
Word, PowerPoint and Excel templates ship with this system, all in German, all built from the same tokens.
Templates
| File | What it is |
|---|---|
BauLynq-Briefbogen.docx | DIN 5008 letterhead — mark, kicker, hairline rules, real page-number fields. |
BauLynq-Bericht.docx | Project report — bleeding near-black cover, live table of contents, KPI row, invoice table. |
BauLynq-Vorlage.dotx | The report as a true Word template with the named style set. |
BauLynq-Praesentation.pptx | Ten German slides — title, agenda, statement, pillars, KPI, table, native chart, suite, timeline, close. |
BauLynq-Vorlage.potx | PowerPoint template — BauLynq theme colours and fonts, eight named layouts. |
BauLynq-Kostenverfolgung.xlsx | Cost-control workbook — 32-position LV, formula-driven KPIs, invoice ageing, two native charts. |
BauLynq-Vorlage.xltx | The workbook stripped to headers, formulas and formatting. |
12Downloads
Everything,
in one pack.
Every artefact in the system. The logo files and tokens are generated from one source each and regenerated whenever it changes.
This document
Logo
System
Using the tokens
<link rel="stylesheet" href="/assets/css/baulynq-tokens.css">
.card {
background: var(--bl-surface);
border: 1px solid var(--bl-line);
border-radius: 12px;
color: var(--bl-ink);
}
.card .amount {
font: 650 var(--bl-fs-data)/var(--bl-lh-data) var(--bl-sans);
font-variant-numeric: tabular-nums;
}Regenerate the CSS from the JSON rather than editing it: npm run tokens. Change a value in one place and everything downstream follows.