diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml
index 11bd2a25..63eab857 100644
--- a/.github/workflows/deploy-gh-pages.yml
+++ b/.github/workflows/deploy-gh-pages.yml
@@ -33,7 +33,7 @@ jobs:
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
- source: ./docs
+ source: ./docs/site
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
diff --git a/.gitignore b/.gitignore
index cf6577b7..c4960956 100644
--- a/.gitignore
+++ b/.gitignore
@@ -398,4 +398,12 @@ FodyWeavers.xsd
*.sln.iml
# Claude Code
-.claude/
\ No newline at end of file
+.claude/
+# Jekyll / GitHub Pages local build
+_site/
+.jekyll-cache/
+.jekyll-metadata
+.sass-cache/
+vendor/
+.bundle/
+docs/site/Gemfile.lock
diff --git a/Hyperbee.Expressions.slnx b/Hyperbee.Expressions.slnx
index 4adcef6c..1015c270 100644
--- a/Hyperbee.Expressions.slnx
+++ b/Hyperbee.Expressions.slnx
@@ -5,7 +5,7 @@
-
+
diff --git a/docs/.todo.md b/docs/.todo.md
deleted file mode 100644
index da778b2d..00000000
--- a/docs/.todo.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Things TODO
-
-## AsyncEnumerable
- - Add support for `IAsyncEnumerable`
-
-## State machine fields
- - Look into shared Exceptions objects
- - Add shared awaiters based on common types
-
-
\ No newline at end of file
diff --git a/docs/site/Gemfile b/docs/site/Gemfile
new file mode 100644
index 00000000..6380d59a
--- /dev/null
+++ b/docs/site/Gemfile
@@ -0,0 +1,13 @@
+source "https://rubygems.org"
+
+gem "jekyll", "~> 4.3"
+gem "just-the-docs"
+
+group :jekyll_plugins do
+ gem "jekyll-remote-theme"
+ gem "jekyll-include-cache"
+ gem "jekyll-seo-tag"
+ gem "jekyll-relative-links"
+end
+
+gem "webrick", "~> 1.8"
diff --git a/docs/_config.yml b/docs/site/_config.yml
similarity index 84%
rename from docs/_config.yml
rename to docs/site/_config.yml
index 1fae88e7..f4ffd8ea 100644
--- a/docs/_config.yml
+++ b/docs/site/_config.yml
@@ -1,5 +1,5 @@
title: Hyperbee Expressions
-description: Documentation for Hyperbee Expressions — async, yield, loop, and compiler extensions for .NET expression trees.
+description: Documentation for Hyperbee Expressions -- async, yield, loop, and compiler extensions for .NET expression trees.
remote_theme: pmarsceill/just-the-docs
baseurl: "/hyperbee.expressions/"
url: "https://stillpoint-software.github.io"
diff --git a/docs/_includes/nav_footer_custom.html b/docs/site/_includes/nav_footer_custom.html
similarity index 100%
rename from docs/_includes/nav_footer_custom.html
rename to docs/site/_includes/nav_footer_custom.html
diff --git a/docs/compiler/api.md b/docs/site/compiler/api.md
similarity index 99%
rename from docs/compiler/api.md
rename to docs/site/compiler/api.md
index 74880f51..17171302 100644
--- a/docs/compiler/api.md
+++ b/docs/site/compiler/api.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: API Reference
parent: Compiler
diff --git a/docs/compiler/compiler.md b/docs/site/compiler/compiler.md
similarity index 99%
rename from docs/compiler/compiler.md
rename to docs/site/compiler/compiler.md
index 17753d22..3d857a88 100644
--- a/docs/compiler/compiler.md
+++ b/docs/site/compiler/compiler.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Compiler
has_children: true
diff --git a/docs/compiler/diagnostics.md b/docs/site/compiler/diagnostics.md
similarity index 99%
rename from docs/compiler/diagnostics.md
rename to docs/site/compiler/diagnostics.md
index 1b8eae3b..22c471ce 100644
--- a/docs/compiler/diagnostics.md
+++ b/docs/site/compiler/diagnostics.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Diagnostics
parent: Compiler
diff --git a/docs/compiler/overview.md b/docs/site/compiler/overview.md
similarity index 99%
rename from docs/compiler/overview.md
rename to docs/site/compiler/overview.md
index 922b0c65..1ade8f91 100644
--- a/docs/compiler/overview.md
+++ b/docs/site/compiler/overview.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Overview
parent: Compiler
diff --git a/docs/compiler/performance.md b/docs/site/compiler/performance.md
similarity index 99%
rename from docs/compiler/performance.md
rename to docs/site/compiler/performance.md
index 9369c671..105c15e1 100644
--- a/docs/compiler/performance.md
+++ b/docs/site/compiler/performance.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Performance
parent: Compiler
diff --git a/docs/configuration/configuration.md b/docs/site/configuration/configuration.md
similarity index 98%
rename from docs/configuration/configuration.md
rename to docs/site/configuration/configuration.md
index 9fce4bac..5bc0d9f4 100644
--- a/docs/configuration/configuration.md
+++ b/docs/site/configuration/configuration.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Configuration
has_children: true
diff --git a/docs/configuration/dependency-injection.md b/docs/site/configuration/dependency-injection.md
similarity index 99%
rename from docs/configuration/dependency-injection.md
rename to docs/site/configuration/dependency-injection.md
index 2e2d317c..ec70a57b 100644
--- a/docs/configuration/dependency-injection.md
+++ b/docs/site/configuration/dependency-injection.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Dependency Injection
parent: Configuration
diff --git a/docs/configuration/module-providers.md b/docs/site/configuration/module-providers.md
similarity index 99%
rename from docs/configuration/module-providers.md
rename to docs/site/configuration/module-providers.md
index 7daf499e..aed9ff39 100644
--- a/docs/configuration/module-providers.md
+++ b/docs/site/configuration/module-providers.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Module Providers
parent: Configuration
diff --git a/docs/configuration/runtime-options.md b/docs/site/configuration/runtime-options.md
similarity index 99%
rename from docs/configuration/runtime-options.md
rename to docs/site/configuration/runtime-options.md
index 434ee339..99891a24 100644
--- a/docs/configuration/runtime-options.md
+++ b/docs/site/configuration/runtime-options.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Runtime Options
parent: Configuration
diff --git a/docs/docs.projitems b/docs/site/docs.projitems
similarity index 100%
rename from docs/docs.projitems
rename to docs/site/docs.projitems
diff --git a/docs/docs.shproj b/docs/site/docs.shproj
similarity index 100%
rename from docs/docs.shproj
rename to docs/site/docs.shproj
diff --git a/docs/expressions/async-block.md b/docs/site/expressions/async-block.md
similarity index 99%
rename from docs/expressions/async-block.md
rename to docs/site/expressions/async-block.md
index 8d15fb3e..d7241e64 100644
--- a/docs/expressions/async-block.md
+++ b/docs/site/expressions/async-block.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Async Block
parent: Expressions
diff --git a/docs/expressions/await.md b/docs/site/expressions/await.md
similarity index 99%
rename from docs/expressions/await.md
rename to docs/site/expressions/await.md
index 2c5552c1..dc18f84f 100644
--- a/docs/expressions/await.md
+++ b/docs/site/expressions/await.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Await
parent: Expressions
diff --git a/docs/expressions/configuration-value.md b/docs/site/expressions/configuration-value.md
similarity index 99%
rename from docs/expressions/configuration-value.md
rename to docs/site/expressions/configuration-value.md
index d310bec3..b362eb51 100644
--- a/docs/expressions/configuration-value.md
+++ b/docs/site/expressions/configuration-value.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Configuration Value
parent: Expressions
diff --git a/docs/expressions/debug.md b/docs/site/expressions/debug.md
similarity index 99%
rename from docs/expressions/debug.md
rename to docs/site/expressions/debug.md
index 1aff65bb..2e21569e 100644
--- a/docs/expressions/debug.md
+++ b/docs/site/expressions/debug.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Debug
parent: Expressions
diff --git a/docs/expressions/enumerable-block.md b/docs/site/expressions/enumerable-block.md
similarity index 99%
rename from docs/expressions/enumerable-block.md
rename to docs/site/expressions/enumerable-block.md
index 341b92e5..55a16661 100644
--- a/docs/expressions/enumerable-block.md
+++ b/docs/site/expressions/enumerable-block.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Enumerable Block
parent: Expressions
diff --git a/docs/expressions/expressions.md b/docs/site/expressions/expressions.md
similarity index 100%
rename from docs/expressions/expressions.md
rename to docs/site/expressions/expressions.md
diff --git a/docs/expressions/for.md b/docs/site/expressions/for.md
similarity index 99%
rename from docs/expressions/for.md
rename to docs/site/expressions/for.md
index 04da82f3..7f4bd7ab 100644
--- a/docs/expressions/for.md
+++ b/docs/site/expressions/for.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: For
parent: Expressions
diff --git a/docs/expressions/foreach.md b/docs/site/expressions/foreach.md
similarity index 100%
rename from docs/expressions/foreach.md
rename to docs/site/expressions/foreach.md
diff --git a/docs/expressions/inject.md b/docs/site/expressions/inject.md
similarity index 99%
rename from docs/expressions/inject.md
rename to docs/site/expressions/inject.md
index 0177b885..451fe7cf 100644
--- a/docs/expressions/inject.md
+++ b/docs/site/expressions/inject.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Inject
parent: Expressions
diff --git a/docs/expressions/string-format.md b/docs/site/expressions/string-format.md
similarity index 99%
rename from docs/expressions/string-format.md
rename to docs/site/expressions/string-format.md
index 2d17bae7..2cde5ec6 100644
--- a/docs/expressions/string-format.md
+++ b/docs/site/expressions/string-format.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: String Format
parent: Expressions
diff --git a/docs/expressions/using.md b/docs/site/expressions/using.md
similarity index 99%
rename from docs/expressions/using.md
rename to docs/site/expressions/using.md
index 0d6db82c..ab089236 100644
--- a/docs/expressions/using.md
+++ b/docs/site/expressions/using.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Using
parent: Expressions
diff --git a/docs/expressions/while.md b/docs/site/expressions/while.md
similarity index 99%
rename from docs/expressions/while.md
rename to docs/site/expressions/while.md
index c8c65a45..58a35a26 100644
--- a/docs/expressions/while.md
+++ b/docs/site/expressions/while.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: While
parent: Expressions
diff --git a/docs/expressions/yield.md b/docs/site/expressions/yield.md
similarity index 100%
rename from docs/expressions/yield.md
rename to docs/site/expressions/yield.md
diff --git a/docs/index.md b/docs/site/index.md
similarity index 99%
rename from docs/index.md
rename to docs/site/index.md
index 41f6a2d5..48688361 100644
--- a/docs/index.md
+++ b/docs/site/index.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Hyperbee Expressions
nav_order: 1
diff --git a/docs/lab/fetch.md b/docs/site/lab/fetch.md
similarity index 99%
rename from docs/lab/fetch.md
rename to docs/site/lab/fetch.md
index 4c46dce4..13765952 100644
--- a/docs/lab/fetch.md
+++ b/docs/site/lab/fetch.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Fetch
parent: Lab
diff --git a/docs/lab/json.md b/docs/site/lab/json.md
similarity index 99%
rename from docs/lab/json.md
rename to docs/site/lab/json.md
index 7ca2de44..b7c26649 100644
--- a/docs/lab/json.md
+++ b/docs/site/lab/json.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: JSON
parent: Lab
diff --git a/docs/lab/lab.md b/docs/site/lab/lab.md
similarity index 100%
rename from docs/lab/lab.md
rename to docs/site/lab/lab.md
diff --git a/docs/lab/map-reduce.md b/docs/site/lab/map-reduce.md
similarity index 99%
rename from docs/lab/map-reduce.md
rename to docs/site/lab/map-reduce.md
index a1754fa3..20ae0048 100644
--- a/docs/lab/map-reduce.md
+++ b/docs/site/lab/map-reduce.md
@@ -1,4 +1,4 @@
----
+---
layout: default
title: Map / Reduce
parent: Lab
diff --git a/docs/site/local-jekyll.md b/docs/site/local-jekyll.md
new file mode 100644
index 00000000..ade9f4b4
--- /dev/null
+++ b/docs/site/local-jekyll.md
@@ -0,0 +1,427 @@
+# Running Jekyll Docs Locally (Docker)
+
+Reusable recipe for previewing `just-the-docs` / GitHub Pages sites locally
+using a throwaway `ruby:3.3` container. Works for any repo -- BlazorX, Hyperbee,
+anything else that follows the same docs convention.
+
+No Ruby install required. Docker Desktop is the only dependency.
+
+---
+
+## First-time setup (teammate onboarding)
+
+Skip this section if you already have Docker and a bash shell working.
+
+### 1. Install Docker Desktop
+
+**Windows / macOS**: download from https://www.docker.com/products/docker-desktop/
+and run the installer. Defaults are fine. On Windows it prompts to enable
+WSL 2 -- accept.
+
+**Linux**: install Docker Engine per your distro's instructions. You do
+not need Docker Desktop specifically; any `docker` CLI that can pull
+public images works.
+
+**Licensing note**: Docker Desktop is free for personal use, education,
+non-commercial open-source work, and companies with fewer than 250
+employees AND less than $10M in annual revenue. Larger companies need
+paid subscriptions. Check the current terms before using it in
+a commercial setting.
+
+### 2. Start Docker and verify
+
+Launch Docker Desktop (Windows/macOS) and wait for the whale icon in
+the system tray to settle. Then in a terminal:
+
+```bash
+docker --version
+docker run --rm hello-world
+```
+
+The first command prints the Docker version. The second pulls and runs
+a tiny test image -- if it prints "Hello from Docker!", you're set.
+
+### 3. Pick a shell
+
+The `docker run` command below works from any shell, but the
+`MSYS_NO_PATHCONV=1` prefix is a Git Bash specific workaround for a
+path-translation bug on Windows. Your options:
+
+- **Git Bash** (Windows) -- use the commands as written. Get it bundled
+ with Git for Windows at https://git-scm.com/
+- **WSL 2** (Windows) -- drop the `MSYS_NO_PATHCONV=1` prefix; WSL
+ doesn't need it. Paths also change from `C:/...` to `/mnt/c/...`.
+- **PowerShell** (Windows) -- drop the prefix; use backticks instead
+ of backslashes for line continuation.
+- **macOS / Linux terminal** -- drop the prefix; paths are already
+ POSIX.
+
+### 4. Pre-pull the image (optional but recommended)
+
+The first `docker run` in the Quick-start section pulls `ruby:3.3`
+(~900 MB). You can do this explicitly up front so the first actual
+use starts fast:
+
+```bash
+docker pull ruby:3.3
+```
+
+After this, every container we spin up reuses the cached image.
+
+---
+
+## Prerequisites (for a running environment)
+
+1. **Docker running** -- verified via `docker --version` and `docker info`.
+2. A project with a `docs/` folder (or `docs/site/`, or wherever you keep
+ Jekyll sources) containing:
+ - `_config.yml`
+ - `Gemfile`
+ - Your markdown content.
+3. Git Bash, WSL, or another bash-capable shell (the `MSYS_NO_PATHCONV`
+ trick below is specifically for Git Bash on Windows).
+
+---
+
+## Quick-start command
+
+From the project root, pick a port and run:
+
+```bash
+MSYS_NO_PATHCONV=1 docker run --rm --name my-jekyll \
+ -v "C:/path/to/project/docs/site:/srv/jekyll" \
+ -w /srv/jekyll -p 4000:4000 \
+ ruby:3.3 \
+ sh -c "bundle install --quiet && bundle exec jekyll serve --host 0.0.0.0 --force_polling"
+```
+
+Then open `http://localhost:4000//` in your browser, where
+`` is whatever `baseurl` is set to in `_config.yml`
+(for example, `/blazorx/`).
+
+**What each flag does**:
+- `MSYS_NO_PATHCONV=1` -- stops Git Bash from rewriting the Windows path
+ into a POSIX-looking path that Docker then fails to mount.
+- `--rm` -- container is deleted when it stops. No cleanup needed.
+- `--name my-jekyll` -- optional, lets you `docker stop my-jekyll` later.
+- `-v :/srv/jekyll` -- bind-mounts your docs folder into the
+ container's working directory.
+- `-w /srv/jekyll` -- makes that the starting directory.
+- `-p 4000:4000` -- publishes port 4000 on your host. Change the left side
+ if 4000 is taken.
+- `ruby:3.3` -- the Debian/glibc Ruby 3.3 image. Avoids the Alpine/musl
+ sass-embedded broken-pipe bug.
+- `sh -c "bundle install --quiet && bundle exec jekyll serve ..."` --
+ installs gems, then runs Jekyll in watch mode.
+- `--host 0.0.0.0` -- needed so the host machine can reach the server
+ through the port mapping.
+- `--force_polling` -- needed on Windows bind mounts for file-change
+ detection to work reliably.
+
+First run downloads `ruby:3.3` (~900 MB). Subsequent runs start in seconds
+because the image is cached locally.
+
+---
+
+## What each repo needs
+
+### `docs//_config.yml`
+
+Minimum viable starting point:
+
+```yaml
+title: My Project
+description: One-line project description
+remote_theme: pmarsceill/just-the-docs
+baseurl: "/myproject/"
+url: "https://example.github.io"
+
+aux_links:
+ "GitHub Repository":
+ - "//github.com/my-org/my-project"
+
+search_enabled: true
+color_scheme: dark
+
+markdown: kramdown
+highlighter: rouge
+permalink: pretty
+
+plugins:
+ - jekyll-remote-theme
+ - jekyll-include-cache
+ - jekyll-seo-tag
+ - jekyll-relative-links
+
+relative_links:
+ enabled: true
+ collections: true
+
+# Optional: Mermaid diagram support (just-the-docs >= 0.5)
+mermaid:
+ version: "10.9.0"
+
+defaults:
+ - scope:
+ path: ""
+ values:
+ layout: "default"
+ # Disable Liquid rendering inside content pages so code fences
+ # containing {{ or }} don't trip the template engine. Adjust the
+ # paths to match your directory layout.
+ - scope:
+ path: "getting-started"
+ values:
+ render_with_liquid: false
+ - scope:
+ path: "guides"
+ values:
+ render_with_liquid: false
+ - scope:
+ path: "reference"
+ values:
+ render_with_liquid: false
+ - scope:
+ path: "index.md"
+ values:
+ render_with_liquid: false
+```
+
+### `docs//Gemfile`
+
+```ruby
+source "https://rubygems.org"
+
+gem "jekyll", "~> 4.3"
+gem "just-the-docs"
+
+group :jekyll_plugins do
+ gem "jekyll-remote-theme"
+ gem "jekyll-include-cache"
+ gem "jekyll-seo-tag"
+ gem "jekyll-relative-links"
+end
+
+gem "webrick", "~> 1.8"
+```
+
+### `.gitignore` entries
+
+Add to the repo's root `.gitignore`:
+
+```
+# Jekyll / GitHub Pages local build
+_site/
+.jekyll-cache/
+.jekyll-metadata
+.sass-cache/
+vendor/
+.bundle/
+docs/site/Gemfile.lock
+```
+
+Adjust `docs/site/Gemfile.lock` to match your docs path.
+
+### GitHub Pages workflow (optional, for publishing)
+
+`.github/workflows/deploy-gh-pages.yml`:
+
+```yaml
+name: Deploy GitHub Pages
+
+on:
+ push:
+ branches: ["main"]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/configure-pages@v5
+ - uses: actions/jekyll-build-pages@v1
+ with:
+ source: ./docs/site
+ destination: ./_site
+ - uses: actions/upload-pages-artifact@v3
+
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - id: deployment
+ uses: actions/deploy-pages@v4
+```
+
+Set `source:` to wherever your docs live (for example `./docs` or `./docs/site`).
+
+---
+
+## Running multiple projects in parallel
+
+Each project gets its own container name and its own host port. The
+`ruby:3.3` image is shared across all of them.
+
+```bash
+# BlazorX on port 4000
+MSYS_NO_PATHCONV=1 docker run --rm --name bzx-jekyll \
+ -v "C:/Development/playground/BlazorX/docs/site:/srv/jekyll" \
+ -w /srv/jekyll -p 4000:4000 ruby:3.3 \
+ sh -c "bundle install --quiet && bundle exec jekyll serve --host 0.0.0.0 --force_polling"
+
+# Hyperbee.Json on port 4001
+MSYS_NO_PATHCONV=1 docker run --rm --name hbjson-jekyll \
+ -v "C:/Development/hyperbee.json/docs:/srv/jekyll" \
+ -w /srv/jekyll -p 4001:4000 ruby:3.3 \
+ sh -c "bundle install --quiet && bundle exec jekyll serve --host 0.0.0.0 --force_polling"
+```
+
+Browse them at `http://localhost:4000//` and
+`http://localhost:4001//` simultaneously.
+
+---
+
+## Reusable helper script
+
+Drop this at a well-known location (for example `C:/Development/tools/jekyll-serve.sh`):
+
+```bash
+#!/usr/bin/env bash
+# Start a Jekyll dev container for any project.
+# Usage: jekyll-serve.sh [docs-dir] [host-port]
+set -eu
+
+DOCS_DIR="${1:-$(pwd)/docs/site}"
+PORT="${2:-4000}"
+
+# Absolute path for Docker bind mount
+DOCS_ABS="$(cd "$DOCS_DIR" && pwd)"
+
+# Pick a reasonable container name from the parent folder
+NAME="jekyll-$(basename "$(dirname "$DOCS_ABS")")-$PORT"
+
+echo "Serving $DOCS_ABS on http://localhost:$PORT/"
+echo "Container: $NAME"
+echo "Stop with: docker stop $NAME"
+
+MSYS_NO_PATHCONV=1 docker run --rm --name "$NAME" \
+ -v "${DOCS_ABS}:/srv/jekyll" \
+ -w /srv/jekyll -p "${PORT}:4000" \
+ ruby:3.3 \
+ sh -c "bundle install --quiet && bundle exec jekyll serve --host 0.0.0.0 --force_polling"
+```
+
+Then from any repo:
+
+```bash
+# Uses ./docs/site, port 4000
+~/dev/tools/jekyll-serve.sh
+
+# Custom path
+~/dev/tools/jekyll-serve.sh ./docs
+
+# Custom path and port
+~/dev/tools/jekyll-serve.sh ./docs 4001
+```
+
+---
+
+## Speeding up repeat starts (optional)
+
+On each cold start the container runs `bundle install` and fetches about
+40 gems. That's ~20 seconds. Cache the bundle directory to reuse across
+runs by adding a volume for `/usr/local/bundle`:
+
+```bash
+MSYS_NO_PATHCONV=1 docker run --rm --name my-jekyll \
+ -v "C:/path/to/docs:/srv/jekyll" \
+ -v "jekyll-bundle-cache:/usr/local/bundle" \
+ -w /srv/jekyll -p 4000:4000 ruby:3.3 \
+ sh -c "bundle install --quiet && bundle exec jekyll serve --host 0.0.0.0 --force_polling"
+```
+
+`jekyll-bundle-cache` is a named Docker volume. It persists across
+containers and projects. Remove with `docker volume rm jekyll-bundle-cache`.
+
+---
+
+## Troubleshooting
+
+### `docker: command not found`
+
+Docker is not installed or not on `PATH`. See the First-time setup
+section above. On Windows, restart your terminal after installing
+Docker Desktop so `PATH` picks up the new entries.
+
+### `Cannot connect to the Docker daemon`
+
+Docker is installed but not running. On Windows/macOS, launch
+Docker Desktop and wait for the whale icon to stop animating. On
+Linux, `sudo systemctl start docker` (or `service docker start`).
+
+### "Could not locate Gemfile"
+
+The bind mount did not land where the container expected. On Git Bash you
+need both the `MSYS_NO_PATHCONV=1` prefix and a Windows-style absolute
+path like `C:/path/...` (forward slashes).
+
+### Port already in use
+
+Another process or container has the host port. Check with
+`docker ps --filter "publish=4000"` or just pick a different port on the
+left side of `-p host:container`.
+
+### Mermaid diagrams don't render
+
+Your `_config.yml` needs a `mermaid:` block with a `version:` key, and
+your markdown must use ``` ```mermaid ``` fenced blocks. The theme
+JavaScript replaces the code block with rendered SVG on page load --
+nothing needs to run server-side.
+
+### SCSS errors ("expected }")
+
+You probably set `render_with_liquid: false` too broadly. Scope it to
+content directories only (see the `defaults` block in `_config.yml`
+above). The theme's SCSS files genuinely need Liquid for
+`{% include %}` directives.
+
+### Links ending in `.md` return 404
+
+Install `jekyll-relative-links` (see `Gemfile` and `_config.yml`
+templates above). Without it, Jekyll does not rewrite `[text](foo.md)`
+links to the final rendered URL.
+
+### File changes not picked up
+
+Windows bind mounts need `--force_polling` on the `jekyll serve` command.
+Without it, Jekyll uses inotify/fsevent which do not fire across the
+Docker VM boundary.
+
+### `_config.yml` edits seem to be ignored
+
+Jekyll does not auto-reload `_config.yml` even with `--force_polling`.
+Stop and restart the container to pick up changes.
+
+---
+
+## Stopping the container
+
+```bash
+docker stop my-jekyll
+```
+
+`--rm` in the run command means the container is removed automatically
+on stop. No manual cleanup.