---
name: felhom-ui-design
description: The Felhom design system v2 — use for ANY work on controller dashboard templates/CSS, hub web UI, the felhom.eu website HTML/CSS, customer-facing copy, or status badges/colors. Triggers - editing any *.html/*.css in felhom-controller, felhom.eu hub templates or website; adding a page, badge, button, icon, or color; writing Hungarian customer copy or operator alert text. Contains the token palette, the hard rules (2px/no-shadow/no-emoji/BOM), and which mechanical gate script must run after each surface.
---

# Felhom design system v2

One visual language across three surfaces: `felhom.eu/website/` (public), the hub UI
(`felhom.eu/hub/internal/web/templates/`), the controller UI
(`felhom-controller/controller/internal/web/templates/`). Deep rationale:
`felhom.eu/documentation/_design-review.md`. Canonical patterns per repo: each `REUSE.md` §2.

## Token palette (verified identical in all three `:root` blocks — reconfirm in the target CSS before use)

```css
--bg-0: #0A1220;  --bg-1: #0F1B2E;  --bg-2: #16263F;          /* navy backgrounds, darkest first */
--line: #22344F;  --line-soft: #1A2A42;                        /* hairline borders */
--text-1: #EDF2F9; --text-2: #94A6BF; --text-3: #5E7392;       /* text hierarchy */
--blue: #0083D8;  --blue-bright: #2EA8F5; --blue-dim: rgba(0,131,216,.13);
--warn: #E0A93E;  --warn-dim: rgba(224,169,62,.12);
--crit: #E5534B;  --crit-dim: rgba(229,83,75,.12);
--radius: 2px;
--font-ui: 'Plus Jakarta Sans', ...;  --font-data: 'JetBrains Mono', ...;
```

Files: `website/assets/site.css`, `hub/internal/web/templates/style.css`,
`controller/internal/web/templates/style.css`. Always tokens — never raw hexes, never inline styles.

## Hard rules

- **Exception-color principle:** healthy/nominal = blue/neutral. Amber (`--warn`) and red (`--crit`)
  appear ONLY on deviation. A stopped-but-intentional state is NEUTRAL, not red.
- **Shape:** `--radius` (2px) everywhere; **no box-shadows**; hairline `--line`/`--line-soft` borders;
  website sections are boxless (rules + spacing, not cards).
- **Two-tone H1:** last word wrapped in `<span>` (renders `--blue-bright`). H1 only — never H2+.
- **Icons:** monochrome sprite (`icons.svg`, `<use href="...#name">`) / Lucide-style. **No emoji
  anywhere** — enforced by gates; never hunt emoji with grep (proven to false-negative multibyte on
  the Windows workstation, and grep was never the sanctioned check regardless — Python gates only).
- **Fonts:** vendored woff2 (latin-ext for Hungarian) — **no CDN fonts** (gate-enforced on the website).
- **Language:** Hungarian for everything customer-facing (controller UI, customer emails); English for
  operator surfaces (hub UI, operator alerts). Hungarian text lives in maps like `severityLabels` /
  `customerMessages` (`hub/internal/notify/templates.go`) — add entries when adding event types.
- **Encoding:** `website/*.html` is UTF-8 **with BOM** (preserve it); Go source + hub/controller
  templates are plain UTF-8, no BOM.
- **Cache-bust:** website `site.css` / `icons.svg` references carry `?v=N` — bump N when the asset changes.

## Status vocabularies (class SUFFIXES, defined in the surface's style.css)

- Hub `statusColor`: `nominal / warn / crit / neutral` (server.go funcMap). Severity badges:
  `severity-{critical,error,warning,info,ok}`.
- Controller `stateColor`: `run / progress / warn / neutral / off` (funcmap.go). `stateLabel` copy is
  frozen byte-identical (unit-tested) — don't reword casually.
- New template funcs go ONLY into the surface's funcMap (hub `server.go` / controller `funcmap.go`).

## Gates — run after every change to the matching surface

| Surface | Gate | When |
|---|---|---|
| website/*.html + site.css | `python scripts/site_gates.py` (in felhom.eu) | after ANY website change; add new pages to its `PAGES` list in the same commit |
| controller templates | `python controller/scripts/template_id_gate.py` + `python controller/scripts/emoji_gate.py` (in felhom-controller) | after ANY controller template change |
| hub templates | render tests: `go test ./internal/web/` (render_test.go, funcmap_test.go) | after template/funcmap changes |

## Canonical patterns to copy (don't reinvent)

- Website page skeleton (nav/footer byte-identical across pages, only `class="active"` differs):
  `website/index.html`.
- Hub badge/count chain: `hub/internal/web/templates/dashboard.html` events cell.
- Controller deploy progress-poll panel (3-step, 3s poll): `controller/internal/web/templates/deploy.html`.
- Controller wizard flow (two-step confirm, flash messages via `?flash=`):
  `controller/internal/web/storage_handlers.go` + its templates.
- Nested sidebar sub-links: controller `.nav-links-nested` pattern (base template).
