---
version: alpha
name: MezBOX
description: >-
  Design system for the self-hosted apps on mezbox.de. Paper-and-graphite
  neutrals, a single signal yellow taken from the lid of the logo, and the
  Red Hat type family. Built for small, dense tools that a family and one admin
  use every day.
colors:
  primary: "#141414"
  on-primary: "#F6F6F3"
  accent: "#FFD900"
  accent-hover: "#F2CE00"
  on-accent: "#141414"
  background: "#F6F6F3"
  surface: "#FFFFFF"
  surface-sunken: "#EFEFEA"
  surface-hover: "#F1F1EC"
  border: "#E2E2DC"
  text: "#141414"
  text-muted: "#6B6F78"
  ink-2: "#4A505B"
  success: "#1F9D55"
  success-text: "#177A42"
  warning: "#E5701A"
  warning-text: "#B2510C"
  danger: "#D93636"
  danger-text: "#B42323"
  info: "#3A6FD8"
  info-text: "#2B57B0"
  dark-background: "#14171C"
  dark-surface: "#1C2027"
  dark-surface-sunken: "#101318"
  dark-surface-hover: "#232831"
  dark-border: "#2C323C"
  dark-text: "#E8EBF0"
  dark-text-muted: "#8A93A3"
  dark-ink-2: "#9AA3B2"
  dark-accent-hover: "#FFE14D"
  dark-success-text: "#4CC77F"
  dark-warning-text: "#F39A52"
  dark-danger-text: "#F07070"
  dark-info-text: "#7FA3F0"
typography:
  display:
    fontFamily: Red Hat Display
    fontSize: 40px
    fontWeight: 800
    lineHeight: 1.1
    letterSpacing: -0.03em
  h1:
    fontFamily: Red Hat Display
    fontSize: 30px
    fontWeight: 800
    lineHeight: 1.15
    letterSpacing: -0.03em
  h2:
    fontFamily: Red Hat Display
    fontSize: 24px
    fontWeight: 800
    lineHeight: 1.2
    letterSpacing: -0.025em
  h3:
    fontFamily: Red Hat Display
    fontSize: 18px
    fontWeight: 700
    lineHeight: 1.3
    letterSpacing: -0.01em
  title:
    fontFamily: Red Hat Display
    fontSize: 15px
    fontWeight: 700
    lineHeight: 1.3
    letterSpacing: -0.01em
  body-lg:
    fontFamily: Red Hat Text
    fontSize: 16px
    fontWeight: 400
    lineHeight: 1.55
  body:
    fontFamily: Red Hat Text
    fontSize: 14px
    fontWeight: 400
    lineHeight: 1.5
  small:
    fontFamily: Red Hat Text
    fontSize: 12.5px
    fontWeight: 400
    lineHeight: 1.45
  button:
    fontFamily: Red Hat Text
    fontSize: 13.5px
    fontWeight: 600
    lineHeight: 1
  label:
    fontFamily: Red Hat Mono
    fontSize: 11.5px
    fontWeight: 500
    lineHeight: 1.3
    letterSpacing: 0.06em
  mono:
    fontFamily: Red Hat Mono
    fontSize: 12px
    fontWeight: 400
    lineHeight: 1.4
rounded:
  xs: 4px
  sm: 6px
  md: 10px
  lg: 14px
  xl: 18px
  full: 9999px
spacing:
  "1": 4px
  "2": 8px
  "3": 12px
  "4": 16px
  "5": 20px
  "6": 24px
  "8": 32px
  "12": 48px
components:
  button-primary:
    backgroundColor: "{colors.accent}"
    textColor: "{colors.on-accent}"
    typography: "{typography.button}"
    rounded: "{rounded.md}"
    padding: 9px 14px
  button-primary-hover:
    backgroundColor: "{colors.accent-hover}"
  button-ink:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.button}"
    rounded: "{rounded.md}"
    padding: 9px 14px
  button-secondary:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    typography: "{typography.button}"
    rounded: "{rounded.md}"
    padding: 9px 14px
  button-ghost:
    backgroundColor: transparent
    textColor: "{colors.text-muted}"
    typography: "{typography.button}"
    rounded: "{rounded.md}"
    padding: 9px 14px
  input:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    typography: "{typography.body}"
    rounded: "{rounded.md}"
    padding: 10px 12px
  card:
    backgroundColor: "{colors.surface}"
    rounded: "{rounded.lg}"
    padding: 16px
  badge-new:
    backgroundColor: "{colors.accent}"
    textColor: "{colors.on-accent}"
    rounded: "{rounded.sm}"
    padding: 0 7px
  badge-soft:
    backgroundColor: "{colors.surface-sunken}"
    textColor: "{colors.text-muted}"
    rounded: "{rounded.sm}"
    padding: 0 7px
  app-bar:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    padding: 12px 20px
  app-tile-own:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: 23.4%
    size: 40px
  app-tile-third-party:
    backgroundColor: "{colors.surface-sunken}"
    textColor: "{colors.text}"
    rounded: 23.4%
    size: 40px
  tab-active:
    textColor: "{colors.text}"
  dialog:
    backgroundColor: "{colors.surface}"
    rounded: "{rounded.xl}"
    padding: 28px
---

# MezBOX

## Overview

MezBOX is the home server behind mezbox.de. It runs a mix of family apps
(Nextcloud, Immich, Tandoor), smart-home and energy tools (Home Assistant,
Sunalyzer, TeslaMate) and a handful of apps built in-house (Gemeinderat
Scanner, MezBOX Video, Stundenplan, MezBOX Sensor). This system gives them
one face.

The character is **a well-labelled box in a tidy workshop**: calm paper and
graphite surfaces, crisp type, and one bright yellow strip of tape that marks
what matters. It's a private tool, not a marketing site. Screens are dense,
scannable and honest about state. Personality comes from the mark, the yellow
and the heavy Red Hat Display headings. Everything else stays quiet.

The brand descends from the original 2022 mezbox.de page (white Clarendon
on black, yellow #FFE400). It keeps the black-and-yellow contrast and the
"BOX", and swaps the slab serif for a modern grotesque.

### Logo

- **Mark: the Lifted Lid.** A box whose top edge dips into an "M", with the lid
  lifted and tilted 7° above it. The body is ink (`#141414`, or `#E8EBF0` on
  dark). The lid is always yellow `#FFD900`, except in one-color versions.
- **Wordmark:** `MezBOX`, always one word with no space. "Mez" is Red Hat
  Display 800 and "BOX" is Red Hat Display 500 in `text-muted`. Never write
  "Mezbox", "MEZBOX" or "Mez BOX".
- **App lockup:** `MezBOX / Video`. The app name is 500 weight in `text-muted`,
  and the slash is in `border` color.
- **Clear space:** at least the lid's height (≈ 0.2 × mark size) on all sides.
  The smallest mark size is 16 px, and the smallest lockup is 18 px font size.
- Files are in `logo/` (mark, lockup, on-dark and mono versions) and
  `logo/apps/` (app lockups). Icons are in `icons/`.

## Colors

The palette is **Paper & Graphite with one yellow**. Neutrals carry a
slight cool-green bias (paper) or blue bias (graphite) so they never look like
default greys.

- **Ink `#141414` / Paper `#F6F6F3`:** the base pair. Ink is text, the mark
  body, the ink button and own-app tiles. Paper is the page.
- **Yellow `#FFD900` (accent):** the lid. It's reserved for exactly these
  jobs: the primary action, the focus ring, "new/unread" markers, the active
  tab underline, link underlines and detection boxes in Video. Text on yellow
  is always ink, in both themes. Never put yellow text on paper (contrast
  1.3:1).
- **Surfaces:** `surface` (#FFF) for cards and bars, `surface-sunken`
  (#EFEFEA) for wells, search and third-party tiles, `surface-hover` for row
  and card hover.
- **Status:** success green, warning **orange** (deliberately not yellow, so a
  warning never looks like brand), danger red and info blue. Each has a `-text`
  variant tuned for body-size text on surfaces. Use the base value for dots,
  borders and tinted badge backgrounds.
- **Dark theme: graphite, not black.** `#14171C` background and `#1C2027`
  surfaces. Yellow stays the same, and status text uses the `-text-dark`
  values from `tokens/tokens.json`. Apps follow the OS setting by default.
  MezBOX Video defaults to dark. `data-theme="light|dark"` on `<html>`
  overrides.

All text pairs meet WCAG AA: ink on paper is 17:1, muted on paper 4.65:1, ink
on yellow 13.3:1, dark text on graphite 15:1 and dark muted on graphite 5.8:1.
Status `-text` colors are 5.1:1 or better on their surface.

## Typography

One family, three cuts, all OFL-licensed and self-hosted from `fonts/`:

- **Red Hat Display** for headings, the wordmark, card titles and big numbers.
  Weights 800 and 700, tracked tight (−0.025 to −0.03em).
- **Red Hat Text** for everything people read: body, buttons, form fields.
  Weights 400, 500 and 600.
- **Red Hat Mono** for things machines produce: hostnames, timestamps, IDs,
  file sizes, counts in tables, and the small uppercase section labels
  (`label`, +0.06em).

The scale is display 40, h1 30, h2 24, h3 18, title 15, body 14 (16 for
reading-heavy pages) and small 12.5. Headings use `text-wrap: balance`. Any
column of digits gets `font-variant-numeric: tabular-nums`. German UIs stay
in German. Write short, direct labels ("Original öffnen", "Als gelesen
markieren").

## Layout

- Use a **4 px spacing grid** (`spacing.1` to `spacing.12`). Use gaps on
  flex/grid rather than margins.
- **App bar** on every own app: lockup on the left (`MezBOX / AppName`), then
  actions and the avatar on the right. The markup is in USAGE.md section 1
  (https://design.mezbox.de/USAGE.md). It's 52–56 px high, with the surface
  color and a bottom border.
- **Content width:** dashboards are fluid up to 1280 px. Reading views keep
  text to about 75 characters.
- **Side nav** (for lists like Gemeinderat search terms) is 240 px on the
  surface, and stacks above the content under 860 px.
- **Card grids:** `repeat(auto-fill, minmax(230px, 1fr))` with 10–12 px gaps.
- Phone layouts are first-class (Stundenplan, ntfy pushes). They use a
  16 px gutter and a bottom tab bar whose active tab is marked with a yellow
  bar.

## Elevation & Depth

The system is mostly **flat with 1 px borders**. Depth is shown by surface
steps (sunken → bg → surface), not shadows. Only things that float above the
page (menus, dialogs, toasts, the login box on a photo background) get
`--mz-shadow-overlay`. Hover states change the border and background, not the
elevation.

## Shapes

- Radii are `md` 10 px for buttons and inputs, `lg` 14 px for cards, `xl` 18 px
  for dialogs and login boxes, and `sm` 6 px for badges. Pills and avatars are
  fully round.
- **App tiles** are 23.4% radius squares (15 on a 64 grid):
  - **Own apps wear the lid:** an ink tile with a tilted yellow bar at the
    top and white initials (Red Hat Display 800).
  - **Third-party apps** get a neutral sunken tile with ink initials. They
    never get the lid.
  - Tiles live in `icons/apps/` (SVG + 256 px PNG). Add new ones in
    `scripts/build_assets.py`.
- The lid's 7° tilt is the only rotated element in the system. Don't tilt
  anything else.

## Components

- **Buttons:** at most **one primary (yellow) per view**. Use `ink` for
  strong secondary actions such as Update and Add, `secondary` (outlined) for
  everything else and `ghost` in app bars. Use `danger` only for destructive
  confirmation.
- **Inputs:** surface fill, 1 px border, 10 px radius. On focus the border
  turns ink and gets a 3 px yellow ring at 70% opacity. The same ring is used
  for all keyboard focus.
- **Links:** text color with a 2 px yellow underline. The underline turns ink
  on hover.
- **Badges:** `new` is yellow with ink text (for unread counts and "Neu").
  `soft` is sunken with muted text (for tags and search terms). Status badges
  are tinted with `-text` colors.
- **Status dots:** 8 px. Green means up, orange slow or degraded, red down and
  muted idle.
- **Unread card:** a 4 px yellow left edge until it's marked as read.
- **Tabs:** muted labels with a 2 px yellow underline on the active tab.
  **Segmented controls** and **filter pills** show the active item as an ink
  fill.
- **Detection boxes (Video):** 2 px yellow outline with a yellow label tab
  showing the class and confidence (`person 0.91`).
- **Push notifications (ntfy):** topic `mezbox-<app>`, with the app tile PNG
  as the icon.

Reference implementation: `css/mezbox.css` (prefix `mz-`), loading
`tokens/tokens.css`.

## Do's and Don'ts

- **Do** use yellow as a signal. If more than two or three yellow things are on
  screen, one of them shouldn't be yellow.
- **Do** keep "MezBOX" as one word with the weight change at "BOX".
- **Do** put hostnames, times and IDs in Red Hat Mono.
- **Do** design dark mode on purpose: graphite surfaces, same yellow.
- **Don't** put white or yellow text on yellow. Text on the accent is always
  ink.
- **Don't** use yellow for warnings. Warnings are orange.
- **Don't** give third-party apps the lid tile, or redraw their logos.
- **Don't** use pure black (`#000`) backgrounds, gradients or glassmorphism.
- **Don't** add drop shadows to cards or tilt anything except the lid.
- **Don't** set body text in Red Hat Display, or headings in Red Hat Text.
