feat(emails): rebrand onboarding + recovery emails to bunyip-web tokens #303

Merged
vas2000-work merged 1 commit from feat/BUNYIP-288-email-rebrand into main 2026-07-01 07:13:31 +02:00
Owner

The onboarding + recovery emails shipped with an indigo dark palette (#0d0b14 body, orange->indigo gradient buttons) that had no relationship to bunyip-web's live theme. A user who clicked from an email to the dashboard read the two surfaces as different products. Also, account_created opened a tier-pricing pitch (Personal $3/mo, Business $15/mo, "locked for life") which is an odd tone for a "welcome, you just signed up" email.

Retarget five onboarding + recovery templates (account_created, email_verify, email_change_verify, password_reset, magic_link) to bunyip-web's warm-green tokens resolved from bunyip-web/input.css's dark-mode block:

--background:         hsl(120,  8%,  9%) -> #151915
--card:               hsl(120,  8%, 12%) -> #1c211c
--foreground:         hsl(120, 21%, 96%) -> #f3f7f3
--primary:            hsl(116, 28%, 31%) -> #395f39
--primary bright:     hsl(116, 34%, 46%) -> #4d9a54
--muted-foreground:   hsl(113, 15%, 60%) -> #93a795

Email clients cannot evaluate CSS variables, so the palette is baked in as resolved hex. Dark palette only: the live dashboard defaults to dark, and a single confident palette renders more predictably across mail clients than a prefers-color-scheme swap. The base.html header comment documents the HSL -> HEX resolution table so a future palette refresh has a greppable trail.

Copy: account_created drops the tier pitch and reframes the email as a welcome that names Bunyip as SSO for the PSA Systems suite, with one CTA to the dashboard. email_verify / email_change_verify / password_reset / magic_link keep their one-paragraph shape with cleaner wording and the same variable surface (verify_url, reset_url, magic_link_url, dashboard_url, app_name, base_url, year); no handler or EmailService::send_* change.

Out of scope: the remaining ~9 transactional templates (payment_*, membership_canceled, grace_period_reminder, feedback_response, admin_*) keep the previous shell for this PR; a follow-up sweeps them once the palette has validated in real clients.

#BUNYIP-288

The onboarding + recovery emails shipped with an indigo dark palette (`#0d0b14` body, orange->indigo gradient buttons) that had no relationship to bunyip-web's live theme. A user who clicked from an email to the dashboard read the two surfaces as different products. Also, `account_created` opened a tier-pricing pitch (Personal $3/mo, Business $15/mo, "locked for life") which is an odd tone for a "welcome, you just signed up" email. Retarget five onboarding + recovery templates (account_created, email_verify, email_change_verify, password_reset, magic_link) to bunyip-web's warm-green tokens resolved from `bunyip-web/input.css`'s dark-mode block: --background: hsl(120, 8%, 9%) -> #151915 --card: hsl(120, 8%, 12%) -> #1c211c --foreground: hsl(120, 21%, 96%) -> #f3f7f3 --primary: hsl(116, 28%, 31%) -> #395f39 --primary bright: hsl(116, 34%, 46%) -> #4d9a54 --muted-foreground: hsl(113, 15%, 60%) -> #93a795 Email clients cannot evaluate CSS variables, so the palette is baked in as resolved hex. Dark palette only: the live dashboard defaults to dark, and a single confident palette renders more predictably across mail clients than a `prefers-color-scheme` swap. The base.html header comment documents the HSL -> HEX resolution table so a future palette refresh has a greppable trail. Copy: `account_created` drops the tier pitch and reframes the email as a welcome that names Bunyip as SSO for the PSA Systems suite, with one CTA to the dashboard. `email_verify` / `email_change_verify` / `password_reset` / `magic_link` keep their one-paragraph shape with cleaner wording and the same variable surface (`verify_url`, `reset_url`, `magic_link_url`, `dashboard_url`, `app_name`, `base_url`, `year`); no handler or `EmailService::send_*` change. Out of scope: the remaining ~9 transactional templates (`payment_*`, `membership_canceled`, `grace_period_reminder`, `feedback_response`, `admin_*`) keep the previous shell for this PR; a follow-up sweeps them once the palette has validated in real clients. #BUNYIP-288
feat(emails): rebrand onboarding + recovery emails to bunyip-web tokens
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 22s
Check / fmt + clippy + build + tests (pull_request) Successful in 16m35s
8680d6eee3
The onboarding + recovery emails shipped with an indigo dark palette (`#0d0b14` body, orange->indigo gradient buttons) that had no relationship to bunyip-web's live theme. A user who clicked from an email to the dashboard read the two surfaces as different products. Also, `account_created` opened a tier-pricing pitch (Personal $3/mo, Business $15/mo, "locked for life") which is an odd tone for a "welcome, you just signed up" email.

Retarget five onboarding + recovery templates (account_created, email_verify, email_change_verify, password_reset, magic_link) to bunyip-web's warm-green tokens resolved from `bunyip-web/input.css`'s dark-mode block:

    --background:         hsl(120,  8%,  9%) -> #151915
    --card:               hsl(120,  8%, 12%) -> #1c211c
    --foreground:         hsl(120, 21%, 96%) -> #f3f7f3
    --primary:            hsl(116, 28%, 31%) -> #395f39
    --primary bright:     hsl(116, 34%, 46%) -> #4d9a54
    --muted-foreground:   hsl(113, 15%, 60%) -> #93a795

Email clients cannot evaluate CSS variables, so the palette is baked in as resolved hex. Dark palette only: the live dashboard defaults to dark, and a single confident palette renders more predictably across mail clients than a `prefers-color-scheme` swap. The base.html header comment documents the HSL -> HEX resolution table so a future palette refresh has a greppable trail.

Copy: `account_created` drops the tier pitch and reframes the email as a welcome that names Bunyip as SSO for the PSA Systems suite, with one CTA to the dashboard. `email_verify` / `email_change_verify` / `password_reset` / `magic_link` keep their one-paragraph shape with cleaner wording and the same variable surface (`verify_url`, `reset_url`, `magic_link_url`, `dashboard_url`, `app_name`, `base_url`, `year`); no handler or `EmailService::send_*` change.

Out of scope: the remaining ~9 transactional templates (`payment_*`, `membership_canceled`, `grace_period_reminder`, `feedback_response`, `admin_*`) keep the previous shell for this PR; a follow-up sweeps them once the palette has validated in real clients.

#BUNYIP-288
vas2000-work force-pushed feat/BUNYIP-288-email-rebrand from 8680d6eee3
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 22s
Check / fmt + clippy + build + tests (pull_request) Successful in 16m35s
to a6503bce50
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 30s
Check / fmt + clippy + build + tests (pull_request) Successful in 2m55s
Create release / Create release from merged PR (pull_request) Has been skipped
2026-07-01 06:55:03 +02:00
Compare
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!303
No description provided.