diff --git a/.gitignore b/.gitignore
index 9d1a5b6..81e74d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -363,3 +363,7 @@ MigrationBackup/
FodyWeavers.xsd
/.idea/.idea.decePubClient/.idea
/.idea/config
+
+# Tailwind standalone + daisyUI downloads (tools/tailwind.sh) and the CSS they generate
+.tools/
+wwwroot/css/app.css
diff --git a/Styles/app.css b/Styles/app.css
new file mode 100644
index 0000000..91725c1
--- /dev/null
+++ b/Styles/app.css
@@ -0,0 +1,11 @@
+/* Entry point compiled by Tailwind CSS standalone (tools/tailwind.sh, TailwindCompile in decePubClient.csproj) into
+ wwwroot/css/app.css. Tailwind scans every file under the project that .gitignore doesn't exclude. */
+@import "tailwindcss" source("../");
+
+@source not "../wwwroot/vendor";
+@source not "../Docs";
+
+@plugin "../.tools/tailwind/daisyui.mjs" {
+ themes: false;
+ logs: false;
+}
diff --git a/decePubClient.csproj b/decePubClient.csproj
index f5151fa..6cb6303 100644
--- a/decePubClient.csproj
+++ b/decePubClient.csproj
@@ -26,6 +26,42 @@
+
+
+ $(MSBuildProjectDirectory)/.tools/tailwind/
+ $(TailwindToolsDir)tailwindcss
+ --minify
+ --optimize
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
True
diff --git a/tools/tailwind.sh b/tools/tailwind.sh
new file mode 100755
index 0000000..e819446
--- /dev/null
+++ b/tools/tailwind.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+# Tailwind CSS standalone + daisyUI, with no Node. MSBuild runs `fetch` (decePubClient.csproj, EnsureTailwindTools)
+# and then compiles Styles/app.css itself; run `watch` beside `dotnet watch` for live CSS work.
+# bash tools/tailwind.sh fetch download and verify the pinned binaries into .tools/tailwind/
+# bash tools/tailwind.sh build one-off build of wwwroot/css/app.css (what MSBuild does in Debug)
+# bash tools/tailwind.sh watch rebuild wwwroot/css/app.css on every change
+# bash tools/tailwind.sh docs fetch daisyUI's llms.txt (component reference, unpinned) into .tools/tailwind/
+set -euo pipefail
+
+TAILWIND_VERSION=4.3.3
+DAISYUI_VERSION=5.7.47
+
+# sha256 of each release asset. Tailwind's are from its release sha256sums.txt; daisyUI publishes none, so these were
+# computed from the v5.7.47 release assets.
+pinned_sha256() {
+ case "$1" in
+ tailwindcss-linux-x64) echo dc61b3ac6b8c9ca874c0cc4c57b2409791a64c5540404ca5f5367360babc313a ;;
+ tailwindcss-linux-x64-musl) echo a04d34ceacc8f52cbe8920ad846cdeb61d3d0021dba32db0d1f77c9d9fad7a6c ;;
+ tailwindcss-linux-arm64) echo 55fd0b241214eff3de1e8ee4f22796662f2d2e7a49bcfca7477cfd0bac398195 ;;
+ tailwindcss-linux-arm64-musl) echo 71ea4be79c9de9827545682df3e040053fb535d37c71ed2cfdedf9385a0868e0 ;;
+ tailwindcss-macos-x64) echo 7922e0953f2110c05976e3bf58f14e643d90427575e766b7d433f5f80cbee7e1 ;;
+ tailwindcss-macos-arm64) echo cdf646702987a743464dff4d9c60fd4480d1c1e73dd819a9a67f1078815dce9d ;;
+ daisyui.mjs) echo 85819d3fe86a852237b439b13f481481aac58e562ac47694cd11c3038e994f2a ;;
+ daisyui-theme.mjs) echo d92d2f488933dab757f046e81ebd4986e51e9423307798dc3545d09a15542c89 ;;
+ *) echo "tailwind.sh: no pinned checksum for $1" >&2; exit 1 ;;
+ esac
+}
+
+ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+TOOLS="$ROOT/.tools/tailwind"
+TAILWIND="$TOOLS/tailwindcss"
+
+tailwind_asset() {
+ local os arch libc=""
+ case "$(uname -s)" in
+ Linux) os=linux ;;
+ Darwin) os=macos ;;
+ *) echo "tailwind.sh: unsupported OS $(uname -s)" >&2; exit 1 ;;
+ esac
+ case "$(uname -m)" in
+ x86_64|amd64) arch=x64 ;;
+ aarch64|arm64) arch=arm64 ;;
+ *) echo "tailwind.sh: unsupported architecture $(uname -m)" >&2; exit 1 ;;
+ esac
+ if [ "$os" = linux ] && ldd --version 2>&1 | grep -qi musl; then libc=-musl; fi
+ echo "tailwindcss-$os-$arch$libc"
+}
+
+sha256_of() {
+ if command -v sha256sum >/dev/null; then sha256sum "$1" | cut -d' ' -f1; else shasum -a 256 "$1" | cut -d' ' -f1; fi
+}
+
+# fetch_one
+fetch_one() {
+ local url="$1" dest="$2" expected="$3"
+ if [ -f "$dest" ] && [ "$(sha256_of "$dest")" = "$expected" ]; then return; fi
+ echo "tailwind.sh: downloading $url"
+ curl -fsSL --retry 3 -o "$dest.part" "$url"
+ local actual
+ actual="$(sha256_of "$dest.part")"
+ if [ "$actual" != "$expected" ]; then
+ rm -f "$dest.part"
+ echo "tailwind.sh: checksum mismatch for $url (expected $expected, got $actual)" >&2
+ exit 1
+ fi
+ mv "$dest.part" "$dest"
+}
+
+fetch() {
+ mkdir -p "$TOOLS"
+ local asset
+ asset="$(tailwind_asset)"
+ fetch_one "https://github.com/tailwindlabs/tailwindcss/releases/download/v$TAILWIND_VERSION/$asset" \
+ "$TAILWIND" "$(pinned_sha256 "$asset")"
+ chmod +x "$TAILWIND"
+ for f in daisyui.mjs daisyui-theme.mjs; do
+ fetch_one "https://github.com/saadeghi/daisyui/releases/download/v$DAISYUI_VERSION/$f" "$TOOLS/$f" "$(pinned_sha256 "$f")"
+ done
+}
+
+cd "$ROOT"
+case "${1:-build}" in
+ fetch) fetch ;;
+ build) fetch; "$TAILWIND" -i Styles/app.css -o wwwroot/css/app.css --optimize ;;
+ watch) fetch; exec "$TAILWIND" -i Styles/app.css -o wwwroot/css/app.css --watch ;;
+ docs) mkdir -p "$TOOLS"; curl -fsSL -o "$TOOLS/llms.txt" https://daisyui.com/llms.txt; echo "$TOOLS/llms.txt" ;;
+ *) echo "usage: tailwind.sh [fetch|build|watch|docs]" >&2; exit 2 ;;
+esac
diff --git a/wwwroot/index.html b/wwwroot/index.html
index 9bdc092..1a227c9 100644
--- a/wwwroot/index.html
+++ b/wwwroot/index.html
@@ -6,7 +6,8 @@
Index
-
+
+