Apple Native Style Guide
Native iOS/macOS companion to the Clapilot UI style guide.
This is the native iOS/macOS companion to the main UI Style Guide. It is written for anyone building SwiftUI screens in the Apple client and lists the FDS tokens, controls, and layout rules that keep native screens visually synced with Clapilot web.
Visual reference page: /clapilot-ios-styleguide.html.
Canonical client file: clients/apple/ClapilotApple/STYLEGUIDE.md.
Core rule
Apple screens should feel synced with Clapilot web: quiet professional workspace, white borderless surfaces, compact controls, navy actions, pale AI gradients, dense list/detail flows, and practical first-view workflows.
The native differences are intentional:
- Use SwiftUI and
FDSiOSMactokens, not copied CSS. - Use SF/System typography, not Avenir or imported web fonts.
- Every native font size follows the device text-size preference (
FDSTextScale, Settings → Profile → Text size,⌘+/⌘−/⌘0on macOS; default 120 % on macOS, 100 % plus Dynamic Type on iOS). The side menu and the settings navigation list keep fixed sizes throughFont.fdsFixedSystem(size:), which is reserved for that navigation chrome. UseFont.fdsSystem(size:)instead of.system(size:)andFont.fdsStyle(.caption)or thefds*tokens instead of bare text styles; AppKit/UIKit text views useFDSTextScale.shared.scaled(_:), and new window/popover roots apply.fdsTextScaleRoot(). - Keep iPhone navigation native: compact rows open dedicated full detail screens.
- Keep bottom composers and reply bars anchored outside scrollable content.
- The profile icon opens profile/settings on a normal tap. A long press on iOS or long-click/right-click on macOS opens the compact account popover for switching among signed-in instances and adding another instance. Keep one account per instance, show the user and instance together, mark the active account with a checkmark, and retain each instance session in its own Keychain slot.
- Agent Orchestrator activity preserves normal runtime chats as first-class
Sessions. Load the full persisted transcript for detail inspection and gate reply, lifecycle, workspace, terminal, diff, checkpoint, and Git controls by the thread projection instead of inferring capabilities from the provider icon. - Agent Orchestrator uses one searchable compact activity list on iPhone, iPad, and macOS instead of an adaptive card grid, mirroring the web module: a compact
FDSSegmentedControlfilter bar with live counts (Coding Agents,Sessions,Alle,Remote Agents,Analytics) plus+and refresh circle buttons in the title bar (iPhone keeps the centered page title and moves the filter tabs into the controls row above the search field), a search field with a⌘Khint on macOS, and borderless white tiles with a soft blue selected fill. Tiles expose category, provider, repository/identity, title, latest output, model, and a tone-colored monospace tool chip, with theHH:mmtime at the top right (no per-row status icon or status text; the chip tone and the detail header dot carry the state, the status stays an accessibility value) and quick actions (fork/close for sessions, restart/delete for jobs) at the bottom right; macOS reveals the actions on hover, touch platforms show them always. iPhone still opens a dedicated full detail screen. - Agent Orchestrator detail headers follow the web
SessionPaneHeader: a circular terminal mark, a 16pt medium title, arepo • model • idmeta row, and provider icon, status dot, and circular utility actions (fork/close, stop) in the trailing group. The detail-mode tabs sit on their own hairline-bounded row below the header (FDSSegmentedControlitems with SF Symbol icons), followed by a muted uppercaseLinked session <id>strip for jobs that own a session. - Agent Orchestrator session details use
FDSSegmentedControlforConversation,Activity, andDetails, plus capability-gatedTerminal,Changes, andFilesfor local repository-backed coding sessions. Keep chronological user/assistant chat in Conversation, work/tool events in Activity, read-only command output in Terminal, read-only Git state in Changes, relative inventory in Files, and identifiers/runtime metadata in Details. Normal chats must not show coding workspace modes; show reply composers only in Conversation. - Detached Agent Orchestrator jobs use the same compact title/context/provider/status header hierarchy as sessions on iPhone, iPad, and macOS. Do not repeat the job title inside the scroll region or show the full job id, runner, workspace, and command metadata grid above the terminal output.
- New Agent uses one model menu across Codex, Claude, and Clapilot Code instead of a separate harness selector. Prefix each model with its harness icon and derive the provider from the selected model; remote jobs expose Codex models only.
- Agent Orchestrator conversations use unboxed assistant markdown, trailing user bubbles, compact recent tool disclosures, collapsed older tool history, and a bounded Terminal output disclosure. Hide routine runtime startup lines and suppress duplicate job prose when a linked session already owns the conversation.
- Personal Chat, Team Chat, and Agent Orchestrator conversation Markdown keep one body size throughout a message. Headings use that same size with semibold weight and compact spacing, so Markdown syntax never causes font-size jumps in a transcript.
- Agent Orchestrator workspace changes use a dedicated Changes segment for sessions and detached jobs; changed-file trees and diffs do not appear inline in conversation history.
- Keep the follow-up composer outside the scrolling transcript. Put the provider-scoped model menu inside its controls instead of adding a separate Follow-up heading or model form.
- Pending image/file attachments on macOS render inside the composer card via
ClapilotComposerAttachmentStrip(compact tiles above the text input: 56pt image thumbnails, icon+name+size mini cards for other files, each with a remove control); iOS keeps its chip strip above the composer. - The composer "+" attachment menu offers, in order: take photo (iOS only, hidden when no camera is available), choose photo, choose file. Camera capture goes through the shared
ChatCameraCapture/ChatCameraPickerhelpers inSources/Clapilot/Views/ChatCameraPicker.swift, which own availability, localized permission handling, orientation normalization, bounded JPEG encoding, and unique filenames; the captured photo then reuses the existing photo-attachment preparation path. Keep the chat, Team Chat, and coding-agent composers in sync when this menu changes. - Keep the floating chat launcher available across top-level app screens and iPhone detail views. Hide it while the side drawer is open so navigation remains the active layer.
- macOS and iPad landscape dock the assistant chat as a collapsible trailing sidebar (web chat rail parity) instead of the floating launcher:
AppChatSidebarHost(Sources/Clapilot/Views/ChatSidebarHost.swift) wraps every module page fromMainTabView, shares oneClapilotSplitPaneDividerwith the content, and hosts the existingChatView/TeamChatView.menuBarpresentation. The panel collapses to a44ptrail with one circularchevron.leftcontrol and persists its state per device (clapilot.chatSidebar.expanded; macOS opens by default, iPad starts collapsed). The expanded width defaults to420pton macOS and344pton iPad; dragging the divider resizes it between320ptand760pt(web rail parity) while the module keeps at least720pt, the width persists per device (clapilot.chatSidebar.width), and double-clicking the divider restores the default. The header shows the module context capsule (Aufgaben · Du arbeitest gerade im Aufgaben-Modul.), the composer placeholder follows the module, and an empty transcript offers the module quick-action prompts fromChatSidebarContext(the native port of the webfloatingChat.*context table; the samefloatingChat.*keys exist in the AppleL10ntable). It is hidden on the Chat and Team Chat modules; iPhone, iPad portrait, and iPad split-screen keep the floating launcher. - Add
clapilotScrollableBottomInset(isCompactLayout:)to scrollable lists so final rows clear the iPhone bottom safe area and floating controls. Do not add this extra inset to chat transcripts that already sit above an anchored composer. - Use SF Symbols for normal controls.
Native tokens
- Colors:
Color.fdsBackground,Color.fdsCard,Color.fdsSidebar,Color.fdsAccent,Color.fdsBorder,Color.fdsDot. - Header surface: plain white
Color.fdsBackgroundwith a subtleColor.fdsBorderbottom hairline viaClapilotPageHeaderBand. - Header tint tokens:
Color.fdsHeaderIceBlueFillandColor.fdsHeaderIceBlueBorderremain only for in-content accents (Tasks Kanban column headers, board badges), not the page header band. - Spacing:
FDSSpacing.micro,micro6,small,small10,small12,medium,medium18,medium20,large,xlarge. - Radius:
FDSCornerRadius.standard(14pt) is the single rounded-box radius; legacy aliases such assmall,medium18,medium20, andlargeresolve to the same value. - Shadows: surfaces are flat. All surface-level
FDSShadowtokens (standard,light,lightAlt,listRow,minimal,medium,mediumAlt,none) resolve to no shadow; hierarchy comes from spacing, typography, fill, and shared separators. OnlyFDSShadow.strongkeeps a real shadow, reserved for true overlays (dialogs, menus, floating launchers, drag previews).
Controls
- Primary actions use
.buttonStyle(.fdsPrimary). - Secondary actions use
.buttonStyle(.fdsSecondary): outline-quiet, white fill, fine navy hairline, navy label, like the web secondary button. - Leading-icon actions use
Label. - Utility actions use borderless circular SF Symbol buttons such as
FDSIconButton,AppTopBarCircleButton, or.fdsCircleSurface(...). On a page background useFDSSecondaryIconButton(white circle, navy border, navy symbol). - Modal sheets close with an icon-only circular X (
.clapilotSheetChrome), on iOS and macOS alike; there is no text "Abbrechen"/"Schließen" button. - Binary settings use
Toggle(...).tint(Color.fdsAccent). - Single-value selects use
FDSDropdown(Clapilot field-style trigger: white fill, hairline border, 32pt height, trailing chevron inset 16pt from the trailing edge) instead ofPicker(...).pickerStyle(.menu)or platform-default popup buttons; render field labels as captions above the control. All tap-triggered dropdowns open the customFDSMenupopup (white rounded card, title left, checkmark plus suffix icon right — provider logos for models, folder icons for folders) instead of the native menu;.contextMenustays native. A per-item secondary action, such as deleting a chat session in the session switcher, is an inline circular icon button in that item's own row (FDSMenuRowAccessory), never a second full-width row per item. - Regular-width list/detail split layouts separate the list column from the adjacent content pane with
ClapilotSplitPaneDivider— a full-height 1ptColor.fdsBorderhairline in a compactFDSSpacing.small12gutter, Apple Mail-style. - On macOS those list columns collapse once the user opens an item, handing the content pane the full window width, and a
sidebar.leadingcircular button next to the side-menu button brings the list back. The flag lives in@SceneStorage("<module>.listPaneCollapsed"), so every module remembers the layout the user last chose for that window. iPhone pushes a detail screen instead and never shows the control; a regular-width iPad, which renders the same inline split in Whiteboard, Canvas and the Dokumente folder rail, keeps the toggle but does not collapse on its own. - Segmented controls use
FDSSegmentedControlwhere possible. The white shell has no outer border. Selected states use deep navy, never the brighter legacy module blue. - Coding-agent approvals and read-only workspace checkpoints share one compact
Approvalsinspector across iPhone, iPad, and macOS. Approval decisions stay explicit, and checkpoint creation is non-mutating. - Coding-agent Git mutations stay inside
Changes: stage/unstage are per-file, commit requires a message, and push requires a second explicit tap. Force push, reset, and arbitrary Git arguments are not native UI actions. - Persist the coding activity filter across launches, but reset each newly selected thread to
Conversation. macOS supports Command-K for activity search and Command-Shift-N for a new agent. - Generic loading states use
ClapilotLoadingAnimation, which renders the Clapilot logo with a clockwise fill and respects Reduce Motion. Chat assistant answer/work indicators use the profile activity selection on both platforms: the compact native three-dot bubble is the default, while explicit Pet selections render their assets. iOS plays built-in Pet GIFs through the embedded animation web view; macOS plays them natively through theNSImageView-backedAgentAnimationNativeGIFView(with Reduce Motion showing the static first frame). Do not add WKWebView-based animation views to macOS rows. - Admin-only operational settings such as Subscription Usage should use the same compact borderless surfaces on iOS and macOS. The macOS menu bar extra uses left click for the chat popover and right click for the compact usage popover.
Haptics
- All haptic feedback goes through
FDSHapticsinFDSiOSMac(no-op on macOS). FDS buttons, toggles, and selection controls fire their own light-impact/selection haptics, so feature code must not double-fire around them. - Feature code adds haptics only for domain events: soft impact when a chat response starts streaming or the app becomes ready, medium impact for sends/stops/drag commits/pull-to-refresh, and notification success/error when AI workflows (mail reply automation, document creation, calendar event save, chat response) finish or fail.
- Remote-push registration is installation-scoped: every locally stored, authenticated account/instance gets its own server subscription for the stable installation ID. Switching accounts keeps all subscriptions; logout removes only the selected account. Notification taps must validate
instance_id, activate that locally known instance first, and only then follow the allowlisted target route. The app badge reflects delivered notifications across all signed-in instances. - Haptics respond to user interaction or workflow completion, never to programmatic state loads or background refreshes.
Lists and forms
- Primary list screens (Mail, News, Notes, Documents, Wiki, Tasks, Automations, Agents, Canvas) render rows directly in the content area — one continuous list with hairline row separators, no surrounding card and no per-row bordered boxes or gaps. Use sticky uppercase group headers only for real groupings (e.g. Mail date buckets, Tasks status lanes); single-entity lists omit the header since the page title already names the screen.
- Rows use two shared heights only: a compact height for the dense Documents list and a standard height for every richer list, kept in one place (
ClapilotListMetrics). - The macOS main app window keeps the native outer window shadow so it remains distinct from other windows. Dashboard tiles, Team Chat surfaces, and anchored chat composers use shared flat borderless surfaces.
- The regular-width Team Chat trailing pane lists every accessible channel with the open channel visibly selected. Its agent section includes the primary assistant only while it is invited to that channel and, for channel rooms, only enabled specialized agents invited there; it must not fall back to the primary assistant or global specialist directory when a channel has no agent invitations. Native channel settings mirror web invite/remove and
mention_only/all_messagescontrols. - Selected rows use soft background or tint. Do not use the retired left vertical selection bar.
- Form labels sit directly above the field they describe. Use a smaller label-to-field gap than row-to-row gap.
- Fields use white fill, neutral border, outlined inset treatment, and subtle navy focus.
AI surfaces
Use pale blue/lavender gradients for AI-specific smart search, generated drafts, summaries, and recommendations. Keep them functional and subtle, not hero banners.
While an assistant response is streaming, model reasoning may appear temporarily as unboxed multiline text with the shared left-to-right AI gradient. Do not add a surrounding card, icon, or persistent Thinking section; remove the reasoning as soon as final answer or Canvas content starts, keep it out of completion notifications, and stop the animation when Reduce Motion is enabled.
Top-level native app screens should use ClapilotPageHeaderBand for the main top bar plus search/filter controls. On iOS/iPadOS this plain white band (subtle bottom hairline) spans the full header and extends into the top safe area, and content should start directly after it with 0pt root stack spacing. Main compact list surfaces should also use clapilotCompactBottomSafeAreaFill(isCompactLayout:) with 0pt root bottom padding so the screen reaches the bottom edge; protect final rows with scroll content margins instead. Do not use bottom safe-area fill or artificial bottom scroll margins on screens with anchored composers or input bars. macOS keeps its frosted translucent title-bar treatment.
Asset prompt
Use the asset generation prompt in clients/apple/ClapilotApple/STYLEGUIDE.md for native icons, thumbnails, onboarding images, and empty-state art. Prefer SF Symbols for ordinary controls. Custom navigation/sidebar icons must match the flat, full-canvas style of the existing Kunden, Kalender, Aufgaben, Dokumente, and Notizen icons.
Settings help
Show one clear label with a ClapilotInfoPopover info button for explanatory
copy. Section cards accept description: to place help beside the heading.
The button opens on hover or click/tap, and compact iPhone layouts retain a small
popover. Keep values, connection status, errors, empty states, and actionable
warnings visible. Use existing localized descriptions and accessible info labels
in German, English, and Italian; help buttons must not activate adjacent controls.
Team Chat conversation navigation
Match web section order: Channels, Direct Messages, Agents. Include human group conversations under Direct Messages, keep invited specialists under Agents, and show channel names without a duplicate # beside the channel icon. Apply this organization to the native members panel and compact channel picker.
Compact settings navigation
Settings use the available workspace width with 12px/pt horizontal outer insets and a 260px/pt desktop navigation column. Web navigation has 8px inner padding, 32px desktop rows, and 2px row gaps; macOS uses 32pt rows without extra row gaps. iOS and narrow web layouts keep at least 44px/pt touch targets and compact 12px/pt outer insets. Search, group expansion, selection, and existing settings destinations remain unchanged. This spacing change does not alter API or chat/live agent tool contracts.
Borderless content hierarchy
Headers sit directly in the workspace. Settings navigation and content use one shared split divider, without separate outer boxes. Avoid nested outlined rectangles throughout iOS and macOS. Use Color.fdsCard for primary surfaces and Color.fdsSidebar for supporting tiles; FDSCard and .fdsInsetSurface(...) are borderless by default. Homogeneous configuration and coding-model priority rows use Divider() between rows, without individual cards. Keep input strokes, focus/validation indicators, true overlay boundaries, and meaningful editor/grid lines. This presentation change preserves existing chat/live agent tools and API contracts.
Subtle section fills
Dashboard tiles and major settings sections use a barely visible translucent white-gray fill: Field Gray (#f3f6fb) at 24% opacity, approximately #fcfdfe over white. Use surface-quiet on web and fdsSurfaceQuiet on Apple clients. Dashboard headers retain the original pale Ice Blue (rgba(96, 165, 250, 0.14)) and fine blue bottom separator. Outer tiles and major settings sections may use a single 1px/pt neutral-gray hairline (rgba(120, 120, 128, 0.12); native fdsTileBorder). Keep nested groups unframed. Inset shortcuts use translucent white. Avoid opaque gray slabs, alternating section colors, or navy/lavender fills for ordinary grouping. Let spacing and internal row separators provide structure. Keep fields white and page headers unboxed. Web dark mode uses white at 2.5% opacity.
Dashboard widget parity
The native Dashboard mirrors the web widget grid (src/components/dashboard-workspace.tsx) instead of using its own tile language. Every widget is one quiet tile with a 36pt Ice Blue header that holds the 16pt navigation icon, a 13pt semibold navy (#344b86) title that opens the module, and optional trailing controls; the body sits flush below the header and adds its own padding. Stat widgets (Neue Mails, Offene Aufgaben, Heute im Kalender, Dokumente) show only the 30pt semibold number under the header, without captions. "Agentenvorschläge" wraps the prompt buttons (title, subtitle, send icon on translucent white) in the same shell. "Anstehende Aufgaben" shows the sort/filter chips (#466197 on white with a #c8d7fb hairline), a header settings menu with the same sort and filter options as the web widget (stored per device in AppStorage), and continuous divided rows with the task title, client line, priority badge, status badge, and due date; tapping a row opens the task detail. "Posteingang", the day calendar, "Letzte Chats", and "Schnellzugriff" use the same divided rows (13pt medium title, 12pt secondary meta, hairline separators, no per-row boxes). Regular width lays widgets out like the web grid: full-width suggestions, four stat tiles, tasks (7/12) beside inbox (5/12), calendar beside recent chats; compact width stacks everything with two stat tiles per row.
Document detail information
The native document detail keeps the preview free of metadata below it. On wide iPad/macOS layouts, summary, workflow, extraction details, and document information share the independently scrolling trailing panel. On narrow layouts, the toolbar Info action opens the same content as a full detail destination. The document title appears once in the navigation bar; description, type, contact, folder, date, year, file size, format, and path belong in the information panel. This Apple-only presentation change preserves the web view and existing document APIs and chat/live agent contracts.
macOS dashboard glass
On macOS, outer dashboard tiles use adaptive ultra-thin material with a translucent white veil, a fine top highlight, and restrained elevation shadows. Agent suggestions, calendar/task/mail/chat rows, and shortcuts inside the dashboard have transparent backgrounds with no separate material, border, or shadow. Preserve their full click targets with a content shape. Keep the material white rather than gray; avoid nesting Liquid Glass effects inside large glass containers. Keep pale-blue tile headers compact: 32pt height and 13pt semibold titles. Clip the complete tile once; header strips have square lower corners and share the tile's outer top corners, avoiding white wedges at the header/body join. iOS keeps its quiet fill and existing header padding, with the same corrected outer clipping. This presentation-only change preserves dashboard actions and agent/API contracts.
