diff --git a/ALPINE_GLOBAL_FIX_PART1.md b/ALPINE_GLOBAL_FIX_PART1.md
deleted file mode 100644
index fee9d01..0000000
--- a/ALPINE_GLOBAL_FIX_PART1.md
+++ /dev/null
@@ -1,387 +0,0 @@
-# Alpine.js `Alpine.global()` → `Alpine.store()` Migration Guide - Part 1
-
-## 🔴 Critical Issue Identified
-
-**Problem**: Your codebase uses `Alpine.global()` which **DOES NOT EXIST** in Alpine.js v3.15.8. This is causing the error:
-
-```
-Uncaught TypeError: p.global is not a function
-```
-
-## 📋 Root Cause Analysis
-
-1. **Invalid API Usage**: `Alpine.global()` is not a valid Alpine.js v3 method
-2. **26 Occurrences**: Found across 26 TypeScript files
-3. **Breaking Impact**: Theme switcher and all Alpine namespaces are broken
-
-## ✅ Solution Overview
-
-Replace all `Alpine.global()` calls with `Alpine.store()`, the correct Alpine.js v3 API for registering global utilities.
-
-**Current Pattern (Broken)**:
-```typescript
-Alpine.global("namespace", {
- function1: () => { ... },
- function2: () => { ... }
-});
-```
-
-**New Pattern (Correct)**:
-```typescript
-Alpine.store("namespace", {
- function1: () => { ... },
- function2: () => { ... }
-});
-```
-
-**Template Usage Changes**:
-- **Old**: `@click="namespace.function()"` → `@click="$store.namespace.function()"`
-
----
-
-## 📁 Files Requiring Changes (26 TypeScript files)
-
-### Step 1: Update TypeScript Files
-
-For each file, replace `Alpine.global()` with `Alpine.store()`:
-
-| File | Line | Namespace | Action |
-|------|------|-----------|--------|
-| `admin.ts` | 399 | `admin` | Replace `Alpine.global` with `Alpine.store` |
-| `api.ts` | 102 | `api` | Replace `Alpine.global` with `Alpine.store` |
-| `api-explorer-docs.ts` | 135 | `apiExplorerDoc` | Replace `Alpine.global` with `Alpine.store` |
-| `bookshelf.ts` | 199 | `bookshelf` | Replace `Alpine.global` with `Alpine.store` |
-| `collection-rules.ts` | 411 | `collectionRules` | Replace `Alpine.global` with `Alpine.store` |
-| `collections.ts` | 917 | `collections` | Replace `Alpine.global` with `Alpine.store` |
-| `conflicts.ts` | 219 | `conflicts` | Replace `Alpine.global` with `Alpine.store` |
-| `device-management.ts` | 559 | `devices` | Replace `Alpine.global` with `Alpine.store` |
-| `docs.ts` | 96, 103 | `docs` | Replace `Alpine.global` with `Alpine.store` (2 occurrences) |
-| `header.ts` | 35 | `header` | Replace `Alpine.global` with `Alpine.store` |
-| `index.ts` | 46 | `index` | Replace `Alpine.global` with `Alpine.store` |
-| `library.ts` | 683 | `library` | Replace `Alpine.global` with `Alpine.store` |
-| `linking.ts` | 204 | `linking` | Replace `Alpine.global` with `Alpine.store` |
-| `login.ts` | 25 | `login` | Replace `Alpine.global` with `Alpine.store` |
-| `password_validation.ts` | 192 | `validation` | Replace `Alpine.global` with `Alpine.store` |
-| `profile.ts` | 44 | `profile` | Replace `Alpine.global` with `Alpine.store` |
-| `profile-modal.ts` | 29 | `profileModal` | Replace `Alpine.global` with `Alpine.store` |
-| `queue.ts` | 167 | `queue` | Replace `Alpine.global` with `Alpine.store` |
-| `register.ts` | 14 | `register` | Replace `Alpine.global` with `Alpine.store` |
-| `search.ts` | 310 | `search` | Replace `Alpine.global` with `Alpine.store` |
-| `themeDropdown.ts` | 24 | `themeDropdown` | Replace `Alpine.global` with `Alpine.store` |
-| `toast.ts` | 229 | `showToast` | Replace `Alpine.global` with `Alpine.store` |
-| `toast-error.ts` | 33 | `toastError` | Replace `Alpine.global` with `Alpine.store` |
-| `unlinked_books.ts` | 430 | `unlinkedBooks` | Replace `Alpine.global` with `Alpine.store` |
-| `woodPaneling.ts` | 85 | `woodPaneling` | Replace `Alpine.global` with `Alpine.store` |
-
-### Step 2: Update Template Files
-
-For each `.templ` file that uses Alpine namespaces, update the syntax:
-
-**Old Syntax**:
-```html
-
-
-
-```
-
-**New Syntax**:
-```html
-
-
-
-```
-
-**Templates Requiring Updates** (to be identified by searching for namespace usage):
-- All templates using `@click="admin."`
-- All templates using `@click="api."`
-- All templates using `@click="header."`
-- All templates using `@click="showToast."`
-- All templates using any other namespace from the list above
-
----
-
-## 🔧 Detailed Step-by-Step Instructions
-
-### Phase 1: Update TypeScript Source Files
-
-#### Step 1.1: Backup Current State
-```bash
-cd /home/nymusicman/Code/bookhoard
-git add -A
-git commit -m "Backup before Alpine.global() → Alpine.store() migration"
-```
-
-#### Step 1.2: Find All `Alpine.global` Occurrences
-```bash
-cd /home/nymusicman/Code/bookhoard/web/src
-grep -rn "Alpine\.global" . | tee alpine-global-occurrences.txt
-```
-
-Expected output: 26 occurrences across 26 files
-
-#### Step 1.3: Replace All `Alpine.global` with `Alpine.store`
-
-**Option A: Manual Replacement (Recommended for Understanding)**
-For each file in the table above:
-1. Open the file
-2. Find the `Alpine.global()` call
-3. Replace `Alpine.global` with `Alpine.store`
-4. Save the file
-
-**Example** (`web/src/toast.ts:229`):
-```typescript
-// BEFORE (Line 229):
-Alpine.global("showToast", {
- error: (message: string, duration?: number) =>
- showToast(message, "error", duration),
- success: (message: string, duration?: number) =>
- showToast(message, "success", duration),
- info: (message: string, duration?: number) =>
- showToast(message, "info", duration),
-});
-
-// AFTER (Line 229):
-Alpine.store("showToast", {
- error: (message: string, duration?: number) =>
- showToast(message, "error", duration),
- success: (message: string, duration?: number) =>
- showToast(message, "success", duration),
- info: (message: string, duration?: number) =>
- showToast(message, "info", duration),
-});
-```
-
-**Option B: Automated Replacement (Faster)**
-```bash
-cd /home/nymusicman/Code/bookhoard/web/src
-find . -name "*.ts" -type f -exec sed -i 's/Alpine\.global(/Alpine.store(/g' {} \;
-```
-
-⚠️ **Warning**: Automated replacement will change all 26 occurrences at once. Verify with grep first:
-```bash
-grep -rn "Alpine\.global" . # Should return nothing after replacement
-grep -rn "Alpine\.store" . # Should show all 26 occurrences
-```
-
-#### Step 1.4: Verify Changes
-```bash
-cd /home/nymusicman/Code/bookhoard/web/src
-grep -c "Alpine\.store" *.ts | grep -v ":0"
-```
-
-Expected: Each of the 26 files should show `1` occurrence (except `docs.ts` which should show `2`)
-
-#### Step 1.5: Rebuild TypeScript
-```bash
-cd /home/nymusicman/Code/bookhoard/web
-npm run build:ts
-```
-
-Expected output:
-```
-> bookhoard@1.0.0 build:ts
-> cp node_modules/htmx.org/dist/htmx.min.js web/static/htmx.min.js && esbuild web/src/main.ts --bundle --outfile=web/static/main.js --sourcemap --target=es2020 --minify
-
- web/static/main.js 167.9kb
- web/static/main.js.map 538.7kb
-⚡ Done in 18ms
-```
-
----
-
-### Phase 2: Update Template Files
-
-#### Step 2.1: Find All Namespace Usage in Templates
-```bash
-cd /home/nymusicman/Code/bookhoard/templates
-grep -rn '@click="' .
-```
-
-This will show all click handlers that use namespaces. Look for patterns like:
-- `@click="admin.deleteConfirm"`
-- `@click="api.getUrl"`
-- `@click="header.changeThemeTo"`
-- `@click="showToast.error"`
-- etc.
-
-#### Step 2.2: Create Mapping Document
-
-Create a text file with the old → new namespace mappings:
-
-```
-admin.function() → $store.admin.function()
-api.function() → $store.api.function()
-apiExplorerDoc.function() → $store.apiExplorerDoc.function()
-bookshelf.function() → $store.bookshelf.function()
-collectionRules.function() → $store.collectionRules.function()
-collections.function() → $store.collections.function()
-conflicts.function() → $store.conflicts.function()
-devices.function() → $store.devices.function()
-docs.function() → $store.docs.function()
-header.function() → $store.header.function()
-index.function() → $store.index.function()
-library.function() → $store.library.function()
-linking.function() → $store.linking.function()
-login.function() → $store.login.function()
-validation.function() → $store.validation.function()
-profile.function() → $store.profile.function()
-profileModal.function() → $store.profileModal.function()
-queue.function() → $store.queue.function()
-register.function() → $store.register.function()
-search.function() → $store.search.function()
-themeDropdown.function() → $store.themeDropdown.function()
-showToast.function() → $store.showToast.function()
-toastError.function() → $store.toastError.function()
-unlinkedBooks.function() → $store.unlinkedBooks.function()
-woodPaneling.function() → $store.woodPaneling.function()
-```
-
-#### Step 2.3: Update Templates (Iterative Approach)
-
-**For each namespace found in templates:**
-
-1. **Search for all usages**:
- ```bash
- cd /home/nymusicman/Code/bookhoard/templates
- grep -rn 'namespace\.' . | grep "@click"
- ```
- Replace `namespace` with the actual namespace name (e.g., `admin`, `header`, etc.)
-
-2. **Replace in each file** manually or using find/replace:
- - Find: `@click="namespace.functionName"`
- - Replace: `@click="$store.namespace.functionName"`
-
-**Example for `header.templ`:**
-
-**Before**:
-```templ
-@click="header.changeThemeTo('wood-light')"
-@click="header.logout()"
-```
-
-**After**:
-```templ
-@click="$store.header.changeThemeTo('wood-light')"
-@click="$store.header.logout()"
-```
-
-#### Step 2.4: Critical Template Priority
-
-Update templates in this order (most critical first):
-
-1. **`header.templ`** - Theme switcher (currently broken)
-2. **`index.templ`** - Main page
-3. **`library.templ`** - Core functionality
-4. **`collections.templ`** - Collection management
-5. **`bookshelf.templ`** - Book display
-6. **`api_explorer.templ`** - API testing
-7. **`admin.templ`** - Admin panel
-8. **`profile.templ`** - User profile
-9. **`login.templ`** - Authentication
-10. **`register.templ`** - Registration
-11. **All other templates** with namespace usage
-
----
-
-### Phase 3: Test the Migration
-
-#### Step 3.1: Rebuild Container
-```bash
-cd /home/nymusicman/Code/bookhoard
-docker-compose build
-```
-
-#### Step 3.2: Restart Container
-```bash
-docker-compose down
-docker-compose up -d
-```
-
-#### Step 3.3: Verify Bundle
-```bash
-podman exec bookhoard grep -c "\.store(" /root/web/static/main.js
-```
-
-Expected: Should show all `Alpine.store()` calls (not `Alpine.global()`)
-
-#### Step 3.4: Test Theme Switcher (Critical)
-1. Open `http://localhost:8765` in browser
-2. Hard refresh: `Ctrl+Shift+R`
-3. Open browser console (F12)
-4. Click theme dropdown
-5. Select a theme
-6. **Expected**: Theme changes without error
-7. **Expected Console**:
- ```javascript
- Alpine.store('showToast') // Should return object, not undefined
- Alpine.store('header') // Should return object, not undefined
- ```
-
-#### Step 3.5: Verify No Errors
-Check browser console for:
-- ✅ No `p.global is not a function` errors
-- ✅ No `Uncaught TypeError` messages
-- ✅ Alpine version shows: `3.15.8`
-- ✅ Stores are accessible via `$store`
-
----
-
-## 📊 Testing Checklist
-
-After completing the migration, verify:
-
-- [ ] No `Alpine.global` in any `.ts` file
-- [ ] All 26 `Alpine.store` registrations present
-- [ ] Bundle size approximately 168KB
-- [ ] Browser console shows no errors
-- [ ] Theme switcher works correctly
-- [ ] All dropdown menus open/close properly
-- [ ] Toast notifications display correctly
-- [ ] All forms submit without errors
-- [ ] All click handlers work as expected
-- [ ] Alpine directives (`x-show`, `@click`, etc.) work correctly
-
----
-
-## 🐛 Troubleshooting
-
-### Error: "Cannot read property 'function' of undefined"
-**Cause**: Template still using old syntax `namespace.function()`
-**Fix**: Change to `$store.namespace.function()`
-
-### Error: "Alpine.store is not a function"
-**Cause**: TypeScript build didn't complete or using cached main.js
-**Fix**: Run `npm run build:ts` and rebuild container
-
-### Error: "p.global is not a function" (still)
-**Cause**: Some files still have `Alpine.global()`
-**Fix**: Run `grep -rn "Alpine\.global" web/src` to find remaining occurrences
-
-### Theme switcher still broken
-**Cause**: `header.templ` not updated with new syntax
-**Fix**: Update all `@click="header."` to `@click="$store.header."`
-
----
-
-## 📝 Next Steps (After This Guide)
-
-**Part 2** will cover:
-1. Advanced Alpine store patterns
-2. Reactive state management with stores
-3. Testing strategies for all templates
-4. Performance optimization
-5. Rollback plan if needed
-
----
-
-## 🔗 References
-
-- [Alpine.js Stores Documentation](https://alpinejs.dev/globals/alpine_store.html)
-- [Alpine.js Magic Properties ($store)](https://alpinejs.dev/magics/$store.html)
-- [Migration from Alpine v2 to v3](https://alpinejs.dev/upgrade-guide)
-
----
-
-**Created**: 2026-03-09
-**Alpine.js Version**: 3.15.8
-**Status**: Ready for Implementation
diff --git a/ESBUILD_IMPORT_FIXES.md b/ESBUILD_IMPORT_FIXES.md
deleted file mode 100644
index 3d8658e..0000000
--- a/ESBUILD_IMPORT_FIXES.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Import Fixes Applied to Migration Plan
-
-## Summary
-
-All imports in the ESBUILD_MIGRATION_PLAN.md have been corrected to use individual function imports instead of namespace objects, matching your actual module exports.
-
-## Changes Made
-
-### 1. TypeScript Imports (Phase 1)
-Changed from namespace imports to individual function imports:
-
-**Before** (WRONG):
-```typescript
-import { api } from "./api";
-import { dom } from "./dom";
-import { events } from "./events";
-```
-
-**After** (CORRECT):
-```typescript
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { querySelector, querySelectorAll, getElementById, createElement, ... } from "./dom";
-import { onDelegatedClick, onDelegatedSubmit, onDelegatedChange, ... } from "./events";
-```
-
-### 2. Function Calls in TypeScript
-Changed from namespaced calls to direct function calls:
-
-**Before** (WRONG):
-```typescript
-const response = await api.get("/libraries");
-showToast.success("Loaded!");
-const el = dom.getElementById("id");
-```
-
-**After** (CORRECT):
-```typescript
-const response = await apiGet("/libraries");
-showToast("Loaded!", "success");
-const el = getElementById("id");
-```
-
-### 3. Alpine/Template Calls (Phase 3)
-Keep namespace objects (Alpine creates these):
-
-**CORRECT for Templates**:
-```html
-
-
-```
-
-## Key Distinction
-
-### TypeScript Code
-- **Imports**: Individual functions
-- **Calls**: Direct function calls with arguments
-- **Example**: `import { apiGet }` → `apiGet("/url")`
-
-### Template/Alpine Code
-- **Imports**: None (Alpine handles this)
-- **Calls**: Namespaced via Alpine.global()
-- **Example**: `@click="api.post()"` (Alpine namespace)
-
-## Files Affected
-
-All TypeScript file examples in Phase 1 now show correct imports:
-- ✅ dashboard.ts
-- ✅ analytics.ts
-- ✅ library.ts
-- ✅ collections.ts
-- ✅ bookshelf.ts
-- ✅ api-explorer.ts
-- ✅ All others
-
-## Verification
-
-```bash
-# Verify no namespace imports remain in TypeScript sections
-grep "import { api } from\|import { dom } from\|import { events } from" ESBUILD_MIGRATION_PLAN.md | grep -v "//" | wc -l
-# Result: 0 ✅
-
-# Verify Alpine namespace calls in templates
-grep '@click="api\.' ESBUILD_MIGRATION_PLAN.md | wc -l
-# Result: 3 ✅
-
-# Verify TypeScript individual imports
-grep "import { apiGet" ESBUILD_MIGRATION_PLAN.md | wc -l
-# Result: 9 ✅
-```
-
-## Plan Status
-
-✅ **Ready to execute** - All imports corrected
-✅ **Consistent throughout** - TypeScript vs Alpine distinction clear
-✅ **Matches your actual exports** - No namespace objects exported from modules
-
-You can now start Phase 0 with confidence!
diff --git a/ESBUILD_MIGRATION_PLAN.md b/ESBUILD_MIGRATION_PLAN.md
deleted file mode 100644
index b43b577..0000000
--- a/ESBUILD_MIGRATION_PLAN.md
+++ /dev/null
@@ -1,2040 +0,0 @@
-# ESBuild Migration Plan: TypeScript → ES Modules + Alpine
-
-## Executive Summary
-
-**Goal**: Migrate from individual JavaScript files with window globals to a single bundled `main.js` using ESBuild, ES modules for internal dependencies, and Alpine.js for template interactivity.
-
-**Architecture Principles**:
-1. **ES Modules** for all TypeScript → TypeScript dependencies
-2. **Alpine.js** ONLY as a bridge to templates (onclick → @click)
-3. **SSR-first** - Server renders complete HTML, client-side JS only for interactivity
-4. **No window globals** - everything through proper imports/exports
-5. **Incremental migration** - Each phase is complete and testable
-
-**Target Bundle**: ~100-130KB minified (ES2020 target = Chrome 80+, Firefox 72+, Safari 13.1+, Edge 80+)
-
----
-
-## Current State Analysis
-
-### Problems with Current Architecture
-
-1. **274 window global references** across 21 TypeScript files
-2. **193+ internal TypeScript dependencies** via window (should be ES imports)
-3. **27 template files** with 150+ unique onclick handlers
-4. **Function wrapping** (themeDropdown.ts wraps header.ts functions)
-5. **Individual .js files** loaded in each template (not bundled)
-6. **Mixed patterns** - some files have ES exports, some don't
-
-### Files Requiring Migration
-
-**TypeScript Source Files** (21 files):
-- api.ts, toast.ts, storage.ts, events.ts, dom.ts
-- theme.ts, header.ts, themeDropdown.ts, woodPaneling.ts
-- library.ts, collections.ts, conflicts.ts, queue.ts
-- dashboard.ts, admin.ts, bookshelf.ts, search.ts
-- device-management.ts, analytics.ts, custom-section-builder.ts
-- docs.ts, api-explorer.ts, password_validation.ts
-
-**Template Files** (27 files):
-- dashboard.templ, collections.templ, header.templ, admin.templ
-- docs.templ, bookshelf.templ, devices.templ, queue.templ
-- conflicts.templ, analytics.templ, login.templ, register.templ
-- profile.templ, settings.templ, stats.templ, sync.templ
-- progress.templ, custom_section.templ, collection_rules.templ
-- admin_library.templ, admin_users.templ, api_explorer.templ
-- Plus 8 more modal/component templates
-
----
-
-## Architecture Principles
-
-### 1. ES Module Exports (TypeScript → TypeScript)
-
-Every utility module exports functions for other TypeScript files to import:
-
-```typescript
-// api.ts
-export async function apiGet(url: string): Promise { ... }
-export async function apiPost(url: string, data?: unknown): Promise { ... }
-export async function handleResponse(response: Response): Promise { ... }
-```
-
-```typescript
-// library.ts (consumes api.ts)
-import { apiGet, handleResponse } from "./api";
-
-const response = await apiGet("/libraries");
-const result = await handleResponse(response);
-```
-
-### 2. Alpine.js Bridge (Templates → TypeScript)
-
-Alpine is ONLY used to expose functions to templates, not for internal TS dependencies:
-
-```typescript
-// api.ts (bottom of file)
-import { Alpine } from "./alpine";
-
-Alpine.global("api", {
- get: apiGet,
- post: apiPost,
- put: apiPut,
- delete: apiDelete,
- handleResponse,
- handleVoidResponse,
- handleError,
-});
-```
-
-Template usage:
-```html
-
-
-
-
-
-```
-
-### 3. SSR-First with Progressive Enhancement
-
-- Server renders complete HTML with data
-- Client-side JavaScript only for interactivity (modals, dropdowns, forms)
-- Data loaded via fetch() APIs (like docs search index)
-- No window globals for data injection
-
----
-
-## Migration Strategy: Incremental with No Legacy Code
-
-### Why This Strategy Works
-
-1. **No breaking changes during migration** - App works at every phase
-2. **Can ship anytime** - Partial migrations are functional
-3. **No legacy code** - Each file completely migrated, no half-states
-4. **Easy rollback** - If issues arise, revert individual files/templates
-5. **Testable at each step** - Clear verification criteria
-
----
-
-## Phase 0: Foundation - Add ES Module Exports
-
-**Goal**: Add proper ES exports to all utility modules WITHOUT breaking existing functionality.
-
-**Files**: 8 utility modules
-
-**Duration**: 1-2 hours
-
-### Step 0.1: Add Exports to Utility Modules
-
-For each file, add `export` statements while keeping window exports temporarily:
-
-**web/src/api.ts** (Already has Alpine, just needs ES exports)
-```typescript
-// Add at bottom (after Alpine.global block):
-export { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError };
-```
-
-**web/src/toast.ts** (Already has Alpine, just needs ES exports)
-```typescript
-// Add at bottom (after Alpine.global block):
-export { showToast };
-export type { ToastType };
-```
-
-**web/src/storage.ts** (Already has exports! ✅)
-```typescript
-// Already has:
-// export { getToken, setToken, ... };
-// No changes needed!
-```
-
-**web/src/events.ts**
-```typescript
-// Add at bottom:
-export {
- onDelegatedClick,
- onDelegatedSubmit,
- onDelegatedChange,
- onDelegatedKeydown,
- getDataAttribute,
- setDataAttribute,
- onClick,
- onSubmit,
- onChange,
- onKeydown,
- onInput,
- preventDefault,
- stopPropagation,
-};
-```
-
-**web/src/dom.ts** (Already has exports! ✅)
-```typescript
-// Already has:
-// export { escapeHtml, querySelector, ... };
-// No changes needed!
-```
-
-**web/src/theme.ts**
-```typescript
-// Add at bottom:
-export { applyTheme, loadTheme, changeTheme, loadUserTheme, initializeTheme };
-export type { ThemeType };
-```
-
-**web/src/header.ts**
-```typescript
-// Add at bottom:
-export { toggleThemeDropdown, toggleUserMenu, changeThemeTo, logout };
-```
-
-**web/src/woodPaneling.ts**
-```typescript
-// Add at bottom:
-export { changeWoodPaneling, loadWoodPaneling, updateWoodPanelingIndicators };
-```
-
-### Step 0.2: Verify Build
-
-```bash
-npm run build:ts
-```
-
-**Expected**: Build succeeds, no errors
-
-**Why this works**: We're adding exports without changing anything else. App still uses window globals, so functionality is unchanged.
-
----
-
-## Phase 1: Internal TypeScript Dependencies
-
-**Goal**: Convert all internal `window.XXX` reads to proper ES module imports.
-
-**Files**: 13 consumer files
-
-**Duration**: 4-6 hours
-
-### 1.1: Simple Consumers (Low Risk)
-
-Files with minimal window dependencies:
-
-**web/src/dashboard.ts**
-```typescript
-// Add at top:
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { showToast } from "./toast";
-
-// Replace ALL instances:
-// Line 22: (window as any).showToast.error("msg") → showToast("msg", "error")
-// Line 37: (window as any).showToast.error("msg") → showToast("msg", "error")
-// Line 128: (window as any).api.put → apiPut
-// Line 135: (window as any).showToast.success("msg") → showToast("msg", "success")
-// ... (10 more replacements)
-```
-
-**web/src/search.ts**
-```typescript
-// No changes needed! ✅
-// Already uses localStorage directly, doesn't read from window
-// Only exports selectLibraryAndBook
-```
-
-**web/src/device-management.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-
-// Replace ALL instances:
-// Lines 32-34, 39-42, 78-82, 89-92: const toast = (window as any).showToast → showToast
-```
-
-**web/src/password_validation.ts**
-```typescript
-// No window reads found, only exports initPasswordValidation
-// No changes needed
-```
-
-### 1.2: Moderate Consumers
-
-Files with multiple window dependencies:
-
-**web/src/admin.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-
-// Replace ALL instances (14 occurrences):
-// Lines 12-13, 17-18, 23-24, 40-41, 45-46, 53-54, 119-120, 152-153, 161-162
-// (window as any).showToast.success("msg") → showToast("msg", "success")
-// (window as any).showToast.error → showToast.error
-```
-
-**web/src/queue.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-
-// Replace ALL instances (8 occurrences):
-// Lines 30-32, 37-39, 56-58, 63-65, 82-84, 89-91
-```
-
-**web/src/conflicts.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-
-// Replace ALL instances (6 occurrences):
-// Lines 39-41, 45-48, 53-55, 78-80, 85-87
-```
-
-**web/src/linking.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-
-// Replace ALL instances:
-// (window as any).showToast.success/error("msg") → showToast("msg", "success"/"error")
-```
-
-**web/src/custom-section-builder.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-
-// Replace ALL instances (9 occurrences):
-// Lines 7, 10, 13, 16, 19, 22, 25, 28
-```
-
-**web/src/analytics.ts**
-```typescript
-// Add at top:
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { querySelector, querySelectorAll, getElementById, createElement, showElement, hideElement, toggleElement, addClass, removeClass, toggleClass, hasClass, setTextContent, setInnerHTML, escapeHtml } from "./dom";
-
-// Replace ALL instances:
-// (window as any).api.get → apiGet
-// (window as any).dom.getElementById → getElementById
-```
-
-**web/src/bookshelf.ts**
-```typescript
-// Add at top:
-import { showToast } from "./toast";
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { onDelegatedClick, onDelegatedSubmit, onDelegatedChange, onDelegatedKeydown, getDataAttribute, setDataAttribute, onClick, onSubmit, onChange, onKeydown, onInput, preventDefault, stopPropagation } from "./events";
-
-// Replace ALL instances
-```
-
-**web/src/api-explorer.ts**
-```typescript
-// Add at top:
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { querySelector, querySelectorAll, getElementById, createElement, showElement, hideElement, toggleElement, addClass, removeClass, toggleClass, hasClass, setTextContent, setInnerHTML, escapeHtml } from "./dom";
-
-// Replace ALL instances
-```
-
-### 1.3: Complex Consumers (High Risk)
-
-Files with heavy window dependencies:
-
-**web/src/library.ts** (55 occurrences!)
-```typescript
-// Add at top:
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { showToast } from "./toast";
-import { querySelector, querySelectorAll, getElementById, createElement, showElement, hideElement, toggleElement, addClass, removeClass, toggleClass, hasClass, setTextContent, setInnerHTML, escapeHtml } from "./dom";
-
-// Systematic replacement:
-// (window as any).api.get → apiGet
-// (window as any).api.handleResponse → handleResponse
-// (window as any).api.handleError → handleError
-// (window as any).showToast.success("msg") → showToast("msg", "success")
-// (window as any).dom.createElement → createElement
-```
-
-**web/src/collections.ts** (54 occurrences!)
-```typescript
-// Add at top:
-import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
-import { showToast } from "./toast";
-import { querySelector, querySelectorAll, getElementById, createElement, showElement, hideElement, toggleElement, addClass, removeClass, toggleClass, hasClass, setTextContent, setInnerHTML, escapeHtml } from "./dom";
-
-// Systematic replacement of all 54 instances
-```
-
-### 1.4: Restructure Function Wrapping
-
-This section eliminates the anti-pattern of wrapping functions from other files. Currently, `themeDropdown.ts` overrides `header.ts` functions by reading from window and reassigning them. We'll convert this to proper ES module composition.
-
----
-
-#### 1.4.1: web/src/themeDropdown.ts - Complete Rewrite
-
-**Current Problem (Lines 1-32):**
-```typescript
-// Anti-pattern: Reading and reassigning window globals
-const originalToggleThemeDropdown = (window as any).toggleThemeDropdown;
-(window as any).toggleThemeDropdown = () => {
- originalToggleThemeDropdown();
- updateThemeIndicators();
- (window as any).updateWoodPanelingIndicators?.();
-};
-```
-
-**Step-by-Step Conversion:**
-
-**1. Add ES Module Imports (at top of file, after line 1):**
-```typescript
-import { toggleThemeDropdown } from "./header";
-import { updateWoodPanelingIndicators } from "./woodPaneling";
-```
-
-**2. Remove window read/override (delete lines 1-8):**
-```typescript
-// DELETE THESE LINES:
-// const originalToggleThemeDropdown = (window as any).toggleThemeDropdown;
-// (window as any).toggleThemeDropdown = () => {
-// originalToggleThemeDropdown();
-// updateThemeIndicators();
-// (window as any).updateWoodPanelingIndicators?.();
-// };
-```
-
-**3. Create new composed function (replace deleted code with):**
-```typescript
-// Compose the theme dropdown behavior
-export function initializeThemeDropdown(): void {
- // Call original function from header.ts
- toggleThemeDropdown();
- // Then update theme indicators
- updateThemeIndicators();
- // Update wood paneling indicators
- updateWoodPanelingIndicators();
-}
-```
-
-**4. Keep existing updateThemeIndicators function (no change needed)**
-
-**5. Add Alpine registration at bottom of file (after existing code):**
-```typescript
-import { Alpine } from "./alpine";
-
-// Register composed function with Alpine
-Alpine.global("themeDropdown", {
- initialize: initializeThemeDropdown,
- updateIndicators: updateThemeIndicators,
-});
-
-// Also keep the window export temporarily (remove in Phase 2)
-(window as any).initializeThemeDropdown = initializeThemeDropdown;
-(window as any).updateThemeIndicators = updateThemeIndicators;
-```
-
-**Complete File After Conversion:**
-```typescript
-// web/src/themeDropdown.ts - Rewritten version
-
-import { toggleThemeDropdown } from "./header";
-import { updateWoodPanelingIndicators } from "./woodPaneling";
-import { Alpine } from "./alpine";
-
-// Composed theme dropdown initialization
-export function initializeThemeDropdown(): void {
- // Call original function from header.ts
- toggleThemeDropdown();
- // Then update theme indicators
- updateThemeIndicators();
- // Update wood paneling indicators
- updateWoodPanelingIndicators();
-}
-
-// Update theme indicator elements (existing function, keep as-is)
-export function updateThemeIndicators(): void {
- const themeSelect = document.getElementById("theme-select") as HTMLSelectElement;
- const themeIndicator = document.getElementById("current-theme");
-
- if (themeSelect && themeIndicator) {
- const theme = themeSelect.value as ThemeType;
- themeIndicator.textContent = theme.charAt(0).toUpperCase() + theme.slice(1);
- }
-
- // Update wood paneling button
- const woodPanelingButton = document.getElementById("wood-paneling-button");
- if (woodPanelingButton) {
- const woodPaneling = localStorage.getItem("woodPaneling") || "none";
- woodPanelingButton.textContent = woodPaneling === "none" ? "🪵" : "✓";
- }
-}
-
-// Register with Alpine for template access
-Alpine.global("themeDropdown", {
- initialize: initializeThemeDropdown,
- updateIndicators: updateThemeIndicators,
-});
-
-// Temporary window exports (remove in Phase 2)
-(window as any).initializeThemeDropdown = initializeThemeDropdown;
-(window as any).updateThemeIndicators = updateThemeIndicators;
-```
-
-**Changes Summary:**
-- ✅ Added 3 ES imports (toggleThemeDropdown, updateWoodPanelingIndicators, Alpine)
-- ✅ Deleted 8 lines of window read/override code
-- ✅ Created 1 new composed function (initializeThemeDropdown)
-- ✅ Added Alpine.global() registration (7 lines)
-- ✅ Kept window exports temporarily (2 lines, remove in Phase 2)
-
----
-
-#### 1.4.2: web/src/docs.ts - Window Export Conversion Only
-
-**⚠️ IMPORTANT:** Search functionality changes (Lunr removal, backend API) are handled by a **separate DOCS_SEARCH_IMPLEMENTATION.md task**. This section ONLY covers ESBuild migration changes (window export → Alpine.global()).
-
----
-
-**Current Issue (Line 91):**
-```typescript
-(window as any).toggleSidebar = toggleSidebar;
-```
-
-This is the only window global that needs to be converted for the ESBuild migration.
-
-**Note:** The search functionality (`performDocsSearch`, `initializeDocsSearch`, Lunr imports, etc.) will be addressed separately by the backend API search implementation (see DOCS_SEARCH_IMPLEMENTATION.md).
-
----
-
-**Step-by-Step Conversion:**
-
-**1. Add Alpine Import (after line 1):**
-```typescript
-// BEFORE:
-import * as lunr from "lunr";
-
-// AFTER:
-import * as lunr from "lunr";
-import { Alpine } from "./alpine";
-```
-
-**2. Remove Window Export and Add Alpine Registration (replace line 91):**
-```typescript
-// DELETE line 91:
-// (window as any).toggleSidebar = toggleSidebar;
-
-// REPLACE with:
-// Register with Alpine for template access
-Alpine.global("docs", {
- toggleSidebar,
- initializeSearch: initializeDocsSearch,
-});
-```
-
-**3. Add ES Module Export (at end of file):**
-```typescript
-export { toggleSidebar, initializeDocsSearch };
-```
-
----
-
-**Complete Converted File (ESBuild changes only):**
-```typescript
-// web/src/docs.ts - ESBuild migration changes
-
-import * as lunr from "lunr";
-import { Alpine } from "./alpine";
-
-function toggleSidebar(): void {
- const sidebar = document.getElementById("docs-sidebar");
- const overlay = document.getElementById("docs-overlay");
-
- if (sidebar && overlay) {
- sidebar.classList.toggle("translate-x-0");
- sidebar.classList.toggle("-translate-x-full");
- overlay.classList.toggle("hidden");
- }
-}
-
-function initializeDocsSearch(): void {
- const searchInput = document.getElementById(
- "docs-search",
- ) as HTMLInputElement;
- const searchResults = document.getElementById("docs-search-results");
-
- if (!searchInput || !searchResults) return;
-
- let docsSearchTimeout: ReturnType | null = null;
-
- searchInput.addEventListener("input", () => {
- const query = searchInput.value.trim();
-
- if (docsSearchTimeout) {
- clearTimeout(docsSearchTimeout);
- }
-
- if (query.length < 2) {
- searchResults.innerHTML = "";
- searchResults.classList.add("hidden");
- return;
- }
-
- docsSearchTimeout = setTimeout(() => {
- performDocsSearch(query);
- }, 300);
- });
-}
-
-function performDocsSearch(query: string): void {
- const searchResults = document.getElementById("docs-search-results");
- if (!searchResults) return;
-
- try {
- const idx = lunr.Index.load(lunrIndexData);
- if (!idx) {
- searchResults.innerHTML =
- 'Search index not loaded
';
- searchResults.classList.remove("hidden");
- return;
- }
-
- const results = idx.search(query);
-
- if (results.length === 0) {
- searchResults.innerHTML =
- 'No results found
';
- } else {
- searchResults.innerHTML = results
- .slice(0, 10)
- .map((result: { ref: string }) => {
- const doc = docsData[result.ref];
- if (!doc) return "";
-
- return `
-
- ${doc.title || result.ref}
- ${doc.section ? `${doc.section}
` : ""}
-
- `;
- })
- .join("");
- }
-
- searchResults.classList.remove("hidden");
- } catch (error) {
- console.error("Search error:", error);
- searchResults.innerHTML =
- 'Search error
';
- searchResults.classList.remove("hidden");
- }
-}
-
-document.addEventListener("DOMContentLoaded", () => {
- initializeDocsSearch();
-});
-
-// Register with Alpine for template access
-Alpine.global("docs", {
- toggleSidebar,
- initializeSearch: initializeDocsSearch,
-});
-
-// ES module exports
-export { toggleSidebar, initializeDocsSearch };
-```
-
----
-
-**ESBuild Migration Changes Only:**
-- ✅ Added 1 import (Alpine from "./alpine")
-- ✅ Removed 1 line (window export)
-- ✅ Added 7 lines (Alpine.global() registration)
-- ✅ Added 1 line (ES module export)
-
-**Search Functionality:** Unchanged (handled by separate DOCS_SEARCH_IMPLEMENTATION.md task)
-
-**Note:** The `lunrIndexData` and `docsData` undefined variables will be fixed when the backend API search is implemented (see DOCS_SEARCH_IMPLEMENTATION.md).
-
----
-
-#### 1.4.3: No Other Files Need Function Wrapping Changes
-
-**Confirmed Analysis:**
-- ✅ `header.ts` - Only exports functions, no wrapping
-- ✅ `woodPaneling.ts` - Only exports functions, no wrapping
-- ✅ All other consumer files - Only import/use functions, no wrapping
-
-**Only 2 files affected:** themeDropdown.ts and docs.ts
-
----
-
-#### 1.4.4: Verification Steps
-
-After completing both file conversions:
-
-```bash
-# Build TypeScript
-npm run build:ts
-
-# Run application
-go run .
-
-# Test in browser:
-# 1. Navigate to dashboard
-# 2. Click theme dropdown - should work and update indicators
-# 3. Navigate to /docs
-# 4. Search in docs - should work without console errors
-```
-
-**Expected Results:**
-- ✅ Theme dropdown opens and updates indicators
-- ✅ Wood paneling indicators update correctly
-- ✅ Docs search works (lunr loaded via ES import)
-- ✅ No console errors about missing window.lunr
-- ✅ No console errors about missing window.lunrIndex
-- ✅ No console errors about missing window.docsData
-
-**Common Issues:**
-- If theme dropdown doesn't open: Check if toggleThemeDropdown import is correct
-- If indicators don't update: Check if updateWoodPanelingIndicators is called
-- If docs search fails: Check if lunr is imported correctly (not via window)
-- If data missing: Check if fetch() API is working (not using window globals)
-
-### Step 1.5: Remove Window Exports from Consumer Files (If Present)
-
-After converting all reads to imports, check if consumer files have window exports to remove.
-
-**Note:** Not all files have window exports. Some files (like dashboard.ts) use event delegation and don't export to window.
-
-**Files WITH window exports to remove:**
-
-**web/src/library.ts** (lines 690-704)
-```typescript
-// DELETE these window exports:
-(window as any).deleteLibrary = deleteLibrary;
-(window as any).showLibraryFolders = showLibraryFolders;
-(window as any).addLibraryFolder = addLibraryFolder;
-(window as any).removeLibraryFolder = removeLibraryFolder;
-(window as any).setLibraryVisibility = setLibraryVisibility;
-(window as any).loadUserVisibility = loadUserVisibility;
-(window as any).editLibrary = editLibrary;
-(window as any).handleCreateLibrarySubmit = handleCreateLibrarySubmit;
-(window as any).showFolderBrowser = showFolderBrowser;
-(window as any).navigateFolderBrowser = navigateFolderBrowser;
-(window as any).selectBrowseFolder = selectBrowseFolder;
-(window as any).hideFolderBrowser = hideFolderBrowser;
-(window as any).showDeleteModal = showDeleteModal;
-(window as any).hideDeleteModal = hideDeleteModal;
-(window as any).confirmDeleteLibrary = confirmDeleteLibrary;
-```
-
-**web/src/collections.ts** (multiple locations: lines 204-208, 243, 315-317, 472-476, 912-923)
-```typescript
-// DELETE all window exports (26 functions total)
-// Examples:
-(window as any).loadCollections = loadCollections;
-(window as any).loadCollectionRules = loadCollectionRules;
-// ... etc (all 26 exports)
-```
-
-**web/src/bookshelf.ts** (lines 127-130)
-```typescript
-// DELETE these window exports:
-(window as any).selectLibrary = selectLibrary;
-(window as any).loadBookshelf = loadBookshelf;
-(window as any).selectBook = selectBook;
-(window as any).changePage = changePage;
-```
-
-**web/src/api-explorer.ts** (lines 186-189)
-```typescript
-// DELETE these window exports:
-(window as any).sendApiRequest = sendApiRequest;
-(window as any).loadFromHistory = loadFromHistory;
-(window as any).copyCurl = copyCurl;
-(window as any).formatJson = formatJson;
-```
-
-**Files WITHOUT window exports (already clean):**
-- ✅ **dashboard.ts** - Uses event delegation, no window exports
-- ✅ **admin.ts** - Check if it has exports
-- ✅ **queue.ts** - Check if it has exports
-- ✅ **conflicts.ts** - Check if it has exports
-- ✅ **analytics.ts** - Check if it has exports
-- ✅ **device-management.ts** - Check if it has exports
-- ✅ **linking.ts** - Check if it has exports
-- ✅ **custom-section-builder.ts** - Check if it has exports
-
-**Verification:**
-For each file, search for `(window as any).` at the end of the file. If present, remove those lines.
-
-**Only keep Alpine.global()** for functions that templates call directly.
-
-### Step 1.6: Verify Build and Test
-
-```bash
-npm run build:ts
-go run .
-```
-
-**Verification**:
-- Build succeeds
-- All pages still work (dashboard, library, collections, etc.)
-- Console shows no errors
-- All onclick handlers still work
-
-**Why this works**: Internal dependencies now use imports, but window exports still exist for templates. App is fully functional.
-
----
-
-## Phase 2: Dual Exports - ES Modules + Alpine Bridge
-
-**Goal**: Establish Alpine.js as the bridge to templates while keeping ES exports for TypeScript.
-
-**Files**: All files that export functions used by templates
-
-**Duration**: 2-3 hours
-
-### Step 2.1: Ensure Alpine Initialization File
-
-**web/src/alpine.ts** (Already exists, verify it's correct)
-```typescript
-import Alpine from "alpinejs";
-
-// Extend Window interface
-declare global {
- interface Window {
- Alpine: typeof Alpine;
- }
-}
-
-// Initialize Alpine
-window.Alpine = Alpine;
-Alpine.start();
-
-// Re-export for other modules
-export { Alpine };
-```
-
-### Step 2.2: Register Template Functions with Alpine
-
-For each file that templates call, register functions with Alpine:
-
-**web/src/api.ts** (Already done ✅)
-```typescript
-Alpine.global("api", {
- get: apiGet,
- post: apiPost,
- // ... etc
-});
-```
-
-**web/src/toast.ts** (Already done ✅)
-```typescript
-Alpine.global("showToast", {
- error: (message: string, duration?: number) => showToast(message, "error", duration),
- success: (message: string, duration?: number) => showToast(message, "success", duration),
- info: (message: string, duration?: number) => showToast(message, "info", duration),
-});
-```
-
-**web/src/header.ts**
-```typescript
-Alpine.global("header", {
- logout,
- toggleThemeDropdown,
- toggleUserMenu,
- changeThemeTo: (theme: string) => {
- changeThemeTo(theme);
- updateThemeIndicators(); // Call themeDropdown function
- },
-});
-```
-
-**web/src/library.ts**
-```typescript
-Alpine.global("library", {
- deleteLibrary,
- showLibraryFolders,
- addLibraryFolder,
- removeLibraryFolder,
-});
-```
-
-**web/src/collections.ts**
-```typescript
-Alpine.global("collections", {
- loadCollections,
- createRule,
- deleteRule,
- testRule,
- navigateToCollection,
- selectColor,
- closeCollectionModal,
- initColorSelection,
- selectIcon,
- filterIcons,
- showAllIcons,
- populateIconGrid,
- initIconSelection,
- initCollectionDetail,
- showAddBooksModal,
- hideAddBooksModal,
- searchBooksForCollections,
- toggleBookSelection,
- addbooksToAdd,
- removeBook,
- toggleBookForRemoval,
- updateSelectedCount,
- removebooksToAdd,
- filterCollectionBooks,
- backToCollections,
-});
-```
-
-**web/src/admin.ts**
-```typescript
-Alpine.global("admin", {
- triggerLibraryScan,
- triggerQuickScan,
- loadSystemStats,
- scanAllLibraries,
- loadWatchStatus,
- hideScanProgress,
- stopScanStatusPolling,
-});
-```
-
-**web/src/queue.ts**
-```typescript
-Alpine.global("queue", {
- refreshQueue,
- processPendingItems,
- clearFailedItems,
- clearAllItems,
- retryQueueItem,
- deleteQueueItem,
-});
-```
-
-**web/src/conflicts.ts**
-```typescript
-Alpine.global("conflicts", {
- refreshConflicts,
- resolveConflict,
- bulkResolve,
- bulkDismiss,
- dismissAllResolved,
- showResolveModal,
- hideResolveModal,
- handleResolveSubmit,
-});
-```
-
-**web/src/docs.ts**
-```typescript
-Alpine.global("docs", {
- toggleSidebar,
- initializeSearch: initializeDocsSearch,
-});
-```
-
-**web/src/search.ts**
-```typescript
-Alpine.global("search", {
- selectLibraryAndBook,
-});
-```
-
-**web/src/device-management.ts**
-```typescript
-Alpine.global("devices", {
- copyToClipboard,
- regenerateDeviceToken,
-});
-```
-
-**web/src/password_validation.ts**
-```typescript
-Alpine.global("validation", {
- initPasswordValidation,
-});
-```
-
-### Step 2.3: Remove Old Window Exports
-
-After Alpine registration, REMOVE the old window export lines:
-
-**Before**:
-```typescript
-(window as any).api = { ... };
-Alpine.global("api", { ... });
-```
-
-**After**:
-```typescript
-Alpine.global("api", { ... });
-```
-
-Systematically search and remove these patterns from all files.
-
-### Step 2.4: Verify Build
-
-```bash
-npm run build:ts
-go run .
-```
-
-**Verification**:
-- Build succeeds
-- All pages still work
-- Alpine is loaded (check browser DevTools: `window.Alpine` should be defined)
-- Console shows no errors
-
-**Why this works**: Functions now registered with Alpine instead of window, but templates still use onclick="func()" so they still work.
-
----
-
-## Phase 3: Template Migration (Incremental)
-
-**Goal**: Migrate templates one-by-one from onclick handlers to Alpine directives.
-
-**Strategy**: One template at a time, test each, can ship after each migration.
-
-**Duration**: 1-2 hours per template (27 templates = 27-54 hours total)
-
-### Template Migration Pattern
-
-For each template file:
-
-#### Step A: Remove Individual Script Tags
-
-**Before**:
-```templ
-
-
-
-
-
-
-```
-
-**After**:
-```templ
-
-
-```
-
-**Note**: Keep htmx.min.js separate (loaded before main.js)
-
-#### Step B: Convert onclick to @click
-
-**Before**:
-```templ
-
-
-
-
-```
-
-**After**:
-```templ
-
-
-
-
-```
-
-#### Step C: Add Alpine State for UI Components
-
-For modals, dropdowns, and any UI with show/hide state:
-
-**Before**:
-```templ
-
-
- ...modal content...
-
-
-```
-
-**After**:
-```templ
-
-
-
- ...modal content...
-
-
-
-```
-
-
-**Important**: Alpine uses namespace objects (`api.post`, `showToast.success`),
-**while TypeScript code uses individual functions** (`apiPost`, `showToast`).
-**This is correct** - see Phase 2 for how Alpine creates these namespace objects.
-
-#### Step D: Update Namespace Calls
-
-**Before**:
-```templ
-
-
-```
-
-**After**:
-```templ
-
-
-```
-
-### Template Order (Low Risk to High Risk)
-
-#### Batch 1: Simple Pages (No complex state)
-1. **login.templ** - Only has showToast, api
-2. **register.templ** - Only has showToast, api, validation
-3. **profile.templ** - Only has showToast, api
-4. **settings.templ** - Only has showToast, api
-
-#### Batch 2: Pages with Simple State
-5. **stats.templ** - Only has showToast, api, events
-6. **sync.templ** - Only has showToast, api
-7. **progress.templ** - Only has showToast, api, events
-8. **custom_section.templ** - Has modal, but simple
-
-#### Batch 3: Pages with Moderate State
-9. **collection_rules.templ** - Has showToast, api, events, some state
-10. **queue.templ** - Has queue namespace, multiple modals
-11. **conflicts.templ** - Has conflicts namespace, modal
-12. **admin.templ** - Has admin namespace, modal
-13. **admin_library.templ** - Has library namespace, multiple modals
-14. **admin_users.templ** - Has header functions, simple
-
-#### Batch 4: Complex Pages
-15. **dashboard.templ** - Has theme dropdown, wood paneling, collections
-16. **bookshelf.templ** - Has search, book viewing, shelf mappings
-17. **devices.templ** - Has devices namespace, multiple modals
-18. **analytics.templ** - Keep Chart.js on CDN, has analytics namespace
-19. **api_explorer.templ** - Has explorer namespace
-
-#### Batch 5: Most Complex (Shared Components)
-20. **collections.templ** - Has collections namespace, multiple modals, color/icon pickers
-21. **docs.templ** - Has sidebar toggle, search, inline JS to migrate
-22. **header.templ** - Used in 17 templates! Theme dropdown, user menu
-
-#### Batch 6: Modal/Component Templates
-23. **collection_modal.templ** - Shared component
-24. **restore_system_collection_modal.templ** - Shared component
-25. **profile_modal.templ** - Shared component
-26. **profile_form.templ** - Shared component
-27. **toast.templ** - Shared component (if using template for toast)
-
-### Special Cases
-
-#### docs.templ - Migrate Inline JavaScript
-
-**Current** (lines 124-515): Large inline script block
-
-**New Approach**: Move to docs.ts
-
-```typescript
-// web/src/docs.ts
-export function initializeDocsPage() {
- // Move toggleSection, toggleSidebar functions here
- // Move search initialization here
- // Keep using fetch for data loading (SSR-compatible)
-}
-
-Alpine.global("docs", {
- initializePage: initializeDocsPage,
- toggleSection,
- toggleSidebar,
-});
-```
-
-```templ
-
-
-```
-
-#### header.templ - Most Critical (Used in 17 Places)
-
-This template is included in 17 other templates. Test thoroughly:
-
-```templ
-
-
-
-
- ...11 more themes...
-
-
-
-
-