These rules are distilled from a systematic critique of the current interface and the redesign direction established for Untangle. They are non-negotiable — every UI change should be checked against them.
Divorce is one of the most stressful experiences in a person's life. Users come to Untangle during a time of confusion, anxiety, and emotional volatility. The interface has a responsibility to make things feel more manageable, not more overwhelming. It should feel like a calm, competent guide — not a government form at the DMV.
-
Use warm neutrals everywhere. Every color in the palette should feel warm and grounded. The beige background (
#E7E0D3), warm dark text (#363330), and sage accents (#A7A488) create a sense of calm. -
Reserve the gold accent for one primary action per screen. The warm gold (
#F5C45B) is the brightest element in the palette. Using it sparingly gives it meaning — it says "this is the thing to do next." -
Use progressive disclosure. Reveal complexity gradually. Show the current phase's tasks, not all 40+ tasks at once. Show task details in a sheet, not inline. Let users drill deeper when they're ready.
-
Collapse completed work. Once a phase is done, it shouldn't dominate the screen. Minimize it — hint at its presence (e.g., a subtle card stack behind the current phase) but give focus to what's next.
-
Use human, approachable language. "Prepare Your Paperwork" instead of "Form Preparation." "Create your Summons" instead of "Generate Summons (JD-FM-3)." The interface should sound like a helpful friend, not a legal filing system.
-
Set expectations. Include time estimates on phases and tasks. Provide "What you'll need" checklists before a task begins. Give brief context explaining what each phase is about and why it matters. Reducing unknowns reduces anxiety.
-
Let the UI speak for itself. Minimize labels, annotations, and explanatory text when the visual design communicates the same thing. Clean interfaces feel more trustworthy.
-
Make primary actions visually obvious. There should be no ambiguity about what to do next. Primary buttons are prominent (gold, full-width or near it). Secondary actions are quieter. Tertiary actions are text links.
-
Create clear visual hierarchy. In any view, the user should be able to instantly identify: where they are, what to do next, and how much is left. Size, weight, color, and spacing should all reinforce this hierarchy.
-
Differentiate containers with fill, not stroke. Cards sit on the warm beige background as white surfaces. Sections use
#F8F6F1for subtle differentiation. No heavy borders or shadows needed. -
Preserve dashboard stack hierarchy. For the active phase card stack, use three distinct fills and offsets: back
#F2EEE7(taller), middle#F6F5EF(shorter), front#FFFFFF. If stack colors blend or heights invert, treat as a bug. -
Keep the estimate pill and phase-number badge the same height. On mobile this is
40pxfor both, so the header row reads as a balanced pair. -
Keep mobile composer width intentionally narrower than the main card. The floating “Ask anything” bar should not span card edge-to-edge; it should read as a separate control.
-
Use semantic spacing tokens, not numeric spacing classes. Default to
xxxs,xxs,xs,s,m,l,xl,xxlfor layout rhythm (m*,p*,gap*,space-*, positioning offsets). -
For forms, keep label/help text close to inputs and separate fields from each other. Intra-field spacing should be tighter than inter-field spacing so users can immediately see which description belongs to which field.
-
For dynamic list sections, keep heading/error/action rhythm deliberate. Use a compact outer stack, show array-level errors directly above the add action, and add explicit separation before the action in empty-error states.
-
Use standard control heights. Default to
h-10for standard controls,h-9for compact controls, andh-11for prominent CTAs; keep controls in the same action row the same height. -
Keep skeleton loaders on the same palette as dashboard. Use
bg-mutedfor soft blocks andbg-muted-foreground/25for primary line placeholders; update loaders whenever the corresponding surface styling changes. -
Use shared form wrappers for user-facing form controls. On app surfaces, use
components/forms/*wrappers (for exampleFormTextField,FormMoneyField,FormTextarea,FormSelectField,FormRadioGroup,FormCheckbox) instead of importing raw field primitives directly. -
Use shared destructive button variants. Use
Buttonvariants (destructivefor high-emphasis confirms,destructive-ghostfor inline delete/remove actions) instead of ad-hoc destructive class combinations. -
Keep styling directives in design-system docs only. Put visual rules in
docs/design-system/*and keepAGENTS.mdfiles focused on workflow, validation, and architecture guidance. -
Use outlined secondary buttons as the standard secondary action treatment. Secondary actions should use a subtle warm border (
rgba(54, 51, 48, 0.1)), while primary and tertiary actions stay borderless. -
Keep form controls borderless. Inputs, textareas, and select triggers should use fill-based surfaces rather than outlined borders.
-
Treat shared form container spacing as canonical.
FORM_FIELD_CONTAINER_CLASSis the default field rhythm owner. Do not override it in feature components with ad-hoccontainerClassNamemargin resets unless the exception is explicitly documented.
-
Never use pure black or cool grays. No
#000000, nogray-500, no blue-tinted neutrals. Every dark should be warm (#363330for primary,#6B6862for muted). Cool tones feel clinical and detached. -
Never use blue as a primary color. The current default blue is generic and cold. It communicates nothing about the brand or the emotional context. The warm gold accent replaces it.
-
Never use purple for AI elements. Purple is the default "AI generated" color across the industry. Using it immediately signals that the interface was made by AI, which undermines the trust and expertise the design needs to convey.
-
Never apply shadows to cards or containers. Shadows feel muddy against the warm palette and add visual noise. Use fill color layering instead — white cards on beige backgrounds create natural elevation without shadow.
-
Never show all tasks at once. A flat list of 40+ items is demoralizing. Always group tasks into phases. Show only the current phase's tasks by default. Let users explore other phases if they want, but don't force the full scope on them.
-
Never use strokes as primary container differentiation. Heavy borders add visual weight and noise. When a border is absolutely needed, use
rgba(54, 51, 48, 0.1)— barely visible, warm-toned. -
Never make completed items visually prominent. Completed phases/tasks should recede. No bright checkmarks, no heavy styling. A muted sage indicator and collapsed layout is sufficient. The user's attention belongs on what's next.
-
Never use clinical or legal terminology in user-facing text when human language works. "JD-FM-3" means nothing to a user. "Your financial affidavit" does. Legal form numbers can appear in metadata or tooltips, never as the primary label.
-
Never show raw task counts like "10/47 tasks complete." This is demoralizing. Instead, communicate progress through phases: "Phase 2 of 5" or a simple progress bar scoped to the current phase.
-
Never animate to
autovalues. Framer Motion cannot interpolateheight: "auto"orwidth: "auto"— it will snap at the end of the animation. Always use fixed pixel values for animated dimensions. -
Never show both chat composers at once. If desktop side chat is visible, hide the floating dashboard “Ask anything” composer.
-
Never rely on emulated viewport-only browser runs for responsive QA. Visual verification must use a normal headed window so manual resizing reflects real responsive behavior.
-
Never introduce new raw numeric spacing utilities by default. Avoid classes like
mt-3,px-4,space-y-1; use semantic tokens unless a one-off calibration is explicitly documented. -
Never let label padding create loose label-to-input spacing. If a field feels disconnected, tighten the label/help-to-input stack first and only then adjust field-to-field spacing.
-
Never stack container
space-y-*spacing and extra add-buttonmt-*spacing without intent. In list-empty states this creates oversized gaps and inconsistent form rhythm. -
Never add decorative icons by default. Icons should appear only when they provide functional meaning.
-
Never import raw form primitives directly on app surfaces. Avoid direct imports of
@/components/ui/input,@/components/ui/textarea,@/components/ui/select,@/components/ui/checkbox, and@/components/ui/radio-groupoutside shared wrapper/component files. -
Never hand-roll destructive button styling on app surfaces. Do not compose one-off destructive button classes when
Buttondestructive variants already cover the pattern. -
Never add UI styling directives to
AGENTS.mdfiles. If a visual rule changes, updatedocs/design-system/design-rules.mdand/ordocs/design-system/visual-language.mdinstead. -
Never use ad-hoc button outlines outside the standard secondary treatment. Do not introduce one-off border colors/widths for button variants when secondary actions already use the canonical warm outline pattern.
-
Never use outlined form-field treatments. Do not add border-based styling as the default for user-facing input/select/textarea controls.
-
Never neutralize shared form container rhythm by default. Avoid local overrides like
containerClassName=\"mb-0\"that compete withFORM_FIELD_CONTAINER_CLASS; if an override is truly required, document and annotate it explicitly.
The following commands are the canonical enforcement contract for these rules:
npm run lint:design-system(changed files + global shared-constant checks)npm run lint:design-system:all(full-repo sweep)npm run lint:spacing-tokensnpm run lint:form-componentsnpm run lint:app-page-stylesnpm run lint:heading-typographynpm run lint:agents-no-style-directives
CI runs npm run lint:design-system -- --against-ref <base-sha> so design drift fails pull requests deterministically.