diff --git a/.gitignore b/.gitignore
index ce93c33..17b974d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,3 @@ users.toml
*.snap.new
repomix-output.xml
tmpdata/
-server/vocab/raw/
diff --git a/server/scripts/build-anatomy.sh b/server/scripts/build-anatomy.sh
deleted file mode 100755
index 9a085dc..0000000
--- a/server/scripts/build-anatomy.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-#
-# Build vocab/anatomy.txt from scratch:
-# 1. Crawl de.wikipedia.org Kategorie:Anatomie → raw/anatomy-wiki.txt
-# 2. Filter against hunspell-de → vocab/anatomy.txt
-#
-# Idempotent: safe to re-run. Commit vocab/anatomy.txt after a successful
-# build so the server uses a deterministic artefact, not a live crawl.
-#
-# Usage: (from anywhere) bash path/to/build-anatomy.sh
-
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-VOCAB_DIR="$(cd "$SCRIPT_DIR/../vocab" && pwd)"
-RAW_DIR="$VOCAB_DIR/raw"
-
-mkdir -p "$RAW_DIR"
-
-RAW_FILE="$RAW_DIR/anatomy-wiki.txt"
-OUT_FILE="$VOCAB_DIR/anatomy.txt"
-
-echo "[1/2] Fetching Wikipedia-de Kategorie:Anatomie..."
-"$SCRIPT_DIR/fetch-wiki-anatomy.sh" > "$RAW_FILE"
-echo " raw titles: $(wc -l < "$RAW_FILE")"
-
-echo "[2/2] Filtering against hunspell-de..."
-"$SCRIPT_DIR/filter-hunspell-de.sh" "$RAW_FILE" "$OUT_FILE"
-echo " kept unknown: $(wc -l < "$OUT_FILE")"
-
-echo "Done. Updated: $OUT_FILE"
diff --git a/server/scripts/fetch-wiki-anatomy.sh b/server/scripts/fetch-wiki-anatomy.sh
deleted file mode 100755
index e5ed4b8..0000000
--- a/server/scripts/fetch-wiki-anatomy.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/env bash
-#
-# Crawl the German Wikipedia "Kategorie:Anatomie" (recursively into
-# subcategories) and print each page title on stdout, one per line,
-# sorted and deduplicated. Progress info goes to stderr.
-#
-# Dependencies: curl, jq.
-# Rate limit: ~10 requests/sec (sleep 0.1 between requests).
-# Depth limit: MAX_DEPTH — prevents infinite recursion via cross-links.
-#
-# Usage: ./fetch-wiki-anatomy.sh > raw/anatomy-wiki.txt
-
-set -euo pipefail
-
-USER_AGENT="doctate-vocab-builder (mould73@gmail.com)"
-API="https://de.wikipedia.org/w/api.php"
-ROOT_CATEGORY="Kategorie:Anatomie"
-MAX_DEPTH=4
-
-for tool in curl jq; do
- if ! command -v "$tool" >/dev/null 2>&1; then
- echo "Error: $tool is required but not installed." >&2
- exit 1
- fi
-done
-
-PAGES=$(mktemp)
-SEEN=$(mktemp)
-trap 'rm -f "$PAGES" "$SEEN"' EXIT
-
-# Fetch all pages under one category, recursing into subcategories.
-# Args: category_title depth
-fetch_category() {
- local cat="$1"
- local depth="$2"
-
- if [[ $depth -gt $MAX_DEPTH ]]; then
- return
- fi
- if grep -qFx "$cat" "$SEEN"; then
- return
- fi
- echo "$cat" >> "$SEEN"
-
- echo "[depth=$depth] $cat" >&2
-
- local cmcontinue=""
- while true; do
- local response
- if [[ -n "$cmcontinue" ]]; then
- response=$(curl -sS -A "$USER_AGENT" -G "$API" \
- --data-urlencode "action=query" \
- --data-urlencode "list=categorymembers" \
- --data-urlencode "cmtitle=$cat" \
- --data-urlencode "cmlimit=500" \
- --data-urlencode "cmtype=page|subcat" \
- --data-urlencode "format=json" \
- --data-urlencode "cmcontinue=$cmcontinue")
- else
- response=$(curl -sS -A "$USER_AGENT" -G "$API" \
- --data-urlencode "action=query" \
- --data-urlencode "list=categorymembers" \
- --data-urlencode "cmtitle=$cat" \
- --data-urlencode "cmlimit=500" \
- --data-urlencode "cmtype=page|subcat" \
- --data-urlencode "format=json")
- fi
-
- # Collect page titles (ns=0 is "Main" namespace, i.e. articles).
- echo "$response" | jq -r '.query.categorymembers[] | select(.ns == 0) | .title' >> "$PAGES"
-
- # Recurse into subcategories (ns=14).
- local subcats
- subcats=$(echo "$response" | jq -r '.query.categorymembers[] | select(.ns == 14) | .title')
- while IFS= read -r subcat; do
- [[ -z "$subcat" ]] && continue
- fetch_category "$subcat" $((depth + 1))
- done <<< "$subcats"
-
- cmcontinue=$(echo "$response" | jq -r '.continue.cmcontinue // empty')
- if [[ -z "$cmcontinue" ]]; then
- break
- fi
-
- sleep 0.1
- done
-}
-
-fetch_category "$ROOT_CATEGORY" 0
-
-echo "Collected $(wc -l < "$PAGES") raw titles, emitting sorted-unique..." >&2
-sort -u "$PAGES"
diff --git a/server/scripts/filter-hunspell-de.sh b/server/scripts/filter-hunspell-de.sh
deleted file mode 100755
index b7e4c9c..0000000
--- a/server/scripts/filter-hunspell-de.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env bash
-#
-# Filter a word list to entries NOT recognised by hunspell-de. Uses
-# `hunspell -l` (list-unknown-words mode) — a single batch invocation,
-# orders of magnitude faster than per-word lookups.
-#
-# Multi-word input lines are split into words by hunspell; only the
-# individual unknown words are kept. That matches our gazetteer's
-# token-level matching model (see gazetteer/mod.rs).
-#
-# Dependencies: hunspell + German dictionary. Package names vary:
-# Arch/CachyOS: pacman -S hunspell hunspell-de
-# Debian/Ubuntu: apt install hunspell hunspell-de-de
-# Fedora: dnf install hunspell hunspell-de
-#
-# Usage: ./filter-hunspell-de.sh