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>
15 KiB
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
3. Color System
Semantic Color Roles
Always use semantic tokens, never raw hex values:
/* 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
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: rightalways - 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
/* 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-primarybackground, 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:
<Dropdown ... class="my-select dropdown-borderless" />
Full pattern reference: 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 → 1transition for discoverability - Interaction:
cursor: help, tooltip shows full percentage on hover/tap
Input Conventions
/* 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
.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
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
/* 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.vuecycles auto → light → dark
Testing Checklist
- Click theme button in header (cycles auto → light → dark)
- DevTools → Rendering → Emulate CSS media →
prefers-color-scheme: dark - Verify all text remains readable
- Verify colored sections (green, blue) are visible but not harsh
10. Accessibility
Targets
- WCAG 2.1 AA compliance
- Color contrast:
--color-textprovides 16.9:1 ratio,--color-text-secondaryprovides 4.6:1
Focus States
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: 44pxon 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-onlyclass for visually hidden but accessible text- ARIA landmarks on major regions
- Meaningful
alttext on all images
Reduced Motion
@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 | Complete token reference with all variables | Looking up specific token values |
| CSS_PATTERNS.md | Reusable component CSS patterns | Building or styling components |
| ONBOARDING_CSS.md | CSS system quick start (5 min) | New to the project's frontend |
| MOBILE_PATTERNS.md | Mobile component library and patterns | Building mobile views |
| 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