# SophiaClaw UI Guidelines

**Version:** 1.0.0  
**Last Updated:** March 10, 2026  
**Applies To:** macOS (SwiftUI), TUI (Terminal), A2UI (Chat), iOS/macOS Shared

## 1. Design Token Usage Across Platforms

### 1.1 Color Palette

#### Primary Brand Colors

| Token               | macOS SwiftUI             | TUI (ANSI)         | A2UI/Chat                    | Usage                      |
| ------------------- | ------------------------- | ------------------ | ---------------------------- | -------------------------- |
| `accentPurple`      | `#7B61FF`                 | `#F6C453` (amber)  | `#9333EA`                    | Primary actions, selection |
| `accentPurpleGlow`  | `#7B61FF` @ 30%           | N/A                | N/A                          | Hover states, focus        |
| `backgroundPrimary` | `.windowBackgroundColor`  | `#E8E3D5` (fg)     | `.systemBackground`          | Main surfaces              |
| `surfaceElevated`   | `.controlBackgroundColor` | `#2B2F36` (userBg) | `.secondarySystemBackground` | Cards, panels              |
| `textPrimary`       | `.labelColor`             | `#E8E3D5`          | `.labelColor`                | Primary text               |
| `textSecondary`     | `.secondaryLabelColor`    | `#7B7F87` (dim)    | N/A                          | Secondary text, captions   |
| `borderSubtle`      | `.separatorColor`         | `#3C414B`          | N/A                          | Dividers, borders          |
| `error`             | `.systemRed`              | `#F97066`          | `.systemRed`                 | Error states               |
| `success`           | `.systemGreen`            | `#7DD3A5`          | `.systemGreen`               | Success states             |

#### Semantic Color Mapping

```swift
// macOS SwiftUI (apps/macos/Sources/SOPHIAClaw/Theme/SophiaTheme.swift)
extension Color {
    static let backgroundPrimary = Color(nsColor: .windowBackgroundColor)
    static let surfaceElevated = Color(nsColor: .controlBackgroundColor)
    static let accentPurple = Color(hex: "#7B61FF")
    static let textPrimary = Color(nsColor: .labelColor)
    static let textSecondary = Color(nsColor: .secondaryLabelColor)
    static let borderSubtle = Color(nsColor: .separatorColor)
}
```

```typescript
// TUI (src/tui/theme/theme.ts)
const palette = {
  text: "#E8E3D5",
  dim: "#7B7F87",
  accent: "#F6C453",
  // Terminal uses amber primary instead of purple
  error: "#F97066",
  success: "#7DD3A5",
};
```

#### TUI Palette Reference

All terminal UI colors use ANSI-safe hex values:

```typescript
const palette = {
  // Base
  text: "#E8E3D5", // Primary foreground
  dim: "#7B7F87", // Muted text
  border: "#3C414B", // Dividers

  // Accents
  accent: "#F6C453", // Primary (amber for terminal)
  accentSoft: "#F2A65A", // Secondary accent

  // Semantic
  success: "#7DD3A5", // Green success
  error: "#F97066", // Red error
  link: "#7DD3A5", // Clickable links

  // Backgrounds
  userBg: "#2B2F36", // User message background
  codeBlock: "#1E232A", // Code block background
  toolSuccessBg: "#1E2D23", // Tool success state
  toolErrorBg: "#2F1F1F", // Tool error state
};
```

### 1.2 Typography

#### macOS Typography Scale

| Token              | Size | Weight   | Design  | Usage           |
| ------------------ | ---- | -------- | ------- | --------------- |
| `sophiaLargeTitle` | 32pt | Bold     | Rounded | Page titles     |
| `sophiaTitle`      | 28pt | Semibold | Rounded | Section headers |
| `sophiaHeadline`   | 17pt | Semibold | Default | Card titles     |
| `sophiaBody`       | 15pt | Regular  | Default | Body text       |
| `sophiaCaption`    | 12pt | Medium   | Default | Captions, hints |

```swift
// apps/macos/Sources/SOPHIAClaw/Theme/SophiaTheme.swift
extension Font {
    static let sophiaTitle = Font.system(size: 28, weight: .semibold, design: .rounded)
    static let sophiaHeadline = Font.system(size: 17, weight: .semibold)
    static let sophiaBody = Font.system(size: 15, weight: .regular)
    static let sophiaCaption = Font.system(size: 12, weight: .medium)
    static let sophiaLargeTitle = Font.system(size: 32, weight: .bold, design: .rounded)
}
```

#### TUI Typography

Terminal uses ANSI formatting for emphasis:

- `chalk.bold()` - Headings, emphasis
- `chalk.italic()` - Secondary information
- `chalk.dim()` - Captions, hints
- `chalk.hex(color)` - Colored text (ANSI-safe)

### 1.3 Animation & Motion

#### macOS Animation Constants

| Token       | Duration | Easing      | Usage                  |
| ----------- | -------- | ----------- | ---------------------- |
| `micro`     | 0.15s    | N/A         | Cursor, small feedback |
| `standard`  | 0.3s     | EaseOut/In  | Transitions, hover     |
| `cinematic` | 0.5s     | N/A         | Large view changes     |
| `spring`    | 0.35s    | Damping 0.8 | Interactive motion     |

```swift
enum AnimationDuration {
    static let micro: Double = 0.15
    static let standard: Double = 0.3
    static let cinematic: Double = 0.5
}

enum AnimationStyle {
    static let spring = Animation.spring(response: 0.35, dampingFraction: 0.8)
    static let easeOut = Animation.easeOut(duration: AnimationDuration.standard)
}
```

#### Motion Reduction Support

```swift
// Respect user accessibility preferences
@Environment(\.accessibilityReduceMotion) private var reduceMotion

// Usage example (ChatMessageViews.swift:576)
animation(
    reduceMotion ? .linear(duration: 0.1) : .spring(response: 0.35, dampingFraction: 0.8),
    value: animatedValue
)
```

## 2. Component Standardization Patterns

### 2.1 Reusable View Modifiers (macOS)

#### Card Style

```swift
struct SophiaCardStyle: ViewModifier {
    let isHovered: Bool

    func body(content: Content) -> some View {
        content
            .background(/* elevated surface */)
            .cornerRadius(16)
            .overlay(/* inner highlight + border */)
            .shadow(color: isHovered ? .accentPurple.opacity(0.2) : .black.opacity(0.08),
                    radius: isHovered ? 16 : 8)
            .animation(.easeOut(duration: 0.25), value: isHovered)
    }
}

extension View {
    func sophiaCard(isHovered: Bool = false) -> some View {
        modifier(SophiaCardStyle(isHovered: isHovered))
    }
}
```

#### Button Style

```swift
struct SophiaButtonStyle: ButtonStyle {
    let isPrimary: Bool

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.sophiaBody.weight(.medium))
            .padding(.horizontal, 20)
            .padding(.vertical, 10)
            .background(Capsule()
                .fill(isPrimary ? .accentPurple : .clear)
                .overlay(Capsule()
                    .stroke(isPrimary ? .clear : .borderSubtle, lineWidth: 1)))
            .foregroundColor(isPrimary ? .white : .textPrimary)
            .scaleEffect(configuration.isPressed ? 0.97 : 1.0)
            .animation(.easeOut(duration: 0.1), value: configuration.isPressed)
    }
}
```

#### Sidebar Item Style

```swift
struct SophiaSidebarItemStyle: ViewModifier {
    let isSelected: Bool
    @State private var isHovered = false

    func body(content: Content) -> some View {
        content
            .padding(.horizontal, 12)
            .padding(.vertical, 8)
            .background(RoundedRectangle(cornerRadius: 10)
                .fill(isSelected ? .accentPurple.opacity(0.12) : .clear))
            .overlay(RoundedRectangle(cornerRadius: 10)
                .stroke(isSelected ? .accentPurple.opacity(0.4) : .clear,
                        lineWidth: isSelected ? 1.5 : 0))
            .onHover { isHovered = $0 }
            .animation(.easeOut(duration: 0.2), value: isSelected)
    }
}
```

### 2.2 Chat UI Components (Shared)

#### Bubble Colors

```swift
enum SOPHIAClawChatTheme {
    static var userBubble: Color {
        Color(purple: 147/255.0, green: 51/255.0, blue: 234/255.0).opacity(0.15)
    }

    static var assistantBubble: Color {
        Color(nsColor: self.assistantBubbleDynamicNSColor)
    }

    static var onboardingAssistantBorder: Color {
        Color.white.opacity(0.12)
    }
}
```

#### Dynamic Color Providers (Dark Mode Support)

```swift
static func resolvedAssistantBubbleColor(for appearance: NSAppearance) -> NSColor {
    appearance.isDarkAqua
        ? NSColor(purple: 35/255, green: 35/255, blue: 45/255, alpha: 0.95)
        : NSColor(white: 0.94, alpha: 0.92)
}
```

### 2.3 TUI Component Patterns

#### Component Themes

All TUI components export consistent theme types:

```typescript
// Theme export pattern
export const markdownTheme: MarkdownTheme = { ... }
export const selectListTheme: SelectListTheme = { ... }
export const editorTheme: EditorTheme = { ... }
```

#### Syntax Highlighting

```typescript
function highlightCode(code: string, lang?: string): string[] {
  const language = lang && supportsLanguage(lang) ? lang : undefined;
  const highlighted = highlight(code, { language, theme: syntaxTheme });
  return highlighted.split("\n");
}
```

## 3. Cross-Platform Consistency Checklist

### 3.1 Visual Consistency

#### Color Alignment

- [ ] Purple accent maps correctly across platforms (SwiftUI `#7B61FF`, Chat `#9333EA`)
- [ ] TUI uses amber `#F6C453` for terminal compatibility (purple doesn't render well in all terminals)
- [ ] Error states use red consistently (`#F97066` TUI, `.systemRed` macOS)
- [ ] Success states use green consistently (`#7DD3A5` TUI, `.systemGreen` macOS)
- [ ] Dark mode supported everywhere (dynamic providers in SwiftUI, dark palette in TUI)

#### Typography Alignment

- [ ] Heading hierarchy consistent (Large > Title > Headline > Body > Caption)
- [ ] Font weights consistent (Bold > Semibold > Medium > Regular)
- [ ] TUI uses ANSI bold/italic to match SwiftUI weight semantics

#### Spacing & Layout

- [ ] Card corner radius: 16pt (macOS) ~ equivalent visual weight in TUI (rounded border)
- [ ] Button padding: 20x10pt (macOS) ~ equivalent proportional spacing in TUI
- [ ] Elevation levels: Primary surface < Elevated surface < Modal

### 3.2 Interaction Patterns

#### Hover States

- [ ] macOS: `.accentPurple.opacity(0.2)` glow on hover
- [ ] TUI: Brighter accent color on hover
- [ ] Timing: 0.15-0.25s transition

#### Press States

- [ ] macOS: `scaleEffect(0.97)` on press
- [ ] TUI: Inverted colors on selection

#### Selection States

- [ ] macOS: `.accentPurple.opacity(0.12)` background + accent border
- [ ] TUI: Bold accent color + prefix marker
- [ ] iOS: System blue equivalent

### 3.3 Animation Timing

| Platform | Micro     | Standard      | Slow |
| -------- | --------- | ------------- | ---- |
| macOS    | 0.15s     | 0.3s          | 0.5s |
| TUI      | _instant_ | 0.2s (cursor) | N/A  |
| iOS      | 0.15s     | 0.3s          | 0.5s |

### 3.4 Consistency Validation Script

```bash
# Run consistency checks
pnpm audit-themes --compare macos,tui,chat
# Verify color hex values align
# Verify component patterns match
# Verify animation timings documented
```

## 4. Accessibility Best Practices

### 4.1 WCAG 2.1 AA Compliance

#### Color Contrast Requirements

**Normal Text (< 18pt or < 14pt bold):**

- Minimum contrast ratio: **4.5:1** against background

**Large Text (≥ 18pt or ≥ 14pt bold):**

- Minimum contrast ratio: **3:1** against background

**UI Components & Graphics:**

- Minimum contrast ratio: **3:1** against adjacent colors

**Verified Color Pairs:**

| Foreground         | Background               | Ratio  | Compliance  |
| ------------------ | ------------------------ | ------ | ----------- |
| `#E8E3D5` (text)   | `#2B2F36` (userBg)       | 6.2:1  | ✅ AA       |
| `#7B7F87` (dim)    | `#2B2F36` (userBg)       | 2.8:1  | ❌ AAA only |
| `#F6C453` (accent) | `#1E232A` (codeBlock)    | 8.1:1  | ✅ AA+      |
| `#F97066` (error)  | `#2F1F1F` (toolErrorBg)  | 5.4:1  | ✅ AA       |
| `.labelColor`      | `.windowBackgroundColor` | System | ✅ AA       |

**Action:** Use `#7B7F87` (dim) only for decorative text, not essential content.

### 4.2 Keyboard Navigation

#### macOS Keyboard Patterns

```swift
// Tab traversal
NavigationView {
    TextField("Search", text: $searchQuery)
        .textFieldStyle(.roundedBorder)

    Button("Submit") { /* */ }
        .keyboardShortcut(.defaultAction)

    Button("Cancel") { /* */ }
        .keyboardShortcut(.cancelAction)
}

// Custom key commands
.onKeyPress(.escape) {
    dismiss()
    .handled(true)
}
```

#### TUI Keyboard Navigation

```typescript
// FilterableList pattern
// Arrow keys: Up/Down navigation
// Enter: Select
// Escape: Cancel
// Tab: Switch focus
// Type-ahead: Filter search

keyboardHandler = {
  ArrowUp: () => selectPrev(),
  ArrowDown: () => selectNext(),
  Enter: () => confirm(),
  Escape: () => cancel(),
  Tab: () => switchFocus(),
};
```

#### Keyboard Accessibility Checklist

- [ ] All interactive elements reachable via Tab
- [ ] Visual focus indicator on all focused elements
- [ ] Logical tab order (top-to-bottom, left-to-right)
- [ ] No keyboard traps (can navigate away from all elements)
- [ ] Skip links for repetitive navigation
- [ ] Mnemonic keys for frequent actions (e.g., `Cmd+S` save)

### 4.3 Screen Reader Support

#### macOS VoiceOver Patterns

```swift
// Accessibility labels
Button("Submit") {
    // action
}
.accessibilityLabel("Submit")
.accessibilityHint("Commits the current configuration")
.accessibilityState(.isSelected, selectionState)

// Grouping related elements
HStack {
    Text("Status:")
    StatusIndicator(isActive: true)
}
.accessibilityElement(children: .combine)
.accessibilityLabel("Status: Active")

// Custom actions
.accessibilityAction(named: "Toggle") {
    toggle()
    return true
}
```

#### Dynamic Content Announcements

```swift
// Accessibility announcements
.onChange(of: status) { newStatus in
    UIAccessibility.post(
        notification: .announcement,
        argument: status
    )
}
```

#### TUI Screen Reader Considerations

Terminal interfaces are inherently screen reader accessible through:

1. **Text-only content** - All information is readable
2. **Linear layout** - Natural reading order
3. **ANSI escape codes** - Some readers parse colors for context

**Best Practices:**

- [ ] Avoid relying solely on color for meaning
- [ ] Use text indicators alongside color (e.g., "[x]" not just green)
- [ ] Maintain logical line ordering
- [ ] Provide text alternatives for box-drawing characters

### 4.4 Focus Management

#### macOS Focus Patterns

```swift
// Initial focus
.onAppear {
    DispatchQueue.main.async {
        focusField.becomeFirstResponder()
    }
}

// Focus restoration after modal
@FocusState private var isFocused: Bool

// Focus indicators
.focused($isFocused)
.overlay(
    RoundedRectangle(cornerRadius: 8)
        .stroke(isFocused ? .accentPurple : .clear, lineWidth: 2)
)
```

#### Move-by-Move Focus (Vision Pro Consideration)

```swift
// Explicit focus scopes
FocusScope {
    ForEach(items) { item in
        FocusableButton {
            select(item)
        }
    }
}
.focusScope(.named("itemList"))
```

### 4.5 Motion & Vestibular Considerations

#### Respect Reduce Motion

```swift
@Environment(\.accessibilityReduceMotion) private var reduceMotion

animation(
    reduceMotion ? .linear(duration: 0.1) : .spring(response: 0.35),
    value: animatedValue
)
```

**Implementation found:** `apps/shared/Sources/SOPHIAClawChatUI/ChatMessageViews.swift:576`

#### Reduced Motion Guidelines

- [ ] Disable parallax effects when `reduceMotion` enabled
- [ ] Replace spring animations with linear ease
- [ ] Reduce animation duration to < 0.2s
- [ ] Avoid automatic scrolling animations
- [ ] Provide static alternatives for loading spinners

### 4.6 Accessibility Audit Checklist

#### Quarterly Audit Items

1. **Color Contrast**
   - [ ] Test all text/background combinations
   - [ ] Verify 4.5:1 ratio for normal text
   - [ ] Verify 3:1 ratio for large text & UI components

2. **Keyboard Navigation**
   - [ ] Tab through all interactive elements
   - [ ] Verify focus visibility
   - [ ] Test with only keyboard (no mouse)
   - [ ] Verify escape closes modals/menus

3. **Screen Reader**
   - [ ] Test all pages with VoiceOver (macOS) / NVDA (Windows)
   - [ ] Verify all images have alt text
   - [ ] Verify form fields have labels
   - [ ] Verify dynamic content announcements

4. **Motion**
   - [ ] Test with "Reduce Motion" enabled
   - [ ] Verify no disorienting animations
   - [ ] Verify content accessible without motion

5. **Cognitive Load**
   - [ ] Consistent navigation patterns
   - [ ] Clear error messages with recovery steps
   - [ ] Predictable component behavior
   - [ ] Undo available for destructive actions

## 5. Implementation Notes

### 5.1 Theme File Locations

| Platform       | Theme File          | Location                                              |
| -------------- | ------------------- | ----------------------------------------------------- |
| macOS SwiftUI  | `SophiaTheme.swift` | `apps/macos/Sources/SOPHIAClaw/Theme/`                |
| macOS/iOS Chat | `ChatTheme.swift`   | `apps/shared/SOPHIAClawKit/Sources/SOPHIAClawChatUI/` |
| TUI            | `theme.ts`          | `src/tui/theme/`                                      |

### 5.2 Adding New Colors

**macOS SwiftUI:**

```swift
extension Color {
    static let customName = Color(hex: "#XXXXXX") ?? Color.fallback
}
```

**TUI:**

```typescript
const palette = {
  ...existing,
  customName: "#XXXXXX",
};
```

**Chat UI:**

```swift
static var customColor: Color {
    Color(purple: R/255, green: G/255, blue: B/255)
}
```

### 5.3 Accessibility Testing Tools

#### macOS

- **VoiceOver:** System Preferences > Accessibility > VoiceOver
- **Contrast Checker:** Use `color-accessibility` Xcode tool
- **Keyboard Navigation:** System Preferences > Keyboard > Shortcuts

#### TUI

- **Manual testing:** Use screen readers (NVDA, JAWS)
- **Contrast:** Use `wcag-contrast` npm package
- **Linear order:** Verify reading order matches visual layout

### 5.4 Accessibility Planned Work

**Scheduled:**

- [ ] Systematic accessibility audit across all platforms
- [ ] Automated contrast ratio testing in CI/CD
- [ ] Screen reader testing documentation
- [ ] Keyboard navigation E2E tests

**Reference:** See `docs/multi-role-analysis/COMMUNITY_EDITION_TODO.md` section 10 for accessibility audit status.

---

## Related Documentation

- [Multi-Role Analysis](/docs/multi-role-analysis/COMMUNITY_EDITION_TODO.md) - Design System status
- [Security Guidelines](/docs/security/SCENARIOS.md) - UI security considerations
- [Testing Guide](/docs/testing.md) - UI testing patterns
