# Sojorn Visual Design System

## Design Philosophy

Sojorn's visual system creates a **warm, welcoming, friends-first** experience through intentional design choices that prioritize human connection.

### Core Principles

1. **Warm, Not Overwhelming**
   - Warm neutrals (beige/paper tones) instead of cold grays
   - Soft shadows, never harsh
   - Muted semantic colors that inform without alarming

2. **Modern, Not Trendy**
   - Timeless color palette
   - Classic typography hierarchy
   - Subtle animations and transitions

3. **Connection-Focused**
   - Generous line height (1.6-1.65 for body text)
   - Optimized for reading and engagement
   - Clear hierarchy without relying on color

4. **Intentionally Smooth**
   - Animation durations: 300-400ms
   - Ease curves that feel natural
   - No jarring transitions

---

## Color Palette

### Background System
```dart
background        = #F8F7F4  // Warm off-white (like paper)
surface           = #FFFFFD  // Barely warm white
surfaceElevated   = #FFFFFF  // Pure white for cards
surfaceVariant    = #F0EFEB  // Subtle warm gray (inputs)
```

**Usage:**
- `background`: Main app background
- `surface`: App bars, bottom navigation
- `surfaceElevated`: Cards, dialogs, elevated content
- `surfaceVariant`: Input fields, disabled states

### Border System
```dart
borderSubtle      = #E8E6E1  // Barely visible dividers
border            = #D8D6D1  // Default borders
borderStrong      = #C8C6C1  // Emphasized borders
```

**Visual Hierarchy:**
- Use `borderSubtle` for dividers between list items
- Use `border` for cards, inputs, default separators
- Use `borderStrong` for focused/active states (rare)

### Text Hierarchy
```dart
textPrimary       = #1C1B1A  // Near-black with warmth
textSecondary     = #6B6A68  // Medium warm gray
textTertiary      = #9C9B99  // Light warm gray
textDisabled      = #BDBBB8  // Very light gray
textOnAccent      = #FFFFFD  // For buttons/accents
```

**Usage:**
- `textPrimary`: Headlines, body text, primary content
- `textSecondary`: Metadata, labels, secondary info
- `textTertiary`: Placeholders, timestamps, tertiary info
- `textDisabled`: Disabled button text, inactive states
- `textOnAccent`: White text on colored backgrounds

### Accent Colors
```dart
accent            = #5D6B7A  // Muted slate (primary)
accentLight       = #8A95A1  // Lighter slate
accentDark        = #3F4A56  // Darker slate
accentSubtle      = #E8EAED  // Barely visible accent
```

**Usage:**
- `accent`: Primary buttons, links, active states
- `accentLight`: Hover states, dark mode primary
- `accentDark`: Pressed states (rare)
- `accentSubtle`: Background for subtle accent areas

### Interaction Colors
```dart
appreciate        = #7A8B6F  // Muted sage green (likes)
save              = #6F7F92  // Muted blue-gray (saves)
share             = #8B7A6F  // Muted warm gray (shares)
```

### Semantic Colors
```dart
success           = #7A8B6F  // Soft sage (not bright green)
warning           = #B89F7D  // Soft amber (not orange alarm)
error             = #B07F7F  // Soft terracotta (not red alarm)
info              = #7A8B9F  // Soft blue
```

**Why Muted?**
Bright red errors create anxiety. Soft terracotta communicates the same information with less stress.

### Trust Tier Colors
```dart
tierNew           = #9C9B99  // Light gray
tierTrusted       = #7A8B6F  // Sage green
tierEstablished   = #5D6B7A  // Slate blue
```

---

## Typography

### Font Stack
```dart
Primary:  'SF Pro Text' → system-ui → sans-serif
Monospace: 'SF Mono' → 'Courier New' → monospace
```

**Why System Fonts?**
- Free, pre-installed, optimized for each platform
- SF Pro Text is warm and highly readable
- No network requests, instant loading

### Type Scale

#### Display (Rare - Only for Large Headings)
```dart
displayLarge:  32px / 600 / 1.2 line-height / -0.8 tracking
displayMedium: 28px / 600 / 1.25 line-height / -0.6 tracking
```

#### Headlines (Section Titles, Screen Titles)
```dart
headlineLarge:  24px / 600 / 1.3 line-height / -0.4 tracking
headlineMedium: 20px / 600 / 1.3 line-height / -0.3 tracking
headlineSmall:  17px / 600 / 1.35 line-height / -0.2 tracking
```

#### Body (Reading-Optimized)
```dart
bodyLarge:  17px / 400 / 1.65 line-height  ← GENEROUS for readability
bodyMedium: 15px / 400 / 1.6 line-height
bodySmall:  13px / 400 / 1.5 line-height
```

**Why 1.65 line-height?**
Research shows 1.5-1.6 is optimal for readability. We use 1.65 to reinforce comfortable spacing.

#### Labels (UI Elements, Buttons, Metadata)
```dart
labelLarge:  15px / 500 / 1.4 line-height / 0.1 tracking
labelMedium: 13px / 500 / 1.35 line-height / 0.1 tracking
labelSmall:  11px / 500 / 1.3 line-height / 0.3 tracking
```

### Typography Guidelines

**DO:**
- Use `bodyLarge` for post content
- Use `headlineMedium` for screen titles
- Use `labelMedium` for metadata (timestamps, handles)
- Use `mono` for technical data (@handles, IDs)

**DON'T:**
- Mix font weights excessively (400 for body, 500 for labels, 600 for headings)
- Use font sizes outside the scale
- Override line-height without good reason

---

## Spacing System

Based on **4px grid**:

```dart
spacing2xs  = 2px   // Rare, internal component spacing
spacingXs   = 4px   // Tight spacing
spacingSm   = 8px   // Small gaps
spacingMd   = 16px  // Default spacing
spacingLg   = 24px  // Large gaps (card padding)
spacingXl   = 32px  // Extra large (section gaps)
spacing2xl  = 48px  // Huge gaps
spacing3xl  = 64px  // Screen-level spacing
spacing4xl  = 96px  // Rare, dramatic spacing
```

### Semantic Spacing
```dart
spacingCardPadding    = 24px  // Internal card padding
spacingScreenPadding  = 16px  // Screen edge padding
spacingSectionGap     = 32px  // Between major sections
```

### Spacing Guidelines

**DO:**
- Use `spacingLg` (24px) for card padding
- Use `spacingMd` (16px) for screen padding
- Use `spacingXl` (32px) between sections

**DON'T:**
- Use arbitrary spacing values (stick to the scale)
- Create cramped UIs (when in doubt, use more space)

---

## Border Radius

```dart
radiusXs   = 4px    // Chips, badges
radiusSm   = 8px    // Small buttons
radiusMd   = 12px   // Inputs, buttons
radiusLg   = 16px   // Cards, dialogs
radiusXl   = 24px   // Large containers
radiusFull = 9999px // Pills, circular elements
```

**Consistency:**
- Cards: `radiusLg` (16px)
- Buttons: `radiusMd` (12px)
- Inputs: `radiusMd` (12px)
- Trust badges: `radiusXs` (4px)

---

## Elevation & Shadows

All shadows use **warm black** (`#1C1B1A`) at very low opacity:

```dart
shadowSm:  4% opacity, 4px blur, 1px offset
shadowMd:  6% opacity, 8px blur, 2px offset
shadowLg:  8% opacity, 16px blur, 4px offset
```

**Usage:**
- `shadowSm`: Default for cards
- `shadowMd`: Elevated cards, modals
- `shadowLg`: Floating action button, dialogs

**Why So Subtle?**
Heavy shadows create visual noise. Soft shadows suggest elevation without aggression.

---

## Animation

### Durations
```dart
durationFast:   200ms  // Hovers, subtle transitions
durationMedium: 300ms  // Default
durationSlow:   400ms  // Modal entrance, page transitions
```

### Curves
```dart
curveDefault: easeInOutCubic  // Most animations
curveEnter:   easeOut         // Elements appearing
curveExit:    easeIn          // Elements leaving
```

**Why Slow?**
Fast animations feel rushed. 300-400ms feels intentional and smooth.

---

## Custom Widgets

### SojornButton
Replaces `ElevatedButton`, `OutlinedButton`, `TextButton`

**Variants:**
- `primary`: Filled accent button
- `secondary`: Outlined button
- `tertiary`: Text-only button
- `destructive`: Filled error button

**Sizes:**
- `small`: 40px height
- `medium`: 48px height
- `large`: 56px height

**Example:**
```dart
SojornButton(
  label: 'Sign In',
  onPressed: _handleSignIn,
  variant: SojornButtonVariant.primary,
  size: SojornButtonSize.large,
  isFullWidth: true,
  isLoading: _isLoading,
)
```

### SojornInput
Replaces `TextField` with consistent styling

**Example:**
```dart
SojornInput(
  label: 'Email',
  hint: 'your@email.com',
  controller: _emailController,
  prefixIcon: Icons.email_outlined,
  keyboardType: TextInputType.emailAddress,
)
```

### SojornTextArea
For long-form content (posts, comments)

**Example:**
```dart
SojornTextArea(
  label: 'Write your post',
  hint: 'Share something thoughtful...',
  controller: _postController,
  maxLength: 500,
  showCharacterCount: true,
)
```

### SojornCard
Replaces `Card` with consistent elevation and borders

**Example:**
```dart
SojornCard(
  onTap: () => navigateToPost(),
  child: Column(
    children: [
      Text('Card title'),
      Text('Card content'),
    ],
  ),
)
```

### SojornDialog
Replaces `showDialog` with friendly styling

**Static Methods:**
```dart
// Confirmation
SojornDialog.showConfirmation(
  context: context,
  title: 'Delete post?',
  message: 'This cannot be undone.',
  isDestructive: true,
)

// Info
SojornDialog.showInfo(
  context: context,
  title: 'Account created',
  message: 'Welcome to Sojorn!',
)

// Error
SojornDialog.showError(
  context: context,
  title: 'Connection failed',
  message: 'Please check your internet.',
)
```

### SojornSnackbar
Replaces `ScaffoldMessenger.showSnackBar`

**Static Methods:**
```dart
SojornSnackbar.show(context: context, message: 'Post saved')
SojornSnackbar.showSuccess(context: context, message: 'Post published')
SojornSnackbar.showError(context: context, message: 'Failed to load')
SojornSnackbar.showWarning(context: context, message: 'Slow connection')
```

---

## Visual Friendliness Enforcement

### How the System Enforces Friendliness

1. **No Hardcoded Colors**
   - All colors come from `AppTheme`
   - Impossible to use bright red/blue by accident

2. **No Arbitrary Spacing**
   - All spacing uses the 4px grid constants
   - Creates visual rhythm

3. **Generous Defaults**
   - Card padding: 24px (not 16px)
   - Line height: 1.65 (not 1.4)
   - Animation: 300ms (not 150ms)

4. **Soft Shadows**
   - Maximum 8% opacity
   - Warm black, never pure black

5. **Warm Tint**
   - All grays have warm undertones
   - Avoids clinical/sterile feel

6. **Limited Font Weights**
   - 400 (regular), 500 (medium), 600 (semibold)
   - No bold (700) or black (900)

---

## Before/After Comparison

### Before (Material Default)
- Cold grays (#FAFAFA, #F5F5F5)
- Bright blue accent (#2196F3)
- Harsh shadows (24% opacity)
- Tight spacing (8px padding)
- Fast animations (100-150ms)
- Narrow line-height (1.4)

### After (Sojorn System)
- Warm neutrals (#F8F7F4, #F0EFEB)
- Muted slate accent (#5D6B7A)
- Soft shadows (4-8% opacity)
- Generous spacing (24px padding)
- Slow animations (300-400ms)
- Reading line-height (1.65)

**Result:** Feels like reading a book, not using an app.

---

## Testing Checklist

- [ ] All screens use `AppTheme` constants (no hardcoded colors)
- [ ] All spacing uses the 4px grid
- [ ] All buttons use `SojornButton` variants
- [ ] All inputs use `SojornInput` or `SojornTextArea`
- [ ] All cards use `SojornCard`
- [ ] All dialogs use `SojornDialog`
- [ ] All snackbars use `SojornSnackbar`
- [ ] Text hierarchy follows the type scale
- [ ] Shadows use the predefined shadow helpers
- [ ] Border radius uses the radius constants

---

## Dark Mode (Optional)

Dark theme uses the same warm philosophy:

```dart
darkBackground      = #1C1B1A  // Warm near-black
darkSurface         = #252422  // Warm dark gray
darkSurfaceElevated = #2E2C2A  // Lighter warm gray
darkTextPrimary     = #ECEBE8  // Warm off-white
```

**Key Difference:**
- No pure black (#000000)
- No pure white (#FFFFFF)
- Reduced contrast for less eye strain

---

## Resources

- [Type Scale Calculator](https://type-scale.com/)
- [Color Palette Generator](https://coolors.co/)
- [Material Design 3 Guidelines](https://m3.material.io/)
- [iOS Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/)

---

**Last Updated:** 2026-01-06
**Maintained By:** Sojorn Design Team
