Kez/kez-chat/web/DESIGN.md
Jason Tudisco 60ff82b4a2 design(kez-chat/web): redesign foundation — tactical-terminal theme + tokens
Phase 0 of the redesign (see DESIGN.md). Establishes the visual
foundation; route restyling + IA reorg follow in subsequent commits.

Design direction (decided with a 3-agent design-team debate):
  • Audience: hackers, privacy absolutists, anti-surveillance, Meshtastic
    / off-grid, journalists in hostile environments.
  • Aesthetic: "muted tactical terminal" — Mullvad-calm restraint, not
    neon cyberpunk cosplay. Monospace as identity. Hard-ish edges.
  • Signature color: electric cyan #28C8E8 on neutral near-black #0B0C0E
    (chosen over signal-amber and phosphor-green — ages better, reads
    "serious infrastructure" without shouting). Verified-green reserved
    for proofs only.

Changes:
  • app.css: full Tailwind v4 @theme token set — elevation ramp, text
    tiers, accent + dim + contrast, semantic colors, Inter + JetBrains
    Mono via Google Fonts, tactical radius scale, accent glow, dark
    color-scheme, cyan text-selection, thin dark scrollbars, and the
    kez-cursor blink keyframe (respects prefers-reduced-motion).
  • Wordmark.svelte: `kez▌` mono wordmark with blinking cyan block
    cursor — the cursor is the brand mark.
  • Avatar.svelte: deterministic 5×5 symmetric identicon from the
    ed25519 key, cyan-arc hue. Every KEZ gets a stable face.
  • kez-icon.svg: amber key → cyan key-meets-cursor glyph; regenerated
    the full PWA icon set + apple-touch-icon from it.
  • manifest + index.html theme/background color → #0B0C0E.
  • DESIGN.md: the full system + IA plan as source of truth.

Note: existing route components still use light-theme utility classes
and will look inconsistent until restyled in the next phases — that
work lands next (shell/nav → Chats → Identity → Settings → Contacts).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 21:45:21 -06:00

168 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

# KEZ Design System
> Source of truth for the kez-chat redesign (`redesign-kez-theme` branch).
> Goal: take the chat app out of the prototype phase into a real,
> WhatsApp/Discord-caliber messenger with an iconic KEZ identity.
## Who we're designing for
Hackers, infosec people, privacy absolutists, anti-surveillance / sovereignty
folks, Meshtastic & off-grid comms operators, journalists/activists in hostile
environments — the Signal / Briar / Tails / Mullvad / Monero crowd. They trust
**verifiability over promises**, have a finely-tuned bullshit detector, and
bounce instantly from anything that smells like VC surveillance-ware.
**Positioning:** _KEZ is the sovereign identity layer + encrypted comms for
people who assume the network is hostile._
## Aesthetic direction
**Muted tactical terminal — restraint, not neon cosplay.** Mullvad's calm
authority. Monospace as identity. The first 3 seconds should feel like opening
an operational tool, not a brochure. Hard-ish edges, visible structure, a single
cold accent. No gradients-blobs, no mascots, no "delightful."
### Hard DO-NOTs
- No rounded-blob/gradient SaaS look, no mascots, no illustrations of laughing people.
- No "military-grade / bank-level" marketing adjectives. Show, don't boast.
- No surveillance tells: no third-party analytics, no social login, no email-required signup.
- No stock photography.
## Color palette (dark-first; light theme = v2, out of scope)
Tailwind v4 `@theme` tokens, in `src/app.css`.
| Token | Hex | Use |
|---|---|---|
| `--color-bg` | `#0B0C0E` | app background (neutral near-black) |
| `--color-surface` | `#16181C` | cards, conversation list, sidebars |
| `--color-elevated` | `#1E2127` | modals, menus, input wells |
| `--color-border` | `#2A2E35` | hairlines, dividers |
| `--color-text` | `#E8EAED` | primary text (neutral off-white) |
| `--color-text-secondary` | `#9BA3AD` | secondary |
| `--color-text-muted` | `#5C636D` | timestamps, meta |
| `--color-text-disabled` | `#3A4049` | disabled |
| `--color-accent` | `#28C8E8` | **the KEZ color** — electric cyan |
| `--color-accent-dim` | `#1B9DBC` | hover/pressed, accent borders |
| `--color-accent-contrast` | `#04131A` | text on accent fills |
| `--color-verified` | `#4ADE80` | proof verified (distinct from accent) |
| `--color-danger` | `#FF5C6C` | destructive, failed |
| `--color-warning` | `#FFB13D` | needs-attention |
| `--color-bubble-recv` | `#1B1F25` | received message bubble fill |
Accent is used surgically: send bubbles, focus rings, active nav, the wordmark
cursor, links, live/streaming indicators. Greys carry the weight. **Verified
green is for proofs only** — never as a general accent, so a verification badge
never camouflages into accent UI.
## Typography
- **UI/body:** `Inter``--font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif`
- **Monospace:** `JetBrains Mono``--font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace`. Used for keys, hashes, handles, the wordmark.
Loaded via Google Fonts.
| Role | Size / weight / line-height | Notes |
|---|---|---|
| Wordmark | 22px / 700 / 1.1 mono | `-0.02em`, + cyan block cursor |
| Section header | 12px / 600 / 1.3 sans | uppercase, `+0.08em`, secondary color |
| Body / message | 15px / 450 / 1.45 sans | |
| Conversation name | 15px / 600 / 1.3 sans | |
| Timestamp/meta | 12px / 500 / 1.2 | muted |
| Mono key display | 13px / 500 / 1.5 mono | `+0.01em` |
## Spacing / radius / shadow
- **Spacing** (4px base): 4, 8, 12, 16, 20, 24, 32, 48.
- **Radius — tactical, mid-soft:** `--radius-sm: 4px` (chips/badges), `--radius-md: 8px` (inputs/buttons), `--radius-lg: 12px` (bubbles/cards), `--radius-xl: 16px` (modals). Fully-round reads consumer-soft; sharp reads unfinished; 812 says "engineered."
- **Shadows = terminal glow, not ambient drop shadows.** Surfaces use `1px solid --color-border` hairlines. Modals: `0 8px 24px -8px rgba(0,0,0,0.6)`. Accent focus/glow: `0 0 0 1px #28C8E833, 0 0 16px -2px #28C8E866`.
## Signature components
- **Message bubbles** — radius `lg`, padding `8px 12px`, max-width ~78%.
- Sent: `--color-accent` fill, `--color-accent-contrast` text, `border-bottom-right-radius: 4px` tail.
- Received: `--color-bubble-recv` fill, `--color-text`, `1px solid --color-border`, `border-bottom-left-radius: 4px`.
- **Conversation row** — 64px tall, 40px avatar (`radius-md`), name 600, preview secondary, time muted. Active = left 2px accent bar + elevated bg. Unread = accent dot + name 700.
- **Buttons** — height 40px, `radius-md`, 600. Primary: accent fill / contrast text / dim hover / 0.98 active / glow focus. Secondary: transparent, `1px solid border`, hover elevated bg + accent-dim border.
- **Inputs** — elevated bg, `1px solid border`, `radius-md`, focus → accent border + `0 0 0 3px #28C8E822` ring. Key inputs use mono.
- **Handle/identity chip** — inline mono, `radius-sm`, `2px 8px`, bg `#28C8E814`, `1px solid #28C8E833`, accent text; leading `@`/`0x` muted.
- **Verified proof badge** — `radius-sm`, bg `#4ADE8014`, border `#4ADE8040`, `--color-verified` text, mono 11/600, leading ✓.
- **Avatars** — deterministic identicon generated from the ed25519 key, so every KEZ has a stable face. Eliminates the biggest "prototype" tell.
## Motion
Fast (120200ms), `cubic-bezier(0.2,0.8,0.2,1)`, on state change only, respect
`prefers-reduced-motion`.
- Received message: slide-up 6px + fade.
- Sent message: spring `scale .96→1` + brief accent-glow pulse decaying ~600ms.
- Thread push/back slide on mobile.
- Tasteful terminal flourish: a single cyan block-cursor blink on the empty
compose field + after the wordmark. No content scanlines.
## Wordmark / icon
- **Wordmark:** `kez` lowercase, JetBrains Mono 700, `-0.02em`, primary text,
followed by a blinking cyan block cursor `▌`. The cursor is the brand mark.
- **Icon:** evolve the amber key → cyan. Recolor `public/kez-icon.svg` stroke
`#fbbf24``#28C8E8` on `#0B0C0E`; reshape so the key reads as a
key-meets-cursor glyph. Drop the literal 🔑 emoji everywhere. Regenerate PWA
icon set. Manifest `theme_color` + `background_color``#0B0C0E`.
## Information architecture (the big structural change)
**Land logged-in users on Chats, not a Dashboard.** The "dashboard" as a
destination is killed; its contents redistribute.
### Navigation — 4 destinations
| Destination | Purpose |
|---|---|
| **Chats** | conversation list + threads (the home) |
| **Contacts** | known KEZs + verification status + start-new-chat |
| **Identity** | your KEZ + claims/proofs (the superpower surface) |
| **Settings** | security, backup, notifications, account, about |
- **Mobile (PWA):** fixed bottom tab bar, 4 tabs, unread badge on Chats.
Thread view pushes full-screen with a back chevron.
- **Desktop:** slim left icon rail (4 destinations) + secondary list column +
main content pane. Replaces the current top nav bar entirely.
### Feature → new home
| Existing | New home |
|---|---|
| Landing/Create/Restore/Unlock | unauthenticated flow (pre-nav), restyled |
| Messages (list+thread+compose, SSE, emoji, unread, notifications) | **Chats** (default surface) |
| Start chat by handle | **Contacts → New chat** (preview card before opening) |
| Claims list | **Identity → My proofs** (grouped verified/failed/pending) |
| AddClaim | **Identity → Add proof** |
| Identity display (handle@server, ed25519 key, registry) | **Identity** header card (avatar, copyable KEZ, fingerprint, QR) |
| Seed/key backup | **Settings → Security → Recovery phrase** (re-auth gated) |
| Biometric/passkey | **Settings → Security → App lock** |
| Notifications perm + test | **Settings → Notifications** |
| Build SHA / source link | **Settings → About** |
### New-conversation flow (the KEZ moment)
+ FAB on Chats (mobile) / "New chat" in Contacts column (desktop) →
"Enter a KEZ" (`handle@server`, paste/QR) → `lookup`**preview card**:
avatar, handle, key fingerprint, and **inline verified proofs** (✓ github:you,
✓ dns:yourdomain) → "Message". Verification is always one tap from a thread via
the contact-detail header. You see who someone is before you trust them.
### Polish signals to ship
1. Identicon avatars everywhere (from ed25519 key).
2. Message status ticks (sent / SSE-delivered) + day separators.
3. Real empty + skeleton-loading states.
4. Verification shield badge system (green verified / neutral none / amber failed), consistent across Chats, Contacts, Identity.
5. Native push/back + send transitions; smooth auto-scroll (already shipped).
## Implementation phases
0. **Foundation**`app.css` Tailwind v4 `@theme` tokens, Google Fonts, recolor icon + regenerate PWA assets, manifest colors.
1. **Shell + nav** — bottom tab bar / left rail, router lands on `/chats`, wordmark component.
2. **Chats** — restyle list + thread + bubbles, identicon avatars, empty/skeleton states. Keep SSE/emoji/notifications/auto-scroll.
3. **Identity** — identity card + proofs (migrate Claims/AddClaim).
4. **Settings** — Account / Security / Notifications / About (migrate Dashboard remainder).
5. **Contacts** — list + new-chat preview card with proofs.
6. **Auth flow restyle** — Landing/Create/Restore/Unlock to the new theme.
All existing functionality is preserved; only its placement and presentation change.