ligth theme design fix

This commit is contained in:
2026-08-10 15:33:13 +05:30
parent 6cc3c9a0b7
commit 5ce580dced
34 changed files with 2399 additions and 87 deletions

View File

@@ -65,6 +65,50 @@ Gray is the accent. The **only** colour permitted is semantic: success, warning,
- `/tokens` (dev-only route) is the audit page. After any theme change, load it and run the
chromatic sweep in the browser console — it should report **0** non-semantic colour nodes.
## The two brand accents (exception to the above)
Store intelligence carries exactly **two** non-semantic hues, and nothing else may add a third.
| | token | light | dark | used for |
|---|---|---|---|---|
| warm | `--color-brand-warm` | `#F4C430` | `#F4C430` | brand, rewards, the activities a merchant runs |
| cool | `--color-brand-cool` | `#7C3AED` | `#A78BFA` | analytics, journeys, AI insight |
- Defined in `src/app/globals.css` in a Tailwind `@theme` block, **not** in `loyalyTheme.ts`.
They are not Astryx tokens: no component variant resolves through them, and putting them in
the theme would let Badge/Banner pick them up as part of the semantic language.
- Three slots per hue. `-ink` is the readable one for text and icons (light mode darkens warm
to `#8A6300`; raw `#F4C430` on white is ~1.7:1). `-soft` is an icon-chip tint only — never a
card background. The base is for non-text marks: chart fills, dots, bars.
- `src/shared/utils/accent.ts` is the only place a hue becomes a class name. Feature files use
`ACCENT[accent].ink` / `.soft`, never `text-brand-warm-ink` by hand.
- Charts stay monochrome by default. `CHART.brand.{warm,cool}` is opt-in per series and is used
on exactly two charts (dashboard Footfall = cool, Revenue = warm). Never make it a ramp
default — `Sparkline` reads `seriesAt(0)`, so that would turn every KPI card's trend line.
- An activity's accent travels on its API payload (`ActivityMetric.accent`), not from grid
position, so an activity is the same colour on every screen.
## Attribution is estimated — say so
Everything downstream of `ActivityImpact.customers` (repeat visits, purchases, revenue) is
**modelled**, not measured. No purchase is joined to a specific spin, selfie or challenge.
- The field is `attributedRevenueInr`, never `revenueInr`, and every payload carries
`attribution: 'estimated' | 'observed'`.
- Copy says *attributed*. Never "generated", "earned" or "drove". A merchant who reads
"Selfie generated ₹3.4L" and spends against it is the failure this rule prevents.
- `<AttributionNote basis={…} />` sits in the header of every panel that shows an attributed
figure, and renders **nothing** when the basis is `'observed'` — so a real attribution
backend retires the disclosure with no copy edit. Read the basis off the payload, never
hardcode it.
- The single sentence lives in `ATTRIBUTION_NOTE` (types/intelligence.ts) so three panels
cannot drift.
## Dashboard supporting analytics are collapsed by default
The six preserved supporting panels (conversion pair, peak hours, reward usage, period rollup,
store comparison) sit inside a `Collapsible`, closed by default, state in
`loyaly.dashboard.supporting-analytics`. Expanded they add ~1,700px desktop / ~3,100px mobile
and push "What needs your attention" — the only actionable section — to 81% of the scroll.
They are evidence, not the finding. Do not re-expand by default; do not delete them either.
## Known upstream issues (Astryx 0.2.0)
- **`useEntryAnimation` breaks SSR hydration.** Its source assumes `'use client'` modules never
run on the server; in the App Router they do. Any `FieldStatus` (i.e. `TextInput`/`TextArea`