diff --git a/docs/DESIGN.md b/docs/DESIGN.md new file mode 100644 index 0000000..b2d71ac --- /dev/null +++ b/docs/DESIGN.md @@ -0,0 +1,431 @@ +# 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 + +``` + +> **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 `` | +| Dark | User toggle | `[data-theme="dark"]` on `` | + +### 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 `

` per page (page title) +- `

` for sections, `

` 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 +``` diff --git a/src/assets/css/layout/containers.css b/src/assets/css/layout/containers.css index ad07a08..fba9439 100644 --- a/src/assets/css/layout/containers.css +++ b/src/assets/css/layout/containers.css @@ -189,6 +189,12 @@ flex-direction: column; align-items: stretch; } + + /* Keep compact upload action bar horizontal on mobile */ + .compact-upload-zone .action-bar { + flex-direction: row; + align-items: center; + } } @media (max-width: 480px) { diff --git a/src/modules/data-entry/components/ocr/OCRConfidenceIndicator.vue b/src/modules/data-entry/components/ocr/OCRConfidenceIndicator.vue index f4e8c5f..8fd928a 100644 --- a/src/modules/data-entry/components/ocr/OCRConfidenceIndicator.vue +++ b/src/modules/data-entry/components/ocr/OCRConfidenceIndicator.vue @@ -73,17 +73,19 @@ const tooltipText = computed(() => { .confidence-indicator { display: inline-flex; align-items: center; - gap: 0.25rem; - padding: 0.15rem 0.5rem; - border-radius: 12px; - font-size: 0.75rem; - font-weight: 500; + gap: var(--space-xs); + padding: 2px var(--space-sm); + border-radius: var(--radius-lg); + font-size: var(--text-xs); + font-weight: var(--font-medium); } /* Sizes */ .size-small { font-size: 0.7rem; - padding: 0.1rem 0.35rem; + padding: 1px var(--space-xs); + border-radius: var(--radius-sm); + line-height: 1; } .size-small i { @@ -96,7 +98,7 @@ const tooltipText = computed(() => { .size-large { font-size: 0.85rem; - padding: 0.2rem 0.6rem; + padding: 2px var(--space-sm); } .size-large i { @@ -105,21 +107,55 @@ const tooltipText = computed(() => { /* Confidence levels */ .high { - background: #dcfce7; - color: #166534; + background: var(--green-100); + color: var(--green-800); } .medium { - background: #fef9c3; - color: #854d0e; + background: var(--yellow-100); + color: var(--yellow-800); } .low { - background: #fee2e2; - color: #991b1b; + background: var(--red-100); + color: var(--red-800); } .percentage { font-variant-numeric: tabular-nums; } + +/* Dark mode — explicit toggle */ +[data-theme="dark"] .high { + background: rgba(34, 197, 94, 0.2); + color: var(--green-400); +} + +[data-theme="dark"] .medium { + background: rgba(234, 179, 8, 0.2); + color: var(--yellow-400); +} + +[data-theme="dark"] .low { + background: rgba(220, 38, 38, 0.2); + color: var(--red-400); +} + +/* Dark mode — auto (prefers-color-scheme) */ +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) .high { + background: rgba(34, 197, 94, 0.2); + color: var(--green-400); + } + + :root:not([data-theme="light"]) .medium { + background: rgba(234, 179, 8, 0.2); + color: var(--yellow-400); + } + + :root:not([data-theme="light"]) .low { + background: rgba(220, 38, 38, 0.2); + color: var(--red-400); + } +} diff --git a/src/modules/data-entry/components/receipts/CompactUploadZone.vue b/src/modules/data-entry/components/receipts/CompactUploadZone.vue index 508a184..9f9c5b1 100644 --- a/src/modules/data-entry/components/receipts/CompactUploadZone.vue +++ b/src/modules/data-entry/components/receipts/CompactUploadZone.vue @@ -425,12 +425,17 @@ defineExpose({ reset, processOCR }) color: var(--text-color-secondary); } -/* Action bar - single line */ +/* Action bar - single line (override global .action-bar from containers.css) */ .action-bar { display: flex; + flex-direction: row; flex-wrap: nowrap; gap: var(--space-sm); - margin-top: 2px; /* minimal margin */ + margin-top: 2px; + margin-bottom: 0; + padding: 0; + background: transparent; + border-radius: 0; justify-content: center; align-items: center; } @@ -490,7 +495,78 @@ defineExpose({ reset, processOCR }) font-size: var(--text-xs); /* 12px - uniform */ } -/* Responsive */ +/* Mobile: compact upload strip */ +@media (max-width: 768px) { + .compact-upload-zone { + margin-bottom: 2px; + } + + .upload-strip { + min-height: 24px; + padding: 1px var(--space-sm); + } + + .upload-strip.has-file { + min-height: 20px; + } + + .empty-state span { + font-size: var(--text-xs); + } + + .file-name { + max-width: 180px; + font-size: var(--text-xs); + } + + .file-size { + font-size: 0.65rem; + } + + /* Action bar: compact row on mobile + Global override is in containers.css (.compact-upload-zone .action-bar) */ + .action-bar { + margin-top: 1px; + gap: 2px; + flex-wrap: nowrap; + justify-content: center; + } + + .action-bar :deep(.p-button) { + height: 24px; + min-width: 24px; + padding: 2px var(--space-xs); + font-size: 0.7rem; + } + + /* Hide refresh button label, keep icon only */ + .action-bar :deep(.p-button .p-button-label) { + font-size: 0.7rem; + } + + .engine-selector { + min-width: 70px; + max-width: 110px; + } + + .engine-selector :deep(.p-dropdown) { + min-height: 24px; + height: 24px; + font-size: 0.7rem; + padding: 0 2px; + } + + .engine-selector :deep(.p-dropdown-label) { + padding: 2px var(--space-xs); + font-size: 0.7rem; + } + + .engine-selector :deep(.p-dropdown-trigger) { + width: 18px; + } +} + +/* Extra-small: hide long text */ @media (max-width: 480px) { .strip-content span:not(.file-name) { display: none; diff --git a/src/modules/data-entry/components/receipts/UnifiedReceiptForm.vue b/src/modules/data-entry/components/receipts/UnifiedReceiptForm.vue index f801879..99fbbec 100644 --- a/src/modules/data-entry/components/receipts/UnifiedReceiptForm.vue +++ b/src/modules/data-entry/components/receipts/UnifiedReceiptForm.vue @@ -108,28 +108,28 @@ /> - -
- TOTAL - - + +
+ +
+ TOTAL + + +
- - - - -
+ +
Card
- :deep(.confidence-indicator) { + flex-shrink: 0; + min-width: 20px; + justify-content: center; + opacity: 0.85; + transition: opacity var(--transition-fast, 150ms); + cursor: help; +} + +.form-row :deep(.confidence-indicator:hover), +.values-total :deep(.confidence-indicator:hover), +.values-payments > :deep(.confidence-indicator:hover) { + opacity: 1; +} + +/* Hide percentage text in compact form — info available via tooltip */ +.form-row :deep(.confidence-indicator .percentage), +.values-total :deep(.confidence-indicator .percentage), +.values-payments > :deep(.confidence-indicator .percentage) { + display: none; +} + /* === SUPPLIER ROW === */ .supplier-input { flex: 1; @@ -595,35 +619,41 @@ defineExpose({ width: 28px; } -/* === TOTAL ROW (with payments inline) === */ -.total-row { +/* === VALUES ROW (TOTAL + Payments) === */ +.values-row { display: flex; - flex-wrap: nowrap; /* FORCE single line */ - align-items: center; - gap: var(--space-xs, 0.25rem); /* smaller gap */ + align-items: stretch; background: var(--green-50); - border-radius: var(--radius-sm, 4px); - padding: var(--space-xs, 0.25rem) var(--space-sm, 0.5rem) !important; - margin: var(--space-xs, 0.25rem) 0; - overflow-x: auto; /* scroll if needed on very small screens */ + border-radius: var(--radius-sm); + padding: var(--space-sm) var(--space-md) !important; + margin: var(--space-xs) 0; + gap: var(--space-md); +} + +/* Left: TOTAL section */ +.values-total { + display: flex; + align-items: center; + gap: var(--space-sm); + flex-shrink: 0; } .total-label { - font-weight: 700; - font-size: var(--text-sm, 0.875rem); + font-weight: var(--font-bold); + font-size: var(--text-sm); color: var(--text-color); flex-shrink: 0; } .total-input { - width: 105px; + width: 140px; flex-shrink: 0; } .total-input :deep(.p-inputnumber-input) { width: 100%; font-size: var(--text-base); - font-weight: var(--font-semibold); /* 600, not 700 */ + font-weight: var(--font-semibold); text-align: right; padding: var(--space-xs) var(--space-sm); height: 32px; @@ -633,44 +663,39 @@ defineExpose({ color: var(--text-color); } -/* Payment separator */ -.pay-separator { - color: var(--text-color-secondary); - font-weight: 300; - margin: 0 var(--space-xs, 0.25rem); -} - -/* Payment methods inline container */ -.pay-inline { +/* Right: Payment breakdown */ +.values-payments { display: flex; - flex-wrap: nowrap; /* stay on same line */ - gap: var(--space-sm, 0.5rem); /* smaller gap */ - align-items: center; + flex-direction: column; + gap: var(--space-xs); + justify-content: center; + margin-left: auto; } .pay-item { display: flex; align-items: center; - gap: var(--space-xs, 0.25rem); + gap: var(--space-sm); } .pay-label { - font-size: var(--text-xs); /* 12px - labels */ + font-size: var(--text-xs); font-weight: var(--font-medium); color: var(--text-color-secondary); + min-width: 32px; } .pay-input { - width: 70px; + width: 120px; } .pay-input :deep(.p-inputnumber-input) { width: 100%; padding: var(--space-xs) var(--space-sm); - font-size: var(--text-sm); /* 14px - uniform for inputs */ + font-size: var(--text-sm); font-weight: var(--font-normal); text-align: right; - height: 32px; /* uniform height */ + height: 32px; background: var(--surface-card); border: 1px solid var(--surface-border); border-radius: var(--radius-sm); @@ -849,7 +874,7 @@ defineExpose({ } /* === MOBILE STACKING === */ -@media (max-width: 480px) { +@media (max-width: 768px) { .form-row { flex-wrap: wrap; gap: var(--space-xs); @@ -914,30 +939,47 @@ defineExpose({ } /* Payment methods stack on mobile */ - .total-row { - flex-wrap: wrap; + .values-row { + flex-direction: column; + gap: var(--space-sm); } - .pay-separator { - display: none; - } - - .pay-inline { + .values-total { width: 100%; - flex-wrap: wrap; - margin-top: var(--space-xs); - justify-content: flex-start; + padding-bottom: var(--space-sm); + border-bottom: 1px dashed var(--green-200); + } + + .total-input { + flex: 1; + width: auto; + } + + .values-payments { + flex-direction: row; + flex-wrap: nowrap; + gap: var(--space-sm); } .pay-item { - flex: 1 1 auto; - min-width: 80px; + flex: 1 1 0%; + min-width: 0; } .pay-input { - flex: 1; - width: auto; - min-width: 60px; + width: 100%; + min-width: 0; + } +} + +/* Extra-small phones: stack payments vertically */ +@media (max-width: 360px) { + .values-payments { + flex-wrap: wrap; + } + + .pay-item { + flex: 1 1 100%; } } @@ -968,7 +1010,7 @@ defineExpose({ color: var(--cyan-300); } -[data-theme="dark"] .total-row { +[data-theme="dark"] .values-row { background: rgba(34, 197, 94, 0.1); }