From b9f1a115d2de9ed307215bde390557c37ca88604 Mon Sep 17 00:00:00 2001
From: Wally Hackenslacker
Date: Fri, 1 May 2026 15:58:04 -0400
Subject: [PATCH] Added agentic files.
---
AGENTS.md | 156 +++++
.../plans/2026-05-01-dark-mode-support.md | 642 ++++++++++++++++++
.../specs/2026-05-01-dark-mode-design.md | 223 ++++++
3 files changed, 1021 insertions(+)
create mode 100644 AGENTS.md
create mode 100644 docs/superpowers/plans/2026-05-01-dark-mode-support.md
create mode 100644 docs/superpowers/specs/2026-05-01-dark-mode-design.md
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..7aeba0b
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,156 @@
+# AGENTS.md
+
+Agent guidance for working in this repository (`mainty`).
+
+## Project Snapshot
+
+- Stack: PHP 8+, SQLite, Apache, Tailwind via CDN, Bootstrap Icons via CDN.
+- Architecture: lightweight MVC-style structure (no Composer, no framework).
+- Entry point: `index.php`.
+- Routing: `core/Router.php` maps routes to `Controller@method`.
+- Data layer: PDO SQLite through singleton in `core/Database.php`.
+- Runtime config: constants and debug flags in `config.php`.
+- Deployment option: Docker (`Dockerfile`, `docker-compose.yml`) or traditional Apache/PHP host.
+
+## Repository Layout
+
+- `index.php`: bootstrap, environment checks, route registration, request dispatch.
+- `core/`: base infrastructure (`Controller`, `Router`, `Database`).
+- `controllers/`: request handlers, auth/setup guards, redirects.
+- `models/`: database queries and persistence logic.
+- `views/`: server-rendered PHP templates and inline JS.
+- `data/`: SQLite DB location (`data/mainty.db`), ignored by Git.
+- `README.md`: user-facing setup notes.
+- `DOCKER.md`: Docker workflow and troubleshooting.
+
+## Build, Lint, and Test Commands
+
+This repo currently has no formal package manager scripts (`composer.json`, `package.json`) and no configured PHPUnit/Pest suite.
+
+### Local runtime checks
+
+- Start app with Docker:
+ - `docker-compose up -d`
+- Rebuild and start:
+ - `docker-compose up -d --build`
+- Stop containers:
+ - `docker-compose down`
+- Follow logs:
+ - `docker-compose logs -f`
+- Open app:
+ - `http://localhost:8080`
+
+### Linting (available today)
+
+- Lint a single PHP file:
+ - `php -l path/to/file.php`
+- Lint all PHP files from repo root:
+ - `find . -name "*.php" -print0 | xargs -0 -n1 php -l`
+
+### Tests (current state)
+
+- There is no automated test suite committed in this repository at this time.
+- Use targeted syntax checks plus manual verification in browser for affected flows.
+
+### Single-test guidance
+
+- Since no test framework is configured, there is no native "run one unit test" command yet.
+- Closest equivalent today:
+ - Run syntax check on changed file: `php -l path/to/changed.php`
+ - Validate one user flow manually (for example setup/login/add vehicle).
+- If PHPUnit is introduced later, single-test pattern should be:
+ - `vendor/bin/phpunit tests/Path/To/TestFile.php`
+ - or `vendor/bin/phpunit --filter testMethodName`
+
+## Development Workflow for Agents
+
+- Prefer small, focused edits in the relevant layer (controller/model/view).
+- Preserve existing architecture; avoid introducing frameworks or heavy abstractions.
+- Keep route definitions centralized in `index.php` unless project conventions change.
+- For DB changes, update `Database::initialize()` schema and ensure migration path for existing DBs.
+- Validate impact on setup/auth guards (`requireSetup()`, `requireAuth()`).
+- When touching rendered output, maintain existing Tailwind + Bootstrap Icons approach.
+
+## Code Style and Conventions
+
+The project does not include an enforced formatter. Follow established in-repo patterns.
+
+### PHP formatting
+
+- Use 4-space indentation; no tabs.
+- Opening braces are on the same line for classes, methods, and control structures.
+- Keep method visibility explicit (`public`, `private`, `protected`).
+- Prefer strict return types and parameter types where already used.
+- Add blank lines between logical blocks to keep controllers readable.
+
+### Imports and file organization
+
+- There are no namespaces and no `use` imports currently.
+- Autoloading is manual via `spl_autoload_register` in `index.php`.
+- New class files should be placed in one of:
+ - `core/`
+ - `controllers/`
+ - `models/`
+- Class name must match filename (e.g., `VehicleController` in `controllers/VehicleController.php`).
+
+### Types and data handling
+
+- Follow existing scalar type hints (`string`, `int`, `array`, `bool`, `void`).
+- For IDs from route params, cast to int in controllers before model calls.
+- Treat user input as untrusted; trim and validate before persistence.
+- Use nullable values consistently when optional fields are absent.
+
+### Naming conventions
+
+- Classes: PascalCase (`MaintenanceController`, `QuickTask`).
+- Methods/functions: camelCase (`changePassword`, `getByVehicleId`).
+- Variables/properties: camelCase (`$maintenanceItems`, `$quickTaskModel`).
+- DB columns: snake_case (`license_plate`, `updated_at`).
+- Route paths: kebab/snake mix already exists; follow existing route patterns.
+
+### Database and SQL conventions
+
+- Use prepared statements for variable-bound SQL (existing standard).
+- Keep SQL readable with multiline strings where complex.
+- Return arrays from model queries (`fetchAll()`/`fetch()`) per current style.
+- Keep persistence logic inside models; avoid SQL in controllers/views.
+
+### Error handling and user feedback
+
+- Controllers use session flash messages (`$_SESSION['error']`, `$_SESSION['success']`).
+- Redirect after mutations instead of rendering directly.
+- For JSON endpoints, return structured JSON via `Controller::json()`.
+- Internal failures are currently handled with basic `die()` or fallback messages.
+- Do not leak sensitive data in production; respect `DEBUG` flag in `config.php`.
+
+### Security and output escaping
+
+- Escape user-facing output in views with `htmlspecialchars()`.
+- Keep password handling through `password_hash()` and `password_verify()`.
+- Maintain auth checks on protected routes.
+- Be cautious with direct echo of exception messages.
+
+### Frontend conventions in views
+
+- Server-rendered PHP templates with inline Tailwind classes.
+- Keep interactions lightweight with inline `
+```
+
+Expected output:
+- `` has `dark` class before body render when resolved theme is dark.
+- `data-theme` is set to `dark` or `light`.
+
+- [ ] **Step 3: Implement `head` shared CSS tokens and semantic utility classes**
+
+```php
+
+```
+
+Expected output:
+- Shared classes exist for page/surface/text/border/input mappings.
+- Toggle has fixed top-right placement and z-index 50.
+
+- [ ] **Step 4: Implement `body` output with toggle markup and no-JS fallback**
+
+```php
+
+
+```
+
+- [ ] **Step 5: Implement `body` behavior script with cookie helpers and state sync**
+
+```php
+
+```
+
+Expected output:
+- Click toggles theme immediately, updates icon, `aria-label`, and `title`.
+- Cookie write attempt does not block visual switch if persistence is restricted.
+
+- [ ] **Step 6: Run syntax check for new partial**
+
+Run: `php -l views/partials/theme.php`
+
+Expected: `No syntax errors detected in views/partials/theme.php`.
+
+- [ ] **Step 7: Commit Task 1**
+
+```bash
+git add views/partials/theme.php
+git commit -m "feat: add shared theme partial with cookie-based dark mode"
+```
+
+### Task 2: Integrate theme partial into login and setup views
+
+**Files:**
+- Modify: `views/login.php`
+- Modify: `views/setup.php`
+- Test: `/login`, `/setup`
+
+- [ ] **Step 1: Insert head include in `views/login.php`**
+
+```php
+
+```
+
+Placement: in ``, after Tailwind/bootstrap includes, before ``.
+
+- [ ] **Step 2: Insert body include in `views/login.php`**
+
+```php
+
+```
+
+Placement: before ``.
+
+- [ ] **Step 3: Apply color-only updates in `views/login.php`**
+
+Apply concrete replacements:
+- `` -> ``
+- login card `bg-white` -> `theme-surface`
+- heading `text-gray-800` -> `theme-text`
+- label text `text-gray-700` -> `theme-text`
+- input `border-gray-300` -> add `theme-input theme-border`
+
+Expected outcome: login card, labels, and input fields are readable in both themes without layout shift.
+
+- [ ] **Step 4: Insert head include in `views/setup.php`**
+
+```php
+
+```
+
+Placement: in ``, after Tailwind/bootstrap includes, before ``.
+
+- [ ] **Step 5: Insert body include in `views/setup.php`**
+
+```php
+
+```
+
+Placement: before ``.
+
+- [ ] **Step 6: Apply color-only updates in `views/setup.php`**
+
+Apply concrete replacements:
+- `` -> ``
+- setup card `bg-white` -> `theme-surface`
+- title and labels `text-gray-*` -> `theme-text` / `theme-text-muted`
+- password inputs `border-gray-300` -> add `theme-input theme-border`
+
+Expected outcome: setup page remains visually consistent, with readable text/inputs in both themes.
+
+- [ ] **Step 7: Run syntax checks for auth/setup views**
+
+Run: `php -l views/login.php && php -l views/setup.php`
+
+Expected: both report `No syntax errors detected`.
+
+- [ ] **Step 8: Manual verification on `/login` and `/setup`**
+
+Expected:
+- toggle appears fixed top-right
+- keyboard Tab focuses toggle with visible focus style
+- Enter/Space toggles theme
+- icon and `aria-label`/`title` change each toggle
+- reload preserves preference
+
+- [ ] **Step 9: Commit Task 2**
+
+```bash
+git add views/login.php views/setup.php
+git commit -m "feat: integrate dark mode toggle on auth and setup views"
+```
+
+## Chunk 2: Main Views, Export Exception, and Final Verification
+
+### Task 3: Integrate theme partial into home view
+
+**Files:**
+- Modify: `views/index.php`
+- Test: `/home`
+
+- [ ] **Step 1: Add head include in `views/index.php`**
+
+```php
+
+```
+
+Placement requirement: after Tailwind/bootstrap includes and before ``.
+
+Expected outcome: exactly one head include in required position.
+
+- [ ] **Step 2: Add body include in `views/index.php`**
+
+```php
+
+```
+
+Placement requirement: before local page scripts and before ``.
+
+Expected outcome: exactly one body include in required position.
+
+- [ ] **Step 3: Update page and header surfaces in `views/index.php`**
+
+Concrete updates:
+- body wrapper `bg-gray-100` -> `theme-page`
+- header/card wrappers `bg-white` -> `theme-surface`
+- heading/body text `text-gray-*` -> `theme-text` / `theme-text-muted`
+
+Expected outcome: page shell and header are readable in both themes.
+
+- [ ] **Step 4: Update table surfaces in `views/index.php`**
+
+Concrete updates:
+- table header `` -> use `theme-surface-alt theme-border`
+- table body divider `divide-gray-200` -> `theme-border`
+- table cell text classes `text-gray-500`, `text-gray-600`, `text-gray-900` -> `theme-text`/`theme-text-muted`
+
+Expected outcome: table head/body text and borders remain readable in both themes.
+
+- [ ] **Step 5: Update vehicle cards/list rows in `views/index.php`**
+
+Concrete updates:
+- grid cards `bg-white` -> `theme-surface`
+- list container `bg-white` -> `theme-surface`
+- row hover `hover:bg-gray-50` -> `hover:opacity-95` and apply `theme-surface-alt` on row container where needed
+- small metadata text `text-gray-*` -> `theme-text-muted`
+
+Expected outcome: vehicle cards/list rows remain readable in both themes.
+
+- [ ] **Step 6: Update modal container and input surfaces in `views/index.php`**
+
+Concrete updates:
+- modal panel `bg-white` -> `theme-surface`
+- modal close/cancel gray text -> `theme-text-muted`
+- inputs with `border-gray-300` -> add `theme-input theme-border`
+- optional helper text gray shades -> `theme-text-muted`
+
+Expected outcome: cards, table, and modal inputs remain readable/usable in both themes.
+
+- [ ] **Step 7: Verify and adjust flash message contrast in `views/index.php`**
+
+Concrete updates:
+- keep existing light-mode classes for base state (`bg-red-100 border-red-400 text-red-700`, `bg-green-100 border-green-400 text-green-700`)
+- add dark-only variants (using `dark:` classes or equivalent conditional class strategy) for error/success contrast in dark mode
+- keep existing rounded/padding/layout classes unchanged
+
+Expected outcome: error and success flash messages are legible and visually distinct in both light and dark modes.
+
+- [ ] **Step 8: Run syntax check for `views/index.php`**
+
+Run: `php -l views/index.php`
+
+Expected: `No syntax errors detected in views/index.php`.
+
+- [ ] **Step 9: Manual verification for `/home`**
+
+Expected:
+- theme toggles correctly
+- theme persists after reload
+- cards/tables/modals remain readable in both themes
+
+- [ ] **Step 10: Commit Task 3**
+
+```bash
+git add views/index.php
+git commit -m "feat: integrate dark mode support in home view"
+```
+
+### Task 4: Integrate theme partial into vehicle detail view
+
+**Files:**
+- Modify: `views/vehicle.php`
+- Test: `/vehicles/{id}`
+
+- [ ] **Step 1: Add head include in `views/vehicle.php`**
+
+```php
+
+```
+
+Placement requirement: after Tailwind/bootstrap includes and before ``.
+
+Expected outcome: exactly one head include in required position.
+
+- [ ] **Step 2: Add body include in `views/vehicle.php`**
+
+```php
+
+```
+
+Placement requirement: before page-local scripts and before `
`.
+- Inject shared theme CSS variables and a concise set of utility mappings for common surfaces and text colors.
+- Expose small JS helpers for:
+ - reading cookie,
+ - writing cookie,
+ - resolving effective theme,
+ - updating UI state/icon/labels,
+ - toggling theme on click.
+
+Why:
+
+- Keeps behavior consistent across all views.
+- Avoids duplicating script/CSS/button logic in each template.
+- Reduces maintenance cost for future theme adjustments.
+
+Interface contract:
+
+- The partial is included with an explicit section selector:
+ - `$themeSection = 'head'; include __DIR__ . '/partials/theme.php';`
+ - `$themeSection = 'body'; include __DIR__ . '/partials/theme.php';`
+- `'head'` section outputs only bootstrap script + shared theme styles.
+- `'body'` section outputs only floating toggle markup + behavior wiring script.
+- Any other/missing section outputs nothing (safe no-op).
+
+## 2) View Integration Points
+
+Integrate the partial into each in-scope view.
+
+- Include contract per themed view:
+ - In `` (after Tailwind CDN script/link and before ``): set `$themeSection = 'head'` and include `views/partials/theme.php`.
+ - In `` (before page-local scripts and before ``): set `$themeSection = 'body'` and include `views/partials/theme.php`.
+ - Partial integration must not require any page-specific IDs.
+ - Partial must be self-contained and safe to include on all in-scope views without per-view conditionals.
+
+Each view keeps existing layout and structure; only color semantics are adjusted where required for dark compatibility.
+
+## 3) Export Exception
+
+`views/export.php` remains standalone light styling:
+
+- No theme partial include.
+- No floating toggle.
+- No dark class application.
+
+## Data Flow
+
+## Initial Load
+
+1. Parse cookie `theme`.
+2. If cookie is `dark` or `light`, use it.
+3. Else query `window.matchMedia('(prefers-color-scheme: dark)')`.
+4. Apply result by toggling `document.documentElement.classList` with `dark`.
+5. Render page using applied theme classes/variables.
+
+## User Toggle Interaction
+
+1. User clicks floating toggle.
+2. Determine next theme (`light` -> `dark`, `dark` -> `light`).
+3. Update `dark` class on `` immediately.
+4. Attempt to write cookie `theme=` with long-lived expiration, `path=/`, `SameSite=Lax`.
+5. Update toggle icon/accessible label/title to reflect new mode.
+6. If cookie persistence fails (blocked by browser/privacy settings), keep the switched theme for the current document and do not show an error; next navigation/load falls back to normal resolution flow (system preference if no valid cookie).
+
+## Subsequent Loads
+
+- Cookie value takes precedence over system preference.
+- Users with no valid cookie continue following system theme.
+
+## Theme Styling Strategy
+
+Use a hybrid of CSS variables + targeted Tailwind class updates.
+
+- Keep existing spacing/layout/structure classes.
+- Introduce semantic surface/text variable mappings for repeated patterns.
+- Update key hardcoded light-only color usages in templates where needed:
+ - page backgrounds,
+ - headers/cards/panels,
+ - tables (head/body row hover),
+ - forms and inputs,
+ - modals/dropdowns,
+ - flash messages.
+
+Acceptance scope boundary for theming edits:
+
+- Only update color-related classes/styles needed for readability/contrast in dark mode.
+- Do not change spacing, typography scale, layout structure, or route/form behavior.
+- A view is considered complete when all listed surface types in that view remain readable and interactive in both light and dark modes.
+
+Action colors (primary blue, danger red) remain recognizable but are adjusted for contrast in dark contexts.
+
+## Component Requirements
+
+## Floating Toggle Button
+
+- Position: fixed top-right, always visible in viewport.
+- Layering: `z-index: 50`, intended to remain visible above regular page content and app modals.
+- Visual states:
+ - sun icon when dark mode is active (indicates switch to light),
+ - moon icon when light mode is active (indicates switch to dark).
+- Accessibility:
+ - semantic `
`.
+
+Expected outcome: exactly one body include in required position.
+
+- [ ] **Step 3: Update page shell, vehicle card, and maintenance form in `views/vehicle.php`**
+
+Concrete updates:
+- body/header/card backgrounds `bg-white/bg-gray-*` -> theme classes
+- text grays on headings/body -> `theme-text` / `theme-text-muted`
+- form inputs/borders -> `theme-input theme-border`
+
+Expected outcome: top section and add-maintenance form are readable in both themes.
+
+- [ ] **Step 4: Update dropdown menu surfaces in `views/vehicle.php`**
+
+Concrete updates:
+- suggestions box `bg-white border-gray-300` -> `theme-surface theme-border`
+- export menu panel `bg-white` -> `theme-surface`
+- export menu links `hover:bg-gray-100` -> `hover:opacity-95`
+- export menu link text grays -> `theme-text`
+
+Expected outcome: dropdown menus remain readable and interactive in both themes.
+
+- [ ] **Step 5: Update maintenance history surfaces in `views/vehicle.php`**
+
+Concrete updates:
+- history container `bg-white` -> `theme-surface`
+- item cards `border-gray-200` -> `theme-border`
+- item card hover `hover:border-blue-300` -> `hover:border-blue-500`
+- item metadata text gray shades -> `theme-text-muted`
+
+Expected outcome: maintenance history cards remain readable in both themes.
+
+- [ ] **Step 6: Update modal panel and input surfaces in `views/vehicle.php`**
+
+Concrete updates:
+- edit modal panels `bg-white` -> `theme-surface`
+- modal input `border-gray-300` -> `theme-input theme-border`
+- modal close/cancel text grays -> `theme-text-muted`
+
+Expected outcome: dropdowns, history cards, and modals remain readable and interactive in both themes.
+
+- [ ] **Step 7: Run syntax check for `views/vehicle.php`**
+
+Run: `php -l views/vehicle.php`
+
+Expected: `No syntax errors detected in views/vehicle.php`.
+
+- [ ] **Step 8: Manual verification for `/vehicles/{id}`**
+
+Expected:
+- theme toggles and persists
+- forms/dropdowns/modals remain readable in both themes
+- navigation to/from `/home` keeps cookie-based preference
+
+- [ ] **Step 9: Commit Task 4**
+
+```bash
+git add views/vehicle.php
+git commit -m "feat: integrate dark mode support in vehicle detail view"
+```
+
+### Task 5: Integrate theme partial into settings view
+
+**Files:**
+- Modify: `views/settings.php`
+- Test: `/settings`
+
+- [ ] **Step 1: Add head include in `views/settings.php`**
+
+```php
+
+```
+
+Placement requirement: after Tailwind/bootstrap includes and before ``.
+
+Expected outcome: exactly one head include in required position.
+
+- [ ] **Step 2: Add body include in `views/settings.php`**
+
+```php
+
+```
+
+Placement requirement: before local scripts (if any) and before ``.
+
+Expected outcome: exactly one body include in required position.
+
+- [ ] **Step 3: Update page/header/card surfaces in `views/settings.php`**
+
+Concrete updates:
+- body/header/cards `bg-white/bg-gray-*` -> `theme-page`/`theme-surface`/`theme-surface-alt`
+- gray text classes -> `theme-text` / `theme-text-muted`
+
+Expected outcome: page shell and cards remain readable in both themes.
+
+- [ ] **Step 4: Update list rows and password form surfaces in `views/settings.php`**
+
+Concrete updates:
+- quick-task row hover/background and borders -> theme classes
+- password input borders/backgrounds -> `theme-input theme-border`
+
+Expected outcome: list rows and form fields are readable and distinguishable in both themes.
+
+- [ ] **Step 5: Verify action/footer contrast in `views/settings.php`**
+
+Concrete updates:
+- logout action danger colors may be adjusted if needed for dark-mode contrast while preserving danger semantics
+- powered footer card `bg-white` -> `theme-surface`
+- powered footer title/body grays -> `theme-text` / `theme-text-muted`
+- GitHub icon/link muted grays -> `theme-text-muted` while preserving blue link emphasis
+
+Expected outcome: call-to-action and footer text remain legible in both themes.
+
+- [ ] **Step 6: Run syntax check for `views/settings.php`**
+
+Run: `php -l views/settings.php`
+
+Expected: `No syntax errors detected in views/settings.php`.
+
+- [ ] **Step 7: Manual verification for `/settings`**
+
+Expected:
+- theme toggles and persists
+- cards/list rows/inputs remain readable in both themes
+- navigation to/from `/home` keeps cookie-based preference
+
+- [ ] **Step 8: Commit Task 5**
+
+```bash
+git add views/settings.php
+git commit -m "feat: integrate dark mode support in settings view"
+```
+
+### Task 6: Validate export exception and complete end-to-end checks
+
+**Files:**
+- Verify unchanged: `views/export.php`
+- Verify behavior: `views/partials/theme.php`
+- Verify integrated views: `views/login.php`, `views/setup.php`, `views/index.php`, `views/vehicle.php`, `views/settings.php`
+
+- [ ] **Step 1: Verify `views/export.php` has no theme include/toggle**
+
+Expected:
+- no `$themeSection` include
+- no `#themeToggle` markup
+- no dark-mode bootstrap script and no `html.dark` application path in export template
+
+- [ ] **Step 2: Verify cookie contract in devtools**
+
+Flow:
+- toggle theme on any themed page
+- inspect cookie attributes
+
+Expected:
+- cookie name `theme`
+- value `dark` or `light`
+- `Max-Age=31536000`
+- `Path=/`
+- `SameSite=Lax`
+
+- [ ] **Step 3: Verify accessibility state updates on toggle**
+
+Flow:
+- focus toggle via keyboard
+- activate twice
+
+Expected per click:
+- icon swaps moon/sun
+- `aria-label` and `title` update to next action
+
+- [ ] **Step 4: Verify export is always light**
+
+Flow:
+- set `theme=dark`
+- open `/vehicles/{id}/export/html`
+
+Expected:
+- export remains light styled
+- toggle not present
+- `` does not receive `dark` class on export, even when `theme=dark`
+
+- [ ] **Step 5: Verify toggle stays visible above modals/dropdowns**
+
+Flow:
+- open each page with modal/dropdown support (`/home`, `/vehicles/{id}`)
+- open add/edit modals and export/suggestions dropdowns
+
+Expected:
+- floating toggle remains visible and clickable above overlays
+
+- [ ] **Step 5a: Apply layering remediation if Step 5 fails**
+
+Flow:
+- if toggle is hidden or unclickable over overlays, adjust stacking order in `views/partials/theme.php`
+
+Concrete remediation:
+- increase `#themeToggle` z-index above conflicting overlay layer
+- if conflict persists, reduce non-critical overlay z-index where safe without breaking modal usability
+
+Expected:
+- toggle remains visible/clickable while modals/dropdowns still function correctly
+
+- [ ] **Step 6: Verify no-cookie fallback uses system preference**
+
+Flow:
+- delete `theme` cookie
+- load `/home`
+
+Expected:
+- resolved theme follows current `prefers-color-scheme`
+
+- [ ] **Step 7: Verify invalid-cookie fallback**
+
+Flow:
+- set `theme=invalid`
+- reload `/home`
+
+Expected:
+- invalid cookie ignored
+- resolved theme follows current system preference
+
+- [ ] **Step 8: Verify no-JS fallback**
+
+Flow:
+- disable JS in browser
+- open `/login`
+
+Expected:
+- light mode only
+- no visible floating toggle
+- login form remains usable
+
+- [ ] **Step 9: Verify cookie-write-failure behavior**
+
+Flow:
+- use a browser mode/policy that blocks cookie writes (or simulate via devtools/privacy settings)
+- click toggle on `/home`
+
+Expected:
+- theme still switches immediately on the current page
+- no error message is shown to the user
+- persistence across reload is not required in this scenario
+
+- [ ] **Step 10: Run final PHP syntax sweep**
+
+Run:
+
+```bash
+php -l views/partials/theme.php && \
+php -l views/login.php && \
+php -l views/setup.php && \
+php -l views/index.php && \
+php -l views/vehicle.php && \
+php -l views/settings.php
+```
+
+Expected: all report `No syntax errors detected`.
+
+- [ ] **Step 11: No additional commit for verification-only task**
+
+Expected:
+- Task 6 records verification results only.
+- No new commit is created unless this task introduces actual file changes.
diff --git a/docs/superpowers/specs/2026-05-01-dark-mode-design.md b/docs/superpowers/specs/2026-05-01-dark-mode-design.md
new file mode 100644
index 0000000..01682c0
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-01-dark-mode-design.md
@@ -0,0 +1,223 @@
+# Dark Mode Support Design
+
+Date: 2026-05-01
+Project: Mainty
+Status: Draft approved by user for implementation planning
+
+## Goal
+
+Add dark mode support across all regular app views with a floating dark/light toggle in the top-right corner at all times (for normal JS-enabled operation). Theme should default to the system preference when no user preference exists, and user preference should persist in a cookie.
+
+## In Scope
+
+- Add theme resolution and apply logic for:
+ - `views/index.php`
+ - `views/vehicle.php`
+ - `views/settings.php`
+ - `views/login.php`
+ - `views/setup.php`
+- Add a floating top-right theme toggle visible on all in-scope views.
+- Persist user-selected theme in a cookie.
+- Apply cookie preference on view load.
+
+## Out of Scope
+
+- No database persistence for theme preference.
+- No account-level sync across devices.
+- No changes to route/controller/model logic.
+- No dark mode support for export/print page.
+
+## Explicit Product Decisions
+
+- Export page remains always light for print readability:
+ - `views/export.php` must ignore cookie and system theme.
+- If JavaScript is disabled, app falls back to light theme.
+
+## Architecture
+
+## 1) Shared Theme Partial
+
+Create a reusable partial: `views/partials/theme.php`.
+
+Responsibilities:
+
+- Inject minimal theme bootstrap script in `
` to resolve theme and apply `dark` class on `` as early as possible.
+- Inject floating theme toggle markup near the start/end of `