diff --git a/CLAUDE.md b/CLAUDE.md
index fe12f0b..5fb82f1 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -52,7 +52,7 @@ A self-hosted OpenAI-compatible LLM proxy: one static Go binary, per-user API ke
## Documentation
-`docs/` is organised by reader intent: `getting-started.md` (tutorial), `install/` (deploy), `guides/` (operate), `reference/` (look up), `concepts/` (understand). Task pages are imperative and step-numbered with expected output; rationale is one sentence plus a link, and lives in `concepts/architecture.md`. The writing rules are in CONTRIBUTING.md. A new page needs an entry in `mkdocs.yml`'s nav and in the `docs/README.md` router. `mkdocs build --strict` fails on broken internal links and runs in CI on any PR touching `docs/`.
+`docs/` is organised by reader intent: `getting-started.md` (tutorial), `install/` (deploy), `guides/` (operate), `reference/` (look up), `concepts/` (understand). Task pages are imperative and step-numbered with expected output; rationale is one sentence plus a link, and lives in `concepts/architecture.md`. The writing rules are in CONTRIBUTING.md. A new page needs an entry in `mkdocs.yml`'s nav and in the `docs/README.md` router. `mkdocs build --strict` fails on broken internal links and runs in CI on any PR touching `docs/`. The site's look is the Greyhaven design system, vendored into `docs/assets/stylesheets/greyhaven.css` from the design system's tokens; re-vendor rather than hand-tune colors, and keep `mkdocs.yml`'s palette on `custom` or the theme's own colors override the stylesheet.
## Deployment files
diff --git a/docs/assets/fonts/Aspekta-400.woff2 b/docs/assets/fonts/Aspekta-400.woff2
new file mode 100644
index 0000000..764b50c
Binary files /dev/null and b/docs/assets/fonts/Aspekta-400.woff2 differ
diff --git a/docs/assets/fonts/Aspekta-500.woff2 b/docs/assets/fonts/Aspekta-500.woff2
new file mode 100644
index 0000000..ba95918
Binary files /dev/null and b/docs/assets/fonts/Aspekta-500.woff2 differ
diff --git a/docs/assets/fonts/Aspekta-600.woff2 b/docs/assets/fonts/Aspekta-600.woff2
new file mode 100644
index 0000000..ea5728e
Binary files /dev/null and b/docs/assets/fonts/Aspekta-600.woff2 differ
diff --git a/docs/assets/fonts/Aspekta-700.woff2 b/docs/assets/fonts/Aspekta-700.woff2
new file mode 100644
index 0000000..b9342d8
Binary files /dev/null and b/docs/assets/fonts/Aspekta-700.woff2 differ
diff --git a/docs/assets/fonts/source-serif-4-italic.woff2 b/docs/assets/fonts/source-serif-4-italic.woff2
new file mode 100644
index 0000000..e99ceb8
Binary files /dev/null and b/docs/assets/fonts/source-serif-4-italic.woff2 differ
diff --git a/docs/assets/fonts/source-serif-4-roman.woff2 b/docs/assets/fonts/source-serif-4-roman.woff2
new file mode 100644
index 0000000..56a26e1
Binary files /dev/null and b/docs/assets/fonts/source-serif-4-roman.woff2 differ
diff --git a/docs/assets/images/favicon.svg b/docs/assets/images/favicon.svg
new file mode 100644
index 0000000..cb5e07e
--- /dev/null
+++ b/docs/assets/images/favicon.svg
@@ -0,0 +1,11 @@
+
diff --git a/docs/assets/images/greyhaven-symbol-white.svg b/docs/assets/images/greyhaven-symbol-white.svg
new file mode 100644
index 0000000..671f72f
--- /dev/null
+++ b/docs/assets/images/greyhaven-symbol-white.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/stylesheets/greyhaven.css b/docs/assets/stylesheets/greyhaven.css
new file mode 100644
index 0000000..06f073a
--- /dev/null
+++ b/docs/assets/stylesheets/greyhaven.css
@@ -0,0 +1,135 @@
+/* Greyhaven design system for mkdocs-material.
+ Colors are vendored from the design system's tokens/color.json;
+ do not hand-tune values here, re-vendor from the design system. */
+
+/* Aspekta: UI labels, nav, buttons (self-hosted, same weights as the web UI). */
+@font-face { font-family: 'Aspekta'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/Aspekta-400.woff2') format('woff2'); }
+@font-face { font-family: 'Aspekta'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/Aspekta-500.woff2') format('woff2'); }
+@font-face { font-family: 'Aspekta'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/Aspekta-600.woff2') format('woff2'); }
+@font-face { font-family: 'Aspekta'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/Aspekta-700.woff2') format('woff2'); }
+
+/* Source Serif 4: headings and body content (variable font, latin subset). */
+@font-face { font-family: 'Source Serif 4'; font-style: normal; font-weight: 200 900; font-display: swap; src: url('../fonts/source-serif-4-roman.woff2') format('woff2'); }
+@font-face { font-family: 'Source Serif 4'; font-style: italic; font-weight: 200 900; font-display: swap; src: url('../fonts/source-serif-4-italic.woff2') format('woff2'); }
+
+:root {
+ --md-text-font: 'Aspekta';
+ /* The design system's mono token is the system mono stack; no font file. */
+ --md-code-font: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas;
+ --gh-serif: 'Source Serif 4', 'Source Serif Pro', Georgia, serif;
+}
+
+/* Light: warm off-white surfaces, off-black text, orange accent. */
+[data-md-color-scheme='default'] {
+ --md-default-bg-color: #F9F9F7; /* off-white */
+ --md-default-fg-color: #161614; /* off-black */
+ --md-default-fg-color--light: #575753; /* grey.7 */
+ --md-default-fg-color--lighter: #A6A69F; /* grey.4 */
+ --md-default-fg-color--lightest: #F0F0EC; /* grey.1 */
+ --md-primary-fg-color: #161614;
+ --md-primary-fg-color--light: #2F2F2C;
+ --md-primary-fg-color--dark: #161614;
+ --md-primary-bg-color: #F9F9F7;
+ --md-primary-bg-color--light: #DDDDD7;
+ --md-accent-fg-color: #D95E2A;
+ --md-accent-fg-color--transparent: rgba(217, 94, 42, 0.1);
+ --md-typeset-a-color: #D95E2A;
+ --md-code-bg-color: #F0F0EC; /* grey.1 */
+ --md-code-fg-color: #2F2F2C; /* grey.8 */
+ --md-typeset-mark-color: rgba(217, 94, 42, 0.25);
+ --md-typeset-table-color: rgba(22, 22, 20, 0.12);
+ --md-typeset-table-color--light: rgba(22, 22, 20, 0.035);
+ --md-footer-bg-color: #161614;
+ --md-footer-bg-color--dark: #161614;
+ --md-footer-fg-color: #F9F9F7;
+ --md-footer-fg-color--light: #C4C4BD;
+}
+
+/* Dark: off-black background, warm grey surfaces, same orange. */
+[data-md-color-scheme='slate'] {
+ --md-hue: 60; /* fallback for anything still derived from hue */
+ --md-default-bg-color: #161614; /* off-black */
+ --md-default-fg-color: #F9F9F7; /* off-white */
+ --md-default-fg-color--light: #C4C4BD; /* grey.3 */
+ --md-default-fg-color--lighter: #7F7F79; /* grey.5 */
+ --md-default-fg-color--lightest: #2F2F2C; /* grey.8 */
+ --md-primary-fg-color: #161614;
+ --md-primary-fg-color--light: #2F2F2C;
+ --md-primary-fg-color--dark: #161614;
+ --md-primary-bg-color: #F9F9F7;
+ --md-primary-bg-color--light: #DDDDD7;
+ --md-accent-fg-color: #D95E2A;
+ --md-accent-fg-color--transparent: rgba(217, 94, 42, 0.1);
+ --md-typeset-a-color: #D95E2A;
+ --md-code-bg-color: #2F2F2C; /* grey.8 */
+ --md-code-fg-color: #F0F0EC; /* grey.1 */
+ --md-typeset-mark-color: rgba(217, 94, 42, 0.3);
+ --md-typeset-table-color: rgba(249, 249, 247, 0.12);
+ --md-typeset-table-color--light: rgba(249, 249, 247, 0.035);
+ --md-footer-bg-color: #111110;
+ --md-footer-bg-color--dark: #111110;
+}
+
+/* Body content reads in serif; headings serif semibold with tight tracking. */
+.md-typeset {
+ font-family: var(--gh-serif);
+ line-height: 1.625;
+}
+.md-typeset h1,
+.md-typeset h2,
+.md-typeset h3,
+.md-typeset h4 {
+ font-family: var(--gh-serif);
+ font-weight: 600;
+ letter-spacing: -0.025em;
+ color: var(--md-default-fg-color);
+}
+.md-typeset h1 {
+ margin-bottom: 1em;
+}
+.md-typeset h5,
+.md-typeset h6 {
+ font-family: 'Aspekta', ui-sans-serif, system-ui, sans-serif;
+}
+
+/* UI chrome stays in the sans: nav, tabs, search, buttons, labels. */
+.md-header,
+.md-tabs,
+.md-nav,
+.md-search,
+.md-footer,
+.md-typeset .md-button,
+.md-top {
+ font-family: 'Aspekta', ui-sans-serif, system-ui, sans-serif;
+}
+
+/* Tables and admonition titles are UI, not prose. */
+.md-typeset table:not([class]) {
+ font-family: 'Aspekta', ui-sans-serif, system-ui, sans-serif;
+}
+.md-typeset .admonition-title,
+.md-typeset summary {
+ font-family: 'Aspekta', ui-sans-serif, system-ui, sans-serif;
+}
+.md-typeset .admonition,
+.md-typeset details {
+ font-size: 0.72rem;
+}
+
+/* Corner radius per the radii tokens. */
+.md-typeset pre > code {
+ border-radius: 0.375rem;
+}
+.md-typeset .admonition,
+.md-typeset details {
+ border-radius: 0.375rem;
+}
+
+/* Header: off-black bar, off-white text, like the app header. */
+.md-header {
+ background-color: #161614;
+ color: #F9F9F7;
+}
+.md-header__title {
+ font-weight: 600;
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index 9070e85..e4767c7 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -12,24 +12,28 @@ docs_dir: docs
theme:
name: material
+ logo: assets/images/greyhaven-symbol-white.svg
+ favicon: assets/images/favicon.svg
features:
- navigation.sections
- navigation.top
- navigation.instant
- content.code.copy
- search.suggest
+ # Colors come from extra_css (the Greyhaven tokens); "custom" stops the
+ # theme from emitting its own color rules that would override them.
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
- primary: black
- accent: indigo
+ primary: custom
+ accent: custom
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
- primary: black
- accent: indigo
+ primary: custom
+ accent: custom
toggle:
icon: material/brightness-4
name: Switch to light mode
@@ -82,6 +86,9 @@ markdown_extensions:
- pymdownx.highlight
- pymdownx.inlinehilite
+extra_css:
+ - assets/stylesheets/greyhaven.css
+
extra:
social:
- icon: fontawesome/brands/github