Redesign the Tessera frontend completely. The current version is functional but has poor UX. This is a complete rewrite of the visual design and layout — keep the existing API client (web/src/lib/api.ts) and types (web/src/lib/types.ts), rewrite everything else. ## DESIGN SYSTEM: Linear-inspired dark mode Use the exact design tokens from the Linear design system: - Background: #08090a (canvas), #0f1011 (panels), #191a1b (cards) - Text: #f7f8f8 (primary), #d0d6e0 (secondary), #8a8f98 (tertiary) - Border: rgba(255,255,255,0.08) (standard), rgba(255,255,255,0.05) (subtle) - Accent: #5e6ad2 (primary), #7170ff (interactive), #828fff (hover) - Font: Inter (from next/font/google), weight 400/510/590 - No pure white anywhere (#f7f8f8 is max brightness) - No color besides indigo/violet accent and status colors Status colors: new=#8a8f98, open=#7170ff, in_progress=#f59e0b, resolved=#22c55e, closed=#6b7280 ## PAGES TO REWRITE ### 1. Layout (web/src/app/layout.tsx) - Full-height app shell: sidebar + main content - LEFT SIDEBAR (240px, fixed): - "Tessera" brand at top (indigo gradient text or icon) - Saved views section with counts: - All tickets (count) - My tickets (count) - Unassigned (count) - Recently updated (count) - Queues section (dynamic list with counts) - Bottom: Admin link (gear icon), user avatar placeholder - Sidebar styling: bg-[#0f1011], border-r border-[rgba(255,255,255,0.05)] - Active view: bg-[rgba(255,255,255,0.05)], text-white - Inactive view: text-[#8a8f98] hover:text-[#d0d6e0] - Each nav item: flex justify-between, icon + label left, count badge right ### 2. Ticket List — the main view (web/src/app/page.tsx) This is THE primary technician view. It must be fast and scannable. - TOP BAR: search input (full width, bg-[#0f1011], border-b), "New ticket" button (indigo) - Below: filter chips row — "All", "Open", "In progress", "Resolved", "My tickets", "Unassigned" — clickable pills - TICKET LIST (not a heavy data table — a sleek list): - Each row: colored status dot (8px circle) + ticket ID (first 8 chars, monospace, muted) + subject (primary text) + queue badge + assignee avatar + relative time - Hover: subtle bg change, show quick actions (assign, change status) - Click: navigate to detail - Loading: skeleton rows (pulsing bg-[#191a1b]) - Empty: "No tickets match your filters" with illustration - Bottom: "Load more" or pagination - CREATE TICKET DIALOG: modal with subject input + queue select + description textarea + submit ### 3. Ticket Detail — two-panel layout (web/src/app/tickets/[id]/page.tsx) This is the heart of the product. Conversation-centric. LAYOUT: - LEFT (60%): Conversation thread + reply box - RIGHT (40%): Properties sidebar CONVERSATION THREAD: - Each entry is a message bubble, not a table row - Customer messages: left-aligned, lighter bg - Agent replies: right-aligned or indigo-tinted - System events (status changes, assignments): centered, muted, small text, no bubble — inline timeline entries like "Gjermund changed status from open → in_progress · 2 minutes ago" - Timestamps: relative (formatDistanceToNow from date-fns), absolute on hover - Avatars: initials circle (first letter of name), colored by hash REPLY BOX (sticky at bottom of thread): - Textarea with placeholder "Reply to this ticket..." - Toggle: "Reply" (public) vs "Internal note" (private) — tab-like toggle - Send button (indigo) + attachment button (paperclip icon, disabled for now) PROPERTIES SIDEBAR (right panel, bg-[#0f1011], border-l): - Status selector: large, prominent dropdown with color indicator - Priority: not yet implemented, show placeholder - Assignee: dropdown to assign/change owner - Queue: display name - Custom fields: name: value pairs, editable inline - Created/Updated: display dates STATUS CHANGE: - Click status in sidebar → dropdown shows allowed transitions (from lifecycle) - Selecting a new status shows preview of scrips that will fire (inline, not modal) - Confirm button: "Apply — 2 scrips will fire" - After apply: show scrip results inline (success/error with message) ### 4. Admin (web/src/app/admin/page.tsx) - Same sidebar layout (no changes) - Content area: tabs across top (Queues, Lifecycles, Scrips, Custom Fields) - Each tab: clean card-based layout, not data tables - Add button in each section header - Forms in slide-over sheets (from right), not dialogs — sheets feel more professional - Delete/edit: subtle icon buttons on hover ### 5. COMMAND PALETTE (new — web/src/components/command-palette.tsx) - Trigger: Cmd+K or Ctrl+K - Modal overlay with search input - Actions: "New ticket", "Go to tickets", "Go to admin", search tickets by subject - Keyboard navigation: arrow keys + enter - Dimmed backdrop with bg-black/60 ## IMPLEMENTATION NOTES - Keep web/src/lib/api.ts and web/src/lib/types.ts as-is (they work) - Delete all current page files and rewrite from scratch - Delete current layout.tsx, page.tsx, tickets/[id]/page.tsx, admin/page.tsx - Install: bun add cmdk (command palette library) or build simple one with shadcn Dialog - All shadcn/ui components import from @/components/ui/... — reuse what's there - Sidebar needs to be a client component with state for active view - Use next/navigation for routing - Loading states: skeleton everywhere (not spinners) - Error states: inline red text with retry - Empty states: helpful text + action button ## VERIFICATION 1. `cd web && bun run build` — zero TypeScript errors 2. Start backend on 9876, frontend on 3000-something 3. Verify: sidebar renders with saved views, ticket list shows real data, ticket detail has conversation thread + sidebar, admin has tabs in sheets 4. Commit each major section ## RULES - All code via OpenCode. Hermes orchestrates. - Rewrite is complete — do not keep old components - Linear design tokens must be used exactly — verify colors match spec - No placeholders that look broken — every state must render properly