Cinatra — Application Design — Components

The shared component vocabulary: the shadcn/ui roster Cinatra ships, the design rules each primitive inherits, and the host-provided composite steps. Part of Cinatra Application Design — the tokens, surfaces and accents these components map to live in that reference. Everything here is normative; match it exactly.

Version 0.2.0

Cinatra ships shadcn/ui primitives with the design tokens of the Application Design reference mapped to their semantic variables. Use the components from @/components/ui directly — do not re-skin them inline. Each component below is a brief on its role and the design rules it inherits; the roster closes with the host-provided Standard scheduling step composite.

Page header

<PageHeader /> · @cinatra-ai/sdk-ui · @/components/page-header

title lg = 28px (default)
md = 24px · sm = 20px
Archivo italic 800
-0.018em · lh 1.05
etched rule below
Example — top-level page title (lg · 28px)
Management

Agents

Build, monitor and manage the agents in this workspace.

The page-header h1 owns the page-title typography end-to-end — Archivo italic 800, -0.018em tracking, 1.05 line-height, balanced wrap — so pages never roll their own. The title scale is lg 28px (the default — every top-level page), md 24px (action-heavy admin / settings / detail subpages with long titles), sm 20px (nested sub-screens); the scale is monotonic — a smaller step never renders larger than the one above it. Title tone is ink by default; brand-mustard is a per-route opt-in for brand-y top-level pages, never on settings or admin chrome. An optional mono uppercase kicker label sits above the h1, an optional one-line description below it. The etched paired-line rule closes the header on every page — unless a toolbar sits directly beneath, which replaces the rule (see Toolbar).

Button

<Button /> · @/components/ui/button

7 variants
5 sizes
cva-driven
primary = indigo
destructive = red on tint
Example

7 variants · 5 sizes · cva

Primary, default, outline, secondary, destructive, ghost, link. Sizes: default, xs, sm, lg, icon (xs/sm/lg). Indigo primary, ink default border, destructive uses red-on-tint not solid red.

Card

<Card /> · @/components/ui/card

surface (default)
surface-strong (interactive)
1px line border
10–12px radius
Example
Clickable card.
Hover lifts it 1px.

Non-interactive cards use --surface. Clickable cards (agent tiles, run rows, popovers, anything with hover or focus) use --surface-strong per rule #8.

Input / Textarea

<Input />, <Textarea /> · @/components/ui/input

surface-strong
line-strong border
7px radius
focus = ring indigo
Example

Always pure white background. Border is the strong navy hairline. Focus ring picks up --ring (indigo). Use InputGroup for compound inputs with addons.

Select / Dropdown

<Select />, <DropdownMenu /> · @/components/ui/select

popover token
surface-strong
inherits input chrome
scrollbar-thin
Example

Trigger mirrors Input chrome. Open popover sits on --surface-strong with the same hairline border, slightly higher shadow. Use scrollbar-thin on long lists.

Dialog / Sheet

<Dialog />, <Sheet /> · @/components/ui/dialog

--paper (= pages)
starts below 4rem navbar
dim overlay
etched header rule
Example
Approve drafts.
Twelve drafts pending your read.

Modal dialogs use --paper — the same background as pages; right-side sheets sit at full-height. Overlay top: 4rem so it doesn't cover the navbar. Dialog header uses an etched paired-line rule for separation.

Badge / Pill

<Badge />, <LifecycleBadge /> · @/components/ui/badge

surface-muted bg
line border
9999px radius
icon-led
Example
Running Approved On hold

Status pills (see V) use bg tinted from the status colour, text in the same colour, border at higher alpha. Use icon-led pills; never just dots.

Tabs

<Tabs />, <TabsList />, <TabsTrigger /> · @/components/ui/tabs

underline tabs
active = indigo 2px
inactive = slate
paired with section rule
Example

Tab labels are 13px sans, slate when inactive, indigo when selected with a 2px indigo underline. No pill tabs; underline only. When tabs appear under a section heading, the etched paired-line rule begins to the right of the last tab and stretches to the page edge — the tablist takes the left portion of the row, the rule the right.

Toolbar

<Toolbar /> · @/components/ui/toolbar (composition)

ground var(--toolbar)
8px radius · no border
embedded controls: borderless
48–56px tall
40px / 7px controls
24px hairline separators
Example

Controls inside a toolbar must look different from standalone ones: they carry no individual border. The toolbar ground is their container, so a button, tab, or field placed inside it drops the border (and the fill) it would have on its own and reads only as a tinted region of the bar. A horizontal bar that groups related view controls — tablist, search, primary view action. The toolbar provides the chrome, so controls inside it carry no individual borders: the toolbar ground is their container. Hover and selected states are background tints on a rounded rectangle (7px radius, same geometry as the search pill); the font weight and colour never change between states. Vertical hairlines (24px tall, centred) separate logical groups: between the tablist and search, and between search and the action button. The search field keeps its white interactive surface — the only white element inside the toolbar. The toolbar sits directly below the page header and replaces the section rule for that view — never stack a toolbar and the etched paired rule.

Nested toolbar

<Toolbar /> → <Toolbar.Child /> · @/components/ui/toolbar (composition)

depth: 3 levels max
parent ground var(--toolbar)
each child +6L lighter
deepest stays darker than paper
child inset 20px / level
6px stack gap
Example

When a selected toolbar item has its own sub-controls, they open in a child toolbar directly beneath the parent rather than in a menu — and that child can in turn carry a third. Each level inherits every toolbar rule (borderless controls, hairline group separators, the lone white search field) and adds three of its own. Ground steps lighter with depth — the parent sits on the darkest chrome (var(--toolbar)) and each child lightens ~6L toward the page, so the deepest row reads as the one nearest the content it edits. The lightening stops short of the paper: even the deepest ground stays a clear step darker than the page, so every level remains legible as its own bar. Each child is inset 20px from the level above and stacked 6px beneath it, so the active path reads top-to-bottom at a glance — the inset and the lightening carry the lineage; no connectors are drawn. Cap the depth at three. A fourth level means the navigation is too deep for a toolbar — move it into the page body or a sidebar instead. Only one item per level is selected, and selecting a different item replaces every level below it.

Sidebar

<Sidebar />, <AppSidebar /> · @/components/ui/sidebar

surface --sidebar
~240px wide
brand head: fedora + wordmark
active = indigo 6%
labels: mono 10px
collapses to 56px rail
Example
Cinatra
Agents
Chat

Cinatra's sidebar from app-sidebar.tsx. Mustard fedora + Archivo wordmark in the brand head. Active item is indigo bg at 6% alpha; section labels are 10px mono uppercase.

Sidebar group label

<SidebarGroupLabel /> · @/components/ui/sidebar

Inter · 600 · 10px
letter-spacing 0.18em
uppercase · slate
padding 8px 12px 4px
Example
Intelligence
Chat
Agents
Management
Desk

Group labels in the sidebar — the small uppercase mono-spaced tag that sits above a cluster of nav items (Intelligence, Management, Information, Tools). Slate-muted slate at 10px with 0.18em letter-spacing reads as a quiet section break rather than a clickable item. Always above its group, never indented to match its children.

Tooltip / Popover

<Tooltip />, <Popover /> · @/components/ui/tooltip

ink ground · cream text
200ms delay
12px tooltip · 13–14px popover
Example
Approve & send to all 12 prospects

Tooltips are navy with cream type; popovers are surface-strong with navy text. Tooltips read at 12px; popovers at 13–14px.

Avatar

<Avatar />, <AvatarImage />, <AvatarFallback /> · @/components/ui/avatar

36–40px square
random accent ground
italic 800 initial
Example
O
E
R
M

User avatars carry the user's initials in Archivo italic 800 on a random categorical accent (never indigo or navy). Per-extension instances same pattern (see IV).

Form / Field / Label

<Form />, <Field />, <Label /> · @/components/ui/form

Label · 12px · 600
Helper · 11px · muted
gap 4–8px
error swaps helper red
Example
Visible only to your team.

Form scaffolding — labels above inputs, helper or error text below. Errors swap helper text colour to brand red and add aria-invalid to the input.

Checkbox / Radio / Switch

<Checkbox />, <RadioGroup />, <Switch /> · @/components/ui

control 16–18px
indigo when on
surface-muted when off
Example

Single-select (radio), multi-select (checkbox), and instant-binary (switch). Indigo for active state. Switches are reserved for immediate-effect settings; checkboxes for confirmable form choices.

Alert / Alert dialog

<Alert />, <AlertDialog /> · @/components/ui/alert

tinted bg + border
12–14px text
icon-led
destructive = red
Example
Approval expired.
The hold window closed at 15:30.

Inline alerts for warnings and errors; AlertDialog for destructive confirmations. Use the destructive variant (red) for terminal failures, warning (mustard) for cautions, info (indigo) for neutral notices.

Toast / Sonner

<Sonner />, toast() · @/components/ui/sonner

popover bg
status-coloured text + border
5 variants
icon led
close + optional copy
Example
Run #2,318 started.
Twelve drafts approved.
Approval expires in 5 minutes.
Connector lost: Err_GMAIL_REFRESH_401

Transient confirmations and async progress. Five variants — default · success · warning · error · info — each on the popover surface with a status-coloured border and matching text; an icon on the left identifies the type. Every toast carries a Copy action and a Close (X) on the right, so the user can grab the message text or dismiss the toast. Never block on a toast; use Dialog when the user must acknowledge. Stack vertically, newest on top.

Table

<Table />, <PaginatedTable /> · @/components/ui/table

header mono 10px 700 uppercase
body 13–14px ink
IDs/times mono 11px slate
cell padding 10–14px
Example
AgentRunStarted
Outreach#2,31814:21

PaginatedTable handles offset, sort, and selection; Table is the dumb DOM primitive. Headers always uppercase mono with the navy underline; never centre body cells; right-align numerics and timestamps.

Command menu

<Command />, <CommandDialog /> · @/components/ui/command

cmdk-style
⌘K trigger
indigo selected row
mono section labels
Example
Suggestions
Open Outreach agent
New campaign

Global cmd+K palette and inline pickers. Section labels in 10px mono; rows at 13px; the selected row uses the indigo soft-tint background, not a border.

Breadcrumb

<Breadcrumb /> · @/components/ui/breadcrumb

chevron 12px 50% opacity
slate links · ink current
max 3–4 crumbs
Example
IntelligenceAgentsRun #2,318

Always in the topbar. Three to four crumbs maximum; truncate the middle with an ellipsis if longer. Never combine with tabs.

Example — Entity names, resolved and placeholder
TeamsBest Team EverSettings
Dashboards9c0dfce6…

A crumb that stands for an entity id shows that entity's display name — at every position, not only the last. Names come from the owning page's server render, strictly after its access checks; the shell never fetches a name from the client after paint. While a name is genuinely unavailable, the crumb shows the id's first eight characters plus an ellipsis ("9c0dfce6…") — never a title-cased raw id. Visiting a not-found or not-authorized surface clears every remembered name before paint, so a previously seen name can never survive into an unauthorized view. The browser-tab title mirrors the resolved trail under the same rules: an id-bearing route never shows a raw id in the tab.

Pagination

<Pagination /> · @/components/ui/pagination

mono 13px
active = ink fill
prev/next chevrons
Example

For long lists and tabular data. Active page is ink-filled; surrounding pages are line-bordered on white. Always pair with a "X of N" caption in mono slate.

Skeleton / Spinner

<Skeleton />, <Spinner /> · @/components/ui/skeleton

Skeleton: surface-muted bars
Spinner: indigo arc
1s linear
Example

Skeletons mirror the layout they're replacing; never use a global spinner overlay when a skeleton would do. Spinner only for short (<500ms) inline waits inside buttons or icons.

Empty state

<Empty /> · @/components/ui/empty

centred
dashed circle icon
14px headline · 12px helper
primary action
Example
No runs yet.
Roll a campaign to see runs here.

Use whenever a list, table, or section has zero content. Always include a single primary action button — never just empty text.

Accordion / Collapsible

<Accordion />, <Collapsible /> · @/components/ui/accordion

navy hairline rows
rotating chevron
200ms ease
Example
Run details
Step 3 of 7 · 12 drafts pending review.
Tool calls

Use for sectioned settings panels and FAQ-style content. Default to single-open; allow multi-open only when items are truly independent.

Separator

<Separator /> · @/components/ui/separator

paired-line for sections
1px low-alpha hairline for rows
Example
Section A

Section B

Section breaks use the etched paired-line (the spec's signature divider). It stretches edge-to-edge of the content column by default. If a tablist is present in the same row, the rule starts immediately to the right of the last tab and runs to the page edge — never overlap a tablist with the rule, and never stack them. If a toolbar sits below the page header, the toolbar replaces the section rule entirely; never stack both.

Slider

<Slider /> · @/components/ui/slider

6px track · muted ground
indigo fill
16px white thumb · indigo ring
mono value caption
Example
062100

Single-value and range. Track is the muted surface, the filled portion indigo, the thumb a white interactive disc with an indigo ring (white per rule #8). Pair with a mono value readout; never label the thumb itself.

Progress

<Progress /> · @/components/ui/progress

6px bar · 9999px radius
indigo fill on muted
determinate + indeterminate
mono % label above
Example
Enriching prospects74%
Generating drafts…

Determinate for known-length work (a run with N steps), indeterminate for open-ended waits. Same geometry as the slider track. Show the percentage in mono above the bar; never render text inside it.

Toggle / Toggle group

<Toggle />, <ToggleGroup /> · @/components/ui/toggle

on = indigo tint + ink
off = transparent + slate
grouped = hairline divides
7px radius
single- or multi-select
Example

A two-state button. Pressed state is the indigo soft-tint with ink/indigo content; rest is transparent with slate content. As a single-select group it becomes a segmented control — the canonical way to choose one of two or more options (the List / Board / Timeline view switcher above); as a multi-select group it toggles several at once (the formatting icons). Either way the buttons share one outer border with hairlines between segments — no gaps, exactly one or any number pressed. Use for view modes and inline formatting, not for settings that take immediate effect (use Switch).

Calendar / Date picker

<Calendar />, <DatePicker /> · @/components/ui/calendar

surface-strong popover
mono weekday heads
selected = indigo fill
today = indigo ring
range = indigo tint band
Example
May 2026
MTWTFSS
282930 1234 567891011 12131415161718 19202122232425 262728293031

Month grid on the white popover surface. Weekday heads are mono uppercase; the selected day is an indigo-filled disc; today carries an indigo ring; a date range fills the in-between days with the indigo soft-tint. DatePicker is the calendar inside a Popover triggered from an Input-styled button.

Combobox

<Combobox /> · @/components/ui/combobox

Input trigger + chevron
cmdk-filtered list
check on selected
indigo tint active row
Example
Gmail Connector
Search connectors…
Gmail Connector
Slack Connector
Salesforce Connector

A Select crossed with the Command menu: an Input-chrome trigger opens a type-to-filter list. The current value carries an indigo check; the highlighted row uses the indigo soft-tint. Reach for it over Select whenever the option count passes ~8.

Hover card

<HoverCard /> · @/components/ui/hover-card

surface-strong popover
700ms open delay
richer than a tooltip
non-interactive trigger
Example
Run owned by @e.reyes
E
Elena Reyes
Revenue Ops · joined Apr 2024
Owns 6 agents · 218 runs approved this quarter.

A preview card on hover — for people, agents, and links. Sits on the white popover surface with a softer, longer open delay than a tooltip (≈700ms). Use when the preview carries structure (an avatar, stats); for a one-line hint use Tooltip instead.

Context menu

<ContextMenu />, <DropdownMenu /> · @/components/ui/context-menu

surface-strong popover
indigo tint active row
mono shortcut hints
red destructive item
hairline group breaks
Example
New run⌘N
Duplicate⌘D
Delete agent

Right-click context menus and the chevron DropdownMenu share this surface. Rows highlight on the indigo soft-tint; keyboard shortcuts sit right-aligned in mono slate; destructive items take brand red. Group with the 1px hairline, never the etched paired rule.

Menubar

<Menubar /> · @/components/ui/menubar

toolbar ground var(--toolbar)
open menu = indigo tint
13px sans triggers
menus reuse context surface
Example
Start run⌘↵
Pause⌘.
Schedule…

A persistent horizontal menu bar (desktop-app style) on the toolbar ground. The open trigger takes the indigo soft-tint; its dropdown reuses the context-menu surface. Reserve it for dense editor surfaces; most product chrome should prefer the Toolbar or a DropdownMenu.

Navigation menu

<NavigationMenu /> · @/components/ui/navigation-menu

topbar links · 13px sans
active = ink + indigo underline
mega-panel on white
two-column item grid
Example
Intelligence Management Information
Agents
Autonomous workers
Chat
Ask anything
Skills
Installable expertise
Context
Operating knowledge

Top-level site/product navigation with optional mega-panels. The active top link takes the 2px indigo underline (same as Tabs); the dropdown panel is a white card holding a two-column grid of titled links. Distinct from the left Sidebar — use this only for marketing or horizontal product shells.

Scroll area

<ScrollArea /> · @/components/ui/scroll-area

6px overlay track
low-alpha navy thumb
fades when idle
no native chrome
Example
Run #2,318 · Outreach
Run #2,317 · Enricher
Run #2,316 · Outreach
Run #2,315 · Scorer
Run #2,314 · Outreach

Replaces the OS scrollbar inside scrollable panels — command lists, sidebars, long popovers. A 6px overlay track with a low-alpha navy thumb that fades when idle. Same scrollbar-thin treatment referenced by Select.

Input OTP

<InputOTP /> · @/components/ui/input-otp

40px white slots
mono 18px digit
active = indigo ring
middle dash separator
Example
3
9

One-time-code and verification entry. Each digit is a 40px white slot with the strong navy border; the focused slot picks up the indigo ring and a blinking caret. Digits set in mono. Split groups with a short navy dash, never a vertical line.

Drawer

<Drawer /> · @/components/ui/drawer

bottom-anchored sheet
grab handle on top
surface-strong · 14px radius
dim overlay below navbar
Example
Roll a new campaign.
Pick a template to start the agent.

A bottom-anchored sheet for mobile and touch flows. Carries the grab handle, white surface, and a 14px top radius; the overlay dims everything below the 4rem navbar like Dialog. On desktop prefer the right-side Sheet; reserve Drawer for narrow viewports.

Resizable

<ResizablePanelGroup /> · @/components/ui/resizable

navy hairline handle
grip dots on hover
handle turns indigo active
horizontal or vertical
Example
Runs list
Run detail

Draggable split panes for master-detail layouts (a runs list beside a run detail). The handle is the strong navy hairline with a small grip; it brightens to indigo while dragging. Supports nested horizontal and vertical groups.

Aspect ratio

<AspectRatio /> · @/components/ui/aspect-ratio

locks a w:h box
16:9 · 4:3 · 1:1
8px radius · clips child
striped placeholder unfilled
Example
cover · 16:9
1:1

Locks a child (image, embed, map, chart) to a fixed width-to-height ratio so layouts don't jump before media loads. Unfilled, it shows the seersucker-striped placeholder with a mono label naming the expected ratio. Clip the child with the 8px radius.

Carousel

<Carousel /> · @/components/ui/carousel

embla-driven
white round arrows
dot pager · indigo active
arrows outside the frame
Example
418
Prospects pulled

Horizontal slide track for stat tiles, onboarding steps, or media. Arrows are white interactive discs placed outside the frame so they never cover content; the dot pager marks the current slide with an elongated indigo pill. Keep slide counts low and never auto-advance critical content.

Chart

<ChartContainer /> · @/components/ui/chart

recharts wrapper
indigo primary series
sea-green positive delta
navy hairline grid
mono axis ticks
Example
Runs / week
Approval rate ▲ 12%

A thin wrapper over Recharts with the tokens pre-mapped: indigo for the primary series (faded indigo for prior periods), sea-green for positive trends and brand red for negative, the navy hairline for gridlines, and mono ticks. Keep charts quiet — one or two series, no drop shadows or gradients beyond a faint area fill.

Standard scheduling step

Host-provided composite · run scheduling gate + persistent /trigger tab · 3 modes · 2 surfaces

Scheduling is a platform default: every agent can run immediately, once at a future time, or on a repeating schedule, with no scheduling declaration of its own. One host-provided standard scheduling step renders the choice — in the run's first step when an agent opens on the scheduling gate, and again as a persistent /trigger tab once a future or repeating run is armed. It supersedes the retired per-agent trigger embed: an agent no longer carries a hand-copied scheduling subflow, its own confirm gate, or a version-pinned trigger dependency. A definition may still carry a metadata flag that disables or restricts scheduling, but that flag is metadata only — never a form or subflow copy.

In-flow step

Run scheduling gate · when-to-run choice + date-time / recurring builder + timezone + Continue

Example — Scheduling step, Recurring selected
When should this run?
Run right after setup
Schedule for later
Run at
2026-07-14 09:00
Timezone
Europe/Berlin
Recurring
Repeat every
1
week(s)
On
Sun Mon Tue Wed Thu Fri Sat
At
09
:
00
Timezone
Europe/Berlin
Estimated run duration
About 45s – 3.4 hr.
A natural-language prompt in the always-visible assistant panel fills these controls when the run carries a request — e.g. “every weekday at 9am”.

The step is the run's first gate whenever an agent opens un-triggered: the workspace content is replaced by this form until a choice is made and submitted. Under the heading When should this run? sit three selectable rows — Run right after setup, Schedule for later, and Recurring. Schedule for later reveals a Run at date-time field and its own Timezone select; Recurring reveals a structured builderRepeat every N day(s) / week(s) / month(s) / quarter / year, the frequency-appropriate selectors beneath it (weekday toggles for weekly; a day-of-month or nth-weekday choice for monthly, quarterly and yearly; a quarter anchor; a month), an At hour:minute time-of-day, and its own Timezone select. There is no raw cron field — the host compiles the builder's selections into the stored 5-field cron expression. An Estimated run duration line sits above the actions, and submitting Continue arms the trigger and advances the run — there is no separate confirm step. When the run carries a natural-language prompt, the always-visible assistant panel pre-fills these controls (the loading state); a validation failure — a past instant, or a recurring schedule with no time chosen — surfaces inline on the field (the error state).

Persistent trigger tab

/trigger · configuration summary + Cancel trigger / Release now (admin)

Example — Armed recurring trigger (viewer is an admin)
Trigger configuration
Typerecurring
ScheduleEvery weekday at 9:00 AM
TimezoneEurope/Berlin
Steps held until trigger fires

No side-effect steps detected. The trigger acts as a start gate only — the run begins when the trigger fires and runs to completion.

Once a scheduled or recurring trigger is armed, the run keeps a persistent /trigger tab. It opens with a read-only Trigger configuration summary — Type, the human-readable Schedule (a recurring row shows the server-rendered plain-language reading of the schedule; a one-off shows its formatted instant), and Timezone — followed by a Steps held until trigger fires list (the side-effect steps gated behind the trigger, or a note that it acts as a start gate only). Two right-aligned controls follow, each confirming through an AlertDialog before it fires: Cancel trigger deletes the trigger and pauses the run (disabled once the trigger has been released); Release now — admin only — makes every gated step eligible immediately. This surface is unchanged by the retirement; only the in-flow step above becomes host-standard.

Modes

Three modes, one required control each. Every mode records an IANA timezone; the stored shape is the platform's per-run schedule row — no per-agent copy.

ModeRequired controlStored as
Run right after setup— (none)triggerType: immediate
Schedule for laterRun at — a future date & timescheduledAt (ISO 8601 UTC) · timezone
RecurringRecurring builder — frequency, interval, day/weekday & time-of-daycronExpression (host-compiled) · timezone

Retiring the in-stepper trigger HITL

The previous approach delivered scheduling as a per-agent renderer chain: a hand-inlined configure subflow, a separate read-only confirm gate, and an exact-version trigger dependency pinned into every embedding agent. That chain is retired. The confirm gate is removed — the in-flow step arms the trigger directly on Continue — and no agent declares a trigger renderer or pins a trigger dependency. What stays is exactly the platform machinery it always ran on: the per-run schedule storage, the schedule firing, and the persistent /trigger tab with its Cancel / Release-now controls. The change is only that the in-flow renderer is now host-standard, available to every agent for free rather than copied into each one.