# MOPC Platform - UI/UX Architecture

## Overview

The MOPC platform uses a mobile-first responsive design built with:

- **Next.js App Router** - Server Components by default
- **shadcn/ui** - Accessible, customizable component library
- **Tailwind CSS** - Utility-first styling
- **Radix UI** - Headless accessible primitives
- **Motion** (Framer Motion) - Buttery smooth animations
- **Vaul** - Native-feeling mobile drawers
- **Sonner** - Beautiful toast notifications
- **cmdk** - Command palette (⌘K)

## Design Philosophy

**CRITICAL: Avoid "AI-built" aesthetic. Platform must look professionally designed.**

### What to AVOID (typical AI-generated look)
| Don't | Why | Instead |
|-------|-----|---------|
| Cards everywhere | Generic, lazy layout | Use varied layouts: tables, lists, grids, hero sections |
| Same border-radius on everything | Monotonous | Vary: sharp corners for data, rounded for actions |
| Identical padding/spacing | Robotic feel | Use intentional rhythm: tight for data, generous for CTAs |
| Blue/purple gradients | Screams "AI template" | Use brand colors with restraint |
| Stock icons everywhere | Impersonal | Custom icons or carefully curated set |
| Centered everything | No visual hierarchy | Left-align content, strategic centering |
| Gray backgrounds | Dull, corporate | Subtle off-white textures, strategic white space |
| "Dashboard" with 6 equal cards | The #1 AI cliché | Prioritize: hero metric, then supporting data |

### What TO DO (professional design)
| Do | Why | Example |
|----|-----|---------|
| Visual hierarchy | Guides the eye | Large numbers for KPIs, smaller for details |
| Intentional white space | Breathability | 32-48px between sections, not uniform 16px |
| Typography scale | Professional rhythm | 12/14/16/20/24/32/48px - skip sizes intentionally |
| Micro-interactions | Delight users | Button hover states, loading skeletons |
| Consistent but varied | Not monotonous | Same colors, different layouts per page |
| Data density where needed | Efficient | Tables for lists, not cards |
| Strategic color accents | Draw attention | Red only for primary CTAs, not decoration |
| Real content sizes | Accommodate reality | Long project names, international characters |

## Brand Colors

```css
:root {
  /* Brand Colors */
  --color-primary: #de0f1e;      /* Primary Red - CTAs, alerts */
  --color-primary-hover: #c00d1a;
  --color-secondary: #053d57;    /* Dark Blue - headers, sidebar */
  --color-accent: #557f8c;       /* Teal - links, secondary elements */
  --color-background: #fefefe;   /* White - backgrounds */

  /* Semantic */
  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error: #ef4444;

  /* Neutrals (warm, not cold gray) */
  --color-gray-50: #fafaf9;
  --color-gray-100: #f5f5f4;
  --color-gray-200: #e7e5e4;
  --color-gray-500: #78716c;
  --color-gray-900: #1c1917;
}
```

## Typography

- **Font Family**: Montserrat
- **Headings**: 600/700 weight
- **Body**: 300/400 weight (Montserrat Light)

```css
:root {
  --font-family: 'Montserrat', system-ui, sans-serif;
  --font-size-xs: 0.75rem;   /* 12px */
  --font-size-sm: 0.875rem;  /* 14px */
  --font-size-base: 1rem;    /* 16px */
  --font-size-lg: 1.25rem;   /* 20px */
  --font-size-xl: 1.5rem;    /* 24px */
  --font-size-2xl: 2rem;     /* 32px */
  --font-size-3xl: 3rem;     /* 48px */
}
```

## Design Principles

1. **Mobile First**: Base styles for mobile, enhanced for larger screens
2. **Accessibility**: WCAG 2.1 AA compliance, keyboard navigation, screen reader support
3. **Performance**: Server Components, minimal client JavaScript
4. **Consistency**: Design tokens, component library, consistent patterns
5. **Feedback**: Loading states, error messages, success confirmations

## Responsive Breakpoints

```css
/* Tailwind CSS default breakpoints */
sm: 640px   /* Small tablets */
md: 768px   /* Tablets */
lg: 1024px  /* Laptops */
xl: 1280px  /* Desktops */
2xl: 1536px /* Large monitors */
```

## Layout Architecture

### Application Shell

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                              DESKTOP LAYOUT                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────┐  ┌──────────────────────────────────────────────────────┐ │
│  │             │  │                        HEADER                         │ │
│  │             │  │  Logo    Search (optional)         User Menu          │ │
│  │             │  └──────────────────────────────────────────────────────┘ │
│  │             │  ┌──────────────────────────────────────────────────────┐ │
│  │   SIDEBAR   │  │                                                      │ │
│  │             │  │                                                      │ │
│  │  - Dashboard│  │                    MAIN CONTENT                      │ │
│  │  - Rounds   │  │                                                      │ │
│  │  - Projects │  │                                                      │ │
│  │  - Jury     │  │                                                      │ │
│  │  - Reports  │  │                                                      │ │
│  │             │  │                                                      │ │
│  │             │  │                                                      │ │
│  └─────────────┘  └──────────────────────────────────────────────────────┘ │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                              MOBILE LAYOUT                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │  ☰  Logo                                            User Avatar       │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                                                                      │  │
│  │                                                                      │  │
│  │                                                                      │  │
│  │                         MAIN CONTENT                                 │  │
│  │                       (full width)                                   │  │
│  │                                                                      │  │
│  │                                                                      │  │
│  │                                                                      │  │
│  │                                                                      │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │   🏠       📋       📊       👤                                       │  │
│  │  Home   Projects  Reports  Profile                                   │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Layout Components

```typescript
// src/components/layouts/app-layout.tsx

import { Sidebar } from './sidebar'
import { Header } from './header'
import { MobileNav } from './mobile-nav'

export function AppLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="min-h-screen bg-background">
      {/* Desktop Sidebar */}
      <Sidebar className="hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64" />

      {/* Main Content Area */}
      <div className="lg:pl-64">
        <Header />
        <main className="p-4 lg:p-8">{children}</main>
      </div>

      {/* Mobile Bottom Navigation */}
      <MobileNav className="fixed bottom-0 left-0 right-0 lg:hidden" />
    </div>
  )
}
```

## Component Hierarchy

```
src/components/
├── ui/                      # shadcn/ui base components
│   ├── button.tsx
│   ├── input.tsx
│   ├── card.tsx
│   ├── table.tsx
│   ├── dialog.tsx
│   ├── dropdown-menu.tsx
│   ├── form.tsx
│   ├── select.tsx
│   ├── textarea.tsx
│   ├── badge.tsx
│   ├── progress.tsx
│   ├── skeleton.tsx
│   ├── toast.tsx
│   └── ...
├── layouts/                 # Layout components
│   ├── app-layout.tsx
│   ├── auth-layout.tsx
│   ├── sidebar.tsx
│   ├── header.tsx
│   └── mobile-nav.tsx
├── forms/                   # Form components
│   ├── evaluation-form.tsx
│   ├── project-import-form.tsx
│   ├── round-settings-form.tsx
│   └── user-invite-form.tsx
├── data-display/            # Data display components
│   ├── project-card.tsx
│   ├── project-list.tsx
│   ├── project-table.tsx
│   ├── evaluation-summary.tsx
│   ├── progress-tracker.tsx
│   └── stats-card.tsx
└── shared/                  # Shared utility components
    ├── file-viewer.tsx
    ├── loading-state.tsx
    ├── error-state.tsx
    ├── empty-state.tsx
    └── confirm-dialog.tsx
```

## Page Layouts by View

### Admin Dashboard

```
┌─────────────────────────────────────────────────────────────────┐
│                      ADMIN DASHBOARD                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│  │ Projects    │ │ Evaluations │ │ Jury Active │ │ Time Left │ │
│  │    130      │ │   234/390   │ │    12/15    │ │   5 days  │ │
│  └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │
│                                                                 │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                   PROGRESS BY PROJECT                       │ │
│  │  ████████████████████████████░░░░░░░░░░░░  60% Complete    │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                 │
│  ┌─────────────────────────────┐ ┌────────────────────────────┐ │
│  │    JURY PROGRESS            │ │   RECENT ACTIVITY          │ │
│  │                             │ │                            │ │
│  │  Alice     ████████░░  80%  │ │  • John submitted eval...  │ │
│  │  Bob       ██████░░░░  60%  │ │  • Sarah started eval...   │ │
│  │  Carol     ████░░░░░░  40%  │ │  • Admin extended window   │ │
│  │  ...                        │ │  • ...                     │ │
│  └─────────────────────────────┘ └────────────────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Mobile: Stats stack vertically, Progress & Activity in tabs
```

### Jury Project List

```
DESKTOP:
┌─────────────────────────────────────────────────────────────────┐
│  MY ASSIGNED PROJECTS                          Filter ▼  Search │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │ Title              │ Team        │ Status    │ Actions     │ │
│  ├────────────────────────────────────────────────────────────┤ │
│  │ Ocean Cleanup AI   │ BlueWave    │ ✅ Done   │ View        │ │
│  │ Coral Restoration  │ ReefGuard   │ 📝 Draft  │ Continue    │ │
│  │ Plastic Tracker    │ CleanSeas   │ ⏳ Pending│ Start       │ │
│  │ ...                │             │           │             │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                 │
│  Showing 1-10 of 15                              < 1 2 >        │
└─────────────────────────────────────────────────────────────────┘

MOBILE (Card View):
┌─────────────────────────────────────┐
│  MY PROJECTS (15)        🔍 Filter  │
├─────────────────────────────────────┤
│                                     │
│  ┌─────────────────────────────────┐│
│  │  Ocean Cleanup AI               ││
│  │  Team: BlueWave                 ││
│  │  ✅ Completed                    ││
│  │                        [View →] ││
│  └─────────────────────────────────┘│
│                                     │
│  ┌─────────────────────────────────┐│
│  │  Coral Restoration              ││
│  │  Team: ReefGuard                ││
│  │  📝 Draft saved                  ││
│  │                    [Continue →] ││
│  └─────────────────────────────────┘│
│                                     │
│  ┌─────────────────────────────────┐│
│  │  Plastic Tracker                ││
│  │  Team: CleanSeas                ││
│  │  ⏳ Not started                  ││
│  │                       [Start →] ││
│  └─────────────────────────────────┘│
│                                     │
└─────────────────────────────────────┘
```

### Evaluation Form

```
DESKTOP (Side Panel):
┌─────────────────────────────────────────────────────────────────┐
│  PROJECT DETAILS                     │  EVALUATION FORM         │
├─────────────────────────────────────────────────────────────────┤
│                                      │                          │
│  Ocean Cleanup AI                    │  Need Clarity            │
│  Team: BlueWave Tech                 │  ○ 1 ○ 2 ○ 3 ● 4 ○ 5    │
│                                      │                          │
│  [📄 Exec Summary] [📊 Deck]         │  Solution Relevance      │
│  [🎬 Video]                          │  ○ 1 ○ 2 ● 3 ○ 4 ○ 5    │
│                                      │                          │
│  Description:                        │  Gap Analysis            │
│  Our AI-powered system uses          │  ○ 1 ○ 2 ○ 3 ○ 4 ● 5    │
│  machine learning to identify        │                          │
│  ocean plastic concentrations...     │  Target Customers        │
│                                      │  ○ 1 ○ 2 ○ 3 ● 4 ○ 5    │
│  Tags: AI, Plastic, Monitoring       │                          │
│                                      │  Ocean Impact            │
│                                      │  ○ 1 ○ 2 ○ 3 ○ 4 ● 5    │
│                                      │                          │
│                                      │  Global Score (1-10)     │
│                                      │  [  8  ]                 │
│                                      │                          │
│                                      │  Semi-finalist?          │
│                                      │  (●) Yes  ( ) No         │
│                                      │                          │
│                                      │  Feedback                │
│                                      │  ┌────────────────────┐  │
│                                      │  │ Strong technical   │  │
│                                      │  │ approach with...   │  │
│                                      │  └────────────────────┘  │
│                                      │                          │
│                                      │  Autosaved 2s ago        │
│                                      │  [Submit Evaluation]     │
│                                      │                          │
└─────────────────────────────────────────────────────────────────┘

MOBILE (Full Screen Wizard):
┌─────────────────────────────────────┐
│  ← Ocean Cleanup AI        Step 3/7 │
├─────────────────────────────────────┤
│                                     │
│  Gap Analysis                       │
│                                     │
│  How well does the project          │
│  analyze market gaps?               │
│                                     │
│  ┌─────────────────────────────────┐│
│  │                                 ││
│  │     1    2    3    4    5       ││
│  │    (○)  (○)  (○)  (○)  (●)      ││
│  │   Poor              Excellent   ││
│  │                                 ││
│  └─────────────────────────────────┘│
│                                     │
│                                     │
│                                     │
│                                     │
│                                     │
│  ┌─────────────────────────────────┐│
│  │   ○ ○ ● ○ ○ ○ ○                 ││
│  └─────────────────────────────────┘│
│                                     │
│  [← Previous]        [Next →]       │
│                                     │
└─────────────────────────────────────┘
```

## Design System

### Color Palette (MOPC Brand)

```css
/* CSS Variables in tailwind.config.ts - MOPC Brand Colors */
:root {
  /* Brand Colors */
  --color-primary: 354 90% 47%;      /* #de0f1e - Primary Red */
  --color-secondary: 198 85% 18%;    /* #053d57 - Dark Blue */
  --color-accent: 194 25% 44%;       /* #557f8c - Teal */

  /* shadcn/ui mapped to MOPC brand */
  --background: 0 0% 100%;           /* #fefefe */
  --foreground: 198 85% 18%;         /* Dark Blue for text */
  --card: 0 0% 100%;
  --card-foreground: 198 85% 18%;
  --popover: 0 0% 100%;
  --popover-foreground: 198 85% 18%;
  --primary: 354 90% 47%;            /* Primary Red - main actions */
  --primary-foreground: 0 0% 100%;
  --secondary: 30 6% 96%;            /* Warm gray */
  --secondary-foreground: 198 85% 18%;
  --muted: 30 6% 96%;
  --muted-foreground: 30 8% 45%;
  --accent: 194 25% 44%;             /* Teal */
  --accent-foreground: 0 0% 100%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 0 0% 100%;
  --border: 30 6% 91%;
  --input: 30 6% 91%;
  --ring: 354 90% 47%;               /* Primary Red for focus */
  --radius: 0.5rem;

  /* Semantic colors */
  --success: 142.1 76.2% 36.3%;
  --warning: 38 92% 50%;
  --info: 194 25% 44%;               /* Teal */
}
```

### Typography (Montserrat)

```typescript
// tailwind.config.ts
const config = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Montserrat', 'system-ui', 'sans-serif'],
        mono: ['JetBrains Mono', 'monospace'],
      },
      fontWeight: {
        light: '300',
        normal: '400',
        semibold: '600',
        bold: '700',
      },
      fontSize: {
        'display-lg': ['3rem', { lineHeight: '1.1', fontWeight: '700' }],
        'display': ['2.25rem', { lineHeight: '1.2', fontWeight: '700' }],
        'heading': ['1.5rem', { lineHeight: '1.3', fontWeight: '600' }],
        'subheading': ['1.125rem', { lineHeight: '1.4', fontWeight: '600' }],
        'body': ['1rem', { lineHeight: '1.5', fontWeight: '400' }],
        'small': ['0.875rem', { lineHeight: '1.5', fontWeight: '400' }],
        'tiny': ['0.75rem', { lineHeight: '1.5', fontWeight: '400' }],
      },
    },
  },
}
```

### Spacing System

```
Base unit: 4px

0    = 0px
1    = 4px
2    = 8px
3    = 12px
4    = 16px
5    = 20px
6    = 24px
8    = 32px
10   = 40px
12   = 48px
16   = 64px
20   = 80px
24   = 96px
```

## Component Patterns

### Loading States

```typescript
// Always show skeleton while loading
function ProjectList() {
  const { data, isLoading } = trpc.project.list.useQuery({ roundId })

  if (isLoading) {
    return (
      <div className="space-y-4">
        {Array.from({ length: 5 }).map((_, i) => (
          <Skeleton key={i} className="h-20 w-full" />
        ))}
      </div>
    )
  }

  return <ProjectTable projects={data.projects} />
}
```

### Error States

```typescript
// Consistent error display
function ErrorState({
  title = 'Something went wrong',
  message,
  onRetry,
}: {
  title?: string
  message: string
  onRetry?: () => void
}) {
  return (
    <div className="flex flex-col items-center justify-center p-8 text-center">
      <AlertCircle className="h-12 w-12 text-destructive" />
      <h3 className="mt-4 text-lg font-semibold">{title}</h3>
      <p className="mt-2 text-muted-foreground">{message}</p>
      {onRetry && (
        <Button onClick={onRetry} className="mt-4">
          Try Again
        </Button>
      )}
    </div>
  )
}
```

### Empty States

```typescript
function EmptyState({
  icon: Icon,
  title,
  description,
  action,
}: {
  icon: React.ComponentType<{ className?: string }>
  title: string
  description: string
  action?: React.ReactNode
}) {
  return (
    <div className="flex flex-col items-center justify-center p-8 text-center">
      <Icon className="h-12 w-12 text-muted-foreground" />
      <h3 className="mt-4 text-lg font-semibold">{title}</h3>
      <p className="mt-2 text-muted-foreground">{description}</p>
      {action && <div className="mt-4">{action}</div>}
    </div>
  )
}
```

### Responsive Patterns

```typescript
// Table on desktop, cards on mobile
function ProjectDisplay({ projects }: { projects: Project[] }) {
  return (
    <>
      {/* Desktop: Table */}
      <div className="hidden md:block">
        <ProjectTable projects={projects} />
      </div>

      {/* Mobile: Cards */}
      <div className="md:hidden space-y-4">
        {projects.map((project) => (
          <ProjectCard key={project.id} project={project} />
        ))}
      </div>
    </>
  )
}
```

## Touch Targets

All interactive elements must have a minimum touch target of 44x44px on mobile:

```typescript
// Good: Large touch target
<Button className="min-h-[44px] min-w-[44px] px-4">
  Click me
</Button>

// Good: Icon button with padding
<Button variant="ghost" size="icon" className="h-11 w-11">
  <Menu className="h-5 w-5" />
</Button>
```

## Form Patterns

### Autosave with Debounce

```typescript
function EvaluationForm({ evaluation }: { evaluation: Evaluation }) {
  const utils = trpc.useUtils()

  const autosave = trpc.evaluation.autosave.useMutation({
    onSuccess: () => {
      utils.evaluation.get.invalidate({ assignmentId: evaluation.assignmentId })
    },
  })

  const debouncedSave = useMemo(
    () => debounce((data: FormData) => autosave.mutate(data), 1000),
    [autosave]
  )

  return (
    <Form
      onChange={(data) => {
        debouncedSave(data)
      }}
    >
      {/* Form fields */}
      <div className="text-sm text-muted-foreground">
        {autosave.isPending ? 'Saving...' : 'Autosaved'}
      </div>
    </Form>
  )
}
```

### Form Validation

```typescript
const evaluationSchema = z.object({
  criterionScores: z.record(z.number().min(1).max(5)),
  globalScore: z.number().min(1).max(10),
  binaryDecision: z.boolean(),
  feedbackText: z.string().min(10, 'Please provide at least 10 characters'),
})

function EvaluationForm() {
  const form = useForm<z.infer<typeof evaluationSchema>>({
    resolver: zodResolver(evaluationSchema),
  })

  return (
    <Form {...form}>
      <FormField
        control={form.control}
        name="feedbackText"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Feedback</FormLabel>
            <FormControl>
              <Textarea {...field} />
            </FormControl>
            <FormMessage /> {/* Shows validation error */}
          </FormItem>
        )}
      />
    </Form>
  )
}
```

## Accessibility Checklist

- [ ] All images have alt text
- [ ] Form inputs have labels
- [ ] Color is not the only indicator (icons + text)
- [ ] Focus states are visible
- [ ] Skip links for main content
- [ ] Keyboard navigation works
- [ ] Screen reader tested
- [ ] Reduced motion respected
- [ ] Sufficient color contrast (4.5:1 for text)

## Animation Patterns

### Page Transitions (Motion)
```typescript
const pageVariants = {
  initial: { opacity: 0, y: 20 },
  enter: { opacity: 1, y: 0, transition: { duration: 0.3, ease: [0.25, 0.1, 0.25, 1] } },
  exit: { opacity: 0, y: -10, transition: { duration: 0.2 } }
}
```

### List Stagger (Items enter one by one)
```typescript
const listVariants = {
  visible: { transition: { staggerChildren: 0.05 } }
}
```

### Spring Physics (Natural movement)
```typescript
const springConfig = { type: "spring", stiffness: 400, damping: 30 }
```

## Mobile-Specific UX Patterns

| Pattern | Implementation |
|---------|----------------|
| Bottom sheets instead of modals | Vaul drawer, thumb-reachable |
| Swipe gestures | Motion drag handlers |
| Pull-to-refresh | Custom spring animation |
| Haptic feedback hints | Visual bounce on limits |
| Large touch targets | Min 44x44px, generous spacing |
| Thumb-zone navigation | Bottom nav, not hamburger menu |
| Native-feeling scrolls | CSS scroll-snap, momentum |

## Performance Targets

| Metric | Target | How |
|--------|--------|-----|
| First Contentful Paint | < 1.5s | SSR, optimized fonts |
| Largest Contentful Paint | < 2.5s | Image optimization, lazy loading |
| Time to Interactive | < 3.5s | Code splitting, minimal JS |
| Cumulative Layout Shift | < 0.1 | Reserved space, skeleton loaders |
| Touch response | < 100ms | Optimistic UI, spring animations |
| Scroll performance | 60fps | CSS transforms, will-change |

## Component Design Rules

### Buttons
- Primary: Solid brand red (#de0f1e), 12px radius, subtle shadow
- Secondary: Ghost/outline, same radius
- Hover: Scale 1.02, slight lift shadow
- Active: Scale 0.98, pressed feel
- Loading: Spinner replaces text, same width

### Tables (for data density)
- Zebra striping: Subtle, not harsh
- Row hover: Slight highlight, not full color change
- Sortable headers: Subtle indicator, not loud
- Mobile: Horizontal scroll with sticky first column

### Forms
- Labels above inputs (not placeholder-as-label)
- Clear focus states (brand color ring)
- Inline validation (not modal alerts)
- Autosave indicator: Subtle, top-right

### Empty States
- Illustration + helpful text
- Clear CTA to fix the empty state
- Not just "No data found"

## Related Documentation

- [Architecture Overview](./README.md) - System design
- [API Design](./api.md) - tRPC endpoints
