git:20260907.83d54dd to git:20260908.5f0275a

75 added, 155 removed. Audit A to A.

# moi applet design
- This visual contract covers widgets and views inside a moi workspace. Applets may be expressive
- while staying related to the calm host. This guide owns design decisions, `SKILL.md` owns
- implementation, and the host owns fonts and semantic color values.
-
- ## Core principles and visual hierarchy
+ Applets should feel useful, clear, and at home in the workspace. Let their content give them character while keeping familiar typography, colors, and interactions.
- Design around the content and task. Give every applet one clear first reading, then add detail in
- proportion to its purpose and space. Dense information needs hierarchy, alignment, and stable lanes.
+ This guide covers widgets and views inside a moi workspace.
- An applet may have one expressive focal point, such as a visualization, image, strong surface, or
- state change. Keep the rest restrained. Avoid decorative clutter and competing effects.
+ ## Content and layout
- Every visible element must explain content, show a real state, or enable an action. Remove repeated
- labels, obvious readiness badges, redundant helper copy, decorative status pills, and meaningless
- icons. Relate a workspace's applets through typography, palette, spacing, or interaction patterns.
+ **Make the purpose clear at a glance.** Lead with the information or activity people came for. Use contrast to create clear levels of emphasis without making the interface feel washed out. Keep the main action easy to find.
- Lead with the main value, message, or task. Quiet supporting content and make tertiary metadata easy
- to ignore. A widget may use one large hero value when its footprint supports it. When two elements
- compete, reduce one.
+ **Choose content before adding structure.** Include the information and controls the task needs. Add summaries, metrics, filters, and explanations when they help people understand or act. Available space is not a reason to add content. A sparse screen can be complete.
- ## Shared system
+ **Consider the screen as a whole.** Individually useful elements can still compete or repeat one another. Consolidate related information and reveal secondary details when needed. Keep essential information and frequent actions readily available.
- ### Color and surfaces
+ **Give expression a clear focus.** Use typography, composition, color, imagery, texture, or a small content-linked metaphor to give the applet character. A visual detail may support the subject or mood without carrying data or enabling an action. Keep the treatment focused so the content remains easy to scan. Expand a focal region only when added working space helps the task.
- Use `h-full w-full bg-background text-foreground` for most roots. Widgets and views share token
- meaning while the host resolves their values differently:
+ **Group through spacing and alignment.** Start with an open layout. Use surfaces only for interactive objects, independent scrolling regions, distinct states, or a dedicated work area. Keep ordinary headings, tabs, summaries, metrics, and sections unboxed. Avoid large rounded page frames and decorative rows of cards or nested cards.
- - **Widgets:** `background` is the workspace `primary`, `foreground` is its readable pair, and the
- local `primary` pair becomes a derived light action surface. The transparent host frame requires
- an opaque root or an opaque fallback behind a full-bleed image or visualization.
- - **Views:** tokens inherit the workspace page theme, so the default root matches the page.
- - **Floating UI:** menus, tooltips, and popovers use `bg-popover text-popover-foreground` inside
- the applet scope.
+ **Keep a consistent rhythm.** Use a 4 px spacing rhythm, with smaller gaps inside groups and larger gaps between them. Apply outer padding once. Align repeated values and actions so content changes do not move them around. When removing a container, remove its unnecessary padding and radius and realign its contents.
- | Intent | Classes and guidance |
- | --- | --- |
- | Main content | `text-foreground` for titles, labels, values, and important icons |
- | Supporting content | `text-muted-foreground` for descriptions and secondary information |
- | Inset surface | `bg-card text-card-foreground`, used only for a distinct functional region |
- | Quiet fill | `bg-muted` for inset regions, skeletons, and disabled structure |
- | Control state | `bg-accent text-accent-foreground` for hover, active, and selected controls |
- | Main action | `bg-primary text-primary-foreground hover:bg-primary/90` |
- | State | Views may use `text-success`, `bg-success/10`, `text-destructive`, or `bg-destructive/10`; widgets use `text-foreground`. Add clear wording and, when useful, an icon or shape. |
- | Object edge | `ring-1 ring-border` for complete container and control outlines |
- | Focus | `focus-visible:ring-2 focus-visible:ring-ring` |
- | Separator | A one-sided border such as `border-b border-border` between adjacent regions |
+ **Keep the layout comfortable.** Give content enough room to scan without making it unnecessarily dense or stretching it to fill the frame. Use natural height for simple tasks and extra space for tables, boards, canvases, and other work areas that benefit from it. When everything fits comfortably, keep essential information and actions within one viewport. Adapt to narrow widths, long content, and chat sharing the workspace. Avoid horizontal page scrolling; wide content may scroll within its own bounded region.
- Use lower foreground opacity only for readable tertiary metadata. Important text needs full
- contrast. Saturated surfaces need an explicit readable light or dark foreground. Never rely on
- color alone.
+ **Keep layers simple.** Prefer normal document order and bundled overlays with their existing portal and stacking behavior. Custom overlays must preserve applet scope and theme by using the closest `[data-applet]` root. Add minimal local z-index only when document order and a scoped portal cannot resolve the overlap.
- Use rings for complete outlines and one-sided borders for separators; never combine both. Keep
- edges subtle and avoid raw high-contrast colors. Derive tonal colors and custom gradients from
- local tokens with `color-mix()`. Tailwind palette colors need a content, data, brand, or user reason.
- Explain consistent data mappings with labels, legends, shapes, or values. Never use palette colors
- for generic decoration or unrelated widget backgrounds. Purple, violet, and fuchsia also need a
- reason and never act as a default creativity or technology cue.
+ ## Shared system
- Use an open layout. Group with spacing, alignment, type, and occasional separators. Add a surface
- only around an interactive object, independent scroller, distinct state, or self-contained work
- area. Standard controls keep their surfaces; headers, tabs, summaries, metrics, and ordinary
- sections stay unboxed.
+ ### Typography
- Avoid large rounded page frames, adjacent or nested cards, and structural wrappers. Align content
- to shared edges or grid columns. Apply outer padding once, then use gaps. Removing a surface also
- means removing its card-like padding and radius and realigning its children.
+ **Use a small, consistent set of styles.** Establish clear roles for headings, ordinary content, and supporting information. Text with the same role and importance shares the same typography.
- ### Stacking and overlays
+ Inherit the workspace font and use sentence case. Use regular weight for most text and medium for emphasis, including focal prompts or values when weight helps establish hierarchy. Reserve other weights for explicit user customization.
- Use DOM order for normal stacking: later siblings appear above earlier ones. Avoid z-index for
- ordinary layout. Use overlays from the UI components library (`moi ui-components`) with their
- existing portal behavior; they preserve applet styles and stay within their intended scope. For
- custom floating UI, portal into the closest
- `[data-applet]` root to preserve scope and theme tokens, rather than directly to `document.body`.
+ **Choose readable defaults.** Use `text-sm` for controls and general UI, and `text-base` for focused content when space allows. Sizes below `text-sm` should be rare, limited to unusually tight controls. Use larger text for headings or a focal value.
- Add a local, minimal z-index only when DOM order and a scoped portal cannot solve the stacking need.
- Several layers or escalating values mean the layout structure needs reconsideration.
+ Reserve `font-mono` for code, commands, and code-like identifiers. Numeric values, measurements, percentages, timers, timestamps, prices, counts, labels, keyboard shortcuts, and key names use the workspace font. Add `tabular-nums` when stable widths or alignment help.
- ### Textures
+ ### Controls
- Texture is optional and belongs only on the applet root. Choose it after the content layout is
- clear, use at most one, and pair it with an opaque semantic base such as
- `bg-background text-foreground texture-checker`.
+ **Use familiar controls.** Follow the [UI component guidelines](UI-COMPONENTS.md) and use bundled components with their existing variants, sizes, and shapes. Controls with the same role and importance share component variants. Keep feedback near the action that caused it.
- Available treatments are `texture-checker`, `texture-grid`, `texture-noise`,
- `texture-gradient-linear`, and `texture-inset-shadow`. They use semantic colors without replacing
- the base background color.
+ ### Icons
- Match treatment to density. Dense root content uses plain `bg-background`,
- `texture-gradient-linear`, or `texture-inset-shadow`; sparse content may use any readable texture.
- Checker, grid, or noise may surround dense content only when it already needs an opaque or tonal
- work surface. Full-bleed images, maps, canvases, and visualizations use no texture.
+ Use Tabler icons when they clarify meaning, identify a familiar action, or reinforce a focused visual metaphor. Avoid adding an icon to every label or control. Set stroke explicitly: `1.75` at 12–16 px and `1.5` at 20–24 px. Let components control icon size when provided.
- Never add wrappers to rescue a busy texture; choose a quieter root. Do not texture cards, panels,
- controls, or text regions, stack textures, or add tuning variables. Check nearby applets: unrelated
- applets use different textures, while a widget representing a view shares its texture. Any texture
- should become easy to ignore while reading.
+ ### Color and surfaces
- ### Type
+ **Follow the workspace theme.** Use semantic tokens and their matching foregrounds. The default root is `h-full w-full bg-background text-foreground`.
- Inherit the workspace font and use sentence case. Use regular weight for most text and medium for
- emphasis; other weights are reserved for owner hand-tuning. `text-sm` (14 px) is the UI default.
- Use smaller text for compact metadata and larger text for headings or one display value. Keep at
- most two clear type roles and avoid near-identical label styles.
+ For widgets, the host sets the `background` token to the workspace’s `primary`, supplies a readable `foreground`, and derives a light local `primary` action surface. The host wrapper is transparent: each widget must paint its own opaque root, normally with `bg-background`, or provide an opaque fallback behind full-bleed media. Views inherit the page theme.
- Reserve `font-mono` for code, commands, and code-like identifiers. Numeric values, measurements,
- percentages, timers, timestamps, prices, counts, and labels use the workspace font. Add
- `tabular-nums` when stable widths or alignment help.
+ | Intent | Classes and guidance |
+ | --- | --- |
+ | Main content | `text-foreground` for primary content and controls |
+ | Supporting content | `text-muted-foreground` for secondary emphasis |
+ | Inset surface | `bg-card text-card-foreground`, used only for a distinct functional region |
+ | Quiet fill | `bg-muted` for inset regions, skeletons, and disabled structure |
+ | Control state | `bg-accent text-accent-foreground` for hover, active, and selected controls |
+ | Main action | `bg-primary text-primary-foreground hover:bg-primary/90` |
+ | State | Views may use `text-success`, `bg-success/10`, `text-destructive`, or `bg-destructive/10`; widgets use `text-foreground`. Add clear wording and, when useful, an icon or shape. |
+ | Object edge | `ring-1 ring-border` for complete container and control outlines |
+ | Focus | `focus-visible:ring-2 focus-visible:ring-ring` |
+ | Separator | A one-sided border such as `border-b border-border` between adjacent regions |
+ | Floating content | `bg-popover text-popover-foreground` for menus, tooltips, and popovers inside the applet scope |
- ### Icons
+ Use `text-foreground` and `text-muted-foreground` together to create clear hierarchy. Keep every level comfortably readable and avoid letting muted text dominate the screen. Communicate meaning through wording, symbols, or shapes as well as color.
- Set `stroke` explicitly on every Tabler icon; the package default of `2` is heavier than the
- workspace chrome. Use `1.75` for 12–16 px icons and `1.5` for 20–24 px icons. When a component sets
- the icon size, omit `size` and use the stroke that matches its rendered size.
+ Use additional colors for meaningful data, imagery, brands, a content-linked visual accent, or an explicit user preference. Keep data mappings consistent and understandable. Derive custom tonal treatments from local tokens.
- ### Spacing and shape
+ **Keep surface treatment restrained.** Use the shared radius scale and existing control shapes. Reserve `rounded-full` for pills, circles, avatars, and status dots; do not turn rectangular controls into capsules. For custom regions, use rings for complete outlines and one-sided borders for separators; avoid doubling them.
- Follow a 4 px spacing rhythm: 4–8 px within a tight group, 12–16 px between groups in a region, and
- 24 px or more at section changes in larger applets. Prefer spacing over dividers. Keep repeated
- rows, chart labels, status markers, counters, and trailing actions in stable lanes so changing
- values do not shift the layout.
+ **Let texture support readability.** Texture is optional, limited to the root, and backed by an opaque semantic color. Available treatments are `texture-checker`, `texture-grid`, `texture-noise`, `texture-gradient-linear`, and `texture-inset-shadow`.
- Use the shared radius scale and default control radii. Use `rounded-lg` or `rounded-xl` for
- ordinary regions, `rounded-2xl` or `rounded-3xl` for one focal surface, and `rounded-full` only for
- real pills, circles, avatars, and status dots. Rectangular controls must not become capsules.
+ For dense root content, use plain `bg-background`, `texture-gradient-linear`, or `texture-inset-shadow`. Checker, grid, and noise may surround dense content only when it already needs an opaque work area. Choose a quieter texture before adding containers. Avoid stacking or tuning textures, and omit them behind full-bleed imagery or visualizations. Coordinate related widgets and views.
- ### Interaction, motion, and states
+ ### Interaction and states
- Controls must be obvious, keyboard-operable, comfortably sized, visibly focused, and accessibly
- named. Use Tabler icons with consistent visual weight. Keep charts understandable through labels,
- legends, patterns, or direct values as needed.
+ **Make every action usable.** Controls need clear names, comfortable targets, keyboard support, and visible focus. Charts need understandable labels or equivalent information. Preserve accessibility when simplifying the screen.
- Use short, interruptible motion for meaningful state changes and control feedback. Respect reduced
- motion and prefer transform and opacity. Avoid looping decoration and animation on frequently
- updating numbers. Audio and video must be user-initiated.
+ **Show the states the applet can reach.**
- Design only states the applet can reach. For data-driven applets, handle these when applicable:
+ - **Loading:** preserve the expected content shape with a skeleton; use spinners for compact or shapeless work.
+ - **Empty:** explain the absence and offer a relevant next step when one exists.
+ - **Error:** explain the problem plainly and provide recovery.
+ - **Refreshing:** keep existing content visible and show progress near the refresh action.
+ - **Stale:** identify outdated information near the affected content.
+ - **Disabled:** keep the control recognizable and make its unavailability understandable.
- - **Loading:** preserve the final layout and surface with a matching skeleton. Use a spinner only
- for compact inline work or work without a meaningful content shape.
- - **Error:** explain the problem in one human sentence and offer retry or a clear recovery action.
- - **Empty:** explain the absence briefly and provide a useful next step; never leave a data region
- blank.
- - **Refreshing:** keep current data visible and show progress on the refresh control.
- - **Stale:** show a quiet, current timestamp or status near the affected data.
- - **Disabled:** preserve the label and structure while making unavailability clear without color
- alone.
+ Keep the main work surface in the same position and size as states change. Feedback must fit the applet’s available space.
- Keep loading, populated, empty, success, and error layouts stable. A primary surface remains in the
- same position and size through those states. Errors and empty states must fit the configured Widget
- height or the View's normal content frame.
+ Use brief, interruptible motion to explain changes or acknowledge input. Respect reduced motion, avoid looping decoration and animation on frequently changing numbers, and make audio and video user-initiated.
## Widgets
- Widgets are compact dashboard surfaces seen beside other widgets. Their main meaning should be
- clear in a quick scan. Larger footprints may add charts, lists, metadata, filters, and direct
- actions while preserving one first reading.
+ **Widgets support a quick glance or immediate action.** Choose the smallest footprint that presents the content clearly. Keep the main information prominent and supporting controls limited to the immediate task. Put tabs, deeper navigation, and multi-step work in a view. Keep hover feedback on controls; leave the widget surface unchanged.
- The host card owns outer radius, border, shadow, clipping, and elevation. Its interior is
- transparent. Fill it with an opaque `h-full w-full` root and add no outer card chrome. Use `p-4` as
- the compact padding default or `p-5` for larger footprints when content still fits. Use a column
- layout when content needs a footer or timestamp and keep lower-priority information at the bottom.
+ The host owns the widget’s outer shape, clipping, and elevation. Its wrapper is transparent. Set an opaque background on the widget’s full-size root without adding another outer card.
- The grid has four columns, 160 px rows, 8 px gaps, and a maximum width of 640 px. A Widget may span
- one to four rows and columns. Width shrinks with the workspace; height remains fixed by row span:
+ The grid has four columns, 160 px rows, 8 px gaps, and a maximum width of 640 px. Widgets span one to four rows and columns. Width is flexible; height is fixed:
`rowSpan × 160 + (rowSpan − 1) × 8`
- Treat width as flexible and height as the hard constraint. Start with the smallest footprint that
- presents the content clearly. Test the narrowest realistic width and longest realistic values.
- Clip decorative overflow deliberately, clamp supporting prose, and prevent horizontal page scroll
- and accidental inner page scrolling.
-
- A small Widget has one primary element and at most two supporting groups. Larger footprints may
- carry more when hierarchy remains clear. Prefer live information over labels that repeat context.
- Limit controls to the immediate task: filters, toggles, refresh actions, and links are appropriate.
- Keep feedback on the control and leave the Widget surface unchanged on hover. Tabs, wizards,
- multi-step workflows, and deep navigation belong in a View.
+ Fit content and reachable states within that height without accidental scrolling or clipped controls.
## Views
- Views are full app screens for denser information and sustained work. They own page hierarchy,
- layout, spacing, chrome, and scrolling. A View must remain complete and usable at the available
- width, including when chat shares the workspace.
+ **Views support sustained work.** Each view represents one screen and owns its layout, padding, and scrolling. Establish clear context, a primary work area, and relevant actions. A title is useful when the content does not already establish context.
- One View represents one screen. Cross-screen navigation belongs to the workspace. Internal tabs,
- filters, and master-detail layouts may organize the current task without adding a client-side
- router.
+ Prefer one main scroller. Add bounded internal scrolling only when independent scroll positions help the task. Internal tabs, filters, and master-detail layouts may organize the current task. Cross-screen navigation belongs to the workspace; do not add a client-side router.
- Let content choose the frame. Most Views need clear page context, a primary work area, and an
- obvious place for the main action. A title with an optional subtitle or action is a useful default;
- a canvas, map, or immersive visualization may establish context another way.
+ ## UI copy
- Use consistent page padding such as 24 or 32 px. Constrain prose, forms, and narrow task flows to a
- readable maximum width. Let tables, boards, maps, and visual workspaces use more of the frame when
- the task benefits.
+ **Keep language direct.** Use clear labels and specific action names. On repeated-use screens, omit coaching, encouragement, and instructions for expected behavior. State necessary help once, near the relevant interaction. Headings, labels, controls, and helper text must not repeat the same meaning.
- Prefer one main page scroller. Use bounded internal scrolling only where independent position helps,
- such as a sticky table body, timeline, or board. Never create horizontal page scroll. Views may use
- more sections, controls, and information layers than Widgets while keeping one primary work area;
- do not stretch a Widget-like card to fill the page.
+ Omit terminal periods in headings, labels, metadata, and short standalone UI lines. Use sentence punctuation for paragraphs or multiple complete sentences.
+ ## Design slop
+
+ Design slop is a repeated visual shortcut that makes an interface feel generic or agent-made. Avoid decorative patterns added by habit instead of because they suit the content.
+
+ - **Decorative accent lines:** Do not place short colored lines, partial borders, or a single colored edge beside headings, prompts, or values as generic decoration. Choose a visual treatment connected to the content, or leave the area open.
+
## Final review
- Remove elements and wrappers that do not improve understanding, action, or state recognition, then
- realign what remains. Confirm the first reading is clear; the visual system stays readable and
- purposeful; realistic content and reachable states fit without overflow or jumps; controls are
- necessary and accessible; and the applet follows its Widget or View contract.
+ - **Focus:** Identify what people notice first and what they can do next. Reduce competing emphasis.
+ - **Subtract:** Temporarily remove secondary groups, helper copy, badges, icons, and wrappers. Restore an element when its absence creates a specific problem with the task, a decision, a state, or recovery. A single deliberate visual metaphor may remain when it gives the content recognizable character without adding copy, controls, or containers. Preserve useful content and accessible labels.
+ - **Deduplicate:** Read all visible copy together and compare meaning, not wording. When two elements communicate the same context or instruction, keep the clearer one closest to the relevant action.
+ - **Character:** Identify the applet’s visual idea. If it relies only on text and standard controls, consider one content-linked accent, metaphor, image, or expressive composition. Keep it subordinate to the main content.
+ - **Unify:** Compare text styles and control variants by role, then check their combined emphasis. Merge unnecessary differences in typography, color, spacing, and shape.
+ - **Contrast:** Check that contrast creates clear levels of emphasis and the screen does not feel washed out.
+ - **Verify:** Check realistic content, narrow widths, reachable states, keyboard use, and whether content that should fit requires scrolling. For widgets, also review how the result sits beside other applets.