---
name: krow-mobile-design-system
description: KROW mobile design system usage rules covering colors, typography, icons, spacing, and UI component patterns. Use this when implementing UI in KROW mobile features, matching POC designs to production, creating themed widgets, enforcing visual consistency, or reviewing UI code compliance. Prevents hardcoded values and ensures brand consistency across staff and client apps. Critical for maintaining immutable design tokens.
---

# KROW Mobile Design System Usage

This skill defines mandatory standards for UI implementation using the shared `apps/mobile/packages/design_system`. All UI must consume design system tokens exclusively.

## When to Use This Skill

- Implementing any UI in mobile features
- Migrating POC/prototype designs to production
- Creating new themed widgets or components
- Reviewing UI code for design system compliance
- Matching colors and typography from designs
- Adding icons, spacing, or layout elements
- Setting up theme configuration in apps
- Refactoring UI code with hardcoded values

## Core Principle

**Design tokens (colors, typography, spacing) are IMMUTABLE and defined centrally.**

Features consume tokens but NEVER modify them. The design system maintains visual coherence across all apps.

## 1. Design System Ownership

### Centralized Authority

- `apps/mobile/packages/design_system` owns:
  - All brand assets
  - Colors and semantic color mappings
  - Typography and font configurations
  - Core UI components
  - Icons and images
  - Spacing, radius, elevation constants

### No Local Overrides

**✅ CORRECT:**
```dart
// Feature uses design system
import 'package:design_system/design_system.dart';

Container(
  color: UiColors.background,
  padding: EdgeInsets.all(UiConstants.spacingL),
  child: Text(
    'Hello',
    style: UiTypography.display1m,
  ),
)
```

**❌ FORBIDDEN:**
```dart
// ❌ Custom colors in feature
const myBlue = Color(0xFF1A2234);

// ❌ Custom text styles in feature
const myStyle = TextStyle(fontSize: 24, fontWeight: FontWeight.bold);

// ❌ Theme overrides in feature
Theme(
  data: ThemeData(primaryColor: Colors.blue),
  child: MyWidget(),
)
```

### Extension Policy

If a required style is missing:
1. **FIRST:** Add it to `design_system` following existing patterns
2. **THEN:** Use it in your feature

**DO NOT** create temporary workarounds with hardcoded values.

## 2. Package Structure

```
apps/mobile/packages/design_system/
├── lib/
│   ├── src/
│   │   ├── ui_colors.dart          # Color tokens
│   │   ├── ui_typography.dart      # Text styles
│   │   ├── ui_icons.dart           # Icon exports
│   │   ├── ui_constants.dart       # Spacing, radius, elevation
│   │   ├── ui_theme.dart           # ThemeData factory
│   │   └── widgets/                # Shared UI components
│   │       ├── custom_button.dart
│   │       └── custom_app_bar.dart
│   └── design_system.dart          # Public exports
├── assets/
│   ├── icons/
│   ├── images/
│   └── fonts/
└── pubspec.yaml
```

## 3. Colors Usage Rules

### Strict Protocol

**✅ DO:**
```dart
// Use UiColors for all color needs
Container(color: UiColors.background)
Text('Hello', style: TextStyle(color: UiColors.foreground))
Icon(Icons.home, color: UiColors.primary)
```

**❌ DON'T:**
```dart
// ❌ Hardcoded hex colors
Container(color: Color(0xFF1A2234))

// ❌ Material color constants
Container(color: Colors.blue)

// ❌ Opacity on hardcoded colors
Container(color: Color(0xFF1A2234).withOpacity(0.5))
```

### Available Color Categories

**Brand Colors:**
- `UiColors.primary` - Main brand color
- `UiColors.secondary` - Secondary brand color
- `UiColors.accent` - Accent highlights

**Semantic Colors:**
- `UiColors.background` - Page background
- `UiColors.foreground` - Primary text color
- `UiColors.card` - Card/container background
- `UiColors.border` - Border colors
- `UiColors.mutedForeground` - Secondary text

**Status Colors:**
- `UiColors.success` - Success states
- `UiColors.warning` - Warning states
- `UiColors.error` - Error states
- `UiColors.info` - Information states

### Color Matching from POCs

When migrating POC designs:

1. **Find closest match** in `UiColors`
2. **Use existing color** even if slightly different
3. **DO NOT add new colors** without design team approval

**Example Process:**
```dart
// POC has: Color(0xFF2C3E50)
// Find closest: UiColors.background or UiColors.card
// Use: UiColors.card

// POC has: Color(0xFF27AE60)
// Find closest: UiColors.success
// Use: UiColors.success
```

### Theme Access

Colors can also be accessed via theme:
```dart
// Both are valid:
Container(color: UiColors.primary)
Container(color: Theme.of(context).colorScheme.primary)
```

## 4. Typography Usage Rules

### Strict Protocol

**✅ DO:**
```dart
// Use UiTypography for all text
Text('Title', style: UiTypography.display1m)
Text('Body', style: UiTypography.body1r)
Text('Label', style: UiTypography.caption1m)
```

**❌ DON'T:**
```dart
// ❌ Custom TextStyle
Text('Title', style: TextStyle(
  fontSize: 24,
  fontWeight: FontWeight.bold,
))

// ❌ Manual font configuration
Text('Body', style: TextStyle(
  fontFamily: 'Inter',
  fontSize: 16,
))

// ❌ Modifying existing styles inline
Text('Title', style: UiTypography.display1m.copyWith(
  fontSize: 28,  // ← Don't override size
))
```

### Available Typography Styles

**Display Styles (Large Headers):**
- `UiTypography.display1m` - Display Medium
- `UiTypography.display1sb` - Display Semi-Bold
- `UiTypography.display1b` - Display Bold

**Heading Styles:**
- `UiTypography.heading1m` - H1 Medium
- `UiTypography.heading1sb` - H1 Semi-Bold
- `UiTypography.heading1b` - H1 Bold
- `UiTypography.heading2m` - H2 Medium
- `UiTypography.heading2sb` - H2 Semi-Bold

**Body Styles:**
- `UiTypography.body1r` - Body Regular
- `UiTypography.body1m` - Body Medium
- `UiTypography.body1sb` - Body Semi-Bold
- `UiTypography.body2r` - Body 2 Regular

**Caption/Label Styles:**
- `UiTypography.caption1m` - Caption Medium
- `UiTypography.caption1sb` - Caption Semi-Bold
- `UiTypography.label1m` - Label Medium

### Allowed Customizations

**✅ ALLOWED (Color Only):**
```dart
// You MAY change color
Text(
  'Title',
  style: UiTypography.display1m.copyWith(
    color: UiColors.error,  // ← OK
  ),
)
```

**❌ FORBIDDEN (Size, Weight, Family):**
```dart
// ❌ Don't change size
Text(
  'Title',
  style: UiTypography.display1m.copyWith(fontSize: 28),
)

// ❌ Don't change weight
Text(
  'Title',
  style: UiTypography.display1m.copyWith(fontWeight: FontWeight.w900),
)

// ❌ Don't change family
Text(
  'Title',
  style: UiTypography.display1m.copyWith(fontFamily: 'Roboto'),
)
```

### Typography Matching from POCs

When migrating:
1. Identify text role (heading, body, caption)
2. Find closest matching style in `UiTypography`
3. Use existing style even if size/weight differs slightly

## 5. Icons Usage Rules

### Strict Protocol

**✅ DO:**
```dart
// Use UiIcons
Icon(UiIcons.home)
Icon(UiIcons.profile)
Icon(UiIcons.chevronLeft)
```

**❌ DON'T:**
```dart
// ❌ Direct icon library imports
import 'package:lucide_icons/lucide_icons.dart';
Icon(LucideIcons.home)

// ❌ Font Awesome direct
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
FaIcon(FontAwesomeIcons.house)
```

### Why Centralize Icons?

1. **Consistency:** Same icon for same action everywhere
2. **Branding:** Unified icon set with consistent stroke weight
3. **Swappability:** Change icon library in one place

### Icon Libraries

Design system uses:
- `typedef _IconLib = LucideIcons;` (primary)
- `typedef _IconLib2 = FontAwesomeIcons;` (secondary)

**Features MUST NOT import these directly.**

### Adding New Icons

If icon missing:
1. Add to `ui_icons.dart`:
```dart
class UiIcons {
  static const home = _IconLib.home;
  static const newIcon = _IconLib.newIcon;  // Add here
}
```
2. Use in feature:
```dart
Icon(UiIcons.newIcon)
```

## 6. Spacing & Layout Constants

### Strict Protocol

**✅ DO:**
```dart
// Use UiConstants for spacing
Padding(padding: EdgeInsets.all(UiConstants.spacingL))
SizedBox(height: UiConstants.spacingM)
Container(
  padding: EdgeInsets.symmetric(
    horizontal: UiConstants.spacingL,
    vertical: UiConstants.spacingM,
  ),
)

// Use UiConstants for radius
Container(
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(UiConstants.radiusM),
  ),
)

// Use UiConstants for elevation
elevation: UiConstants.elevationLow
```

**❌ DON'T:**
```dart
// ❌ Magic numbers
Padding(padding: EdgeInsets.all(16.0))
SizedBox(height: 24.0)
BorderRadius.circular(8.0)
elevation: 2.0
```

### Available Constants

**Spacing:**
```dart
UiConstants.spacingXs   // Extra small
UiConstants.spacingS    // Small
UiConstants.spacingM    // Medium
UiConstants.spacingL    // Large
UiConstants.spacingXl   // Extra large
UiConstants.spacing2xl  // 2x Extra large
```

**Border Radius:**
```dart
UiConstants.radiusS     // Small
UiConstants.radiusM     // Medium
UiConstants.radiusL     // Large
UiConstants.radiusXl    // Extra large
UiConstants.radiusFull  // Fully rounded
```

**Elevation:**
```dart
UiConstants.elevationNone
UiConstants.elevationLow
UiConstants.elevationMedium
UiConstants.elevationHigh
```

## 7. Smart Widgets Usage

### When to Use

- **Prefer standard Flutter Material widgets** styled via theme
- **Use design system widgets** for non-standard patterns
- **Create new widgets** in design system if reused >3 features

### Navigation in Widgets

Widgets with navigation MUST use safe methods:

**✅ CORRECT:**
```dart
// In UiAppBar back button:
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/krow_core.dart';

IconButton(
  icon: Icon(UiIcons.chevronLeft),
  onPressed: () => Modular.to.popSafe(),  // ← Safe pop
)
```

**❌ FORBIDDEN:**
```dart
// ❌ Direct Navigator
IconButton(
  icon: Icon(UiIcons.chevronLeft),
  onPressed: () => Navigator.pop(context),
)

// ❌ Unsafe Modular
IconButton(
  icon: Icon(UiIcons.chevronLeft),
  onPressed: () => Modular.to.pop(),  // Can crash
)
```

### Composition Over Inheritance

**✅ CORRECT:**
```dart
// Compose standard widgets
Container(
  padding: EdgeInsets.all(UiConstants.spacingL),
  decoration: BoxDecoration(
    color: UiColors.card,
    borderRadius: BorderRadius.circular(UiConstants.radiusM),
  ),
  child: Column(
    children: [
      Text('Title', style: UiTypography.heading1sb),
      SizedBox(height: UiConstants.spacingM),
      Text('Body', style: UiTypography.body1r),
    ],
  ),
)
```

**❌ AVOID:**
```dart
// ❌ Deep custom widget hierarchies
class CustomCard extends StatelessWidget {
  // Complex custom implementation
}
```

## 8. Theme Configuration

### App Setup

Apps initialize theme ONCE in root MaterialApp:

**✅ CORRECT:**
```dart
// apps/mobile/apps/staff/lib/app_widget.dart
import 'package:design_system/design_system.dart';

class StaffApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      theme: StaffTheme.light,  // ← Design system theme
      darkTheme: StaffTheme.dark,  // ← Optional dark mode
      themeMode: ThemeMode.system,
      // ...
    );
  }
}
```

**❌ FORBIDDEN:**
```dart
// ❌ Custom theme in app
MaterialApp.router(
  theme: ThemeData(
    primaryColor: Colors.blue,  // ← NO!
  ),
)

// ❌ Theme override in feature
Theme(
  data: ThemeData(...),
  child: MyFeatureWidget(),
)
```

### Accessing Theme

**Both methods valid:**
```dart
// Method 1: Direct design system import
import 'package:design_system/design_system.dart';
Text('Hello', style: UiTypography.body1r)

// Method 2: Via theme context
Text('Hello', style: Theme.of(context).textTheme.bodyMedium)
```

**Prefer Method 1** for explicit type safety.

## 9. POC → Production Workflow

### Step 1: Implement Structure (POC Matching)

Implement UI layout exactly matching POC:
```dart
// Temporary: Match POC visually
Container(
  color: Color(0xFF1A2234),  // ← POC color
  padding: EdgeInsets.all(16.0),  // ← POC spacing
  child: Text(
    'Title',
    style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),  // ← POC style
  ),
)
```

**Purpose:** Ensure visual parity with POC before refactoring.

### Step 2: Architecture Refactor

Move to Clean Architecture:
- Extract business logic to use cases
- Move state management to BLoCs
- Implement repository pattern
- Use dependency injection

### Step 3: Design System Integration

Replace hardcoded values:
```dart
// Production: Design system tokens
Container(
  color: UiColors.background,  // ← Found closest match
  padding: EdgeInsets.all(UiConstants.spacingL),  // ← Used constant
  child: Text(
    'Title',
    style: UiTypography.heading1sb,  // ← Matched typography
  ),
)
```

**Color Matching:**
- POC `#1A2234` → `UiColors.background`
- POC `#3498DB` → `UiColors.primary`
- POC `#27AE60` → `UiColors.success`

**Typography Matching:**
- POC `24px bold` → `UiTypography.heading1sb`
- POC `16px regular` → `UiTypography.body1r`
- POC `14px medium` → `UiTypography.caption1m`

**Spacing Matching:**
- POC `16px` → `UiConstants.spacingL`
- POC `8px` → `UiConstants.spacingM`
- POC `4px` → `UiConstants.spacingS`

## 10. Anti-Patterns & Common Mistakes

### ❌ Magic Numbers
```dart
// BAD
EdgeInsets.all(12.0)
SizedBox(height: 24.0)
BorderRadius.circular(8.0)

// GOOD
EdgeInsets.all(UiConstants.spacingM)
SizedBox(height: UiConstants.spacingL)
BorderRadius.circular(UiConstants.radiusM)
```

### ❌ Local Themes
```dart
// BAD
Theme(
  data: ThemeData(primaryColor: Colors.blue),
  child: MyWidget(),
)

// GOOD
// Use global theme defined in app
```

### ❌ Hex Hunting
```dart
// BAD: Copy-paste from Figma
Container(color: Color(0xFF3498DB))

// GOOD: Find matching design system color
Container(color: UiColors.primary)
```

### ❌ Direct Icon Library
```dart
// BAD
import 'package:lucide_icons/lucide_icons.dart';
Icon(LucideIcons.home)

// GOOD
Icon(UiIcons.home)
```

### ❌ Custom Text Styles
```dart
// BAD
Text('Title', style: TextStyle(
  fontSize: 24,
  fontWeight: FontWeight.bold,
  fontFamily: 'Inter',
))

// GOOD
Text('Title', style: UiTypography.heading1sb)
```

## 11. Design System Review Checklist

Before merging UI code:

### ✅ Design System Compliance
- [ ] No hardcoded `Color(...)` or `0xFF...` hex values
- [ ] No custom `TextStyle(...)` definitions
- [ ] All spacing uses `UiConstants.spacing*`
- [ ] All radius uses `UiConstants.radius*`
- [ ] All elevation uses `UiConstants.elevation*`
- [ ] All icons from `UiIcons`, not direct library imports
- [ ] Theme consumed from design system, no local overrides
- [ ] Layout matches POC intent using design system primitives

### ✅ Architecture Compliance
- [ ] No business logic in widgets
- [ ] State managed by BLoCs
- [ ] Navigation uses Modular safe extensions
- [ ] Localization used for all text (no hardcoded strings)
- [ ] No direct Data Connect queries in widgets

### ✅ Code Quality
- [ ] Widget build methods concise (<50 lines)
- [ ] Complex widgets extracted to separate files
- [ ] Meaningful widget names
- [ ] Doc comments on reusable widgets

## 12. When to Extend Design System

### Add New Color
**When:** New brand color approved by design team

**Process:**
1. Add to `ui_colors.dart`:
```dart
class UiColors {
  static const myNewColor = Color(0xFF123456);
}
```
2. Update theme if needed
3. Use in features

### Add New Typography Style
**When:** New text style pattern emerges across multiple features

**Process:**
1. Add to `ui_typography.dart`:
```dart
class UiTypography {
  static const myNewStyle = TextStyle(
    fontSize: 20,
    fontWeight: FontWeight.w600,
    fontFamily: _fontFamily,
  );
}
```
2. Use in features

### Add Shared Widget
**When:** Widget reused in 3+ features

**Process:**
1. Create in `lib/src/widgets/`:
```dart
// my_widget.dart
class MyWidget extends StatelessWidget {
  // Implementation using design system tokens
}
```
2. Export from `design_system.dart`
3. Use across features

## Summary

**Core Rules:**
1. **All colors from `UiColors`** - Zero hex codes in features
2. **All typography from `UiTypography`** - Zero custom TextStyle
3. **All spacing/radius/elevation from `UiConstants`** - Zero magic numbers
4. **All icons from `UiIcons`** - Zero direct library imports
5. **Theme defined once** in app entry point
6. **POC → Production** requires design system integration step

**The Golden Rule:** Design system is immutable. Features adapt to the system, not the other way around.

When implementing UI:
1. Import `package:design_system/design_system.dart`
2. Use design system tokens exclusively
3. Match POC intent with available tokens
4. Request new tokens only when truly necessary
5. Never create temporary hardcoded workarounds

Visual consistency is non-negotiable. Every pixel must come from the design system.
