# MVNexus UI/UX Redesign Plan

**Version:** 1.0  
**Date:** May 2026  
**Scope:** Frontend (`resources/js/src/`) — React, styled-components, EN/AR RTL  
**Goal:** Transform MVNexus from a developer CRUD aesthetic into a polished, premium enterprise SaaS experience.

---

## Executive Summary

MVNexus has a functional React SPA with a DocuForge-inspired theme, shared UI primitives, and feature-based architecture. The foundation is sound, but the visual layer suffers from **surface homogeneity**, **weak hierarchy**, **inconsistent spacing**, **legacy CSS variable usage**, and **feature pages that re-implement layout ad hoc**. This document defines the audit findings, target design language, and phased implementation strategy.

**North-star references:** Linear, Notion, Zendesk, Intercom, Stripe Dashboard — calm, separated, scannable, emotionally comfortable.

---

## 1. Current Design Problems

### 1.1 Visual Melting (Critical)

| Symptom | Root cause | Affected areas |
|---------|------------|----------------|
| Sections blend together | `background`, `surface`, and `border` are nearly identical (`#FAFAFA` / `#FFFFFF` / `#F4F4F5`) | All authenticated pages |
| Cards lack elevation hierarchy | Default card = thin border + minimal shadow; no `surfaceMuted` layer | Dashboard, tickets, admin |
| Content area feels flat | `AppLayout` main uses same background as page sections | Global shell |
| Filters/tables collide | No grouped panel containers; filters sit directly on page background | Tickets, search, admin |

### 1.2 Status System (Critical)

| Symptom | Root cause |
|---------|------------|
| Statuses hard to scan | `Badge` uses saturated semantic variants; ticket status mapped heuristically via string matching (`statusBadgeVariant`) |
| Open tickets show as `error` (red) | `ticketDisplay.ts` maps "open/new" → `error` variant |
| No unified semantic tokens | Status colors not in theme; pills lack border tint |
| SLA/status conflated | Multiple ad-hoc badge mappings across features |

### 1.3 Typography & Hierarchy (High)

| Issue | Detail |
|-------|--------|
| Page titles inconsistent | Mix of `h1` styled per-page vs theme defaults |
| Weak section titles | `h2` at `lg` size without overline/section spacing rhythm |
| Metadata undifferentiated | Timestamps, labels, helpers use similar `sm` gray text |
| No layout typography tokens | Missing `pageTitle`, `sectionTitle`, `cardTitle` presets |

### 1.4 Spacing Rhythm (High)

| Issue | Detail |
|-------|--------|
| Inconsistent section gaps | `margin-bottom: spacing[6]` vs `[8]` without system |
| Card internal padding varies | `md`/`lg` used arbitrarily per feature |
| Dense ticket detail | Grid `gap: spacing[6]` with stacked sections at same visual weight |
| Forms lack grouped spacing | Setting rows, admin forms feel CRUD-dense |

### 1.5 Color & Surfaces (High)

| Issue | Detail |
|-------|--------|
| Flat lifeless palette | Primary blue + gray scale only; no accent warmth |
| DocuForge shadows feel "stacked border" | `0 4px 0 0` offset shadows read as harsh, not floating |
| Dark mode surface contrast low | `background`/`surface` gap minimal in dark theme |
| Chart colors OK but cards don't harmonize | `chartColors.ts` isolated from surface system |

### 1.6 Technical Debt (Medium)

| Issue | Files affected |
|-------|----------------|
| Undefined CSS variables `var(--text-secondary)`, `var(--error)` | ~17 files in settings, admin, notifications, tickets |
| Inline styles mixed with styled-components | Search, ticket detail, settings |
| No shared page layout primitives | Every page defines own `Title`, `Section`, grids |
| Method badge hardcoded hex in Badge | `get/post/put/delete` bypass theme |

### 1.7 Component-Specific Gaps

| Component | Problem |
|-----------|---------|
| **Sidebar** | Active state uses left border (breaks RTL symmetry); same surface as header |
| **Header** | Flat bar; dropdowns basic; no glass/elevation separation |
| **Replies thread** | List dividers only; not chat-bubble modern |
| **Tables (admin)** | Raw bordered rows; no hover band, no sticky header polish |
| **Notifications dropdown** | Uses `background` not `surface`; tight padding |
| **Onboarding wizard** | Functional but not celebratory / step hierarchy weak |
| **Search** | Filter panel doesn't feel like a power-tool command palette |
| **Empty states** | Exist (`EmptyStateCard`) but underused and visually plain |

---

## 2. Target Visual Direction

### 2.1 Principles

1. **Layered surfaces** — page → section → card → inset (4 elevation levels)
2. **Soft separation** — whitespace + subtle shadow, not heavy borders
3. **Semantic color** — status/priority/SLA always use theme tokens
4. **Comfortable density** — default "comfortable"; compact only for data tables
5. **Friendly enterprise** — rounded corners (12–16px cards), warm neutrals, restrained accent
6. **Instant scan** — status pills, metric cards, timeline markers optimized for peripheral vision

### 2.2 Anti-patterns (DO NOT)

- Giant 1px borders on every container
- Saturated badge fills (bootstrap alert style)
- Identical background for page + card + sidebar
- Childish gradients or over-glassmorphism
- Tailwind-demo utility soup
- Breaking RTL for active nav indicators

---

## 3. Design System Proposal

### 3.1 Surface Layers

```
Layer 0: canvas     → colors.background     (#F5F6F8 light)
Layer 1: shell      → colors.surface        (header, sidebar)
Layer 2: elevated   → colors.surfaceElevated (cards, dropdowns)
Layer 3: muted      → colors.surfaceMuted   (filter bars, table headers)
Layer 4: inset      → colors.surfaceInset   (code, reply composer, nested fields)
```

### 3.2 Color System

#### Neutrals (light)

| Token | Value | Usage |
|-------|-------|-------|
| `background` | `#F4F6F9` | Page canvas |
| `surface` | `#FFFFFF` | Primary cards, header |
| `surfaceElevated` | `#FFFFFF` | Floating panels (shadow distinguishes) |
| `surfaceMuted` | `#F0F2F6` | Filter strips, grouped sections |
| `surfaceInset` | `#F8F9FB` | Nested inputs, thread backgrounds |
| `border` | `#E8ECF1` | Soft dividers |
| `borderStrong` | `#D5DCE6` | Emphasized separators |
| `text.primary` | `#0F172A` | Headings, body |
| `text.secondary` | `#64748B` | Metadata |
| `text.tertiary` | `#94A3B8` | Hints, timestamps |

#### Brand

| Token | Value | Usage |
|-------|-------|-------|
| `primary` | `#4F6BED` | Actions, links (softer than `#2563EB`) |
| `primaryLight` | `#EEF2FF` | Active nav, focus backgrounds |
| `accent` | `#7C8DB5` | Secondary emphasis |

#### Semantic Status (soft pills)

Each status token provides: `bg`, `border`, `text`, `icon` (optional)

| Status | Light bg | Border | Text |
|--------|----------|--------|------|
| `open` | `#EFF6FF` | `#BFDBFE` | `#1D4ED8` |
| `pending` | `#FFFBEB` | `#FDE68A` | `#B45309` |
| `inProgress` | `#F5F3FF` | `#DDD6FE` | `#6D28D9` |
| `resolved` | `#ECFDF5` | `#A7F3D0` | `#047857` |
| `closed` | `#F1F5F9` | `#CBD5E1` | `#475569` |
| `breached` | `#FEF2F2` | `#FECACA` | `#B91C1C` |
| `warning` | `#FFF7ED` | `#FED7AA` | `#C2410C` |
| `paused` | `#F8FAFC` | `#E2E8F0` | `#64748B` |
| `active` | `#ECFEFF` | `#A5F3FC` | `#0E7490` |
| `unread` | `#EEF2FF` | `#C7D2FE` | `#4338CA` |
| `success` | `#F0FDF4` | `#BBF7D0` | `#15803D` |
| `error` | `#FEF2F2` | `#FECACA` | `#DC2626` |
| `draft` | `#FAFAF9` | `#E7E5E4` | `#78716C` |

Dark mode: invert lightness relationships; maintain 4.5:1 contrast on text.

### 3.3 Typography System

| Role | Font | Size | Weight | Line-height | Letter-spacing |
|------|------|------|--------|-------------|----------------|
| Page title | Plus Jakarta Sans | 30px (`3xl`) | 700 | 1.2 | -0.02em |
| Page subtitle | Inter | 15px (`sm`) | 400 | 1.6 | 0 |
| Section title | Plus Jakarta Sans | 18px (`lg`) | 600 | 1.3 | -0.01em |
| Section overline | Inter | 11px | 600 | 1.4 | 0.08em uppercase |
| Card title | Inter | 16px (`base`) | 600 | 1.4 | 0 |
| Label | Inter | 14px (`sm`) | 500 | 1.4 | 0 |
| Helper | Inter | 12px (`xs`) | 400 | 1.5 | 0.01em |
| Metadata | Inter | 13px | 400 | 1.5 | 0 — `text.tertiary` |
| Status | Inter | 12px (`xs`) | 500 | 1.4 | 0.02em |
| Table header | Inter | 12px (`xs`) | 600 | 1.4 | 0.06em uppercase |
| Table cell | Inter | 14px (`sm`) | 400 | 1.5 | 0 |

**Implementation:** `PageHeader`, `SectionHeader` components + GlobalStyles utility classes.

### 3.4 Spacing System

#### Layout rhythm

| Token | Value | Usage |
|-------|-------|-------|
| `layout.pagePadding` | `32px` (spacing.8) | Main content horizontal |
| `layout.sectionGap` | `40px` (spacing.10) | Between major sections |
| `layout.cardGap` | `24px` (spacing.6) | Grid gap between cards |
| `layout.stackGap` | `16px` (spacing.4) | Vertical stacks |
| `layout.inlineGap` | `12px` (spacing.3) | Badge rows, meta |

#### Component padding

| Component | Padding |
|-----------|---------|
| Card sm | 16px |
| Card md | 24px |
| Card lg | 32px |
| Modal body | 28px |
| Form section | 24px vertical between groups |
| Table row | 14px vertical |

### 3.5 Shadows & Radius

| Token | Light value | Usage |
|-------|-------------|-------|
| `shadows.xs` | `0 1px 2px rgba(15,23,42,0.04)` | Subtle lift |
| `shadows.sm` | `0 1px 3px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04)` | Cards at rest |
| `shadows.md` | `0 4px 12px rgba(15,23,42,0.08)` | Hovered cards, dropdowns |
| `shadows.lg` | `0 12px 32px rgba(15,23,42,0.12)` | Modals |
| `borderRadius.md` | `10px` | Inputs, buttons |
| `borderRadius.lg` | `14px` | Cards |
| `borderRadius.xl` | `18px` | Modals, panels |

### 3.6 Animation Guidelines

| Interaction | Duration | Easing |
|-------------|----------|--------|
| Hover surface | 150ms | ease-out |
| Modal enter | 200ms | cubic-bezier(0.16, 1, 0.3, 1) |
| Dropdown | 150ms | ease-out |
| Page section | none | avoid layout shift |
| Skeleton pulse | 1.5s | ease-in-out |

**Rule:** No decorative animations > 300ms. Respect `prefers-reduced-motion`.

---

## 4. Component Redesign Plan

### 4.1 Shared UI (`shared/components/ui/`)

| Component | Changes |
|-----------|---------|
| **Button** | Softer primary, `soft` variant, improved ghost hover on muted surface |
| **Card** | `elevated` default, `muted` variant, larger radius, optional `interactive` |
| **Badge** | Pill shape (`borderRadius.full`), semantic border tint |
| **StatusBadge** | NEW — maps ticket/SLA/notification statuses to theme tokens |
| **Input/Textarea/Select** | Inset background option, larger touch targets, focus ring |
| **Modal** | Backdrop blur (subtle), xl radius, header typography |
| **Spinner** | Themed stroke color |

### 4.2 Layout Primitives (`shared/components/layout/`)

| Component | Changes |
|-----------|---------|
| **PageHeader** | NEW — title, subtitle, actions slot, breadcrumbs |
| **PageSection** | NEW — overline, title, description, children with gap |
| **ContentPanel** | NEW — muted/elevated wrapper for filters/tables |
| **Stack** | NEW — vertical/horizontal gap utility |
| **AppLayout** | Canvas background, max-width container optional, increased padding |
| **Header** | Elevated surface, softer border, refined dropdowns |
| **Sidebar** | Muted canvas inset, pill active state (RTL-safe), section separators |

### 4.3 Feature Components (priority)

| Area | Key files | Changes |
|------|-----------|---------|
| Tickets | `RepliesThread`, `TicketDetailSidebar`, `TicketListCard` | Chat bubbles, sidebar card stack, status pills |
| Dashboard | `DashboardPage`, `ChartCard`, stat cards | Metric hero cards, section panels |
| Search | `SearchPage`, `SearchFiltersPanel` | Command-bar search, chip filters |
| Notifications | `NotificationDropdown`, `NotificationListItem` | Card items, unread accent |
| Onboarding | `SetupWizard`, `ChecklistCard` | Step progress, celebration state |
| Admin | All `Admin*Page` | `ContentPanel` tables, form sections |
| Settings | `SettingsPage`, `SettingFieldRow` | Grouped settings workspace |

---

## 5. Page-by-Page Strategy

### 5.1 Dashboard (`/dashboard`)

**Current:** Stats grid + charts + recent tickets + checklist — functional but generic.

**Target:**
- `PageHeader` with greeting subtitle
- Stat cards: icon + label + large value + trend hint; accent only on SLA breach
- Charts in `PageSection` with `elevated` cards
- Recent tickets: compact list with status pills
- Checklist: progress ring visual, softer item cards

### 5.2 Tickets List (`/tickets`)

**Target:**
- `ContentPanel` for `TicketFiltersBar`
- Increased gap between `TicketListCard` items
- Row hover: subtle shadow lift, not translateY (reduces jitter)
- Quick status color strip on card leading edge (optional)

### 5.3 Ticket Detail (`/tickets/:id`)

**Target:**
- Hero header: ticket number overline, subject as page title, status/priority pills row
- Main column: description card → replies as chat thread → reply composer inset panel
- Sidebar: stacked elevated cards (assignee, SLA, metadata, history)
- Internal notes: distinct `warning`/`draft` tinted panel
- Timeline: vertical line + dot markers

### 5.4 Search (`/search`)

**Target:**
- Prominent search input (lg size, icon, full-width in panel)
- Filters in collapsible `surfaceMuted` panel
- Active filter chips below search
- Results with consistent card spacing

### 5.5 Notifications

**Target:**
- Dropdown: `surfaceElevated`, 12px item gap, unread left border accent
- Inbox page: grouped by date, card rows
- Preferences: toggle rows in grouped sections

### 5.6 Settings & Admin

**Target:**
- Settings: category tabs + `PageSection` per group + `SettingFieldRow` with description
- Admin: `PageHeader` + action bar + `ContentPanel` table
- Destructive actions: `destructive` button + confirmation modal
- Replace all `var(--*)` with theme tokens

### 5.7 Onboarding

**Target:**
- Wizard: step indicator dots/progress bar, illustration area, primary CTA
- Tour: spotlight overlay with rounded highlight
- Completion: confetti-free celebration (checkmark + message card)

### 5.8 Auth pages

**Target:**
- Centered elevated card on muted canvas
- Softer login form spacing
- OTP input polish (already exists, align with Input system)

---

## 6. Accessibility Improvements

| Area | Action |
|------|--------|
| Contrast | All status pills ≥ 4.5:1 text; verify dark mode |
| Focus | Consistent `focus-visible` ring using `primary` |
| Motion | `prefers-reduced-motion: reduce` disables transitions |
| Touch | Minimum 44px tap targets on mobile nav |
| Screen readers | StatusBadge includes semantic text; modals trap focus |
| Tables | `scope` on headers; row actions keyboard reachable |

---

## 7. RTL Improvements

| Area | Action |
|------|--------|
| Sidebar active | Use `border-inline-start` not `border-left` |
| Chat bubbles | Mirror alignment for requester vs agent |
| Icons | Directional icons flip where semantic |
| Dropdowns | `inset-inline-end` positioning (already in notifications) |
| Timeline | Line position mirrors to inline-end in RTL |

---

## 8. Responsive Improvements

| Breakpoint | Behavior |
|------------|----------|
| `< 768px` | Sidebar drawer (existing), reduce page padding to 16px |
| `< 1024px` | Ticket detail single column |
| Tables | Horizontal scroll in `ContentPanel` with shadow fade |
| Dashboard charts | Stack single column |
| Modals | Full-bleed on mobile with safe-area padding |

---

## 9. Empty States Strategy

Use `EmptyStateCard` consistently with:
- Soft illustration icon (24–32px, `text.tertiary`)
- Title + description + primary CTA
- `surfaceMuted` background, dashed border optional
- Context-specific copy per feature (tickets, search, notifications)

---

## 10. Implementation Phases

### Phase 1 — Foundation (this sprint)
- [x] Audit document
- [ ] Extend `theme.ts` (surfaces, status, layout, shadows)
- [ ] `GlobalStyles` CSS variable bridge
- [ ] `StatusBadge`, layout primitives
- [ ] Polish Button, Card, Badge, Input, Modal

### Phase 2 — Shell
- [ ] AppLayout, Header, Sidebar
- [ ] Fix `var(--*)` usages across pages

### Phase 3 — Core workflows
- [ ] Dashboard redesign
- [ ] Ticket list + detail + replies
- [ ] Search + notifications

### Phase 4 — Admin & onboarding
- [ ] Settings + admin pages
- [ ] Onboarding wizard + checklist
- [ ] Auth pages

### Phase 5 — QA
- [ ] Visual regression (e2e screenshots)
- [ ] RTL pass (ar locale)
- [ ] Dark mode pass
- [ ] a11y audit (axe)

---

## 11. File Change Map

| File | Phase | Change type |
|------|-------|-------------|
| `styles/theme.ts` | 1 | Extend tokens |
| `styles/GlobalStyles.ts` | 1 | CSS vars + utilities |
| `shared/components/ui/*` | 1 | Component polish |
| `shared/components/ui/StatusBadge/*` | 1 | New |
| `shared/components/layout/PageHeader/*` | 1 | New |
| `shared/components/layout/PageSection/*` | 1 | New |
| `shared/components/layout/ContentPanel/*` | 1 | New |
| `shared/components/layout/AppLayout/*` | 2 | Canvas + padding |
| `shared/components/layout/Header/*` | 2 | Elevation |
| `shared/components/layout/Sidebar/*` | 2 | Pill nav RTL |
| `features/dashboard/pages/DashboardPage.tsx` | 3 | Layout + stats |
| `features/tickets/**` | 3 | Thread + cards |
| `features/search/pages/SearchPage.tsx` | 3 | Search panel |
| `features/notifications/**` | 3 | Dropdown + list |
| `features/settings/**` | 4 | Workspace layout |
| `features/admin/pages/**` | 4 | Tables + panels |
| `features/onboarding/**` | 4 | Wizard polish |
| `features/tickets/utils/ticketDisplay.ts` | 3 | StatusBadge mapping |

---

## 12. Success Metrics

| Metric | Target |
|--------|--------|
| Visual separation | User can identify 3+ distinct surface layers per page |
| Status scan time | < 2s to identify ticket status in list (user test) |
| CSS variable debt | 0 undefined `var(--*)` references |
| Component reuse | 80%+ pages use PageHeader/PageSection |
| RTL regressions | 0 layout breaks in ar locale smoke test |
| Bundle impact | < 15KB gzipped increase from new components |

---

## Appendix A: Component Inventory (Current)

```
shared/components/ui/
  Button, Input, Select, Textarea, Card, Badge, Spinner, Modal, ColorPicker

shared/components/layout/
  AppLayout, Header, Sidebar, SidebarNavContext

features/*/pages/
  DashboardPage, TicketsPage, TicketDetailPage, CreateTicketPage,
  SearchPage, SettingsPage, NotificationsPage, NotificationPreferencesPage,
  Admin* (10 pages), LoginPage, MagicLinkPage, AcceptInvitePage,
  DepartmentPortal* (4 pages), ProfilePage
```

## Appendix B: Screenshot Targets (for QA)

1. Dashboard — stat row + charts + recent tickets
2. Ticket list — filters + 3 cards
3. Ticket detail — header + replies + sidebar
4. Search — query + filters + results
5. Notifications dropdown + inbox
6. Settings — grouped fields
7. Admin users table
8. Onboarding wizard step 2
9. Dark mode — dashboard + ticket detail
10. RTL — sidebar + ticket detail

---

*This document is the source of truth for the MVNexus visual redesign. Implementation PRs should reference section numbers when addressing specific areas.*
