Files
roa2web-service-auto/docs/DESIGN.md
Claude Agent 8234103884 fix(design): mobile receipt form layout + confidence badges + DESIGN.md
Fix mobile layout issues on /data-entry/create after OCR upload:
- CompactUploadZone action bar forced horizontal on mobile (was stacking
  vertically due to global .action-bar column rule in containers.css)
- TOTAL input stretches full width on mobile (was fixed 140px)
- Card/Cash/Alte payment inputs equal width via flex: 1 1 0%
- Extra-small (≤360px) fallback stacks payments vertically
- OCR confidence badges: fixed width (icon-only), hidden percentage text,
  hover opacity effect — prevents input misalignment
- OCRConfidenceIndicator: replace hardcoded colors with design tokens
  (green-100/800, yellow-100/800, red-100/800), add three-tier dark mode
- Smaller size-small badge variant (border-radius-sm, line-height: 1)

Create docs/DESIGN.md as design source of truth for /design-review,
/plan-design-review, and /frontend-design skills.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:40:42 +00:00

432 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ROA2WEB Design System
**Version:** 1.0.0 | **Updated:** 2026-03-23 | **Status:** Source of Truth
---
## 1. Design Philosophy
ROA2WEB is an ERP application for accounting and financial data management. The design prioritizes:
- **Data density over whitespace** — Users process hundreds of records daily; every pixel earns its space
- **Scan-friendly hierarchy** — Bold totals, muted labels, color-coded sections guide the eye
- **Compact, not cramped** — 32px input height, 8px gaps, systematic spacing scale
- **Professional restraint** — No decorative elements, no hero sections, no gratuitous animation
- **Trust at the pixel level** — Financial data demands precision; misaligned inputs erode confidence
- **System fonts for speed** — No custom font loading; native OS typography feels fast and familiar
- **Progressive disclosure** — Show summary first, reveal detail on demand (collapsible sections, tooltips, bottom sheets)
---
## 2. Visual Identity
### Brand Colors
| Role | Token | Hex (Light) | Usage |
|------|-------|-------------|-------|
| Primary | `--color-primary` | #2563eb | Actions, links, focus rings, active states |
| Primary Dark | `--color-primary-dark` | #1d4ed8 | Hover states, pressed buttons |
| Success | `--color-success` | #059669 | Approvals, positive values, confirmations |
| Warning | `--color-warning` | #d97706 | Pending states, caution alerts, mismatches |
| Error | `--color-error` | #dc2626 | Rejections, validation errors, negative values |
| Info | `--color-info` | #0891b2 | Informational badges, OCR hints |
### Surface Hierarchy
```
Ground (#f8fafc) → Section → Card (#ffffff) → Overlay
↓ darkest ↓ lightest ↓ modal/dropdown
```
Each level uses progressively elevated surface tokens. In dark mode, the scale inverts (darker = lower, lighter = higher).
| Token | Light | Dark | Purpose |
|-------|-------|------|---------|
| `--surface-ground` | #f8fafc | #0f172a | Page background |
| `--surface-card` | #ffffff | #1e293b | Card/container backgrounds |
| `--surface-hover` | #f1f5f9 | #334155 | Hover states, chips |
| `--surface-border` | #e2e8f0 | #475569 | Borders, dividers |
| `--text-color` | #111827 | #f9fafb | Primary text |
| `--text-color-secondary` | #6b7280 | #d1d5db | Labels, hints, metadata |
> **Full palette reference**: [DESIGN_TOKENS.md](./DESIGN_TOKENS.md)
---
## 3. Color System
### Semantic Color Roles
Always use semantic tokens, never raw hex values:
```css
/* Backgrounds */
background: var(--surface-card); /* Cards, modals */
background: var(--surface-ground); /* Page background */
background: var(--surface-hover); /* Hover states, chips */
/* Text */
color: var(--text-color); /* Primary text */
color: var(--text-color-secondary); /* Labels, hints */
/* Borders */
border-color: var(--surface-border); /* Standard borders */
```
### Status Color Scales
Each status has a 50-900 scale. Use **100** for backgrounds, **800** for text in light mode:
| Status | Background | Text | Border | Use For |
|--------|-----------|------|--------|---------|
| Success | `--green-100` | `--green-800` | `--green-300` | Approvals, positive values, OCR high confidence |
| Warning | `--yellow-100` | `--yellow-800` | `--yellow-300` | Pending, caution, OCR medium confidence |
| Error | `--red-100` | `--red-800` | `--red-300` | Rejections, errors, OCR low confidence |
| Info | `--blue-100` | `--blue-800` | `--blue-300` | Informational, OCR hints, categorization |
### OCR Confidence Colors
| Level | Threshold | Background | Text | Icon |
|-------|-----------|-----------|------|------|
| High | >= 85% | `--green-100` | `--green-800` | `pi-check-circle` |
| Medium | >= 60% | `--yellow-100` | `--yellow-800` | `pi-exclamation-circle` |
| Low | < 60% | `--red-100` | `--red-800` | `pi-question-circle` |
### Color-Coded Form Sections
- **Green background** (`--green-50`): Financial values (TOTAL, payments, TVA)
- **Blue background** (`--blue-50`): Categorization (expense type, description)
- **Cyan background** (`--cyan-50`): Client/B2B information
- **No background**: Standard form fields (supplier, document)
---
## 4. Typography
### Font Stack
```css
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-family: var(--font-mono); /* For financial values, code */
```
### Scale
| Token | Size | Usage |
|-------|------|-------|
| `--text-xs` | 12px | Labels, badges, metadata, timestamps, hints |
| `--text-sm` | 14px | Table cells, form inputs, secondary text, buttons |
| `--text-base` | 16px | Body text, primary content (default) |
| `--text-lg` | 18px | Subheadings |
| `--text-xl` | 20px | Card titles, section headings |
| `--text-2xl` | 24px | Page titles, metric values, KPI numbers |
| `--text-3xl` | 32px | Dashboard hero numbers |
| `--text-4xl` | 40px | Reserved for exceptional emphasis |
### Weight Rules
| Token | Value | Usage |
|-------|-------|-------|
| `--font-normal` | 400 | Body text, table cells, descriptions |
| `--font-medium` | 500 | Labels, buttons, badges, emphasis |
| `--font-semibold` | 600 | Headings, financial totals, card titles |
| `--font-bold` | 700 | TOTAL labels, strong emphasis, alerts |
### Financial Numbers
All financial values use `font-variant-numeric: tabular-nums` for column alignment.
---
## 5. Spacing & Layout
### Spacing Scale
| Token | Value | Primary Use |
|-------|-------|------------|
| `--space-xs` | 4px | Icon gaps, badge padding, tight internal spacing |
| `--space-sm` | 8px | Related item gaps, compact form spacing |
| `--space-md` | 16px | Standard component padding, section gaps |
| `--space-lg` | 24px | Card padding, section separation |
| `--space-xl` | 32px | Page margins, major separations |
| `--space-2xl` | 48px | Layout sections |
| `--space-3xl` | 64px | Page-level spacing |
### Form Layout Rules
- **Input height**: 32px for compact forms, 40px for standalone forms
- **Input font**: `--text-sm` (14px) for form inputs
- **Numeric inputs**: `text-align: right` always
- **Labels**: `--text-xs` (12px), `--font-semibold`, `--text-color-secondary`
- **Layout**: Inline labels next to inputs on desktop, stacked on mobile
- **Row gaps**: `--space-sm` (8px) between form rows
- **Row borders**: `1px solid var(--surface-border)` between rows
### Breakpoints
| Name | Width | Layout Behavior |
|------|-------|----------------|
| Extra-small | 360px | Payment inputs stack vertically, minimal padding |
| Mobile | 768px | Single column, stacked forms, bottom sheets for filters |
| Tablet | 769-1023px | Hybrid layout, wider cards |
| Desktop | 1024px | Full multi-column, inline forms, side-by-side panels |
| Wide | 1400px | Max content width, centered layout |
---
## 6. Component Patterns
### Cards
```css
/* Standard card */
background: var(--surface-card);
border-radius: var(--radius-md); /* 8px */
padding: var(--space-lg); /* 24px */
box-shadow: var(--shadow-sm);
/* Compact card (data-dense views) */
padding: var(--space-md); /* 16px */
/* Metric/KPI card */
/* Icon + --text-2xl value + --text-xs label + trend indicator */
```
### Buttons
- Primary: `--color-primary` background, white text
- Secondary: Outlined or text-only (`severity="secondary"`)
- Minimum touch target: 44x44px on mobile
- Icon buttons: 32x32px on desktop, 44x44px on mobile
### Tables (PrimeVue DataTable)
- Separate Debit/Credit columns (never stacked in one cell)
- Filter buttons on dedicated row below filters
- Export exports ALL data, not just current page
- All overrides in `vendor/primevue-overrides.css` never use `:deep()` in components
### Dropdowns in Compact Forms
Use `dropdown-borderless` class for inline dropdowns:
```html
<Dropdown ... class="my-select dropdown-borderless" />
```
> **Full pattern reference**: [CSS_PATTERNS.md](./CSS_PATTERNS.md)
---
## 7. Form Design
### Receipt Form Layout (UnifiedReceiptForm)
Ultra-compact flat layout with color-coded sections:
```
┌─────────────────────────────────────────────┐
│ Furnizor [AutoComplete____] CUI [___] 🟢 ↻ │ ← white bg
├─────────────────────────────────────────────┤
│ OCR: Lidl Discount SRL (22891860) │ ← blue-50 hint
├─────────────────────────────────────────────┤
│ [Bon fiscal ▾] Nr. [___] Data [___] 🟢 │ ← white bg
├─────────────────────────────────────────────┤
│ TOTAL [_140px_] 🟢 Card [_120px_] │ ← green-50 bg
│ Cash [_120px_] │
│ Alte [_120px_] 🟢 │
├─────────────────────────────────────────────┤
│ TVA: [19% ▾][___] [9% ▾][___] 🟢 │ ← white bg
├─────────────────────────────────────────────┤
│ [Cheltuiala... ▾] │ ← blue-50 bg
│ [Descriere...________________________] │
├─────────────────────────────────────────────┤
│ Atasamente: [📄 bon.pdf ✕] [] │ ← white bg
└─────────────────────────────────────────────┘
```
### OCR Confidence Badges
- **Placement**: Inline, next to the input they describe
- **Display**: Icon-only in compact form (percentage hidden, available via tooltip)
- **Sizing**: Fixed reserved width (20px) to prevent input misalignment
- **Hover**: `opacity: 0.85 → 1` transition for discoverability
- **Interaction**: `cursor: help`, tooltip shows full percentage on hover/tap
### Input Conventions
```css
/* All compact form inputs */
height: 32px;
padding: var(--space-xs) var(--space-sm);
font-size: var(--text-sm);
border: 1px solid var(--surface-border);
border-radius: var(--radius-sm);
/* Financial inputs additionally */
text-align: right;
font-variant-numeric: tabular-nums;
```
---
## 8. Mobile Strategy
### Philosophy
MD3-inspired (Material Design 3) touch-first design. Mobile is not "desktop shrunk" it gets intentional layout.
### Required Components (ALL mobile views)
| Component | Location | Purpose |
|-----------|----------|---------|
| MobileTopBar | `@shared/components/mobile/MobileTopBar.vue` | Fixed header (56px), title, actions |
| MobileBottomNav | `@shared/components/mobile/MobileBottomNav.vue` | Fixed footer (56px), tab navigation |
| BottomSheet | `@shared/components/mobile/BottomSheet.vue` | Filters, extended options (slides up) |
| MobileSelectionFooter | `@shared/components/mobile/MobileSelectionFooter.vue` | Batch actions when items selected |
### Content Padding
```css
.mobile-content {
padding-top: 56px; /* MobileTopBar height */
padding-bottom: 56px; /* MobileBottomNav height */
}
```
### Mobile Form Rules
- **Full-width inputs**: Stacked vertically, `width: 100%`
- **Payment inputs**: Equal-width side-by-side (`flex: 1 1 0%`), stack on extra-small (≤360px)
- **Confidence badges**: Icon-only, no percentage text
- **Filters**: Always in BottomSheet, never inline
- **Selection actions**: Always in MobileSelectionFooter, never in header
- **Upload zone**: Reduced height (24px min) after file selection
### Touch Targets
- **Minimum**: 44x44px for all interactive elements (buttons, links, checkboxes)
- **Input font**: 16px minimum to prevent iOS zoom
- **Active feedback**: `scale(0.98)` on touch for responsive feel
> **Full mobile guide**: [MOBILE_PATTERNS.md](./MOBILE_PATTERNS.md)
---
## 9. Dark Mode
### Three-Tier System
| Mode | Trigger | CSS Selector |
|------|---------|-------------|
| Auto (default) | OS preference | `@media (prefers-color-scheme: dark)` + `:root:not([data-theme])` |
| Light | User toggle | `[data-theme="light"]` on `<html>` |
| Dark | User toggle | `[data-theme="dark"]` on `<html>` |
### CSS Priority
```
[data-theme="dark/light"] > @media (prefers-color-scheme) > :root (light default)
```
### Implementation Pattern
```css
/* Light mode (default) */
.component { background: var(--green-100); color: var(--green-800); }
/* Dark mode — explicit toggle */
[data-theme="dark"] .component {
background: rgba(34, 197, 94, 0.2);
color: var(--green-400);
}
/* Dark mode — auto (prefers-color-scheme) */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) .component {
background: rgba(34, 197, 94, 0.2);
color: var(--green-400);
}
}
```
### Key Rules
- **Always** use semantic tokens (`--surface-card`, `--text-color`) they auto-adapt
- **Status colors**: Use `rgba()` overlays in dark mode, not the inverted scale tokens
- **Persistence**: `localStorage['user-theme']` stores user choice
- **Toggle**: Theme button in `AppHeader.vue` cycles auto light dark
### Testing Checklist
1. Click theme button in header (cycles auto light dark)
2. DevTools Rendering Emulate CSS media `prefers-color-scheme: dark`
3. Verify all text remains readable
4. Verify colored sections (green, blue) are visible but not harsh
---
## 10. Accessibility
### Targets
- **WCAG 2.1 AA** compliance
- **Color contrast**: `--color-text` provides 16.9:1 ratio, `--color-text-secondary` provides 4.6:1
### Focus States
```css
outline: 2px solid var(--color-primary);
outline-offset: 2px;
```
### Touch Targets
- All interactive elements: minimum 44x44px on mobile
- Added via `min-height: 44px; min-width: 44px` on touch devices
### Heading Hierarchy
- Sequential: h1 > h2 > h3 (no skipping levels)
- One `<h1>` per page (page title)
- `<h2>` for sections, `<h3>` for subsections
### Screen Reader Support
- `.sr-only` class for visually hidden but accessible text
- ARIA landmarks on major regions
- Meaningful `alt` text on all images
### Reduced Motion
```css
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
```
---
## 11. Reference Index
| Document | Purpose | Read When |
|----------|---------|-----------|
| [DESIGN_TOKENS.md](./DESIGN_TOKENS.md) | Complete token reference with all variables | Looking up specific token values |
| [CSS_PATTERNS.md](./CSS_PATTERNS.md) | Reusable component CSS patterns | Building or styling components |
| [ONBOARDING_CSS.md](./ONBOARDING_CSS.md) | CSS system quick start (5 min) | New to the project's frontend |
| [MOBILE_PATTERNS.md](./MOBILE_PATTERNS.md) | Mobile component library and patterns | Building mobile views |
| [ARCHITECTURE-DECISIONS.md](./ARCHITECTURE-DECISIONS.md) | Technical architecture decisions | Understanding "why" behind choices |
### CSS File Structure
```
src/assets/css/
├── core/ # Foundation: variables, tokens, md3-tokens, reset, typography
├── layout/ # Grid, containers, navigation
├── components/ # Cards, buttons, tables, forms, stats
├── patterns/ # Interactive, dashboard, animations
├── utilities/ # Spacing, display, text, flex, colors
├── vendor/ # PrimeVue overrides (centralized, never :deep())
├── mobile.css # Mobile optimizations (imported last)
└── main.css # Entry point with import cascade
```