| Element | Hex | Usage |
|---|---|---|
| Title Bar | #EBEBEB |
Top header bar containing search and navigation |
| App Bar (Nav Rail) | #EBEBEB |
Far-left vertical icon navigation |
| Search Bar | #FAFAFA |
Search input in the title bar |
| Chat List | #F5F5F5 |
Chat list panel (right of the app bar) |
| Chat Canvas | #FFFFFF |
Main area where chat messages are displayed |
| Agents Rail | #FAFAFA |
Right-side rail for per-conversation agents |
| Channel Thread Rail | #FFFFFF |
Right-side rail for a channel post's replies |
The title bar, app bar, and chat list form a cool neutral palette that matches current Microsoft Teams. The chat list is slightly lighter than the chrome so its surface reads as a container nested inside it. The search bar is the lightest surface in the header, floating on top of the title bar.
| Element | Hex | Alignment |
|---|---|---|
| Other User | #F5F5F5 |
Left-aligned |
| Current User | #E8EBFA |
Right-aligned |
| Element | Hex | Notes |
|---|---|---|
| Chat item hover + selected | #FCFBFA |
Same fill for both states — a chat doesn't get a separate "selected" treatment. Subtle off-white above the #F5F5F5 panel. |
| Active tab text | #242424 |
Bold, no background fill |
| Inactive tab text | #616161 |
Regular weight, no background fill |
Shape: hover/selected fills render as a rounded rectangle with side insets (margin: 0 8px, border-radius: 4px, content padding reduced by the same amount) — the highlight does not stretch full-width of the panel. Applies uniformly to chat items, pinned items (Copilot / Quick views), team rows, and channel rows.
Sourced from live Teams (dev-tools inspection).
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Web', sans-serif;Set globally on body in src/index.css. All components should inherit — avoid overriding font-family in component CSS.
- Size:
14px(Teams expresses this as1.4remon a10pxroot; we use px directly) - Line height:
1.4286(unitless, inherited; produces 20px for 14px text)
- Size: 14px
- Weight:
400regular,600when the chat is bold/unread
- Size: 18px
- Weight:
700 - Line height: inherits the body
1.4286(≈25.7px at 18px)
- Size: 14px
- Weight:
400inactive,600active - Color:
#424242inactive,#242424active - Spacing:
6pxgap between tabs - Truncation:
max-width: 150pxwithtext-overflow: ellipsisandwhite-space: nowrap— keeps long chat names from breaking the header layout - Active tab marker: 3px underline in Teams purple (
#6264A7),2pxborder-radius, spans the tab label width only (not the full button click area — rendered via::afteron the content box)
Pass size to the common Avatar component. Established sizes:
| Surface | Size |
|---|---|
| Chat list item | 20 |
| Title bar (current user) | 28 |
| Chat view header | 28 |
| Message row | 32 |
| Agents rail list + detail header | 24 |
| Prompt-suggestions empty state | 72 |
The status dot scales automatically (~28% of avatar size, min 6px) — no need to tune it per surface. Matches real Teams: 20px avatar → 6px dot, 28px → 8px, 32px → 9px, 36px → 10px.
- People, groups, agents: circle (
border-radius: 50%). - Channels (
contact.isChannel): rounded square. Radius is ~18% of size (min 3px) so it scales with the surface — matches the way Teams visually distinguishes channels from chats in the unified chat list.
Standard divider used throughout the app (chat list header rows, chat view tab bar, section separators):
- Style:
1px solid #E8E8E8 - Use consistently anywhere a subtle horizontal rule is needed between sections.
When you need a new icon, start your search at fluenticons.co — it's the Fluent UI icon set that matches Teams' visual language.
Before adding an icon inline, check src/components/common/Icon.jsx — the shared library already covers common cases (Close, Plus, ChevronDown, ChevronLeft, Send, Clock, Search, Dots, EmojiAdd, Edit, Lock). Add new reusable icons there rather than inlining SVG in feature components.
- Size: 24×24 SVG inside a 28×28 wrap (larger than Teams' typical 20px — the icons read more clearly at this size and the prototype skews the detail up slightly)
- Inactive state: Outlined icons,
#666666 - Active state: Filled icons, Teams purple (
#5B5FC7); same color drives a 3px left-edge active indicator spanning the full height of the nav-item row (flush top to bottom, not capped) and an 8% tinted background fill (rgba(91, 95, 199, 0.08)) - Clickable surfaces:
chatandactivitytoggle the left pane (ChatList ↔ ActivityList). Others are decorative for now.
Bubble edges line up with the edges of the compose field in all chat canvases (1:1, group, and channel) so the conversation reads as a single vertical column anchored to the same left/right rails as input:
- Others' bubble left edge aligns with compose left edge
- Mine bubble right edge aligns with compose right edge
- Avatars extend past those rails (to the left for others, to the right for mine in group chats)
Implemented by setting .messages-container side padding to 24px (matching .chat-compose), then pulling the message row horizontally with margin-left: -40px (others) / margin-right: -40px (mine + avatar) so the 32px avatar + 8px gap lands outside the compose rail. In 1:1 chats my own messages have no avatar, so the mine row sits flush with no negative margin.
Reaction pills render under the bubble (left-aligned for others' messages, right-aligned for mine). Pills are oval (border-radius: 12px, height: 24px), white background with a 1px solid #E0E0E0 border. A reaction the current user has added flips the border to Teams purple (#6264A7) so "mine" vs "theirs" is visually clear.
- Hover toolbar (
MessageActions) appears above the bubble on hover: four quick-reaction emojis (👍 ❤️ 😂 😮), a full emoji-picker trigger, a divider, thenEditandMore options. Quick reactions toggle the current-user flag on that emoji when clicked.
Under a bubble that has replies (channel posts with replies, private agent threads with a threadReply badge), a small pill shows:
- Up to 3 participant avatars (18px, overlapping
-6pxwith a 1.5px white ring) 1 reply/N replieslabel in 12px/600 Teams purple (#6264A7)- Hover fills with
#F0F0F0
Click behavior depends on surface:
- Channel post: opens
ChannelThreadRailwith root + replies + compose - Private agent thread (Jira demo flow): toggles the
AgentsRailopen/closed on the agent who owns the thread
Used for the anchor message of an agent thread that's visible only to the user and the agent:
- A
PrivateDisclaimerstrip at the top: lock icon +Only you can see this conversationin 11px#616161 - A thin
1px solid #BDBDBDborder around the whole bubble - Background stays the standard mine color (
#E8EBFA)
Channel chats render a "Threads" layout. Each post has a subject (15px/600) rendered inside the bubble above the body. Posts live in src/data/channelPosts.js keyed by channel contact id. Replies are shown in ChannelThreadRail, not in the main canvas — the main canvas only shows the root posts.
Channel post bubbles get a slightly wider max-width (80% vs the default 65%) because they tend to be announcement-style and run longer.
New-session empty state for an agent chat: centered 72px avatar + agent name + short description + a 2×3 grid of suggestion cards. Defined in src/data/promptSuggestions.js keyed by agent contact id; each card has a title, description, the text to send, and a canned response.
Agents send rich, interactive content via the Adaptive Cards framework — the format the Teams team recommends for agent-authored content. When the user asks you to have an agent send content (status summaries, ticket details, action prompts, etc.), reach for an adaptive card rather than freeform text when the content is structured.
In the prototype's message model, adaptive cards attach to a message via message.cards — an array of card objects. The renderer (in MessageRow.jsx) currently supports:
{
accentColor: '#5B5FC7', // left border color (3px stripe)
// Header row — optional Office-app icon tile + title + optional badge.
iconType: 'word', // 'word' | 'excel' | 'powerpoint' | 'outlook' | 'teams'
title: 'Northwind partner readout — Brief.docx',
subtitle: 'One-pager covering scope, status, key risks, and partner asks.',
badge: { text: 'Ready', tone: 'green' }, // tone: 'amber' | 'green' | 'purple' | 'neutral'
// Plan steps with status pips (pending → running → done).
steps: [
{ text: 'Aggregate context from the last 30 days', status: 'done' },
{ text: 'Pull external signals with citations', status: 'running' },
{ text: 'Draft one-page brief in Word', status: 'pending' },
],
// Grouped sections — each can mix headings, bullets, free text, and facts.
sections: [
{ heading: 'Sources', bullets: ['Northwind launch channel', '3 partner email threads'] },
{ heading: 'Output', text: 'One-page Word summary with inline citations.' },
],
// Inline label/value pairs (still useful for compact metadata).
facts: [
{ label: 'Citations', value: '8 sources' },
{ label: 'Saved to', value: 'Northwind / Launch /' },
],
// Subtle metadata strip with a top divider — good for "Generated by..." lines.
footer: 'Generated by Cowork · Mon 9:11 AM',
// Link-style action buttons.
actions: ['Open in Word', 'Show citations'],
}Schema rules:
- Office-app icon tiles (
iconType: 'word' | 'excel' | 'powerpoint' | 'outlook' | 'teams') render a 32px rounded-square tile with the brand color and capital letter — use them for artifact cards so generated deliverables read as M365 outputs at a glance. Pair withaccentColormatching the brand color (#2B579AWord,#217346Excel,#B7472APowerPoint,#0078D4Outlook,#5B5FC7Teams). - Plan cards should use
iconType: 'teams',badge: { text: 'Awaiting approval', tone: 'amber' }, andstepswith allstatus: 'pending'. Useactions: ['Approve & run', 'Edit plan'](or similar) so the plan reads as a checkpoint. - Artifact cards (a deliverable Cowork produced) should use the matching Office
iconType, asubtitledescribing what the artifact is, optionally abadge: { text: 'Ready', tone: 'green' }, and afooter: 'Generated by Cowork · <time>'. - Daily/recurring outputs (digests, summaries, reports) should use
sectionswith one heading per theme — preserves the "scannable, themed" reading pattern users expect from agent reports.
Real Adaptive Cards support richer elements still (images, input fields, action sets, containers, choice sets). Extend the renderer in MessageRow.jsx and the CSS in ChatView.css (.adaptive-card, .card-*) as the prototype needs them — match the official Adaptive Cards samples and the design best-practices guide for visual fidelity.
Channels appear in the chat list grouped under their parent team:
- Teams are defined in
contacts.jsvia theteamsexport (id, name, initials, color,channels: [{ id, bold? }]). - Team icons use the rounded-square treatment (same as channel avatars), indent-aligned with their channel rows.
- Clicking a channel selects it; channel chats use the "Conversation" / "Shared" tabs (vs "Chat" / "Shared" / "Recap" / "Storyline" for regular chats).
Red pulsing arrows (#E8173A) cue the viewer to the next click target during a prototype walkthrough. Use the reusable DemoArrow component in components/common/ — do not inline a new SVG arrow.
Visual spec:
- Color:
#E8173A - Animation: ~1.5s opacity (
1→0.4) +translatenudge (3px) toward the target - Directions:
'left' | 'right' | 'up' | 'down' - Size: 24px default, caller-tunable
Usage rules:
- Positioning is the caller's job. Typically
position: absoluteanchored near the target, inside a wrapper withpointer-events: noneso clicks pass through to the target underneath. WrapDemoArrowin a positioning<span>/<div>rather than relying on the arrow's own layout. - Arrows are ephemeral. Track a
show/hidestate wherever the target's click handler lives and unmount the arrow once the target is clicked so it doesn't linger after the action is taken. Clearing persistently (rather than toggling) matches demo/tutorial conventions. - One arrow per target at a time — don't stack hints.
The disabled scripted Jira flow in ChatView.jsx retains pre-DemoArrow inline arrow styles (.main-compose-hint-arrow, .demo-hint-arrow-send in Compose.css; .agent-chat-hint-arrow in AgentsRail.css) as a reference pattern only. Any new walkthrough should use DemoArrow instead.