diff --git a/.gitea/workflows/docs.yml b/.gitea/workflows/docs.yml
new file mode 100644
index 0000000..cbaf3e8
--- /dev/null
+++ b/.gitea/workflows/docs.yml
@@ -0,0 +1,45 @@
+name: docs
+
+# docs/ as a site at portal.uhhm.no: built with mdBook and put to
+# git-pages on every push to main that touches it (the uhhm pages
+# pattern, uhhm/infrastructure PAGES.md). The changelog rides along as
+# the book's last page. Authorized by the _git-pages-forge-allowlist
+# TXT record for portal.uhhm.no plus a token the forge confirms may
+# push to this repo (the GITEA_TOKEN secret).
+
+on:
+ push:
+ branches: [main]
+ paths: ["docs/**", "book.toml", "CHANGELOG.md", ".gitea/workflows/docs.yml"]
+ workflow_dispatch:
+
+env:
+ MDBOOK_VERSION: v0.5.4
+
+jobs:
+ deploy:
+ runs-on: bare
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: build the book
+ run: |
+ set -eu
+ tool=/var/local/cargo-target/mdbook-$MDBOOK_VERSION
+ if [ ! -x "$tool/mdbook" ]; then
+ mkdir -p "$tool"
+ curl -sSfL "https://github.com/rust-lang/mdBook/releases/download/$MDBOOK_VERSION/mdbook-$MDBOOK_VERSION-x86_64-unknown-linux-gnu.tar.gz" | tar -xz -C "$tool"
+ fi
+ cp CHANGELOG.md docs/changelog.md
+ "$tool/mdbook" build
+ test -f target/book/index.html
+ test -f target/book/memberships.html
+
+ - name: deploy to portal.uhhm.no
+ run: |
+ tar -czf site.tar.gz -C target/book .
+ curl --fail -sS -X PUT "https://portal.uhhm.no/" \
+ -H "Content-Type: application/x-tar+gzip" \
+ -H "Forge-Authorization: token ${{ secrets.GITEA_TOKEN }}" \
+ --data-binary @site.tar.gz \
+ -w "deployed: %{http_code}\n"
diff --git a/.gitignore b/.gitignore
index d58c33b..00837a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/target
.claude/
+docs/changelog.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad4f751..00b1368 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -351,7 +351,7 @@ content repos pin the tag they run (see the end of this file).
- README: what the engine provides
- Feature icons: masked span painted by currentColor, not
- Responsible note: one line, same hue and size as the hero description
-- Responsible note as : meta information, dimmer than the description
+- Responsible note as ``: meta information, dimmer than the description
- Responsible note back to the footer, above the question nav
- Bound inputs: a field that loads its value from a sibling-parameterized resource
- add some more width to our alternatives
diff --git a/book.toml b/book.toml
new file mode 100644
index 0000000..8c56b41
--- /dev/null
+++ b/book.toml
@@ -0,0 +1,23 @@
+# The docs as a site: portal.uhhm.no, built by .gitea/workflows/docs.yml
+# from docs/ with mdBook and put to git-pages (see uhhm/infrastructure
+# PAGES.md). `mdbook serve` here previews it.
+[book]
+title = "portal"
+description = "A Git repo of YAML becomes a running site: pages, desks, cases, people."
+authors = ["uhhm"]
+language = "en"
+src = "docs"
+
+[build]
+build-dir = "target/book"
+create-missing = false
+
+[output.html]
+default-theme = "light"
+preferred-dark-theme = "navy"
+git-repository-url = "https://project.uhhm.no/uhhm/portal"
+site-url = "/"
+no-section-label = true
+
+[output.html.search]
+limit-results = 20
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
new file mode 100644
index 0000000..9f92544
--- /dev/null
+++ b/docs/SUMMARY.md
@@ -0,0 +1,21 @@
+# Summary
+
+[portal](README.md)
+
+# Using it
+
+- [Getting started](getting-started.md)
+- [Content reference](content-reference.md)
+- [State machines](state-machines.md)
+- [Access](access.md)
+- [Memberships](memberships.md)
+- [Operations](operations.md)
+
+# How it is made
+
+- [Architecture](architecture.md)
+- [Filesystem routes](design/filesystem-routes.md)
+
+---
+
+[Changelog](changelog.md)
diff --git a/docs/operations.md b/docs/operations.md
index dd7b815..6131a12 100644
--- a/docs/operations.md
+++ b/docs/operations.md
@@ -129,6 +129,14 @@ then `GARAGE_S3_ENDPOINT`, `GARAGE_ACCESS_KEY`, `GARAGE_SECRET_KEY` and
`GARAGE_UPLOADS_BUCKET` in that instance's env. Unset, an upload field
fails closed rather than appearing to work and storing nowhere.
+## The docs site
+
+These pages are [portal.uhhm.no](https://portal.uhhm.no): `docs/` built
+with mdBook (`book.toml`, `docs/SUMMARY.md`) by `.gitea/workflows/docs.yml`
+on every push to main that touches them, and put to git-pages the way
+every static site on uhhm.no is (uhhm/infrastructure `PAGES.md`). The
+changelog is the book's last page. `mdbook serve` previews it locally.
+
## Who deploys what
Both hosts deploy from CI now, and a rollout is the same commit either