diff --git a/README.md b/README.md index 60ccd3429..dea191d60 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@
+ Multi-Agent Chat Interface Logo +

Multi-Agent Chat Interface

@@ -52,6 +54,19 @@ Multi-agent chat interface that enables users to select from configured AI agents and interact with them through n8n workflow webhooks. Built with Next.js 15 and deployed to Cloudflare Workers for global edge performance. +### Screenshots + +

+ Desktop Interface +

Desktop interface with glass-morphism design

+ + Mobile Interface +

Mobile-optimized responsive layout

+ + Chat View +

Chat interface with markdown rendering and syntax highlighting

+
+ ### Key Features - **Multi-agent support:** Dynamically configured agents via environment variables diff --git a/design.json b/design.json new file mode 100644 index 000000000..90d28d5c2 --- /dev/null +++ b/design.json @@ -0,0 +1,447 @@ +{ + "meta": { + "title": "Inspiration Repo Multi-Agent Chat Design DNA", + "generated": "2025-11-15T01:05:52-07:00", + "sourceScreens": [ + "public/ui/desktop.png", + "public/ui/mobile.png", + "public/ui/chat.png", + "public/ui/chatinput.png" + ], + "sourceCode": [ + "src/app/globals.css", + "src/app/layout.tsx", + "src/app/page.tsx", + "src/components/chat-interface.tsx", + "src/components/agent-selector.tsx", + "src/components/header.tsx", + "src/components/markdown-renderer.tsx", + "src/components/diff-display.tsx", + "src/components/ui/button.tsx", + "src/components/ui/dropdown-menu.tsx", + "src/components/ui/dialog.tsx", + "src/components/ui/input.tsx" + ], + "summary": "High-level creative direction that bridges the cinematic mockups with the Tailwind/Radix/Framer code so every contributor can recreate the soft, glassy correspondence room consistently." + }, + "foundations": { + "structure": { + "pageShell": { + "description": "A full-bleed, gradient washed canvas with radial glows that feel like dawn light spilling into a studio. Implemented with .gallery-shell and body background layers (globals.css:126-205).", + "layout": "Stage everything inside a centered column capped at max-w-5xl with generous vertical breathing room. Use px-3/py-4 gutters on mobile and sm:px-6/py-6 on desktop (src/app/page.tsx:57-87).", + "responsive": "At <=639px the shell locks to 100dvh, pads for safe areas, hides scroll bounce, and increases background opacity (globals.css:267-320)." + }, + "centerPanel": { + "description": "The glass manuscript that houses both the empty-state hero and the running conversation. It is a rounded-[2.5rem] surface with layered inset shadows (chat-interface.tsx:285-303).", + "layout": "Use padding px-4 py-8 on phones, sm:px-8 sm:py-10 on desktop. Keep internal content at max-w-[52rem] for text legibility.", + "responsive": "Mobile overrides tighten the radius to 1.75rem, add warm gradients, and enforce overflow hidden (globals.css:304-333)." + }, + "heroStage": { + "description": "The \"hello, user\" marquee introduces the correspondence ritual with oversized type, uppercase prompts, and chip selectors (chat-interface.tsx:382-452).", + "layout": "Stack hero heading, eyebrow copy, agent chips, and two-column prompt cards with gap-6. Keep hero text centered; chips wrap flexibly.", + "responsive": "On mobile the hero collapses into vertical cards styled via .mobile-hero-* helpers (globals.css:332-420)." + }, + "messageFeed": { + "description": "Scrollable column of chat messages with AnimatePresence transitions and max width of 52rem (chat-interface.tsx:306-381).", + "layout": "Use space-y-10 between exchanges, align user bubbles to the right, assistant bubbles to the left, and reserve 10rem bottom padding to clear the composer.", + "responsive": "Mobile feed removes lateral padding and increases bubble radius while maintaining vertical rhythm (globals.css:314-333)." + }, + "composerDock": { + "description": "Floated manuscript panel for input, agent selection, and actions (chat-interface.tsx:460-615).", + "layout": "Width is clamped to 85%/max-w-2xl with p-5 padding. The textarea autosizes up to 224px, and the toolbar flexes between dropdown and actions.", + "responsive": "max-sm:mobile-composer swaps to a dark, pill-shaped dock with white text and saturated send button (globals.css:498-548)." + }, + "dialogCanvas": { + "description": "Palette-shell surfaces establish a museum-like agent picker with swatch cards, blur, and radial tint (agent-selector.tsx:93-165, globals.css:642-782).", + "layout": "Cards live in a responsive 2-column grid inside a rounded 1.5rem container. Each card includes eyebrow, heading, description, and CTA microcopy.", + "responsive": "Intersection observer animates cards in sequence; on narrow screens the grid collapses to a single column with intact spacing." + } + }, + "spacing": { + "baseUnit": "4px (Tailwind default) with compositional emphasis on 12px and 16px steps.", + "scale": { + "xxs": "4px / 0.25rem – icon padding, divider offsets.", + "xs": "8px / 0.5rem – tight gaps between labels and icons.", + "sm": "12px / 0.75rem – message stack gaps, chip gutters.", + "md": "16px / 1rem – standard padding for cards and prompt buttons.", + "lg": "24px / 1.5rem – hero spacing, composer internal gutters.", + "xl": "32px / 2rem – panel padding, hero breathing room.", + "2xl": "40px / 2.5rem – chat-panel outer padding, manuscript radius curvature.", + "3xl": "64px / 4rem – stage-level margins around the primary canvas." + }, + "rules": [ + "Pairs of components should sit on 12px multiples to align with AnimatePresence translate values (15-18px).", + "Use at least 24px vertical gap between stacked sections (hero -> chips -> prompts) to preserve the airy tone.", + "Maintain 16px minimum inset around text within pills or cards to keep glyphs from touching the rounded walls.", + "Composer height changes should never exceed 224px; overflow is hidden to keep the panel silhouette intact." + ] + }, + "typography": { + "fonts": { + "heading": "Playfair Display (var --font-heading, layout.tsx:8-27) – used for hero lines, agent names, dropdown selections.", + "body": "Space Grotesk (var --font-body) – default for conversational text, chips, and descriptive copy.", + "mono": "Geist Mono – reserved for Markdown code, diff displays, and subtle tech cues." + }, + "styles": { + "hero": "Lowercase Playfair at 3.5rem on mobile up to 7rem on desktop, tracking-tight with drop shadow and animation delay per letter.", + "eyebrow": "0.6-0.7rem uppercase, 0.35em letter spacing, muted charcoal (#2d2d2d) at 60% opacity.", + "body": "1rem Space Grotesk at 1.5 line-height inside bubbles, 0.95rem for supportive copy.", + "bubbleTone": "Assistant replies appear in charcoal/dark foreground; user bubbles lean lighter with slight italic for emphasis when needed.", + "buttonCaps": "Chips and CTA buttons use 0.55-0.65rem uppercase text with 0.3em tracking to mimic typewritten labels.", + "monoBlocks": "Markdown code runs at 0.9rem Geist Mono with translucent background capsules." + }, + "usage": [ + "Always mix serif (guiding voice) and grotesk (utility voice) within the same panel to reinforce the sense of correspondence between eras.", + "Limit hero headings to sentence case or lowercase to keep the entrance calm; shouty all caps are reserved for micro labels.", + "Paragraphs should never exceed 75 characters per line; max-w-[52rem] handles this automatically in code." + ] + }, + "colors": { + "palette": { + "burntOrange": "#e67e50 (var --burnt-orange) – glow accents, send button core.", + "terracotta": "#d87850 (var --terracotta) – secondary CTA backgrounds.", + "sageConcrete": "#7a8b8b (var --sage-concrete) – assistant bubbles and neutral glass.", + "charcoalInk": "#2d2d2d (var --charcoal-ink) – primary text, icon strokes.", + "sandstone": "#f3e8d1 (var --sandstone) – accent highlight and prompt cards.", + "inkVeil": "#fdf9f4 – used for popovers and base glass fill.", + "mutedMist": "#cbd2d2 (var --muted) – dividers, placeholders.", + "destructive": "#b3473b (light) / #ff8f7f (dark) – warning feedback (globals.css:28,66)." + }, + "semanticUsage": { + "background": "Dual radial gradients plus a linear haze (globals.css:132-143) to create depth.", + "foreground": "charcoalInk in light mode, #f6ede0 in dark (globals.css:14-68).", + "primary": "burntOrange for CTAs, focus rings, and breathing indicator on agent dropdown (agent-picker-prompt).", + "accent": "Sandstone, used for scroll-reveal cards and hint callouts.", + "border": "Transparent whites or muted sage at 10-20% opacity to keep edges soft.", + "popover": "InkVeil with 10-30% opacity for menus and dialogs." + }, + "gradients": [ + "Background: radial gradient at 20%/80% plus 135° + 180° layers (globals.css:132-140).", + "Chat panel: from white/0 to white/45 for a frosted look (chat-interface.tsx:285-291).", + "Agent picker prompt: animated gradient between burnt orange and sage (globals.css:850-874).", + "Send button (mobile): linear-gradient(135deg, var(--burnt-orange), lighter mix) (globals.css:498-533)." + ], + "opacityGuidelines": "Typical glass overlays sit between 5% and 45% white/black tint. Buttons lean on 15-30% backgrounds with inset 1px white strokes to read as acrylic." + }, + "effects": { + "styleKeywords": [ + "Glassmorphism with inset rim lights.", + "Soft, shallow depth-of-field shadows (0 15px 35px rgba(45,45,45,0.1)).", + "Rounded geometry between 1.25rem and 2.75rem.", + "Backdrops with 12px-18px blur.", + "Subtle motion (fade-slide 18px, shimmer loaders, Framer spring)." + ], + "radii": { + "base": "var(--radius)=0.75rem for inputs.", + "large": "1.5rem+ for cards, message bubbles, composer.", + "pill": "999px for chips and icon buttons.", + "panel": "2.5rem for the chat manuscript." + }, + "shadows": { + "surface": "0 15px 35px rgba(45,45,45,0.1) + inset white strokes for light mode (chat-interface.tsx:285).", + "floatingCTA": "0 10px 25px rgba(0,0,0,0.2) on icon buttons and send button.", + "dialog": "0 25px 45px rgba(45,45,45,0.25) for palette-shell (globals.css:642-690)." + }, + "motion": { + "framerDefaults": "easeOut durations between 0.35s–0.9s; hero letters cascade by 0.05s increments (chat-interface.tsx:390-404).", + "css": "fade-slide keyframe for scroll-reveal, shimmer for loading indicators, agent-picker-breathe for dropdown prompt." + }, + "borders": "Use 1px translucent strokes (border-white/15, border-border/30). In dark mode, switch to rgba(255,255,255,0.12). Corners never go sharp." + }, + "principles": [ + "Treat every interaction like a letter-writing ritual: slow entrances, generous whitespace, serif headings guiding the story.", + "Never expose raw UI rails—cover them with frosted layers or soft gradients to maintain the dreamy atelier mood.", + "Accessibility: uphold 4.5:1 contrast for text on glass; dark mode palette already in globals.css:51-84 handles this.", + "Responsiveness is holistic: rather than shrinking everything, reshape components (mobile-composer, mobile agent chips) to keep the experience bespoke.", + "Consistency: chip shapes, letter spacing, and radius scale must match across dropdowns, hero chips, and composer controls." + ] + }, + "components": { + "AppShell": { + "role": "Scene-setting background that frames the entire conversation.", + "structure": "Full viewport div with class gallery-shell, radial gradient layers, ::after glow veil, and isolation to keep blur effects independent.", + "visuals": { + "background": "Gradient stack defined in globals.css:132-143.", + "overlay": "Pseudo-element adds radial highlight at 15%/85% (globals.css:342-352)." + }, + "states": ["default", "mobile-safe-area", "dark-mode (html.dark)"], + "responsive": "Switch to fixed-height 100dvh, hide scrollbars, and scale down padding (globals.css:267-333).", + "codeRefs": [ + "src/app/page.tsx:57-90", + "src/app/globals.css:255-333" + ] + }, + "HeroEmptyState": { + "role": "Welcomes the user before any conversation exists.", + "structure": "Motion block comprising heroGreeting letters, guidance copy, chip selector, and suggestion grid.", + "visuals": { + "text": "Playfair Display 3.5-7rem, text-white/85 + drop shadow.", + "chips": "Rounded-full borders with two visual states (active vs hover).", + "suggestions": "Scroll-reveal cards with white/80 backgrounds." + }, + "states": [ + "default (no messages): show hero, chips, prompts.", + "agents-loading: display placeholder copy.", + "agent-selected: highlight active chip with white fill." + ], + "interactions": "Motion spans animate via Framer, prompt buttons set the composer input, chips trigger handleComposerAgentSelect.", + "codeRefs": [ + "src/components/chat-interface.tsx:382-452" + ] + }, + "AgentChip": { + "role": "Represents each correspondent option both in hero chips and dropdown menu.", + "structure": "Rounded-full button with uppercase label, 0.35em tracking, px-4 py-2 padding.", + "visuals": { + "default": "border-white/10 bg-white/5 text-white/70.", + "active": "border-white/25 bg-white/25 text-white with shadow.", + "mobile": "full-width pill (.mobile-agent-chip) with warm white fill (globals.css:399-419)." + }, + "states": ["default", "hover", "active", "disabled (when agents loading)"], + "codeRefs": [ + "src/components/chat-interface.tsx:406-428", + "src/app/globals.css:399-419" + ] + }, + "PromptCard": { + "role": "One-tap inspiration snippet inside the hero state.", + "structure": "Rounded-2xl card with border-border/30, white/80 background, p-4 text-left body copy.", + "states": ["rest", "hover (border-ring/60 + bright background)"], + "codeRefs": [ + "src/components/chat-interface.tsx:435-450" + ] + }, + "ChatPanel": { + "role": "Primary conversation container providing the glass manuscript look.", + "structure": "motion.div with gradient background, px-4/py-8 padding, shadow stack, and rounded-[2.5rem].", + "visuals": { + "light": "From white/0 to white/45 fill, inset highlights.", + "dark": "Transparent to white/20 gradient with deeper drop shadow (chat-interface.tsx:285-291)." + }, + "states": ["empty (shows hero)", "active conversation (shows feed + toolbar)"], + "codeRefs": [ + "src/components/chat-interface.tsx:285-304" + ] + }, + "MessageBubble": { + "role": "Displays user and assistant messages with distinct glass treatments.", + "structure": "div with class message-bubble plus .user or .assistant modifiers.", + "visuals": { + "assistant": "rgba(255,255,255,0.56) background, 1px charcoal mix border, 1.5rem radius (globals.css:809-828).", + "user": "Lighter background, inset white strokes, tighter padding (globals.css:818-824).", + "darkMode": "Switch to darker glass with 0.15 opacity borders (globals.css:831-848)." + }, + "states": ["user", "assistant", "error (plain text in destructive color)", "loading shimmer placeholder"], + "interactions": "Assistant bubbles contain Markdown-rendered content with copy + diff actions.", + "codeRefs": [ + "src/components/chat-interface.tsx:324-369", + "src/app/globals.css:784-848" + ] + }, + "MessageToolbar": { + "role": "Inline actions beneath assistant replies (copy button, hints).", + "structure": "Flex row with copy icon button, border-t accent, opacity transition.", + "visuals": "Buttons use 7x7 px icon pill with border-white/20 and hover scale. Hints appear as rounded accent cards (chat-interface.tsx:347-369).", + "states": ["rest", "hover (opacity 100%)", "copied (scale-90 + white background)", "hint present (accent panel)"], + "codeRefs": [ + "src/components/chat-interface.tsx:347-369" + ] + }, + "HintCallout": { + "role": "Optional assistant side-note or remediation tip.", + "structure": "Rounded-lg border border-accent/60 background accent/40, px-3 py-2 text-xs.", + "visuals": "Sandstone hue with charcoal text keeps hints friendly.", + "codeRefs": [ + "src/components/chat-interface.tsx:363-369" + ] + }, + "MarkdownBlock": { + "role": "Renders formatted assistant content with diff tool support.", + "structure": "ReactMarkdown with remark-gfm + rehype-highlight, wrapped by markdown-glass class (markdown-renderer.tsx:1-205).", + "visuals": { + "text": "Space Grotesk 0.95rem, base tone text-charcoal/dark:foreground.", + "code": "Rounded capsules with white/60 backgrounds; block code uses PreWithCopy with inline copy button.", + "tables": "Translucent backgrounds with subtle borders (markdown-renderer.tsx:84-152)." + }, + "states": ["default", "diff-tool placeholder (replaced at runtime)", "copy success (button scales)."], + "codeRefs": [ + "src/components/markdown-renderer.tsx:1-205" + ] + }, + "Composer": { + "role": "Input system for crafting the next note, including textarea, agent dropdown, send and attachment controls.", + "structure": "motion.div (composer-affix) containing form, optional image preview grid, and manuscript-panel with flex column.", + "visuals": { + "panel": "Frosted acrylic with inset highlights (globals.css:876-888).", + "textarea": "Borderless, hide-scrollbar, 1rem-1.125rem text.", + "toolbar": "Dropdown pill + action buttons aligned end." + }, + "states": [ + "idle (prompt highlight pulses if no agent chosen).", + "typing (textarea animates height).", + "sending (send button shows Loader2).", + "disabled (buttons opacity 50%).", + "image-selected (thumb grid appears)." + ], + "responsive": "Mobile variant (mobile-composer) flips to dark background, white text, saturated send button, and full-width layout (globals.css:498-548).", + "codeRefs": [ + "src/components/chat-interface.tsx:460-615", + "src/app/globals.css:498-633" + ] + }, + "AgentDropdown": { + "role": "Radix-powered list to pick which agent the composer routes to.", + "structure": "DropdownMenuTrigger -> DropdownMenuContent with DropdownMenuItem entries.", + "visuals": { + "trigger": "Rounded-2xl pill, border-white/20, bg-white/30, uppercase microcopy (chat-interface.tsx:528-535).", + "menu": "Glass sheet with border-white/15, white/10 fill, and text-white icons (chat-interface.tsx:536-569, dropdown-menu.tsx:1-200)." + }, + "states": ["prompt highlight (agent-picker-breathe), default, disabled (no agents), active item showing \"Active\" badge."], + "codeRefs": [ + "src/components/chat-interface.tsx:528-569", + "src/components/ui/dropdown-menu.tsx:1-200", + "src/app/globals.css:626-656" + ] + }, + "Button": { + "role": "Primary interactive primitive from shadcn/ui.", + "structure": "cva-powered variants (default, destructive, outline, secondary, ghost, link) plus size scale (button.tsx:1-60).", + "visuals": "Rounded-md base with focus rings using var(--ring); icon variants are perfect squares (size-8/9/10).", + "states": ["hover (color lighten/darken), focus-visible ring, disabled pointer-events-none."], + "codeRefs": [ + "src/components/ui/button.tsx:1-60" + ] + }, + "InputField": { + "role": "Text + file inputs share the same translucent style (input.tsx:1-23).", + "structure": "h-9, px-3, border border-input, placeholder muted, selection colors follow primary palette.", + "states": ["focus-visible ring", "disabled (opacity 50%)", "aria-invalid (destructive ring)."], + "codeRefs": [ + "src/components/ui/input.tsx:1-23" + ] + }, + "IconButton": { + "role": "Circular or rounded-square button for single glyph actions (new chat, copy, send, attach).", + "structure": "Button component with size=\"icon\" or custom classes (h-11 w-11) plus backdrop blur.", + "visuals": "Use 10-20% white fill, 20% border, slight drop shadow. Send button uses 12x12 icon at center with group hover transitions.", + "states": ["default", "hover lighten", "disabled (opacity)", "copied state scale-90].", + "codeRefs": [ + "src/components/chat-interface.tsx:292-303", + "src/components/chat-interface.tsx:573-608" + ] + }, + "ImageAttachmentThumb": { + "role": "Preview of uploaded images prior to sending.", + "structure": "3.4rem square, rounded-lg, border-border/40, object-cover image plus remove FAB at -right-2 -top-2.", + "visuals": "Shadow-md drop, charcoal-ink close button with white icon (chat-interface.tsx:467-485, globals.css:575-616).", + "states": ["default", "hover remove button (opacity 80%)."], + "codeRefs": [ + "src/components/chat-interface.tsx:467-485", + "src/app/globals.css:575-616" + ] + }, + "DiffPanel": { + "role": "Expandable timeline of code/text changes for responses requesting diff visualization.", + "structure": "Collapsible card with header (title, language, expand button, copy button) and optional diff body (diff-display.tsx:1-200).", + "visuals": { + "header": "Neutral-900/50 background, border-neutral-800, text-white/neutral.", + "diffLines": "Green for additions, red for removals, neutral for unchanged; column shows old|new numbers." + }, + "states": ["collapsed", "expanded", "copied (Check icon)."], + "codeRefs": [ + "src/components/diff-display.tsx:1-200" + ] + }, + "AgentSelectorDialog": { + "role": "Modal palette for browsing configured agents.", + "structure": "Radix Dialog overlay + palette-shell container with scroll-reveal card grid (agent-selector.tsx:93-165).", + "visuals": { + "shell": "Linear-gradient background, border color-mix charcoal, 25px drop shadow (globals.css:642-690).", + "cards": "Swatch cards with tinted overlays, uppercase eyebrow, Playfair name, avatar coin (globals.css:699-782)." + ], + "states": ["loading (Loader2 + caption)", "error (destructive block)", "ready (card grid)."], + "interactions": "Click card selects agent, stores to localStorage, closes dialog.", + "codeRefs": [ + "src/components/agent-selector.tsx:1-165" + ] + }, + "HeaderBar": { + "role": "Optional sticky heading (header.tsx) for contexts outside the main chat manuscript.", + "structure": "Stacked serif heading + dropdown button when no agent is selected.", + "visuals": "Text-white hero, dropdown uses same glass pill treatment as composer but full width (header.tsx:10-63).", + "states": ["agent-selected (shows name only)", "no-agent (shows dropdown)."], + "codeRefs": [ + "src/components/header.tsx:1-74" + ] + } + }, + "patterns": { + "conversationFlow": { + "description": "Hero stage invites selection, conversation feed takes over once a message exists, and composer remains anchored at the bottom.", + "steps": [ + "No messages -> show HeroEmptyState with chips and prompts.", + "User selects agent or prompt -> composer label updates and highlight stops pulsing.", + "Message send triggers user bubble append, then assistant bubble, plus copy toolbar.", + "New chat resets state and animates hero back in." + ], + "codeRefs": [ + "src/components/chat-interface.tsx:278-369" + ] + }, + "agentPersistence": { + "description": "Selected agents and chat sessions persist in localStorage so the UI can reload context silently.", + "details": "ChatInterface stores chat-session-{agentId} and chat-messages-{agentId}; AgentSelector/Header store selected-agent JSON (chat-interface.tsx:68-154, agent-selector.tsx:83-90, page.tsx:10-70).", + "codeRefs": [ + "src/components/chat-interface.tsx:58-155", + "src/app/page.tsx:10-70", + "src/components/agent-selector.tsx:83-90" + ] + }, + "imageUpload": { + "description": "Optional image attachments convert to base64, preview in a thumb reel, and can be removed via floating X.", + "states": ["images empty", "images present -> preview grid + remove buttons."], + "codeRefs": [ + "src/components/chat-interface.tsx:127-200", + "src/components/chat-interface.tsx:467-485" + ] + }, + "diffInspection": { + "description": "Assistant replies can embed ```diff-tool``` blocks that render a collapsible diff viewer with copy-to-clipboard.", + "codeRefs": [ + "src/components/markdown-renderer.tsx:15-91", + "src/components/diff-display.tsx:1-200" + ] + }, + "emptyStateToActive": { + "description": "AnimatePresence swaps hero for conversation with slide/fade transitions while preserving chat-panel height to avoid layout jump.", + "codeRefs": [ + "src/components/chat-interface.tsx:314-381", + "src/components/chat-interface.tsx:382-452" + ] + }, + "responsiveStrategy": { + "description": "Custom CSS classes override Tailwind tokens for small screens: body overflow hidden, safe-area paddings, composer redesign, chip restyling.", + "codeRefs": [ + "src/app/globals.css:267-563" + ] + }, + "interactionShortcuts": { + "description": "Enter submits, Shift+Enter inserts newline; copy buttons provide quick clipboard access; new chat button resets session; dropdown disabled state communicates loading.", + "codeRefs": [ + "src/components/chat-interface.tsx:252-275", + "src/components/chat-interface.tsx:292-305", + "src/components/chat-interface.tsx:324-369" + ] + } + }, + "codeIntegration": { + "stylingApproach": "Tailwind CSS v4 via @import plus bespoke component classes live in src/app/globals.css (lines 1-940). Utility helper cn() merges classes (src/lib/utils.ts:1-7).", + "componentArchitecture": "UI primitives from shadcn (Button, Input, DropdownMenu, Dialog) live in src/components/ui, while experience-level pieces (ChatInterface, AgentSelector, Header, MarkdownRenderer, DiffDisplay) compose those primitives. Naming stays PascalCase with descriptive file names.", + "designTokens": "CSS variables defined in :root/.dark (globals.css:6-84) provide color + radius tokens; @theme inline exports them for Tailwind usage. Maintain palette references when adding new surfaces.", + "stateManagement": "React hooks manage UI: ChatInterface tracks messages, inputs, loading states, composer agent, textarea height, and copiedMessageId; useEffect wires localStorage persistence and scroll behavior; useFlags (src/lib/use-flags.ts:1-50) gates optional features (image uploads, diff tool).", + "compositionPatterns": "Framer Motion powers fades/slides (chat-interface.tsx:285-463). Radix primitives supply semantics for dropdowns and dialogs. MarkdownRenderer pipelines remark/rehype for formatting and diff embedding.", + "responsiveImplementation": "Globals define mobile overrides using @media (max-width:639px) plus helper classes like mobile-feed and mobile-composer (globals.css:267-563). Components toggle those classes with Tailwind responsive modifiers (e.g., max-sm:mobile-composer).", + "accessibility": "Focus-visible rings built into Button/Input, aria-invalid states, sr-only spans on dialog close, and uppercase microcopy with adequate color contrast. Enter handling prevents multi-line send mistakes, but shift+enter is respected.", + "dataFlow": "API calls hit /api/agents and /api/chat; responses feed MarkdownRenderer or set error states that bubble into message list. Feature parity between design + code requires storing new metadata (hints, images) on Message records (src/lib/types.ts:20-55)." + } +}