DESIGN.md
Rama main · réplica de lectura del repositorio original.
---
name: Mogplex App
description: Design guidance for Mogplex's repository workspaces and authenticated product surfaces.
colors:
brand-accent: "oklch(66.57% 0.225 36.57)"
brand-accent-hover: "oklch(61.6% 0.2079 36.63)"
background-light: "oklch(96.88% 0.007 96)"
card-light: "oklch(98.84% 0.006 95)"
background-dark: "oklch(10.88% 0.006 132)"
card-dark: "oklch(13.92% 0.007 128)"
foreground-light: "oklch(17.48% 0.008 124)"
foreground-dark: "oklch(94.57% 0.008 98)"
muted-foreground-light: "oklch(54.72% 0.012 108)"
muted-foreground-dark: "oklch(74.58% 0.011 103)"
border-light: "oklch(89.8% 0.01 101)"
border-dark: "oklch(28.11% 0.01 116)"
success: "oklch(72.25% 0.192 149.58)"
warning: "oklch(76.86% 0.1647 70.08)"
destructive: "oklch(63.68% 0.2078 25.33)"
info: "oklch(62.31% 0.188 259.81)"
typography:
body:
fontFamily: "Geist, system-ui, sans-serif"
fontSize: "0.875rem"
lineHeight: 1.4285714286
label:
fontFamily: "Geist, system-ui, sans-serif"
fontSize: "0.75rem"
lineHeight: 1.3333333333
mono:
fontFamily: "Geist Mono, SF Mono, monospace"
rounded:
sm: "2px"
md: "4px"
lg: "6px"
xl: "10px"
2xl: "12px"
spacing:
1: "4px"
2: "8px"
3: "12px"
4: "16px"
6: "24px"
8: "32px"
components:
button-primary:
backgroundColor: "{colors.brand-accent}"
textColor: "{colors.card-light}"
typography: "{typography.body}"
rounded: "{rounded.md}"
height: "36px"
input:
rounded: "{rounded.md}"
height: "36px"
card:
rounded: "{rounded.lg}"
app-navigation-link:
rounded: "{rounded.lg}"
height: "40px"
---
# Design System: Mogplex App
## Overview
This guide covers the authenticated app: repository workspaces, Control,
agents, flows, models, settings, and operational views. Read [PRODUCT.md](./PRODUCT.md)
for users, purpose, and accessibility principles. The interface should be
precise, calm, and capable, with the selected repository, runtime, task, and
action consequences visible where they matter.
**Scope matters.** This is product UI guidance, not a universal marketing style.
Landing pages and public marketing/auth surfaces have their own scoped styles in
[components/marketing](./components/marketing), including `landing-v2.css`,
`subpage.css`, and `auth.css`. Preserve their established typography and visual
direction when working there; do not apply this document as a marketing redesign.
The code is the source of truth. Values above describe the shared app defaults,
not every contextual override. Use the semantic tokens in
[app/globals.css](./app/globals.css), the fonts in [app/layout.tsx](./app/layout.tsx),
and the existing [UI primitives](./components/ui). Update this guide in the same
change when those defaults change. Do not copy its literal colors into components.
Dense layouts are appropriate when they preserve readable context and actions.
At narrow widths, rearrange or collapse panels deliberately instead of shrinking
text and controls. Keep motion tied to state feedback and respect reduced motion.
Page and dashboard scrolling suppress vertical overscroll on devices whose
primary pointer is fine, including touchscreen laptops. Coarse-pointer devices
keep native overscroll; horizontal navigation gestures remain available. The
root background matches the page theme behind native touch overscroll. Nested
run details and agent reports contain vertical scrolling so reaching their ends
does not move the surrounding page.
The former generated `DESIGN.json` remains a historical archive, not an active
token source or required companion to this guide.
## Colors
Warm neutrals carry the app, with orange for primary actions and restrained
semantic colors for state. Light and dark themes use the same semantic roles.
- Use `background`/`foreground` for the page and its text, `card`/`card-foreground`
for raised content, and `popover`/`popover-foreground` for floating content.
- Use `primary`/`primary-foreground` for primary actions. The CSS `accent` role is
a neutral interaction surface; it is different from the orange `brand-accent`.
- Use `muted-foreground` for secondary text and `border`/`input` for boundaries.
Keep the `sidebar-*` roles for navigation.
- Use `accent-green`, `accent-amber`, `destructive`/`accent-red`, and `accent-blue`
for success, warning, failure, and information. Preserve established chart and
project-color mappings rather than assigning new meanings to their colors.
- Control has an existing `ink-*` scale and `addg`/`delr` roles. Preserve those
mappings when editing Control; do not replace them with literal color values.
**State needs more than color.** Pair status with text, an icon, or another
accessible indicator. Confirm text and focus contrast in both themes.
**Toasts always carry a status.** Use `toast.success()` for completed actions
(created, saved, connected, copied), `toast.info()` for neutral state changes
(archived, paused, removed, queued), `toast.warning()` for partial success or
something that needs attention, and `toast.error()` (variant `destructive`) for
failed actions. Each variant tints the surface, adds an accent bar, and
shows a distinct, high-contrast icon with a screen-reader label.
Notifications use the measured space between workspace tools and the composer.
When that space is short, a compact row keeps text scrollable and actions fixed
at 44px. Stop remains above the footer on short landscape screens.
They never take focus when they appear. Bursts preserve every open message and action in a scrollable stack; newly
added messages release already-dismissed cards and their removal timers.
Respect reduced motion, and let users pause expiry by
hovering or focusing a notification. Routine updates, including warnings, use
polite screen-reader announcements; failures interrupt by default. Override
the announcement type only when a specific message requires urgency.
## Typography
Use `font-sans` for human-readable text and `font-mono` for code, paths, commands,
identifiers, and machine values. The layout loads Geist Sans and Geist Mono;
the CSS font variables supply their fallback stacks.
Shared controls and descriptions commonly use `text-sm` (14px with a 20px line
height); compact metadata uses `text-xs` (12px with a 16px line height). These are
common roles, not a requirement to resize every view. Use the surrounding
screen's heading hierarchy instead of inventing a global heading size.
The shared input uses `text-base` (16px) below the `md` breakpoint and `text-sm`
from `md` upward. Preserve this distinction. Use display typography only within
surfaces that already define it, not in routine app labels or controls.
## Elevation
Use tonal surfaces and one-pixel borders for ordinary separation. The app's
`--radius` is 6px; the frontmatter radius keys match the Tailwind aliases derived
from it. The badge's explicit 3px radius is a component-specific exception.
Resting cards and bordered section surfaces use `rounded-lg` (6px), including
hand-authored sections in Settings, Connections, and the agent library. This
matches Geist's [base material](https://vercel.com/geist/materials). Reuse that
token when adding a surface; keep dividers and adjoining rows inside the same
card square. Clip edge-to-edge row fills to the card's corners when needed.
Inline callouts and alert boxes use `rounded-md` (4px), matching their existing
settings counterparts.
The app shadow vocabulary in `app/globals.css` is:
| Token | Geometry | Role |
| --- | --- | --- |
| `--app-shadow-sm` | `0 1px 2px`, 5% opacity | Small control separation |
| `--app-shadow-md` | `0 4px 12px`, 10% opacity | Raised content |
| `--app-shadow-lg` | `0 10px 30px`, 18% opacity | Floating overlays |
| `--app-shadow-card` | `0 12px 30px`, 12% opacity | Surfaces using `shadow-app-card` |
| `--app-shadow-panel` | `0 18px 50px`, 14% opacity | Surfaces using `shadow-app-panel` |
All five use the dark neutral hue defined in CSS. These app tokens are distinct
from Tailwind's `shadow-xs`, `shadow-sm`, and `shadow-lg` utilities used by shared
primitives. Reuse the component's existing elevation before adding another shadow.
## Components
Reuse the implementations below, including their variant APIs and accessibility
behavior. Defaults can be overridden by the owning screen; inspect it first.
- **[Button](./components/ui/button.tsx):** 4px corners; default, small, and large
heights of 36px, 32px, and 40px. Use the existing primary, destructive, outline,
secondary, ghost, and link variants. Primary hover uses `primary/90`, not the
separate brand-hover token. Focus uses a 3px ring; active feedback scales to
97% with a 150ms base transition. Keep loading labels stable in width where
practical and explain unavailable actions nearby.
Native bordered app action buttons use the same 4px radius. Preserve pill
buttons, circular icon buttons, and the seams of grouped controls.
Shared primitives marked with `data-slot` retain their own radius variants;
native pill buttons and tab, radio, and switch roles are excluded from the
action-button override.
- **[Input](./components/ui/input.tsx):** 36px height, 4px corners, horizontal
padding of 12px. In the authenticated app, bordered inputs and textareas use
the secondary surface background. Hand-authored fields use the same corners,
focus ring, invalid state, and disabled treatment as the shared primitive.
Preserve the focus ring, `aria-invalid` treatment, responsive text size, and
associated label. A placeholder is not a label.
- **[Password input](./components/ui/password-input.tsx):** password and secret
fields always show an eye button. Newly entered values can be shown or hidden
without changing the value or submitting the form, and hide when focus leaves
the field and its eye button. Saved secrets that the
server does not return use a disabled, muted eye; unavailable saved API-key
fields are muted and disabled. An editable replacement field stays usable.
Give each eye the field or provider name so multiple secrets have distinct
accessible controls. Preserve compact text sizes at desktop breakpoints.
- **Native bordered dropdowns:** secondary surface background, 4px corners, and an inset,
vertically centered chevron,
matching the shared control scale. The app stylesheet reserves room for the
indicator on pages and in portaled dialogs. Native keyboard and picker
behavior remain available; multiple-select listboxes keep their native
treatment. Forced-color mode uses the system indicator.
- **[Switch](./components/ui/switch.tsx):** 36px by 20px capsule with a 14px
thumb. Off is a quiet secondary track with a 2px `border` outline and a grey
`neutral-5` thumb; the thumb, not the outline, carries the 3:1 contrast
against the page. On is a solid green `--switch-on` track (darker in light
theme so it keeps 3:1 against the page) with a white thumb. Every toggle in
the app uses this one style. Keep text outside the control. Thumb position
conveys state alongside color.
The quiet Off track and outline are a deliberate WCAG 1.4.11 exception
chosen by Charles (2026-11-09): they sit near 1.2 to 1.4:1 against the page,
so the grey thumb (3:1 or more against the page, asserted in
`switch-appearance.spec.ts`) is what identifies the control and its state.
If this is revisited, hold the Off outline at `--muted-foreground` and keep
the `secondary` fill. An invisible surrounding
hit area keeps the pointer target at least 24px tall.
Keep the Radix switch semantics, associated label, keyboard focus ring,
disabled treatment, and reduced-motion behavior.
- **[Card](./components/ui/card.tsx):** 6px corners, border, and `shadow-sm`.
The container has 24px vertical padding and gap; header, content, and footer
provide their own 24px horizontal padding. Do not add another blanket padding
layer or wrap every section in a card.
- **[Badge](./components/ui/badge.tsx):** 3px corners, 12px medium text, and
padding of 2px vertically and 8px horizontally. Reuse `live`, `warn`, and
`error` variants for their existing meanings and include a readable label.
- **[App navigation](./components/app-sidebar.tsx):** app links use 40px rows,
6px corners, Iconoir icons, and `aria-current` on the active destination.
The generic [sidebar menu](./components/ui/sidebar-menu.tsx) has different
defaults (32px rows, 4px corners); these are separate components.
Settings opens a secondary menu in the same sidebar, with a back arrow to
restore the main navigation. Each Settings section has a scoped page URL.
The mobile navigation sheet follows the same pattern and closes after a
section is selected. Billing has Billing Settings and Usage tabs.
Connections has Integrations and MCP Servers tabs; MCP Servers is not a
Settings section.
- **[Command Center](./components/control/task-workspace.tsx):** use a compact
app navigation rail, a resizable task sidebar, and a persistent conversation.
Preview, changes, files, and plan open in a resizable right pane; commands,
terminal, and logs open in a bottom drawer. Closing a pane hides its content
without ending execution. At narrow workspace widths, tools fill the available
space and their close control returns to the same conversation. Sandbox
selection belongs to the task; ambiguous environments require an explicit
choice. Read-only command output and the interactive shell remain separate tabs.
Repository workspace links select the repository's latest task, or a new
composer with that repository selected. Run links open the original run in
Command Center. Live runs accept guidance; completed runs can continue in
the same chat after saved history loads. Opening a link never starts an agent.
Follow-ups and steering stay in one continuous, scrollable transcript. Keep
earlier requests and their open tool details mounted when another turn arrives;
do not move them behind an automatic history disclosure. Only the latest
request shows live activity. Follow new output while the reader is at the
bottom; scrolling up pauses automatic following.
Show workspace verification as four compact rows: typecheck, lint, build, and
tests. Each row discloses the actual command, exit result, and output without
losing its open state when the chat is steered. Preserve stack frames and
source literals in output; redact credentials. Distinguish failed,
unconfirmed, unavailable, and explicitly skipped checks. A passing headline
requires all four full checks against the checked source contents; later edits
invalidate earlier results. Operator limits stay visible with their reason.
Durable workspace files do not require always-running compute. Pause idle
compute after task work, retaining it for an active preview, worker, command,
or explicit keep-running request. Show routine running/paused state in the
sandbox controls; chat explains known reasons cleanup was refused and
warns when its outcome cannot be confirmed. Preserve each distinct warning
when cleanup touches several workspaces, with actionable refusals first.
Active tool buttons also collapse their pane. Right panes and the terminal
drawer can expand into the workspace and restore their previous split size;
Escape restores the split view. Sidebar collapse preserves project disclosure
and scroll state. Use short, interruptible transform transitions for these
layout changes, keeping controls interactive and live previews and editors
mounted. Respect reduced-motion preferences with immediate updates.
- **[Dialog](./components/ui/dialog.tsx):** reuse the Radix-backed focus and
dismissal behavior, 6px corners, 24px padding, and responsive action layout.
Provide a title and description. Use inline disclosure when it can complete
the task without interrupting the surrounding work.
For each changed interaction, account for hover, focus, active, disabled,
loading, empty, error, and success states where applicable. Use semantic controls
and accessible names for icon actions. Preserve usable touch targets and verify
keyboard flow and narrow layouts when changing UI.
## Do's and Don'ts
- Do show the exact resource and context affected by an action.
- Do reuse semantic theme tokens and existing primitives.
- Do distinguish repository state, agent execution, and sandbox lifecycle.
- Do explain unavailable actions and errors in language the operator can act on.
- Do preserve light/dark behavior, visible focus, and reduced-motion support.
- Do update this document when shared defaults change, with code as evidence.
- Don't resemble a decorative AI demo, a disconnected chatbot, or a Git client
that obscures runtime behavior, as described in PRODUCT.md.
- Don't add ornamental motion, novelty controls, or broad visual churn.
- Don't collapse distinct resources into one label or icon.
- Don't copy marketing display treatments into routine app controls.
- Don't infer new token values or universal component rules from the old archive.