# Zemail (iMail) — Design System & UI/UX Guidelines

> **Version:** 1.1.0 — Last updated: 2026-03-06
>
> This document is the single source of truth for every visual, interactive, and architectural decision in the Zemail project. Any developer or AI agent working on this codebase **must** read this document before making any frontend changes, and **must** update it after completing any UI/UX-related work.

---

## Table of Contents

1. [Activated Skills & References](#1-activated-skills--references)
2. [Design Philosophy](#2-design-philosophy)
3. [Tech Stack](#3-tech-stack)
4. [Aesthetic Preset: "DevTool Dark"](#4-aesthetic-preset-devtool-dark)
5. [Design Tokens (CSS Custom Properties)](#5-design-tokens-css-custom-properties)
6. [Typography](#6-typography)
7. [Color System](#7-color-system)
8. [Spacing & Layout](#8-spacing--layout)
9. [Component Library](#9-component-library)
10. [Animation & Micro-Interactions](#10-animation--micro-interactions)
11. [Real-Time UI Patterns](#11-real-time-ui-patterns)
12. [Responsive Design Rules](#12-responsive-design-rules)
13. [Accessibility](#13-accessibility)
14. [Iteration History & Design Decisions](#14-iteration-history--design-decisions)
15. [Maintenance Protocol (MANDATORY)](#15-maintenance-protocol-mandatory)

---

## 1. Activated Skills & References

The following `.agents/skills` were activated during the initial design and development of this project. **Any future developer or AI agent must activate the relevant skill before working in that domain.**

| Skill | Path | When to Activate |
|-------|------|------------------|
| **`bento-landing-page-generator`** | `.agents/skills/bento-landing-page-generator/SKILL.md` | Building or modifying Bento-style landing pages, hero sections, feature grids. This was the **primary skill** used to establish the entire visual language of this project. |
| **`tailwindcss-development`** | `.agents/skills/tailwindcss-development/SKILL.md` | Any styling work. Uses Tailwind CSS **v4** with CSS-first `@theme` configuration. Never use deprecated v3 utilities. |
| **`fluxui-development`** | `.agents/skills/fluxui-development/SKILL.md` | Building forms, modals, inputs, or interactive UI components. Uses the **Flux UI Free** edition. |
| **`volt-development`** | `.agents/skills/volt-development/SKILL.md` | Creating single-file Livewire components. Check existing Volt components for functional vs. class-based style before creating new ones. |
| **`cinematic-landing-page-builder`** | `.agents/skills/cinematic-landing-page-builder/SKILL.md` | Building cinematic, pixel-perfect landing pages with strict design system enforcement, micro-interactions, and GSAP animations. |
| **`pest-testing`** | `.agents/skills/pest-testing/SKILL.md` | Writing or modifying tests. Uses Pest 3. |

### External References Used

- **Appwrite Dashboard** — Dark UI inspiration for surface colors, card borders, and glow effects.
- **Vercel** — Minimal dark theme, clean typography hierarchy, terminal-style code blocks.
- **Stripe / BentoNow** — Asymmetric Bento Grid layout patterns, card span ratios.
- **Heroicons** — Default icon set. Search at [heroicons.com](https://heroicons.com/). Never guess icon names.

---

## 2. Design Philosophy

### Core Principles

1. **Premium-First**: Every element must feel premium and state-of-the-art. No basic MVPs, no generic layouts. The user should be "wowed" at first glance.
2. **Dark Mode Native**: The application is dark-mode-only (`class="dark"` on `<html>`). All design tokens, colors, and contrasts are optimized for dark backgrounds.
3. **Cinematic Motion**: Interfaces should feel alive. Use GSAP for scroll-driven reveals, Alpine.js for instant state transitions, and CSS `transition-all` for micro-interactions.
4. **Information Density**: Mailbox UIs are information-dense by nature. Use compact typography (`text-[10px]`, `text-[11px]`), uppercase tracking (`tracking-widest`, `tracking-[0.2em]`), and monospace fonts for data.
5. **No Placeholders**: Never use placeholder images or `lorem ipsum`. Build all visuals with HTML/CSS/SVG. Use `generate_image` tool if real images are needed.
6. **Glassmorphism & Glow**: Frosted glass effects (`backdrop-blur-xl`, `bg-white/5`) and colored glows (`shadow-[0_0_30px_rgba(236,72,153,0.3)]`) are signature visual elements.

### The "Bento Box" Layout Rules

- Use **asymmetric CSS Grids** (e.g., `grid-cols-1 md:grid-cols-3` or `md:grid-cols-4`).
- Cards must have **distinct spans** (`col-span-2`, `row-span-2`) to create a mosaic effect.
- All cards use `rounded-2xl` or `rounded-3xl` border radii.
- Cards use `bg-zinc-900` surface color with `border border-white/5` borders.
- Background glows inside cards use `blur-2xl` with accent color at very low opacity (`bg-pink-500/5`).

---

## 3. Tech Stack

| Layer | Technology | Version |
|-------|-----------|---------|
| Backend | Laravel | v12 |
| Real-Time | Livewire | v3 |
| Client-Side Reactivity | Alpine.js | (bundled with Livewire) |
| Styling | Tailwind CSS | v4 |
| Animations | GSAP | 3.12.5 |
| Component Library | Flux UI Free | v2 |
| WebSocket | Laravel Reverb | v1 |
| Fonts | Google Fonts (via Bunny) | Inter, JetBrains Mono |
| Icons | Heroicons (via Flux) | — |
| QR Generator | QRious | 4.0.2 |
| Build Tool | Vite | v7 |

### Asset Pipeline

```
resources/css/app.css    → Tailwind v4 with @theme design tokens
resources/js/app.js      → Laravel Echo + Pusher + WebSocket status dispatching
resources/views/          → Blade templates, Livewire components, anonymous components
```

All frontend changes require `npm run build` (or `npm run dev` during development) to take effect.

---

## 4. Aesthetic Preset: "DevTool Dark"

This project uses **Preset A — "DevTool Dark"**, inspired by Appwrite and Vercel.

| Property | Value |
|----------|-------|
| Background | `#09090B` (`bg-app-bg`) |
| Surface | `#18181B` (`bg-app-surface` / `bg-zinc-900`) |
| Borders | `#27272A` (`border-app-border` / `border-white/5`) |
| Primary Accent | `#EC4899` (Pink) |
| Secondary Accent | `#10B981` (Emerald) |
| Text Primary | `#FAFAFA` |
| Text Secondary | `#737373` (`text-zinc-500`) |
| Text Muted | `#525252` (`text-zinc-600`) |
| Selection Highlight | `rgba(236, 72, 153, 0.3)` (`selection:bg-[#EC4899]/30`) |

---

## 5. Design Tokens (CSS Custom Properties)

All design tokens are defined in `resources/css/app.css` using Tailwind v4's CSS-first `@theme` directive.

```css
@theme {
  /* Core Application Colors */
  --color-app-bg: #09090B;
  --color-app-surface: #18181B;
  --color-app-border: #27272A;
  --color-app-red: #EC6A5F;     /* macOS-style traffic light red */
  --color-app-yellow: #F4BF4F;  /* macOS-style traffic light yellow */
  --color-app-green: #61C554;   /* macOS-style traffic light green */

  /* Zinc Scale (Dark Mode Neutrals) */
  --color-zinc-50: #fafafa;
  --color-zinc-500: #737373;
  --color-zinc-600: #525252;
  --color-zinc-800: #262626;
  --color-zinc-900: #171717;
  --color-zinc-950: #0a0a0a;

  /* Primary (Purple/Indigo Scale — used for accents) */
  --color-primary-500: #787ddc;
  --color-primary-600: #615dce;

  /* App Primary (oklch scale — for gradients and advanced color) */
  --color-app-primary-500: oklch(0.589 0.137 290.02);
  --color-app-primary-600: oklch(0.506 0.16 288.92);

  /* Typography */
  --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif;
}
```

### Important Token Rules

- **Never hardcode colors** that already exist as tokens. Use `bg-app-bg`, `text-zinc-500`, etc.
- **Opacity modifiers** use the Tailwind v4 slash syntax: `bg-pink-500/10`, not the deprecated `bg-opacity-*`.
- **New tokens** must be added to `@theme {}` in `app.css`, not in a `tailwind.config.js` file (Tailwind v4 is CSS-first).

---

## 6. Typography

### Font Stack

| Usage | Font | Weight | Loaded Via |
|-------|------|--------|------------|
| Body & UI | **Inter** | 400, 500, 600, 700 | Bunny Fonts CDN |
| Code, Data, Addresses | **JetBrains Mono** | 400, 500 | Bunny Fonts CDN |

### Font Loading

```html
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=inter:400,500,600,700|jetbrains-mono:400,500" rel="stylesheet" />
```

### Typography Scale

| Element | Classes | Example Usage |
|---------|---------|---------------|
| Page Heading | `text-2xl font-black tracking-tight uppercase italic` | Confirm modal title |
| Section Label | `text-[10px] font-bold text-zinc-500 uppercase tracking-widest` | "Active Mailbox", "Your Sessions" |
| Category Label | `text-[10px] font-bold text-zinc-600 uppercase tracking-[0.2em]` | Sidebar section headers |
| Data Display (email) | `text-[11px] font-mono text-white break-all` | Email address display |
| Toast Type Label | `text-[10px] font-black uppercase tracking-[0.2em] opacity-40` | Toast "SUCCESS", "INFO" label |
| Toast Message | `text-[11px] font-bold tracking-wide whitespace-pre-wrap` | Toast notification body |
| Button Text | `text-xs font-bold` | Primary action buttons |
| Compact Button Text | `text-[10px] font-black uppercase tracking-[0.2em]` | Modal confirm/cancel buttons |
| Timer Display | `text-[10px] font-mono text-pink-500` | Expiration countdown |
| Badge/Count | `text-[10px] font-bold px-1.5 py-0.5` | Unread count badge |

### Typography Rules

- **No comments in code** unless logic is exceptionally complex. Use PHPDoc blocks instead.
- **Uppercase + Wide Tracking** is the signature style for labels and metadata text.
- **Monospace (`font-mono`)** is used for any machine-readable data: email addresses, timers, code blocks.
- **`break-all`** must be applied to email addresses to prevent overflow on small screens.

---

## 7. Color System

### Semantic Color Mapping

These semantic colors are used consistently across all components (toasts, modals, buttons, indicators):

| Semantic | Background | Border | Text | Icon BG | Glow |
|----------|-----------|--------|------|---------|------|
| **Success** | `bg-emerald-500/10` | `border-emerald-500/20` | `text-emerald-100` | `bg-emerald-500/20 text-emerald-400` | `bg-emerald-500/10` |
| **Info** | `bg-blue-500/10` | `border-blue-500/20` | `text-blue-100` | `bg-blue-500/20 text-blue-400` | `bg-blue-400/10` |
| **Warning** | `bg-amber-500/10` | `border-amber-500/20` | `text-amber-100` | `bg-amber-500/20 text-amber-400` | `bg-amber-400/10` |
| **Danger** | `bg-rose-500/10` | `border-rose-500/20` | `text-rose-100` | `bg-rose-500/20 text-rose-400` | `bg-rose-400/10` |

### Important Color Rules

- **Never use generic red/blue/green**. Always use the curated semantic mapping above.
- **Pink (`#EC4899` / `pink-500`)** is the project's primary accent. Used for highlights, CTAs, gradients, and the expiration progress bar.
- **Emerald (`emerald-500`)** is the secondary accent. Used for success states and the WebSocket connection indicator.
- **Rose (`rose-500`)** is used for destructive actions, errors, and the disconnected WebSocket indicator.
- The **expiration progress bar** uses a gradient from pink to emerald: `bg-gradient-to-r from-pink-500 to-emerald-500`.
- **Toast notification types**: `success`, `info`, `warning`, `danger`. **Never** use `error` — use `danger` instead.

---

## 8. Spacing & Layout

### Global Spacing Constants

| Context | Value | Tailwind Class |
|---------|-------|----------------|
| Card Padding | 16px | `p-4` |
| Card Border Radius | 16px | `rounded-2xl` |
| Modal Border Radius | 32px | `rounded-[32px]` |
| Button Border Radius | 16px | `rounded-2xl` |
| Icon Container Radius | 12px | `rounded-xl` |
| Section Gap | 24px | `space-y-6` |
| Inner Element Gap | 8px | `space-y-2` / `gap-2` |
| Toast Container Spacing | 12px | `gap-3` |
| Screen Edge Margin | 24px | `bottom-6 left-6 right-6` (responsive) |

### Layout Architecture

The main mailbox view (`mailbox.blade.php`) uses a **three-panel layout**:

```
┌──────────┬──────────────┬──────────────────────┐
│ Sidebar  │  Email List   │   Email Detail       │
│ (280px)  │  (flex-1)     │   (flex-1, lg only)  │
│          │               │                      │
│ - Active │  - Search     │   - Header           │
│   Mailbox│  - Email rows │   - Body (iframe)    │
│ - Create │  - Pagination │   - Attachments      │
│ - Sessions               │                      │
└──────────┴──────────────┴──────────────────────┘
```

- Sidebar uses `w-[280px]` when open, collapses on smaller screens.
- `overflow-hidden` on `<body>` prevents page-level scrolling. Each panel scrolls independently.
- Use `scrollbar-hide` utility class (custom CSS) to hide scrollbars in compact panels.

### Body-Level Styling

```html
<body class="bg-app-bg text-[#FAFAFA] antialiased selection:bg-[#EC4899]/30 h-full overflow-hidden">
```

---

## 9. Component Library

### 9.1 Global Toast Notification System

**Location:** `resources/views/components/layouts/app.blade.php`
**Trigger:** `$this->dispatch('notify', message: '...', type: 'success')` from Livewire, or `addToast('...', 'success')` from Alpine.js.
**Event:** `@notify.window` on `<body>`.

#### Architecture

```
<body x-data="{ toasts: [], wsConnected: true, addToast(msg, type) {...} }">
  └── @notify.window="addToast($event.detail.message, $event.detail.type)"
  └── @ws-status.window="wsConnected = $event.detail.connected"
  └── <div class="fixed bottom-6 left-6 right-6 sm:left-auto sm:right-6 z-[100]">
        └── <template x-for="toast in toasts">
              └── Toast card with icon, type label, message, close button
```

#### Allowed Types

| Type | Visual | Use Case |
|------|--------|----------|
| `success` | Emerald green | Copy to clipboard, successful actions |
| `info` | Blue | New email received, informational alerts |
| `warning` | Amber/Orange | Cooldown period active, soft warnings |
| `danger` | Rose red | Address already in use, destructive errors |

#### Design Specifications

- **Container:** `fixed bottom-6 left-6 right-6 sm:left-auto sm:right-6 z-[100]`
  - Mobile: Full-width with 24px margins on both sides.
  - Desktop: Anchored to bottom-right.
- **Toast Card:** `w-full sm:min-w-[320px] p-4 rounded-2xl border backdrop-blur-xl shadow-2xl`
- **Auto-dismiss:** 4000ms timeout.
- **Enter Animation:** `transition ease-out duration-500` — slides in from right with scale.
- **Leave Animation:** `transition ease-in duration-300` — fades out with scale.
- **Multiline Support:** `whitespace-pre-wrap` on message div. Use `\n` in PHP strings for line breaks.
- **Icon:** 40×40px container (`w-10 h-10 rounded-xl`) with SVG stroke icon.
- **Close Button:** `p-1.5 rounded-lg hover:bg-white/5` with X icon.

#### Toast Message Formatting Examples

```php
// Single-line (copy confirmation)
$this->dispatch('notify', message: 'Address copied to clipboard', type: 'success');

// Multi-line (new email notification)
$this->dispatch('notify',
    message: "Sender: {$sender}\nSubject: {$subject}",
    type: 'info'
);

// Cooldown warning with precise timer
$this->dispatch('notify',
    message: "Address is in cooldown. Try again in {$remaining}.",
    type: 'warning'
);

// Error (address conflict)
$this->dispatch('notify', message: 'Address already in use.', type: 'danger');
```

### 9.2 Confirm Modal

**Location:** `resources/views/components/bento/confirm-modal.blade.php`
**Trigger:** `$dispatch('open-confirm-modal', { title, message, confirmLabel, type, action })`

#### Design Specifications

- **Backdrop:** `bg-zinc-950/80 backdrop-blur-xl` — heavy frosted glass overlay.
- **Card:** `max-w-[400px] bg-zinc-900 border border-white/10 rounded-[32px] p-8` — super-rounded.
- **Glow:** `w-64 h-64 rounded-full blur-[80px] opacity-20` — type-colored radial glow behind the card.
- **Icon:** `w-16 h-16 rounded-2xl` — large, prominent, type-colored icon container.
- **Title:** `text-2xl font-black text-white tracking-tight uppercase italic` — bold, dramatic.
- **Message:** `text-xs font-bold text-zinc-500 uppercase tracking-widest leading-relaxed` — subdued.
- **Buttons:** `grid grid-cols-2 gap-4` — two equal-width buttons with `py-4 rounded-2xl`.
- **Cancel:** `bg-white/5 border border-white/10 text-zinc-400` — ghost style.
- **Confirm:** Solid type-colored background (e.g., `bg-rose-600 text-white` for danger).

#### Supported Types

Same four types as the toast system: `danger`, `info`, `warning`, `success`.

### 9.3 WebSocket Connection Indicator

**Location:** `resources/views/livewire/mailbox.blade.php` (Active Mailbox card)
**State Source:** Global `wsConnected` from `<body x-data>`.

```html
<div class="w-1.5 h-1.5 rounded-full animate-pulse transition-colors duration-500"
     :class="wsConnected ? 'bg-emerald-500' : 'bg-rose-500'"></div>
```

- **Connected:** Emerald green pulsing dot.
- **Disconnected:** Rose red pulsing dot.
- **Transition:** `duration-500` smooth color transition between states.
- The dot sits next to the "ACTIVE MAILBOX" label in the sidebar card.

### 9.4 Expiration Progress Bar

**Location:** `resources/views/livewire/mailbox.blade.php`

#### Design Specifications

- **Track:** `h-1 bg-white/5 rounded-full overflow-hidden`
- **Fill:** `bg-gradient-to-r from-pink-500 to-emerald-500 transition-all duration-1000 ease-linear`
- **Timer Text:** `text-[10px] font-mono text-pink-500`
- **Label:** `text-[10px] text-zinc-500 uppercase font-black tracking-tighter` — "EXPIRES IN"

#### Time Display Rules (User Iteration)

The expiration timer processes remaining time **in seconds** and displays with adaptive precision:

```javascript
// Display hierarchy (most precise possible):
if (days > 0)  → "14d 23h 59m 59s"
if (hours > 0) → "23h 59m 59s"
if (mins > 0)  → "59m 59s"
else           → "59s"
```

> **User Iteration Note:** Originally showed "0 minutes" when only seconds remained. Fixed to always show seconds-level precision and cascade upward to days.

#### Auto-Expiration Behavior

When the timer reaches zero:
1. Alpine.js sets `isExpired = true` and fires `$wire.deleteMailbox(id)`.
2. This triggers a soft delete on the Mailbox model.
3. The `deleted` Eloquent event fires cleanup (MongoDB email bodies, MariaDB email metadata).
4. UI refreshes to show a new auto-generated mailbox.

### 9.5 Cinematic Creation Overlay

**Location:** `resources/views/livewire/mailbox.blade.php`

Shown when a first-time visitor arrives or all mailboxes are deleted:

- **Backdrop:** `fixed inset-0 z-[200] bg-zinc-950/90` — full-screen dark overlay.
- **Logo:** `animate-pulse` with scale transition (`scale-110 opacity-100` → `scale-90 opacity-0`).
- **Spinner:** Custom CSS spinner using `border-4 border-pink-500 border-t-transparent animate-[spin_1.5s_cubic-bezier(0.4,0,0.2,1)_infinite]` with pink glow shadow.
- **Auto-dismiss:** `setTimeout(() => $wire.finishAutoCreation(), 1000)` — 1 second cinematic delay.

### 9.6 Action Button Patterns

#### Icon Buttons (Toolbar Style)

```html
<!-- Standard action button -->
<button class="p-1.5 rounded-lg bg-white/5 text-zinc-500 hover:text-white hover:bg-white/10 transition-all cursor-pointer">
    <svg class="w-3.5 h-3.5" ...></svg>
</button>

<!-- Destructive action button -->
<button class="p-1.5 rounded-lg bg-rose-500/10 text-rose-500/60 hover:text-rose-500 hover:bg-rose-500/20 transition-all cursor-pointer">
    <svg class="w-3.5 h-3.5" ...></svg>
</button>
```

#### Full-Width CTA Button

```html
<button class="w-full py-3 px-4 rounded-2xl bg-white/5 border border-white/10 text-white text-xs font-bold flex items-center justify-center gap-2 hover:bg-white/10 hover:border-pink-500/30 transition-all group cursor-pointer">
    <div class="w-5 h-5 rounded-lg bg-pink-500/20 text-pink-500 flex items-center justify-center group-hover:scale-110 transition-transform">
        <svg class="w-3.5 h-3.5" ...></svg>
    </div>
    Create New Mailbox
</button>
```

#### Key Button Rules

- All buttons must have `cursor-pointer`.
- Icon containers inside buttons use `group-hover:scale-110 transition-transform` for a micro-interaction.
- Destructive buttons use the rose color scale at reduced opacity (`rose-500/10`, `rose-500/60`).
- Ghost buttons use `bg-white/5 border border-white/10`.

---

## 10. Animation & Micro-Interactions

### GSAP (Heavy Scroll Animations)

Loaded via CDN in the layout:

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
```

- Used primarily on the **landing page** for cinematic scroll reveals.
- Initialize inside Alpine's `x-init` hook: `x-init="gsap.from($el, { opacity: 0, y: 50, scrollTrigger: $el })"`.
- GSAP is **not used** in the mailbox application UI — Alpine.js handles all reactive transitions there.

### Alpine.js (Instant UI State)

All immediate user interactions must be handled client-side with Alpine.js:

| Pattern | Usage |
|---------|-------|
| `x-show` + `x-transition` | Modals, overlays, conditional panels |
| `x-data` + `$watch` | Reactive state management (timers, mobile view switching) |
| `@click` + `$wire` | Livewire method calls from the client |
| `@click` + `$dispatch` | Triggering global events (toasts, modals) |
| `@resize.window` | Responsive sidebar behavior |
| `:class` bindings | Dynamic styling (WebSocket indicator, toast types) |

### CSS Transitions

| Property | Duration | Easing | Usage |
|----------|----------|--------|-------|
| `transition-all` | default (150ms) | default | Button hover states |
| `transition-colors duration-500` | 500ms | default | WebSocket indicator color change |
| `transition-all duration-1000 ease-linear` | 1000ms | linear | Progress bar width |
| `transition ease-out duration-500` | 500ms | ease-out | Toast enter |
| `transition ease-in duration-300` | 300ms | ease-in | Toast leave |
| `transition ease-out duration-700` | 700ms | ease-out | Full-screen overlay enter |
| `transition ease-in duration-500` | 500ms | ease-in | Full-screen overlay leave |
| `transition ease-out duration-500` | 500ms | ease-out | Modal card enter (with scale + translateY) |

### Custom Keyframes

```css
@keyframes slide-right {
    from { opacity: 0; transform: translateX(-10px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes slide-up {
    from { opacity: 0; transform: translateY(20px); }
    to   { opacity: 1; transform: translateY(0); }
}

.animate-slide-up {
    animation: slide-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
```

---

## 11. Real-Time UI Patterns

### WebSocket Architecture

```
app.js → Laravel Echo (Reverb broadcaster)
       → Pusher connection state listeners
       → Dispatches window events: 'ws-status'

app.blade.php → Listens for @ws-status.window
              → Updates global Alpine 'wsConnected' state

mailbox.blade.php → Reads 'wsConnected' for indicator color
```

### Connection Status Lifecycle

```javascript
// resources/js/app.js
window.Echo.connector.pusher.connection.bind('connected',    () => dispatchStatus(true));
window.Echo.connector.pusher.connection.bind('unavailable',  () => dispatchStatus(false));
window.Echo.connector.pusher.connection.bind('disconnected', () => dispatchStatus(false));
window.Echo.connector.pusher.connection.bind('failed',       () => dispatchStatus(false));
```

### Conditional Echo Initialization

Echo is only initialized on pages that need it, controlled by a data attribute:

```html
<div data-requires-reverb="true"> ... </div>
```

```javascript
if (document.querySelector('[data-requires-reverb]')) {
    window.Echo = new Echo({ ... });
}
```

### New Email Real-Time Flow

1. `ProcessIncomingEmail` job saves email to MariaDB + MongoDB.
2. `NewEmailReceived` event broadcasts on `mailbox.{domain}` channel.
3. Livewire listener `echo:mailbox.{domain},.new.email` fires `onNewEmail()`.
4. `onNewEmail()` dispatches a toast notification with sender + subject.
5. `onNewEmail()` dispatches `$refresh` to reload the email list.

---

## 12. Responsive Design Rules

### Breakpoint Strategy

| Breakpoint | Prefix | Behavior |
|-----------|--------|----------|
| < 640px | (none) | Mobile: full-width toast, collapsed sidebar, single-panel view |
| ≥ 640px | `sm:` | Toast anchors to bottom-right, min-width restored |
| ≥ 1024px | `lg:` | Email detail panel becomes visible. Mobile view switcher deactivated |
| ≥ 1280px | `xl:` | Sidebar always open |

### Mobile View Switching

On mobile (`< 1024px`), the mailbox uses an Alpine-driven view switcher:

```javascript
$watch('selectedId', value => { if (value && window.innerWidth < 1024) mobileView = 'detail' });
$watch('mobileView', value  => { if (value === 'list' && window.innerWidth < 1024) selectedId = null });
```

### Toast Responsiveness (User Iteration)

> **User Iteration Note:** The toast container originally used `fixed bottom-6 right-6` with a hard `min-w-[320px]`, causing it to overflow and touch the left screen edge on small devices. This was fixed by:
> - Container: `left-6 right-6 sm:left-auto sm:right-6` — full-width with margins on mobile, bottom-right anchor on desktop.
> - Toast card: `w-full sm:min-w-[320px]` — fluid on mobile, minimum width on desktop.

---

## 13. Accessibility

### Required Patterns

- All interactive elements must have `cursor-pointer`.
- Icon-only buttons must have a `title` attribute for tooltip/screen-reader context.
- `antialiased` is applied globally on `<body>` for smoother font rendering.
- `selection:bg-[#EC4899]/30` provides a branded text selection color.
- Use semantic HTML elements wherever possible (`<nav>`, `<button>`, `<main>`).
- All interactive elements should have unique, descriptive IDs for browser testing.

### Scrollbar Handling

```css
.scrollbar-hide::-webkit-scrollbar { display: none; }
.scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; }
```

---

## 14. Iteration History & Design Decisions

This section documents every significant design iteration from the conversation thread, in chronological order. Each entry includes the rationale so future developers understand **why** a decision was made.

### Iteration 1: Expiration Timer Precision

**Problem:** When a mailbox had only seconds remaining, the timer displayed "0 minutes" instead of showing seconds.

**Solution:** Rewrote the Alpine.js timer to process time in seconds and display with cascading precision: `days → hours → minutes → seconds`. The timer now always shows the most granular unit available.

**Files Changed:** `resources/views/livewire/mailbox.blade.php`

---

### Iteration 2: Soft Deletes Instead of Hard Deletes

**Problem:** Clicking the delete button permanently removed the mailbox record from the database, losing all audit trail.

**Solution:** Added `SoftDeletes` trait to the `Mailbox` model. Created a migration to add `deleted_at` timestamps. All delete operations now soft-delete, preserving records for analytics and potential reclamation.

**Files Changed:** `app/Models/Mailbox.php`, `database/migrations/2026_03_05_202748_add_soft_deletes_to_mailboxes_table.php`

---

### Iteration 3: Mailbox Duplication Prevention & Cooldown System

**Problem:** Random address generation could produce duplicates. Users could snipe deleted addresses instantly.

**Solution:**
- **Random addresses:** `do-while` loop checks `withTrashed()` to ensure uniqueness.
- **Same user reclaiming:** Automatically restores soft-deleted mailbox and updates expiration.
- **Different user claiming:** Tier-based cooldown enforced (Guest: 24h, Free: 12h, Pro: 6h, Enterprise: instant).
- **Cooldown toast:** Shows precise remaining time down to seconds (e.g., "11h 42m 18s").

**Files Changed:** `app/Livewire/Mailbox.php`

---

### Iteration 4: Toast Notification Type Fix

**Problem:** Cooldown and error notifications were dispatched with `type: 'error'`, which didn't match the global toast's four supported types (`success`, `info`, `warning`, `danger`). The toast would render without proper styling.

**Solution:** Changed "address already in use" to `type: 'danger'` (rose red) and cooldown warnings to `type: 'warning'` (amber). **Rule: Never use `'error'` as a toast type.**

**Files Changed:** `app/Livewire/Mailbox.php`

---

### Iteration 5: Session Linking on Login

**Problem:** Guest users creating mailboxes via session would lose access when they registered or logged in.

**Solution:** Added an `Event::listen(Login::class)` in `AppServiceProvider` to automatically transfer mailboxes from `session_id` to `user_id` when a guest authenticates.

**Files Changed:** `app/Providers/AppServiceProvider.php`

---

### Iteration 6: Automatic Expiration Cleanup

**Problem:** If a user closed their browser, expired mailboxes would never be cleaned up.

**Solution:** Dual approach:
1. **Live UI Hook:** Alpine.js timer triggers `$wire.deleteMailbox()` when countdown reaches zero.
2. **Background Worker:** `CleanupExpiredMailboxes` Artisan command runs every minute via Laravel Scheduler.
3. **Data Cleanup:** Eloquent `deleted` event on `Mailbox` model wipes associated `EmailBody` (MongoDB) and `Email` (MariaDB) records.

**Files Changed:** `app/Console/Commands/CleanupExpiredMailboxes.php`, `routes/console.php`, `app/Models/Mailbox.php`, `resources/views/livewire/mailbox.blade.php`

---

### Iteration 7: WebSocket Status Indicator

**Problem:** The "Active Mailbox" pulse indicator was always green, regardless of connection state.

**Solution:**
1. Added `connected/disconnected/unavailable/failed` listeners to Echo in `app.js`.
2. Stored `wsConnected` in global Alpine state on `<body>`.
3. Bound indicator color dynamically: emerald for connected, rose for disconnected.

**Files Changed:** `resources/js/app.js`, `resources/views/components/layouts/app.blade.php`, `resources/views/livewire/mailbox.blade.php`

---

### Iteration 8: New Email Toast Notification

**Problem:** Users had no visual cue when a new email arrived while reading another email.

**Solution:** Updated `onNewEmail()` to dispatch a toast with sender and subject before refreshing the list. Used `type: 'info'` (blue) for the notification.

**Files Changed:** `app/Livewire/Mailbox.php`

---

### Iteration 9: Multiline Toast Formatting

**Problem:** Toast notification for new emails displayed sender and subject on a single line, making it hard to scan.

**Solution:**
1. Changed message format to `"Sender: {$sender}\nSubject: {$subject}"` using `\n`.
2. Added `whitespace-pre-wrap` to the toast message div to render line breaks.

**Files Changed:** `app/Livewire/Mailbox.php`, `resources/views/components/layouts/app.blade.php`

---

### Iteration 10: Mobile Toast Overflow Fix

**Problem:** On small screens (< 320px viewport), the toast's `min-w-[320px]` caused it to overflow beyond the left edge of the screen.

**Solution:**
- Container: Changed from `fixed bottom-6 right-6` to `fixed bottom-6 left-6 right-6 sm:left-auto sm:right-6`.
- Toast card: Changed from `min-w-[320px]` to `w-full sm:min-w-[320px]`.

**Files Changed:** `resources/views/components/layouts/app.blade.php`

---

### Iteration 11: Random Address Format

**Problem:** Random mailbox addresses included an underscore before the number suffix (e.g., `john_doe_42@imail.app`).

**Solution:** User manually removed the underscore from the format string. Addresses now generate as `johndoe42@imail.app`.

**Files Changed:** `app/Livewire/Mailbox.php` (user edit)

---

## Appendix: File Reference Map

| File | Purpose |
|------|---------|
| `resources/css/app.css` | Tailwind v4 theme tokens, Flux UI imports, dark mode config |
| `resources/js/app.js` | Laravel Echo init, WebSocket status dispatching |
| `resources/views/components/layouts/app.blade.php` | Global layout: fonts, GSAP, global Alpine state, toast system |
| `resources/views/livewire/mailbox.blade.php` | Main mailbox UI: sidebar, email list, detail view, modals |
| `resources/views/components/bento/confirm-modal.blade.php` | Reusable confirm modal with type-based theming |
| `resources/views/livewire/landing-page.blade.php` | Bento-style SaaS landing page |
| `app/Livewire/Mailbox.php` | Mailbox Livewire component: CRUD, WebSocket, analytics |
| `app/Models/Mailbox.php` | Mailbox Eloquent model: soft deletes, cleanup events |
| `app/Events/NewEmailReceived.php` | WebSocket broadcast event for incoming emails |
| `app/Console/Commands/CleanupExpiredMailboxes.php` | Scheduled cleanup of expired mailboxes |

---

> **For AI Agents:** Before making any UI change, re-read the relevant sections of this document. Match existing patterns exactly. When in doubt, check sibling components for conventions. Always activate the appropriate skill from `.agents/skills/` before starting work. **After completing any UI/UX change, update this document per Section 15.**

---

## 15. Maintenance Protocol (MANDATORY)

This document is a **living document**. Every developer or AI agent who makes a UI/UX-related change **must** update it before considering their work complete. This ensures no knowledge is lost and prevents future confusion or hallucination.

### 15.1 When to Update

| Scenario | What to Update | Priority |
|----------|---------------|----------|
| New component created | Add to **§9 Component Library** with full spec | 🔴 Required |
| Existing component modified | Update the relevant subsection in **§9** | 🔴 Required |
| New design token added | Add to **§5 Design Tokens** | 🔴 Required |
| Color or typography changed | Update **§6 Typography** or **§7 Color System** | 🔴 Required |
| New animation or transition | Add to **§10 Animation** table | 🟡 Recommended |
| New real-time event or flow | Add to **§11 Real-Time UI Patterns** | 🔴 Required |
| Responsive behavior changed | Update **§12 Responsive Design Rules** | 🔴 Required |
| Any iterative design refinement | Add to **§14 Iteration History** | 🔴 Required |
| New file created that affects UI | Add to **Appendix: File Reference Map** | 🟡 Recommended |
| New external dependency added | Add to **§3 Tech Stack** table | 🔴 Required |
| New skill activated | Add to **§1 Activated Skills** table | 🟡 Recommended |

### 15.2 Iteration Entry Template

Every design change must be logged in **§14 Iteration History** using this exact format:

```markdown
### Iteration N: [Short Descriptive Title]

**Date:** YYYY-MM-DD
**Conversation/PR:** [Link or ID if available]

**Problem:** One sentence describing what was wrong or what the user requested.

**Why:** One sentence explaining *why* this matters (UX impact, visual regression, accessibility, etc.).

**Solution:** Bullet points detailing what was changed. Include:
- Exact Tailwind classes added/removed/changed.
- Any new Alpine.js state or events introduced.
- Any new Livewire methods or events.

**Files Changed:** Comma-separated list of relative file paths.

**Design Rules Established:** (Optional) Any new rules that emerged from this change.
```

#### Example — Well-Written Entry

```markdown
### Iteration 12: Attachment Preview Thumbnails

**Date:** 2026-03-10
**Conversation:** c1ba6ccd-8bd9-4670-94e4-50b936242f39

**Problem:** Attachments in the email detail view showed only filenames with no visual preview.

**Why:** Users couldn't quickly assess whether an attachment was an image, document, or archive without downloading it.

**Solution:**
- Added thumbnail preview for image attachments using `<img>` with `w-16 h-16 rounded-lg object-cover`.
- Non-image attachments show a colored icon badge: `bg-blue-500/10 text-blue-400` for documents, `bg-amber-500/10 text-amber-400` for archives.
- Thumbnails are lazy-loaded with `loading="lazy"` to avoid blocking the main render.

**Files Changed:** `resources/views/livewire/mailbox.blade.php`

**Design Rules Established:** All file-type indicators must use the semantic color mapping from §7. Image previews always use `rounded-lg object-cover`.
```

#### Example — Poorly-Written Entry (DO NOT DO THIS)

```markdown
### Iteration 12: Fixed attachments

**Problem:** Attachments looked bad.

**Solution:** Made them look better.

**Files Changed:** mailbox.blade.php
```

> ⚠️ **This lacks specificity.** It doesn't explain *why* it mattered, *what* CSS classes were used, or *what rules* emerged. A future developer reading this would learn nothing and likely re-implement differently.

### 15.3 Component Documentation Template

When adding a new component to **§9 Component Library**, use this structure:

```markdown
### 9.N [Component Name]

**Location:** `path/to/file.blade.php`
**Trigger:** How to invoke (dispatch event, Livewire property, Alpine method, etc.)
**State Source:** Where the component gets its data.

#### Design Specifications

- **Container:** Exact Tailwind classes for the outermost wrapper.
- **Card/Body:** Exact Tailwind classes for the main content area.
- **[Other visual elements]:** One bullet per distinct visual element.

#### Behavior

- How it appears (animation/transition).
- How it dismisses.
- How it responds to different screen sizes.

#### Supported Variants

Table of variants (types, sizes, states) if applicable.

#### Code Example

```php
// Minimal working example showing how to trigger/use the component.
```
```

### 15.4 Update Checklist for AI Agents

Before marking any UI/UX task as complete, run through this checklist:

- [ ] **Read** relevant sections of `DESIGN.md` before starting work.
- [ ] **Match** existing patterns from this document (colors, spacing, typography, animations).
- [ ] **Update §14** with a new Iteration entry if any visual or behavioral change was made.
- [ ] **Update §9** if a component was created or modified.
- [ ] **Update §5/§6/§7** if design tokens, fonts, or colors were added/changed.
- [ ] **Update §3** if a new dependency was added.
- [ ] **Update Appendix** if a new file was created.
- [ ] **Bump the version** at the top of the file (patch for fixes, minor for features).
- [ ] **Update the "Last updated" date** at the top of the file.

### 15.5 Versioning Convention

The version number at the top of this file follows **Major.Minor.Patch**:

| Change Type | Bump | Example |
|------------|------|--------|
| New section or major restructure | Major | 1.0.0 → 2.0.0 |
| New component, new iteration, new design token | Minor | 1.0.0 → 1.1.0 |
| Typo fix, clarification, minor class update | Patch | 1.0.0 → 1.0.1 |

### 15.6 Context Preservation Rules

To keep entries **light but sufficient** (no confusion, no hallucination):

1. **Always include exact Tailwind classes.** Don't write "made it rounded" — write `rounded-2xl`.
2. **Always include the file path.** Don't write "the modal" — write `resources/views/components/bento/confirm-modal.blade.php`.
3. **Always state the user's intent.** Don't write "changed the color" — write "User requested rose for destructive actions instead of generic red."
4. **Always state the technical reason.** Don't write "it was broken" — write "The toast type `'error'` had no matching `:class` binding in the Alpine template."
5. **Keep it to 3-5 sentences max per entry.** More detail goes in the component spec (§9), not the iteration log (§14).
6. **Reference existing sections.** Instead of re-explaining the color system, write "Uses semantic Danger mapping from §7."
