# ADR-082: Dark Mode and Theming Architecture — Forced Light Mode for ERP PWAs, Dark UI for Standalone Apps

## Status

Accepted, 2026-06-27.

## Status History

```yaml
status_history:
  - date: 2026-06-27
    status: Proposed
    changed_by: hkl
    reason: Formalising theming architecture decision — light mode for ERP PWAs vs dark UI for standalone apps (Health Tracker, future isolated PWAs)
    changed_via: adr-kit (360lm)
  - date: 2026-06-27
    status: Accepted
    changed_by: hkl
    reason: Field teams require high-contrast light UI for outdoor data entry; dark mode across 20 inconsistent PWAs would fragment UX; standalone apps retain autonomy
    changed_via: adr-kit (360lm)
```

## Context

The 360lm platform comprises ~20 PWAs deployed across two categories:

1. **ERP PWAs** (activity, admin, counters, finance, hub, learn, recce, sales, tour-planner, vehicle, etc.) — Used by field teams (recce agents, installation crews, activity reporters) on Android smartphones in varying light conditions: outdoors in daylight, warehouses with artificial lighting, night shifts, and field deployments.

2. **Standalone Apps** (Health Tracker, future isolated PWAs per ADR-086) — Independent applications with their own design and deployment lifecycle, not bound by ERP theming conventions.

**Current state:**
- All ERP PWAs use light UI (implicitly, not by documented decision).
- Health Tracker (standalone, separate database, separate deployment) uses dark UI.
- ADR-076 mandates `theme-color` meta tag per PWA but does not address dark mode strategy.
- Some PWAs use CSS custom properties (`--primary`, `--surface`, etc.) but naming and token values are not standardised.
- `prefers-color-scheme` media query exists in CSS but no PWA currently honours `prefers-color-scheme: dark`.
- No platform decision exists on: forced mode vs user toggle vs OS preference, CSS variable naming conventions, or dark/light token colour contracts.

**Field team considerations:**
- Outdoor data entry requires high contrast to read form labels and dropdowns in sunlight.
- Field users often work in harsh lighting (glare, low light) where UI inconsistency increases cognitive load.
- Android `prefers-color-scheme` preference is common on modern devices, but honouring it across 20 PWAs without a unified design system would create a fragmented experience (some PWAs light, some dark).
- Support burden: inconsistent theming across PWAs increases help-desk load as users become confused by different chrome/button styles.

## Decision

**For 360lm ERP PWAs (all shared-schema employee-facing PWAs):**

1. **Forced light mode** — All ERP PWAs MUST declare `color-scheme: light only` in CSS (root rule) and in the meta tag (per ADR-076). This declaration:
   - Prevents the browser from rendering form controls in dark mode even if `prefers-color-scheme: dark` is set on the device.
   - Ensures consistent light UI across all 20 PWAs, regardless of user device settings.
   - Rationale: Field data entry (forms, dropdowns, lists) requires high contrast in outdoor sunlight and warehouse environments. A consistent light mode across all PWAs is better UX than a fragmented mix of light and dark (20 different visual styles, 20 different button patterns, 20 different form chrome).

2. **No dark mode toggle in ERP PWAs** — Do not add a user-selectable light/dark mode toggle. Rationale: Reduces complexity (no new UI, no localStorage state, no CSS variant maintenance), reduces support burden (one visual standard to document and support), and keeps each PWA's single HTML file lean (no theme-switcher JavaScript).

3. **CSS custom properties (tokens) are recommended but not mandated** — If a PWA uses CSS custom properties for colour values (`--primary`, `--surface`, `--text-primary`, etc.), follow naming conventions:
   - Prefix with `--` (CSS standard).
   - Use semantic names (`--text-primary`, `--bg-surface`, `--border-subtle`) rather than hue names (`--blue-500`).
   - Include a comment block in CSS declaring the colour contract (e.g., `/* Light theme tokens: --text-primary #000, --bg-surface #fff */`).
   - Each PWA owns its palette; naming does not need to be globally standardised across all 20 PWAs.

4. **`theme-color` meta tag must match PWA primary colour** — As per ADR-076, the `theme-color` value MUST match the primary colour defined in `manifest.json`. Examples:
   - Light PWAs use a vibrant or muted colour matching brand: `theme-color="#2563eb"` (blue), `theme-color="#059669"` (green).
   - Never use black (`#000000`) or very dark greys as `theme-color` for light-mode PWAs — the status bar would become visually indistinguishable from the PWA chrome.
   - Standalone apps (Health Tracker) may use `theme-color` values matching their own dark UI if appropriate.

5. **If a future ERP PWA requires dark mode, update this ADR first** — Dark mode is a breaking design change affecting field team UX at scale. Any proposal to add dark mode to an ERP PWA (or family of PWAs) MUST:
   - Create or amend this ADR to document the rationale (new lighting context, new user cohort, new accessibility requirement).
   - Propose a unified dark design system (shared CSS, consistent button/form chrome across PWAs).
   - Undergo cross-PWA safety review (ADR-067) before implementation.

**For standalone apps (Health Tracker, future isolated PWAs per ADR-086):**

- Standalone apps are **not bound** by the ERP light-mode requirement.
- Health Tracker retains its dark UI; no change required.
- Future standalone PWAs may choose light, dark, or adaptive theming at their own discretion.
- Standalone apps do not use the hub session bridge, do not access shared schemas, and do not affect field team UX consistency.

**Decision Maker:** hkl

## Implementation Notes

### For existing ERP PWAs

Add or update the root CSS rule:

```css
:root {
  color-scheme: light only;
}
```

Verify the meta tag in `<head>`:

```html
<meta name="theme-color" content="#<primary-colour>">
```

Verify manifest.json contains a matching primary colour:

```json
"theme_color": "#<primary-colour>"
```

### For new ERP PWAs (check before ship):

- Include `color-scheme: light only;` in root CSS.
- Include `theme-color` meta tag matching brand colour.
- Include `theme-color` in manifest.json (same value).
- If using CSS custom properties, document the colour contract in a comment block.
- No dark-mode media queries; no user toggle.

### For standalone apps (no changes):

- Health Tracker continues to use dark UI without modification.
- Future standalone PWAs may define their own theming rules in their own ADRs if needed.

## Alternatives Considered

- **Honour `prefers-color-scheme` OS preference.** Rejected: Creates a fragmented experience where some devices render light, others render dark, even for the same PWA. Field teams would see inconsistent button styles, form chrome, and layouts across devices. Support burden explodes as users report "the app looks different on my phone vs yours." Light-only is consistent across all devices for all users.

- **Add a user-selectable light/dark toggle in each PWA.** Rejected: Increases complexity (new UI, localStorage state, CSS variants), increases code size (each PWA adds ~100–300 lines of toggle logic + dark CSS), increases support burden (users toggle at random, report bugs for "the mode they forgot they switched"), and violates the single HTML file minimalism (ADR-013). Not worth the trade-off for field teams who need consistent light contrast.

- **Create a shared dark theme CSS library in /shared/.** Rejected: Implies the platform intends to support dark mode; contradicts the field use case (outdoor sunlight, high-contrast requirement). If dark mode is ever needed, it will require a unified design system for 20 PWAs simultaneously, not a bolt-on CSS file. Better to amend this ADR first and plan a coordinated design system.

- **Adaptive theme based on time-of-day or location (GPS sunrise/sunset).** Rejected: Over-engineered for the problem. Field teams don't need the app to switch themes at sunset; they need consistent, reliable light UI in variable lighting. If a user works a night shift, they'll use a night-mode setting on their device for everything; the app should honour OS preferences globally (not decide theme per-PWA) or stay light-only (current decision).

- **Allow PWAs to opt-in to dark mode individually.** Rejected: Creates inconsistency across the platform. A field team member using recce (light) + vehicle (dark) + activity (light) would experience three different visual languages. The decision here is platform-wide consistency, not per-PWA autonomy. Standalone apps are exempt because they are not field-team platforms.

- **Use a theme detection library (e.g., Tailwind CSS dark mode).** Rejected: Adds an external dependency, increases complexity, and still requires every PWA to adopt it. For a light-only decision, a single CSS rule (`color-scheme: light only`) is simpler and more explicit than a dependency.

## Consequences

**Positive:**
- **Consistency.** All ERP PWAs render with identical light UI, form chrome, and button styles — no visual fragmentation for field teams.
- **High contrast for outdoor use.** Light backgrounds with dark text meet WCAG AA contrast requirements in sunlight and outdoor conditions.
- **Reduced support burden.** One visual standard documented; field teams don't report "the app looks different on different devices."
- **Simpler code.** No theme toggle logic, no localStorage state, no CSS variants — each PWA stays lean (single HTML file principle, ADR-013).
- **Future-proof.** If dark mode is needed later, a single ADR amendment + coordinated design system can introduce it; no need to retrofit toggle logic across 20 PWAs.
- **Accessibility.** Light mode is easier to read for users with vision loss; no reduction in accessibility. Pinch-zoom (ADR-076) still works.

**Negative / Trade-offs:**
- **Users who prefer dark mode (device-wide) will not see dark PWAs.** Users with OLED-burn-in concerns or eye strain sensitivity will need to use OS-wide dark mode (which affects all apps) or accept light PWAs. Mitigated: Light mode is consistent across all 360lm PWAs, so users are not frustrated by fragmented theming; they know what to expect. If user cohort feedback later indicates dark mode is critical (e.g., new night-shift division), this ADR can be amended.
- **No per-PWA theming autonomy for ERP PWAs.** Designers cannot customise colours beyond the `theme-color` value. Mitigated: CSS custom properties are recommended, so PWAs can define their own secondary colours; only the light/dark mode decision is fixed. Standalone apps retain full autonomy.
- **Maintenance burden if design system expands.** If a future ERP PWA adds a custom colour palette, developers must ensure it's still readable in light mode. Mitigated: Code review gates; simple checklist (contrast ratio check).

**Risks and mitigations:**
- **A PWA accidentally includes `prefers-color-scheme: dark` CSS or omits the `color-scheme: light only` rule, rendering dark UI.** Mitigated: Code review checklist; automated test (grep for dark media queries in new PWAs); VCC pre-build checklist (ADR-068) should include colour-scheme verification.
- **A user disables JavaScript and CSS custom properties don't work, leaving the PWA unstyled.** Not a realistic risk; PWAs require CSS and JS (ADR-013 single HTML includes full inline CSS). Mitigated: All colour values inlined or in `<style>` block.
- **Field teams demand dark mode mid-project because of new use case (e.g., warehouse lighting shift).** Mitigated: This ADR exists; amendment process is clear. A proposal must come with rationale, unified design, and safety review before implementation.
- **`theme-color` is set to black (#000000), rendering status bar invisible.** Mitigated: Code review; this ADR explicitly forbids dark `theme-color` values. VCC checklist can include verification.

## Related Decisions

- **ADR-076** (Mobile-First Viewport and Meta Tag Standard) — Defines `theme-color` meta tag; this ADR specifies what values are valid for light mode.
- **ADR-013** (Single HTML File, No Framework) — Enforces lean, self-contained PWAs; no external theme libraries or toggle complexity.
- **ADR-086** (Isolated PWAs, once created) — Standalone apps (Health Tracker) are exempt from this decision and may define their own theming rules.
- **ADR-067** (Cross-PWA Change Safety Gate) — Any future proposal to add dark mode to ERP PWAs must undergo cross-PWA safety review.
- **ADR-068** (VCC Pre-Build Safety Checklist) — Should include verification that `color-scheme: light only` is declared and no dark-mode media queries exist.

## References

- MDN Web Docs: [CSS `color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme)
- MDN Web Docs: [`prefers-color-scheme` media query](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme)
- WCAG 2.1 Level AA: [1.4.3 Contrast (Minimum)](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html) — light backgrounds with dark text meet this requirement in outdoor conditions.
- Web.dev: [Prefers Color Scheme](https://web.dev/articles/prefers-color-scheme)
- Health Tracker PWA: `/var/www/Others/health/` — standalone app, dark UI, not bound by this decision.
- Memory: `feedback_maps_provider.md` — analogous decision-making for platform-wide architectural consistency.
