Pack for Friday demo
Cards summarize a thing, show compact metadata, and click through to details.
Design system
Use typography, spacing, and color to clarify hierarchy and state. Avoid decoration that does not help someone decide what to read or do next.
Foundations
Use semantic CSS variables from app/globals.css for product UI. Add new roles there first, then consume them with Tailwind arbitrary values.
--surface-pagePage background--surface-panelCards, panels, sidebars--surface-inputInputs and quiet controls--surface-controlPills and tonal controls--surface-hoverHover surface step--text-primaryPrimary text--text-secondarySecondary text and helper copy--text-completedCompleted item text--border-subtleForm and quiet control borders--border-controlInteractive control borders--border-strongPanel and card borders--border-dividerInterior separators--accent-primaryPrimary actions and focus--accent-dangerDestructive actionsFoundations
Keep the type scale compact. Use the system sans stack for UI and reserve the display face for the Buttle wordmark.
text-2xl font-semiboldtext-lg font-semiboldtext-xs font-medium uppercase tracking-[0.08em] text-[var(--text-secondary)]text-sm text-[var(--text-primary)]text-sm text-[var(--text-secondary)]text-xs font-medium tabular-numsActions
Use shared button recipes for repeated tones. Filled buttons reduce opacity on hover, tonal and danger buttons use the hover surface, and text actions shift to the accent hover color.
Surfaces
Panels use a quiet background with a strong border. Do not nest full panel surfaces for layout. Framed form question groups can sit inside a form panel when each group needs its own scanning boundary.
Forms
Form controls use input surfaces, subtle borders, clear labels, visible focus, and immediate feedback for pending or changed states.
Feedback
Every action needs a visible acknowledgement: active state, disabled pending state, optimistic row state, inline status text, or a spinner.
Disable the control while the server action is pending.
Saved just now
Could not sync calendar
Interests
Public profiles lead with identity, status, and clear interest choices. Interest cards and pills need selected, disabled, and read-only states because visitors use them to start a chat.
@ada
Bio copy stays narrow and direct. The fallback avatar uses the display face, but the rest of the profile stays in the system sans.
Large ranked interest cards may use filled accent for selected state. Compact interest pills use the quieter outline selected state.
Interests
The composer uses large ranked tiles for top interests, wrapped pills for the rest, and visible states for adding, dragging, editing, archiving, and empty slots.
Rows
Dense lists reveal detail in place. Disclosure buttons sit inside the row, recurring badges stay attached to titles, and truncated groups use a small text action.
Note reveal copy stays secondary and appears directly under the row.
What time should we start?
Scheduling
Scheduling surfaces use panel shells, two-column slot grids on wider screens, radio-like rows, inline sentence selects, and plain privacy copy.
Pick a 10-minute slot. Slot rows use the same hover surface and selected accent as other option controls.
We only store your busy times. We will not see event names, attendees, or locations.
Let people book up todays out withminutes notice.
Calls
Call UI is more immersive than admin UI. The live call surface is full-bleed, while request trays stay compact and action-oriented.
Live requests
Jules wants to chat about espresso gear
Waiting for 1 minute.
Remote video fills the call surface.
Trust
Authorization and copy flows need explicit feedback. Show what is being approved or copied, make long URLs readable, and acknowledge success in place.
Allow Local Agent to access Buttle?
This app was created recently. Check the redirect URL before you continue.
https://example.localhost/oauth/callback?client_id=local-agent
Copyable URL fields should match the radius of surrounding form controls. Use rounded-sm only for dense inline chips or toolbar-scale controls. Copy feedback swaps the icon, updates nearby text, and announces the change with aria-live.
Implementation
Keep one-off style ownership local. Promote styles when multiple files need the same behavior or when the behavior is easy to miss.
Keep local *ClassName constants when one component owns the style.
Use composeButtonClassName() for repeated button tones and composePanelClassName() for standard panels.
Add new color roles in app/globals.css before using them in JSX.
Every clickable element needs hover and active feedback, and pending actions need local acknowledgement.