Replace the flat 8-tab Settings page with a cleaner information
architecture: a grouped left rail (Account / Workspace) plus a new
Overview landing with live status tiles. Related concerns are merged —
"Login & security" (password + sessions) and "Fields & tags" (tags +
custom fields).
- New shell: settings-sections (section model + legacy ?tab= mapping,
tags/custom-fields -> fields), settings-rail, settings-overview
(live counts + identity), security-panel, fields-and-tags-panel,
settings-panel-head, settings-chip, role-meta (shared role chip
metadata, de-duped from members-tab).
- Restyle the light panels to the mockup; reframe the heavy panels
(WhatsApp, Templates) with the shared panel header, internals intact.
- Tokens: add --card-2 (light+dark) and @theme mappings for
primary-hover/soft/soft-2 so the redesign stays fully tokenized.
- ?tab= remains the URL source of truth, keeping existing sidebar/header
deep-links working.
Overview decouples the slow WhatsApp Meta health-ping from the cheap
count queries so a flaky ping never blanks the whole landing; template
counts use head-only count queries.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a light/dark MODE axis orthogonal to the existing accent
themes. Neutral surface tokens now live in html[data-mode="light|dark"]
blocks; accent tokens (--primary*, --ring, --chart-1, --sidebar-primary*)
stay in html[data-theme] blocks, so any accent works in either mode.
- globals.css: split neutrals (mode) from accent (theme); add light
palette; dark values unchanged (dark stays the default).
- lib/themes.ts: Mode type, DEFAULT_MODE=dark, MODE_STORAGE_KEY, isMode.
- use-theme.tsx: provider owns mode/setMode/toggleMode + cross-tab sync.
- layout.tsx: boot script applies persisted mode before first paint
(no flash); colorScheme "dark light".
- mode-toggle.tsx (header sun/moon) + themed-toaster.tsx (mode-aware).
- appearance-panel.tsx: light/dark control + updated copy.
- Tokenize hardcoded neutral colors (slate/white/gray) -> semantic
tokens across the app so every surface flips with mode. Flow canvas
and message-bubble timestamps made mode-aware too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a new "Appearance" tab in Settings with 5 dark color themes
(Violet, Emerald, Cobalt, Amber, Rose). Pick a theme → applied
immediately and persisted to localStorage. Boot script in the root
layout replays the pick before first paint so there's no
flash-of-default on subsequent loads.
Implementation, ordered the way it's read:
1. `globals.css` — 5 `html[data-theme="..."]` blocks extracted
verbatim from the design handoff at project/Color Themes.html.
`:root` mirrors Violet so SSR / first-paint renders correctly
even before the boot script runs. Three new tokens
(`--primary-hover`, `--primary-soft`, `--primary-soft-2`) added
to all themes — used by tinted-primary surfaces.
2. `src/lib/themes.ts` — single source of truth for the catalog
(id, name, tagline, swatch). Adding a theme = append a CSS
block + append an entry here.
3. `src/hooks/use-theme.tsx` — ThemeProvider client component. Reads
what the boot script already applied, syncs across tabs via the
`storage` event, persists to localStorage. Falls back to a no-op
setter when used outside the provider.
4. `src/app/layout.tsx` — inline `beforeInteractive` script that
reads localStorage and sets `documentElement.dataset.theme`
before React hydrates. Knowledge of valid theme IDs comes from
the THEME_IDS constant so adding a theme doesn't silently break
the boot path. Wraps the tree in ThemeProvider.
5. `src/components/settings/appearance-panel.tsx` — picker UI. 5
cards, swatch + name + tagline + a 4-tone preview strip. Active
card carries a primary-tinted ring + "Active" chip.
6. `src/app/(dashboard)/settings/page.tsx` — new "appearance" tab
alongside profile/whatsapp/templates/tags.
7. Key-surface tokenization — replaced hard-coded `violet-*` with
`primary` tokens on the high-visibility surfaces so the theme
switch feels real: sidebar logo + active nav + unread dot +
avatar fallback, header avatar, dashboard-shell loading
spinner, Flows header icon + entry-node picker icon + entry
badge + flash ring, Flows list page (template card hover,
FlowCard icon), Flows editor + runs "back" links, Settings tabs
active state.
NOT touched (intentional follow-ups):
- Per-node-type colors in flow-builder.tsx NODE_META — those are a
deliberate per-type rainbow, not a brand accent.
- The inbox/contacts/pipelines surfaces — many `violet-*` usages
there. Sweep is a contained follow-up; the user explicitly
scoped this PR to "tokens + tab + key surfaces".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The legal brief on third-party trademark use says: avoid the WhatsApp
teal/green palette and any visual treatment that could read as a
WhatsApp/Meta product. Emerald-500 was used as the primary brand colour
across hero, CTAs, sidebar, charts, badges, and the favicon — close
enough in hue to WhatsApp's signature green to muddy the line.
Swapping to Tailwind violet (which matches the Hostinger brand purple
#7c3aed) makes the visual identity unambiguously ours.
Scope:
- Mechanical Tailwind class swap: emerald-* → violet-* across src/.
- src/app/globals.css: --primary, --ring, --sidebar-primary, --sidebar-ring,
--chart-1 oklch tokens swapped from emerald (oklch 0.696 0.17 162) to
Hostinger-aligned violet (oklch 0.526 0.247 293).
- src/app/icon.tsx: favicon background #10b981 → #7c3aed.
- src/app/opengraph-image.tsx: badge bg, accent text, gradient.
- src/components/landing/hero.tsx + cta-banner.tsx: radial-gradient hex.
- src/components/landing/mock/analytics-mock.tsx: marketing chart line.
- src/components/dashboard/conversations-chart.tsx + response-time-chart.tsx:
"Outgoing" series colour. Distinguishable from "Incoming" blue at a
glance; we can revisit the chart pair later for stronger colourblind
contrast (separate concern).
- README.md: license badge colour parameter.
Out of scope:
- src/components/settings/tag-manager.tsx still offers "Emerald" as one
of the user-pickable contact-tag colours alongside Blue / Yellow / Red
/ etc. — that's a user data choice, not a brand mark.
Contrast check: white text on #7c3aed measures ~4.78:1 (WCAG AA passing
for normal body text). Violet-400 (#a78bfa) on slate-950 measures ~10:1
for accent text, well clear of AA.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>