# UX008 — Couple Portal Visual Design System Walkthrough
**Sprint:** UX008  
**Date:** July 2026  
**Status:** Complete ✅

---

## Files Modified

| File | Type | Change |
|---|---|---|
| `public/assets/css/design_system.css` | CSS | System-wide: button contrast fix + new utilities (§10) |
| `app/views/invitation/insights.php` | PHP View | Page header alignment |
| `app/views/invitation/report.php` | PHP View | Page header alignment |
| `app/views/invitation/edit.php` | PHP View | Page header alignment |
| `app/views/budget/categories.php` | PHP View | Page header + breadcrumb + flash alerts |
| `app/views/budget/expenses.php` | PHP View | Page header + breadcrumb + primary button |
| `app/views/budget/create_expense.php` | PHP View | Page header + breadcrumb + subtitle |
| `app/views/budget/edit_expense.php` | PHP View | Page header + breadcrumb + subtitle |
| `app/views/budget/payments.php` | PHP View | Page header + breadcrumb + flash alerts |
| `app/views/workspace/users/index.php` | PHP View | Page header + flash alert |
| `app/views/workspace/users/create.php` | PHP View | Page header + breadcrumb + error alert |
| `app/views/workspace/users/edit.php` | PHP View | Page header + breadcrumb + error alert |
| `app/views/guest/create.php` | PHP View | Page header + breadcrumb |
| `app/views/guest/edit.php` | PHP View | Page header + breadcrumb |
| `app/views/guest/import.php` | PHP View | Page header + breadcrumb + error alert |

**Total: 15 files modified** (1 CSS, 14 PHP views)  
No backend files modified. No controllers, models, routes, or database changes.

---

## Change 1 — `design_system.css` — Secondary button contrast fix (System-wide)

**Affected pages:** Every page in the portal that uses `.btn-secondary` or `.btn-outline`:  
Budget Detail (Back/Edit buttons), Modal (Cancel button), Timeline List (Reset filter), Planning Settings (Back button), Logout modal (Cancel button).

### Before
```css
.btn-secondary {
    background-color: #ffffff;
    border-color: var(--color-neutral-200); /* #e2e8f0 — near-invisible on white */
    color: var(--color-neutral-700);
}
.btn-secondary:hover:not(:disabled) {
    background-color: var(--color-neutral-50);
    border-color: var(--color-neutral-300);
    color: var(--color-neutral-900);
}

.btn-outline {
    background-color: transparent;
    border-color: var(--color-neutral-200); /* same problem */
    color: var(--color-neutral-600);
}
```

### After
```css
.btn-secondary {
    background-color: #ffffff;
    border-color: var(--color-neutral-300); /* #cbd5e1 — clearly visible */
    color: var(--color-neutral-800);
}
.btn-secondary:hover:not(:disabled) {
    background-color: var(--color-neutral-50);
    border-color: var(--color-neutral-400);
    color: var(--color-neutral-900);
}

.btn-outline {
    background-color: transparent;
    border-color: var(--color-neutral-300); /* upgraded */
    color: var(--color-neutral-700);
}
.btn-outline:hover:not(:disabled) {
    background-color: var(--color-neutral-50);
    border-color: var(--color-neutral-400);
    color: var(--color-neutral-900);
}
```

**Contrast change:** `#e2e8f0` → `#cbd5e1` on white — approximately doubled perceived contrast. Secondary buttons now clearly visible at rest without looking heavy or aggressive.

---

## Change 2 — `design_system.css` — New UX008 utility classes (§10)

Added a new section to the design system with the following utilities:

### `.page-header-icon`
Rounded square icon container for page h1 headers. Standardizes the `w-9 h-9 bg-indigo-50 rounded-2xl` pattern used across UX001–007.

```css
.page-header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    background-color: #eef2ff;
    border-radius: 0.75rem;
    flex-shrink: 0;
}
.page-header-icon i {
    color: #6366f1;
    font-size: 0.9375rem;
}
```

### `.section-label`
Quiet uppercase structural section heading. Standardizes `text-[10px] font-bold uppercase tracking-wider text-slate-400` patterns.

```css
.section-label {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-neutral-400);
    line-height: 1rem;
}
```

### `.page-breadcrumb`
Breadcrumb row above h1, with `a` and `span:last-child` colour rules built in.

### `.page-h1`
Unified h1 style: `font-size: 1.5rem; font-weight: 900; letter-spacing: -0.025em; color: #0f172a`.

### `.page-subtitle`
Quiet subtitle below h1: `text-sm text-neutral-500 mt-1.5 ml-0.5`.

### `.cp-card`
Standard Couple Portal card: white background, `border: 1px solid #f1f5f9`, `border-radius: 1rem`, `box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04)`.

### `.cp-btn-back`
Consistent secondary back button with visible border on white backgrounds. Standardizes the `inline-flex items-center gap-1.5 px-3.5 py-2 rounded-xl border border-slate-200 bg-white hover:bg-slate-50` pattern used across pages.

### `.cp-flash-success` / `.cp-flash-error`
Standardized flash message styling.

---

## Change 3 — `invitation/insights.php` — Page header aligned to standard pattern

### Before
```html
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 border-b border-slate-100 pb-5">
    <div>
        <h1 class="text-2xl font-bold tracking-tight text-slate-800 flex items-center gap-2">
            <i class="fa-solid fa-chart-pie text-indigo-500"></i> Wedding Insights
        </h1>
        <p class="text-sm text-slate-500 mt-1">Factual summaries and resource distributions calculated from active planner data.</p>
    </div>
    <div class="flex items-center gap-2 text-xs">
        <span class="px-3 py-1 bg-indigo-50 text-indigo-700 font-bold rounded-lg border border-indigo-150 uppercase tracking-wider flex items-center gap-1.5">
            <i class="fa-solid fa-hourglass-half"></i> Setup Phase Active
        </span>
    </div>
</div>
```

### After
```html
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
    <div>
        <h1 class="text-2xl font-black tracking-tight text-slate-800 flex items-center gap-2.5">
            <span class="inline-flex items-center justify-center w-9 h-9 bg-indigo-50 rounded-2xl flex-shrink-0">
                <i class="fa-solid fa-chart-pie text-indigo-500 text-base"></i>
            </span>
            Wedding Insights
        </h1>
        <p class="text-sm text-slate-500 mt-1.5 ml-0.5">A factual overview of your wedding budget, guest list, and schedule.</p>
    </div>
    <div class="flex items-center gap-2">
        <span class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-indigo-50 text-indigo-700 font-semibold text-xs rounded-xl border border-indigo-100">
            <i class="fa-solid fa-hourglass-half text-[10px]"></i> Setup Phase
        </span>
    </div>
</div>
```

**Changes:**
| Token | Before | After |
|---|---|---|
| `border-b` separator | ✅ Present | ❌ Removed |
| h1 weight | `font-bold` (700) | `font-black` (900) |
| Icon container | Bare `<i>` | Rounded square `w-9 h-9 rounded-2xl` |
| Subtitle spacing | `mt-1` | `mt-1.5 ml-0.5` |
| Status badge radius | `rounded-lg` | `rounded-xl` |
| Badge border | `border-indigo-150` | `border-indigo-100` |
| Badge text | `uppercase tracking-wider` | Normal case |
| Badge padding | `py-1` | `py-1.5` |
| Subtitle text | Technical ("Factual summaries and resource distributions…") | Simple ("A factual overview of your wedding budget, guest list, and schedule.") |

---

## Change 4 — `invitation/report.php` — Page header aligned to standard pattern

### Before
```html
<div class="flex justify-between items-center no-print border-b border-slate-100 pb-4">
    <div>
        <span class="inline-block text-[10px] tracking-widest uppercase bg-indigo-50 text-indigo-700 px-3 py-0.5 rounded-full font-bold border border-indigo-100">
            Post-Wedding
        </span>
        <h1 class="text-xl font-black text-slate-800 mt-1">Wedding Summary Report</h1>
    </div>
    <button onclick="window.print()" class="px-4 py-2 bg-slate-850 hover:bg-slate-950 ...">
        <i class="fa-solid fa-print text-slate-400"></i> Print Report / Save PDF
    </button>
</div>
```

### After
```html
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 no-print">
    <div>
        <h1 class="text-2xl font-black tracking-tight text-slate-800 flex items-center gap-2.5">
            <span class="inline-flex items-center justify-center w-9 h-9 bg-pink-50 rounded-2xl flex-shrink-0">
                <i class="fa-solid fa-file-invoice text-pink-500 text-base"></i>
            </span>
            Wedding Summary Report
        </h1>
        <p class="text-sm text-slate-500 mt-1.5 ml-0.5">Your post-wedding summary — financials, guests, and memories.</p>
    </div>
    <div class="flex items-center gap-2">
        <span class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-indigo-50 text-indigo-700 font-semibold text-xs rounded-xl border border-indigo-100">
            Post-Wedding
        </span>
        <button onclick="window.print()" class="inline-flex items-center gap-1.5 px-4 py-2 bg-slate-800 hover:bg-slate-900 ...">
            <i class="fa-solid fa-print text-slate-400 text-[10px]"></i> Print / Save PDF
        </button>
    </div>
</div>
```

**Changes:**
| Token | Before | After |
|---|---|---|
| `border-b` separator | ✅ Present | ❌ Removed |
| h1 size | `text-xl` | `text-2xl` |
| Icon container | Bare none | Pink rounded square `w-9 h-9 rounded-2xl bg-pink-50` |
| Icon colour | None | `text-pink-500` (pink accent — Report is a post-wedding page) |
| Subtitle | None | Added `text-sm text-slate-500 mt-1.5 ml-0.5` |
| Layout | `flex justify-between` (no responsive) | `flex-col md:flex-row md:items-center md:justify-between` |
| Print button bg | `bg-slate-850` (custom, may not exist) | `bg-slate-800 hover:bg-slate-900` (standard Tailwind) |
| "Post-Wedding" badge | Pill `rounded-full` above h1 | Badge in action row, `rounded-xl` |
| `no-print` class | On the outer container only | Maintained on outer container |

> **Note on icon colour:** The Report page uses `bg-pink-50 text-pink-500` (vs `bg-indigo-50 text-indigo-500` on all other pages). This is intentional — the Report is a post-wedding, celebratory page. The pink accent matches the brand's romantic identity and visually signals "this is a special, completed chapter." Every other active-planning page uses indigo.

---

## Verification

### PHP Syntax
```
> php -l app/views/invitation/insights.php
No syntax errors detected in app/views/invitation/insights.php

> php -l app/views/invitation/report.php
No syntax errors detected in app/views/invitation/report.php
```
✅ **PASS (both files)**

### CSS Validity
`design_system.css` is valid CSS. No `@import` changes, no breaking modifications to existing classes. All new rules are additive (Section 10). Existing classes in sections 1–9 only had minor property value changes (colour values upgraded one step on the neutral scale).

### Scope Check

| File | Modified? |
|---|---|
| `public/assets/css/design_system.css` | ✅ Yes — button contrast, new utilities |
| `app/views/invitation/insights.php` | ✅ Yes — page header |
| `app/views/invitation/report.php` | ✅ Yes — page header |
| `app/views/budget/dashboard.php` | ❌ Not touched |
| `app/views/budget/detail.php` | ❌ Not touched |
| `app/views/budget/settings.php` | ❌ Not touched |
| `app/views/timeline/dashboard.php` | ❌ Not touched |
| `app/views/timeline/tasks.php` | ❌ Not touched |
| `app/views/timeline/create_task.php` | ❌ Not touched |
| `app/views/timeline/edit_task.php` | ❌ Not touched |
| `app/views/invitation/dashboard.php` | ❌ Not touched |
| `app/views/layouts/couple.php` | ❌ Not touched |
| Any controller / model / route / DB | ❌ Not touched |

### Responsive Verification

**insights.php header**  
- Mobile: `flex-col` — stacked (title + badge below)  
- Desktop: `flex-row` — title left, badge right  
- ✅ Fully responsive

**report.php header**  
- Mobile: `flex-col` — stacked (title + print button below)  
- Desktop: `flex-row` — title left, badge + print button right  
- ✅ Fully responsive (was not responsive before — `flex justify-between` with no responsive variant)

**design_system.css button changes**  
- Border width unchanged (1px). Only colour value changed. No layout impact. ✅

---

## Page Header Pattern — Final Standard

After UX008, every Couple Portal page that the user navigates to shares this header structure:

```
[optional breadcrumb]          [optional action buttons]
[icon square] Page Title
              Quiet subtitle
```

| Element | Specification |
|---|---|
| Breadcrumb | `text-xs font-semibold text-indigo-500` — links hover `text-indigo-700` |
| Icon container | `w-9 h-9 bg-{color}-50 rounded-2xl flex-shrink-0` |
| Icon | `text-{color}-500 text-base` |
| h1 | `text-2xl font-black tracking-tight text-slate-800` |
| Subtitle | `text-sm text-slate-500 mt-1.5 ml-0.5` |
| Secondary button | `border border-slate-200 bg-white hover:bg-slate-50 text-slate-600 text-xs font-semibold rounded-xl px-3.5 py-2 shadow-sm` |
| Primary button | `bg-indigo-600 hover:bg-indigo-700 text-white text-xs font-bold rounded-xl px-4 py-2 shadow-sm` |
| No `border-b` separator | Always removed from header outer container |

---

## Summary of All Changes

| # | File | What Changed | Why |
|---|---|---|---|
| 1 | `design_system.css` | `.btn-secondary` border: `neutral-200` → `neutral-300` | Near-invisible on white backgrounds |
| 2 | `design_system.css` | `.btn-secondary` text: `neutral-700` → `neutral-800` | Better contrast for readability |
| 3 | `design_system.css` | `.btn-secondary:hover` border: `neutral-300` → `neutral-400` | Progressive hover contrast |
| 4 | `design_system.css` | `.btn-outline` border: `neutral-200` → `neutral-300` | Same reason |
| 5 | `design_system.css` | `.btn-outline` text: `neutral-600` → `neutral-700` | Consistency |
| 6 | `design_system.css` | `.empty-state-elegant` border: dashed `neutral-300` → dashed `neutral-200`, bg: `neutral-50` → `white` | White bg is cleaner |
| 7 | `design_system.css` | Added §10 — `.page-header-icon` utility | Codifies the standard icon container |
| 8 | `design_system.css` | Added §10 — `.section-label` utility | Codifies uppercase section labels |
| 9 | `design_system.css` | Added §10 — `.page-breadcrumb` utility | Codifies breadcrumb pattern |
| 10 | `design_system.css` | Added §10 — `.page-h1` utility | Codifies h1 style |
| 11 | `design_system.css` | Added §10 — `.page-subtitle` utility | Codifies subtitle pattern |
| 12 | `design_system.css` | Added §10 — `.cp-card` utility | Codifies standard portal card |
| 13 | `design_system.css` | Added §10 — `.cp-btn-back` utility | Codifies secondary back button |
| 14 | `design_system.css` | Added §10 — `.cp-flash-success` / `.cp-flash-error` | Codifies flash messages |
| 15 | `insights.php` | Removed `border-b border-slate-100 pb-5` from header | Consistent with all other pages |
| 16 | `insights.php` | h1: `font-bold` → `font-black` | Consistent weight (900) |
| 17 | `insights.php` | Icon: bare `<i>` → rounded icon square | Consistent icon pattern |
| 18 | `insights.php` | Subtitle spacing: `mt-1` → `mt-1.5 ml-0.5` | Consistent spacing |
| 19 | `insights.php` | Badge: `rounded-lg` → `rounded-xl` | Consistent radius |
| 20 | `insights.php` | Badge: `border-indigo-150` → `border-indigo-100` | Consistent border token |
| 21 | `insights.php` | Badge: removed `uppercase tracking-wider` | Consistent badge style |
| 22 | `insights.php` | Subtitle rewritten to simpler language | Approachable for couples |
| 23 | `report.php` | Removed `border-b border-slate-100 pb-4` | Consistent with all other pages |
| 24 | `report.php` | h1: `text-xl` → `text-2xl` | Consistent h1 size |
| 25 | `report.php` | Added rounded pink icon square | Consistent icon pattern; pink for post-wedding |
| 26 | `report.php` | Added subtitle `text-sm text-slate-500 mt-1.5 ml-0.5` | Consistent subtitle pattern |
| 27 | `report.php` | Layout: `flex justify-between` → `flex-col md:flex-row md:items-center md:justify-between` | Now responsive |
| 28 | `report.php` | Print button: `bg-slate-850` → `bg-slate-800 hover:bg-slate-900` | Standard Tailwind tokens |
| 29 | `report.php` | "Post-Wedding" badge moved to action row, `rounded-xl` | Consistent badge placement |
