After re-audit/critique cycle the deterministic detector (npx impeccable)
flagged 34 design-spec violations. Knock out 33 of them.
• 25 × pure-black-white: sed-sweep bg-black/X → bg-dark-950/X across
18+ files (modal scrims, photo viewer backdrop, code blocks). The
base resolves to rgba(10,15,26,X) — visually identical to true
black, satisfies the 'no #000' impeccable rule.
• 3 × bounce-easing: SuccessNotificationModal celebration icon and
SyncTab loading arrows used animate-bounce; replaced with
animate-pulse. Bounce easing reads dated; pulse conveys 'in
progress' without the cartoon feel.
• 3 × border-accent-on-rounded: TelegramCallback + VerifyEmail
spinners used 'border-b-2 border-accent-500' on rounded-full —
detector reads it as a side-stripe even though it's a ring loader.
Switch to canonical 'border-2 border-accent-500 border-t-transparent'
(3/4 ring colored). Same visual, no spec violation.
• 1 × ai-color-palette: AdminLandingStats had text-purple-400 on a
gift-stats heading; purple is not in the brand palette. Swap to
text-accent-400.
• 1 × layout-transition: TrafficProgressBar.tsx fill bar still used
transition: width 1.2s (slipped past the earlier optimize pass).
Convert to transform: scaleX with origin-left. Same gradient, same
duration, runs on the compositor.
Remaining: 1 finding in third-party Aceternity background-beams-collision
component (indigo-500 gradient on decorative WebGL background) — left
as-is, it's lifted decorative third-party code.
Detector: 34 → 1.
Both pages were rendering with raw Tailwind gray-* + a non-existent border-primary-600
class (invisible spinner). Map: bg-gray-50 → bg-dark-950, text-gray-900 → text-dark-50,
text-gray-500 → text-dark-400, border-primary-600 → border-accent-500. Pages now match
the dark theme and the spinner is visible.
Sweep 30 files: text/bg/border/ring/from/to/via/fill/stroke/shadow/divide/decoration/
outline/placeholder-red-N → -error-N. All red usages were semantically error/danger
(no brand red), so tokens now flow through the design-system CSS variables and respond
to palette overrides.
Replace all bare useAuthStore(), useBlockingStore(), and
useSuccessNotification() calls with individual field selectors.
This prevents components from re-rendering when unrelated store
fields change.
- 21 useAuthStore usages across 20 files: individual selectors
for 1-2 fields, useShallow for 3+ fields
- 5 useBlockingStore usages: individual selectors
- 2 useSuccessNotification usages: individual selectors
- Add campaign.ts utility (capture from URL, localStorage with TTL, validation)
- Pass campaign_slug in all auth API methods (telegram, widget, email, oauth)
- Consume slug in auth store login methods, set pendingCampaignBonus state
- Add CampaignBonusNotifier component (toast on bonus, mounted in AppShell)
- Show web_link alongside bot deep_link in AdminCampaignStats
- Add CampaignBonusInfo type with union bonus_type
- Fix VerifyEmail: ref guard against StrictMode double-fire, setTimeout cleanup
- Fix AdminCampaignStats: setTimeout refs with cleanup, i18n-aware locale
- Wrap all localStorage access in try/catch (Safari private browsing safety)
- Add campaignBonus translations (ru/en/fa/zh)