08 – MkDocs Design Guide¶
How a MkDocs site, its interactive app pages and its app icon look and behave: colours, typography, spacing, components, drawings, printing and the web app (PWA) setup. It is not tied to one product. Use this file as the single reference when you build a new MkDocs site or app that must look and behave the same.
Note for this repository (Receptsamling). This is a copy of
design-guide.mdfrom the Workshop repository (mkdocs/docs/design-guide.md), which in turn is a copy of the Load_Cell guide. Here the app icon and the header logo are a plate with fork and knife (overrides/.icons/recept/plate.svg, masterdocs/assets/icons/icon.svg) instead of the tap glyph. The site language is Swedish (language: sv); everything else is followed as written. The scan page (docs/03-scan.md) uses the app page components of section 6.4: 46 px buttons, 44 px fields, 12 px cards and the glowing edge in dark mode.
Source of truth: every value below was read from the files of the reference site. The file that defines each value is named in the "Source" column or the line under each heading. Where a value is not defined there, it is marked not defined and listed in Open points.
1. Design principles¶
These follow from how the reference site is built.
| Principle | How it shows in the code |
|---|---|
| One brand colour (teal) with one warm accent | primary: teal, accent: deep orange in mkdocs.yml; app pages use --accent teal |
| Light and dark mode everywhere | Two palettes in mkdocs.yml; prefers-color-scheme in app.css; [data-md-color-scheme="slate"] in explorer.css |
| Phone first, large touch targets | Buttons min-height: 46px, inputs min-height: 44px, tab buttons ≥ 2.6 rem |
| Rounded, card based layout | border-radius: 12px on cards, figures, frames and tiles |
| Colour carries meaning, never alone | Status (pass / fail / warning) always have a text label or chip as well as a colour |
| Works offline and installs as an app | PWA manifest, service worker, icons (section 9) |
2. MkDocs setup (mkdocs.yml)¶
| Setting | Value |
|---|---|
| Theme | material (MkDocs Material) |
| Custom theme folder | overrides/ |
| Language | en |
| Logo icon | loadcell/load-cell (custom icon in overrides/.icons/loadcell/load-cell.svg) |
| Favicon | assets/icons/icon-192.png |
| Extra CSS | assets/extra.css, assets/explorer.css |
| Extra JavaScript | assets/pwa.js |
| Hook | hooks/pwa.py (fills in the service worker after every build) |
Palette¶
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
accent: deep orange
toggle:
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: teal
accent: deep orange
toggle:
icon: material/weather-sunny
name: Switch to light mode
Theme features¶
navigation.tabs, navigation.sections, navigation.top, navigation.footer,
navigation.indexes, toc.follow, search.suggest, search.highlight, content.tabs.link
Markdown extensions¶
admonition, attr_list, md_in_html, tables, toc (with permalink: true), pymdownx.details,
pymdownx.highlight, pymdownx.inlinehilite, pymdownx.keys, pymdownx.tasklist
(custom_checkbox: true), pymdownx.tabbed (alternate_style: true), pymdownx.emoji
(Material Twemoji, SVG output), pymdownx.superfences (with a mermaid custom fence).
3. Colours¶
3.1 Brand colours¶
| Role | Light | Dark | Source |
|---|---|---|---|
| Site primary | #00897b (light #4db6ac, dark #00695c) |
same | mkdocs.yml (primary: teal) with own values in docs/assets/extra.css |
| Site accent | #d84315 |
#ffab76 |
mkdocs.yml (accent: deep orange) with own values in docs/assets/extra.css |
| Web app theme colour | #00897b |
– | docs/manifest.webmanifest, overrides/main.html, app pages |
| Web app background colour | #ffffff |
– | docs/manifest.webmanifest |
| App icon background | #00897b |
– | docs/assets/icons/icon.svg |
| App icon glyph | #ffffff |
– | docs/assets/icons/icon.svg |
| App page accent | #00897b |
#26a69a |
docs/app/app.css |
App page theme-color meta |
#00897b |
– | docs/app/index.html, docs/app/pd.html |
| Interactive page accent | #00897b |
#4db6ac |
docs/assets/explorer.css |
One brand teal
#00897b is the only teal (decision DS-001). The icon, manifest, site, app pages and interactive pages all use it.
The site primary and accent are set with own hex values in docs/assets/extra.css (DS-002), not the
theme defaults. Copy that block into every new MkDocs site.
3.2 Dark mode surfaces (decision DS-006)¶
The dark scheme (slate) is near black with clear white text. Light mode is unchanged. All values are set in the [data-md-color-scheme="slate"] block at the end of docs/assets/extra.css; the page CSS files (viewer.css, lasermark.css) use the same values.
| Surface | Value | Variable |
|---|---|---|
| Page background | #0b0b0a |
--md-default-bg-color |
| Cards, code | #141413 |
--md-code-bg-color, --tv-card, --lm-bg |
| Text and number fields | #2c2c2a (lighter than the card around them) |
[data-md-color-scheme="slate"] input, select in extra.css |
| Chips, soft fills | #1e1e1c |
--tv-soft, --lm-soft |
| Footer | #050505 |
--md-footer-bg-color |
| Dividers and table rules | #2b2b29 |
--md-default-fg-color--lightest, --tv-sep |
| Text and numbers | #faf9f5 (clear white, no light grey) |
--md-default-fg-color, --md-typeset-color |
| Secondary text | #c2c0b6 |
--md-default-fg-color--lighter |
| Links | #4db6ac |
--md-typeset-a-color |
3.3 Glowing edge on cards and boxes (decision DS-007)¶
In dark mode every card, filter box, form group, preview area and input has a 1 px edge in the header teal #00897b with a glow. The glow is strongest on the line and fades both outwards and inwards, like a lit tube.
| Part | Rule |
|---|---|
Large boxes (--ws-glow) |
Outer: 0 0 3px at 90 %, 0 0 9px at 45 %, 0 0 20px at 20 %. Inner: inset 0 0 3px at 80 %, inset 0 0 9px at 35 %, inset 0 0 18px at 14 %. Colour rgb(0 137 123) |
Buttons, chips, inputs (--ws-glow-soft) |
Same colour, weaker: 0 0 3px at 70 %, 0 0 8px at 30 %, and the same inside |
| Not glowing | Dividers inside a card, table rows and list separators (--tv-sep, #2b2b29) |
3.4 Orange for names, white for values (decision DS-008)¶
Anything that names a thing is orange; anything that is a value stays white. The orange is the site accent from 3.1 (#d84315 light, #ffab76 dark).
| Orange (name) | White (value) |
|---|---|
Page headings h1 to h4, tool titles such as M2x0.4, card titles on Home |
Text the user types or selects |
Field labels (ID number, Date, filter names), group titles (Card data, Filters) |
Numbers and text in spec tables (2.5 mm, DIN 338) |
Spec table names (Diameter Ø, Brand), card bar titles (Drawing, Specification, 3D model) |
Option texts (Single card, Batch, Show logo) |
The large Workshop title on the green Home banner stays white, because orange has too little contrast on green.
4. Typography¶
| Context | Font | Size and weight | Source |
|---|---|---|---|
| Site (MkDocs Material) | Roboto (text), Roboto Mono (code) | Theme default sizes | mkdocs.yml (theme.font) |
| App pages | system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif |
16px/1.45 |
app.css |
| SVG text in symbols | var(--md-text-font-family, system-ui, sans-serif) |
10 px, weight 600 | extra.css |
| Numbers in tables and results | font-variant-numeric: tabular-nums |
– | app.css, explorer.css |
App page sizes:
| Element | Size |
|---|---|
h2 |
1.15rem |
h3 |
1rem |
| Brand name in header | 1.1rem, weight 700 |
Key-number value (.kv b) |
1.3rem |
| Banner | 1.1rem, weight 700 |
| Small text, table header | .8rem |
Interactive page sizes: h2 1.5rem (1.25rem on phones), control label .7rem uppercase with
letter-spacing: .06em, tag .6rem uppercase.
5. Layout and spacing¶
| Item | Value | Source |
|---|---|---|
| App page content width | max-width: 980px, centred |
app.css |
| App page gap between cards | 1rem |
app.css |
| Card padding | 1rem (.85rem under 520 px) |
app.css |
| Card | border: 1px solid var(--line), border-radius: 12px, background var(--card) |
app.css |
| Card grid | repeat(auto-fit, minmax(190px, 1fr)), gap .75rem |
app.css |
| Key-number tiles | repeat(auto-fit, minmax(150px, 1fr)), gap .6rem |
app.css |
| Interactive value cards | repeat(auto-fit, minmax(300px, 1fr)), gap .9rem |
explorer.css |
| Symbol grid | repeat(auto-fill, minmax(250px, 1fr)), gap .9rem |
extra.css |
| Phone breakpoint (app page) | max-width: 520px |
app.css |
| Phone breakpoint (site pages) | max-width: 44.984em |
extra.css, explorer.css |
| Safe areas | env(safe-area-inset-top) and env(safe-area-inset-bottom) |
app.css |
5.1 Responsive rules (phone portrait and desktop landscape)¶
Every page must work on a phone held upright (360–430 px wide) without sideways scrolling, and must
use the full screen width on a desktop in landscape. This site implements it in extra.css and
tables.js (in overrides/assets/).
| Situation | Rule |
|---|---|
| Phone, page margin | .5rem (10 px) on each side instead of Material's .8rem; full-bleed blocks (code, tab labels) use the same value as negative margin; table cards run to the content edge with no extra padding |
| Phone, page width | No page element is wider than the screen; images, SVG and video use max-width: 100%; long words, paths and identifiers wrap (overflow-wrap: anywhere) |
| Phone, tables | Each row becomes a card with 12px radius: first cell is the card title (grey fill, bold), every other cell shows its column heading as a small uppercase label above the value. tables.js adds data-label and data-stacked to each table; without JavaScript the table scrolls sideways as a fallback |
| Phone, code | Code blocks wrap (white-space: pre-wrap) instead of scrolling |
| Phone breakpoint | max-width: 44.984em (the Material phone breakpoint), as in section 5 |
Desktop, from 76.25em |
.md-grid has no maximum width: header, tabs, navigation, content and table of contents use the whole screen; tables fill the content column |
| Wide pictures | A picture that carries a lot of detail may grow to min(100%, 1200px) |
| Check | Open every page at 360 and 390 px (portrait) and at 1920 px (landscape); document.documentElement.scrollWidth must equal the window width, and no element inside the content may scroll sideways |
6. Components¶
6.1 Site components (MkDocs)¶
| Component | How to build it |
|---|---|
| Landing cards | <div class="grid cards" markdown> with a Material icon, bold title, --- rule, text and an arrow link (:octicons-arrow-right-24:) |
| "At a glance" tiles | <div class="grid cards glance" markdown>; value in <strong class="big"> (1.6rem, 1.2rem on phones; two tiles per row on phones) |
| Figure | { .rig }: full width, max-width: 960px, centred, border-radius: 12px |
| Mermaid diagram | Fenced mermaid block; centred, scrolls sideways on phones |
| Step number in tables | First column in bold; does not wrap |
| Embedded app page | .logger-frame: 80vh high, min-height: 560px, 1 px border in --md-default-fg-color--lightest, 12px radius |
| Symbol card | .sym with an SVG and a figcaption (bold title, text, italic i line for the source) |
| Note flag | .flag: boxed bold number, 2px border, 3px radius |
| Home button in the header | Home icon next to the palette toggle and search (overrides/partials/header.html, class .ws-home-btn, 44 px touch target); goes to the start page without opening the menu (DS-009) |
| Page icon | The whole Home card picture (16:10, not cropped) as a rounded icon (docs/assets/home/icon-*.webp, 320 × 200 px) in front of the page title (112 × 70 px, 80 × 50 px on phones) and in the menu (76 × 48 px, teal 1px border). All pictures have the same light background. Side menu and drawer also show the page description from the Home card under the title; the top tabs show a 40 × 25 px icon only. Added by docs/assets/nav-icons.js (DS-011) |
| Primary action button | Solid accent fill with dark text (#00897b light, #4db6ac dark). Used for Download SVG on every page and for Send by email in the laser card generator, so the two main actions look the same (DS-010) |
6.2 Admonitions (coloured boxes)¶
Defined in docs/guides/index.md. Use these meanings consistently.
| Type | Title | Meaning |
|---|---|---|
!!! abstract |
"In one sentence" | Summary at the top of a guide |
!!! info |
"Why?" | Reason behind a step |
!!! danger |
"Stop" | Do not continue; something is wrong or unsafe |
!!! tip |
"Tip" | Practical trick |
!!! note |
"Internal proposal" | Our interpretation where the specification is silent; must link to an open-points ID |
!!! warning |
"Open points" | Known gaps; link to the open-points list |
6.3 Standard guide layout¶
Every step-by-step guide page uses the same nine sections (from docs/guides/index.md of the reference site):
- At a glance
- What does it show?
- The setup
- Values per variant (one tab per variant)
- The whole procedure as a flow chart
- Step by step (tick-boxes, with "why" and "stop" boxes)
- Pass or fail?
- Common mistakes
- Open points
6.4 App page components (docs/app/app.css)¶
| Component | Class | Style |
|---|---|---|
| Header bar | .top |
Background --accent, text --accent-ink, padding .7rem 1rem plus top safe area |
| Warning bar | .warn-bar |
--warn-bg / --warn |
| Tabs | .tabs button |
Sticky; top corners rounded; active tab (aria-current="page") is --accent |
| Card | .card |
See section 5 |
| Primary button | button.btn |
--accent fill, 10px radius, min-height: 46px, weight 600 |
| Secondary button | button.btn.secondary |
Transparent, --accent text and border |
| Danger button | button.btn.danger |
Transparent, --fail text and border |
| Small button | button.btn.small |
min-height: 36px |
| Input, select, textarea | – | --bg fill, 1px --line border, 8px radius, min-height: 44px |
| Focus ring | :focus-visible |
3px solid var(--accent), offset 1px |
| Key-number tile | .kv > div |
--accent-soft fill, 10px radius; value bold 1.3rem, label .8rem muted |
| Note | .note |
4px left border and soft fill; variants .warn, .bad, .ok |
| Verdict chip | .chip |
Pill (999px), .8rem bold; variants .PASS, .FAIL, .IN_PROGRESS, .NOT_STARTED, .NOT_REQUIRED (dashed border, no fill) |
| Verdict banner | .banner |
12px radius, 1.1rem bold; same variants as chips |
| Progress bar | .progress |
8px high, --line track, fill uses currentColor |
| Picker buttons | .pairs button, .seg button |
2px border, 10px radius, min-height: 56px; selected (aria-pressed="true") uses --accent border and --accent-soft fill |
| Checklist | .steps |
24 px checkbox with accent-color: var(--accent); ticked rows turn muted with strike-through |
| Toggle (fault flag) | .toggles label |
2px border; checked state uses --fail border, fill and text |
| Table | table |
.92rem; header .8rem muted; numbers right-aligned; row states .invalid (warn) and .failed (fail) |
| Toast | #toast |
Fixed at the bottom centre, --ink fill, 10px radius; .bad variant uses --fail |
| Photo slot | .phslot, .ph |
10px radius; thumbnails 56 × 56 px, 8px radius |
| Chart | svg.chart |
Full width, --bg fill, 8px radius, 11px muted axis text |
6.5 Interactive page components (docs/assets/explorer.css)¶
| Component | Class | Style |
|---|---|---|
| Segmented control | .ux-seg |
1.5px accent border, 10px radius; selected button (.on) is solid accent |
| Tabs | .ux-tabs |
2px bottom line; selected tab has a 3px accent underline and soft fill |
| Key chips | .ux-keys li |
Pill with --ux-soft fill, .8rem |
| Value card | .ux-card |
12px radius, 1px line; title .95rem in accent |
| Source tag | .ux-tag |
spec = accent, int = orange (internal proposal), ref = grey |
| Player controls | .ux-ctl |
Buttons with 1.5px accent border; play button solid accent, min width 7.5rem |
| Progress bar | .ux-bar2 |
6px high |
| "Now" box | .ux-now |
4px accent left border, soft fill |
| Step chips | ol.ux-steps |
Done = accent border; current = solid accent |
| Verdict list | .ux-verdicts li |
ok = accent border and soft fill; bad = red border |
7. Drawings and diagrams¶
| Rule | Value | Source |
|---|---|---|
| Line style | fill: none, round caps and joins; stroke currentColor |
extra.css |
| Stroke widths | normal 2, thin 1.2, thick 3.2 (symbols); 2.5 for set-up parts |
extra.css, explorer.css |
| Hidden / auxiliary line | dashed 5 3; centre line 12 3 2 3 |
extra.css |
| Main line | var(--md-primary-fg-color), width 5 (7 in wide drawings) |
extra.css |
| Main line in interactive set-up | --ux-pipe, width 9 |
explorer.css |
| Dimension lines and values | --ux-orange, 1.6 stroke |
explorer.css |
| Limits | --ux-red, dashed 5 4 |
explorer.css |
| Data series | A = accent (solid); B = orange (dashed 6 3); tare = muted (dashed 3 3) |
explorer.css |
| Backgrounds | Symbol drawings sit on var(--md-code-bg-color); set-up drawings on var(--md-default-bg-color) |
extra.css, explorer.css |
| Colours in SVG | Always CSS variables so light and dark mode both work | – |
8. Printing¶
From app.css: on print the page is white with black text; only the #printArea is shown; headings
16pt / 13pt; tables 9.5pt with 1px #999 borders; chips are black outline only; each run avoids
page breaks (break-inside: avoid).
9. App icon and web app (PWA)¶
9.1 Icon¶
| Item | Value |
|---|---|
| Master file | docs/assets/icons/icon.svg (viewBox="0 0 512 512") |
| Background | Rounded square, rx="96", fill #00897b |
| Glyph | Load cell: a load arrow on a column cell with three bore holes and a base plate, white #ffffff, fill-rule="evenodd", transform="translate(96 96) scale(13.3333)" (glyph is 320 × 320 px, centred) |
| Glyph licence | Own drawing for this project, no third-party licence |
| Same glyph in the site header | theme.icon.logo: loadcell/load-cell (same path in overrides/.icons/loadcell/load-cell.svg) |
Glyph path (24 × 24 grid), copy as is when you make a new icon in another colour:
M11 1.5h2V6h2.4L12 9.8 8.6 6H11zM9 11h6v1.6H9zM5.5 13h13a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM12 14.4a1.6 1.6 0 1 0 0 3.2 1.6 1.6 0 1 0 0-3.2zM7.6 15.1a.9.9 0 1 0 0 1.8.9.9 0 1 0 0-1.8zM16.4 15.1a.9.9 0 1 0 0 1.8.9.9 0 1 0 0-1.8zM3 19.8h18V22H3z
9.2 Icon files¶
| File | Size | Format | Use |
|---|---|---|---|
icon.svg |
any | SVG | Manifest (purpose: any) |
icon-192.png |
192 × 192 | PNG, RGBA | Favicon, manifest, shortcuts |
icon-512.png |
512 × 512 | PNG, RGBA | Manifest (purpose: any) |
icon-maskable-512.png |
512 × 512 | PNG, RGB | Manifest (purpose: maskable): full-bleed teal square with the white glyph in the centre |
apple-touch-icon.png |
180 × 180 | PNG, RGB | iOS home screen |
9.3 Manifest (docs/manifest.webmanifest)¶
| Field | Value |
|---|---|
name |
Full site name (here: Load Cell) |
short_name |
Short name for the home screen (here: Load Cell) |
display |
standalone |
orientation |
any |
theme_color |
#00897b |
background_color |
#ffffff |
start_url, scope, id |
./ |
lang, dir |
en, ltr |
categories |
productivity, utilities |
shortcuts |
One per app page or key page (here: the user manual and the open items), each with icon-192.png |
9.4 Page head for an installable page¶
From overrides/main.html (site) and docs/app/index.html (app page):
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#00897b">
<link rel="apple-touch-icon" href="assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="<short name>">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
In overrides/main.html the links use {{ '...' | url }}; the app pages also set
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> and
<meta name="color-scheme" content="light dark">.
9.5 Offline behaviour¶
docs/assets/pwa.jsregisterssw.jsfrom the site root (found from the script's own address).docs/sw.jsis network first; the cached copy is used only when offline.hooks/pwa.pywrites the list of all built files (skipssw.js,sitemap.xml,sitemap.xml.gzand files over 5 MB) and a content hash intosw.jsafter every build.
10. Checklist for a new MkDocs site¶
- Copy
mkdocs.ymland change onlysite_name,site_description,repo_name,repo_urlandnav. - Keep the
theme,palette,featuresandmarkdown_extensionsblocks unchanged. - Copy
docs/assets/extra.css(andexplorer.cssif interactive pages are needed). - Copy
overrides/main.html,overrides/partials/header.html(Home button),hooks/pwa.py,docs/assets/pwa.js,docs/sw.jsanddocs/manifest.webmanifest; update the names in the manifest and theapple-mobile-web-app-title. - Copy
docs/assets/icons/or generate a new icon from section 9.1 (same size, corner radius, glyph scale and colours). - Copy
requirements.txtand.github/workflows/site.ymlif the site is built the same way. - Write pages with the layout in 6.3 and the admonition meanings in 6.2.
- Check light and dark mode, a 360 px wide phone, and print preview.
Open points¶
None. Design decisions DS-001 to DS-005 were decided 2026-10-16 and DS-006 to DS-011 on 2026-10-18; all are closed.