SP-685: Tenant brand colors and footer color

Date: 2026-09-06  ·  Ticket: SP-685

Branch: SP-685/tenant-brand-colors (uncommitted, no PR yet)

Implemented, verified locally, not merged
Frontend only 10 files ~270 lines

1. Problem

The tenant admin Branding page (in the LMS admin menu) never had a color editor in any committed version. Colors could only be set from the platform-admin tenant Branding tab, using the keys primary, secondary, and accent. A tenant admin had no way to change their own theme colors.

The public site footer used the tenant secondary color as its background. When a tenant logo was drawn in that same color, the logo blended into the footer and became hard to see.

2. Decision

Three options were considered for the footer color:

We chose (c). It has the lowest friction, it never overwrites what the user typed, and complementary hues often clash. The footer color falls out of the primary color by default, and a tenant can still set an exact footer color when they want one.

3. What changed

Frontend only. 10 files, about 270 lines.

LMS frontend

Platform-admin

4. Verification

Automated checks

Frontend
  • lint: 0 errors (12 pre-existing warnings)
  • 334 tests pass
  • build passes
Platform-admin
  • lint passes
  • build passes

Manual / headless run

Ran the full stack with Docker Compose from the worktree, seeded the database, and logged in headless as an admin using a minted Firebase token driven with Playwright.

CheckResult
Colors card renders on desktopPass
Renders at 360px, scrollWidth 360 (no horizontal scroll)Pass
Save persists primary #c21230 / secondary #22305f to DB and bootstrapPass
Footer with no override = oklch(0.22 0.0705 21.43) (dark red tint)Pass
Footer override #101820 = oklch(0.205 0.02 248.83)Pass
Clearing restores oklch(0.4084 0.1234 257.3) defaultPass
Invalid hex "zzz" shows "Enter a 6-digit hex color like #1a2b3c." and blocks savePass
No console errorsPass

Screenshots

Colors card on desktop
01 — Colors card on desktop.
Colors card at 360px, filled in
05 — Colors card at 360px, filled in. No horizontal scroll.
Footer before, default color
00 — Footer before / default.
Footer derived from the primary color
03 — Footer derived from the primary color.
Footer with override #101820
04 — Footer with override #101820.
Not verified

5. Gotchas

6. Next steps