# Mechanica UI Shell This document describes the production catalogue and shell UI delivered for the Mechanica milestone. ## Design principles Mechanica should feel like a premium engineering reference tool rather than a generic content grid. The shell uses: - A deep neutral background (`#0B0E14`) with layered radial light fields. - Raised glass panels for primary surfaces. - Hairline borders for precision and low visual noise. - Sky blue (`#4C8DFF`) as the primary accent and warm amber (`#FFB04C`) for highlights. - Tabular numerals for counts, RPM ranges, complexity values, and engineering facts. - Smooth but restrained transitions that respect `prefers-reduced-motion`. ## Theme system Theme state supports three modes: 1. `system` 2. `dark` 3. `light` The current mode is stored in Zustand and persisted to localStorage under `mechanica.preferences.v2`. The document `` element receives: - `data-theme="dark"` or `data-theme="light"` - the `dark` class when the resolved theme is dark - a matching `color-scheme` The inline script in `index.html` applies the persisted theme before React hydrates to avoid a white flash. ## Layout The shell consists of: - Skip link for keyboard users. - Sticky top navigation with logo, catalogue route, global search, favourite count, and theme cycle button. - Main route outlet with responsive padding. - Bottom status bar showing current route context, library size, and favourite count. - Background grid/radial field rendered by CSS only, so it does not affect runtime performance. Desktop catalogue layout uses a two-column grid: sticky filters on the left and machine results on the right. Tablet and mobile collapse to a single-column flow while preserving filter order and semantic form controls. ## Shared UI primitives The UI primitives live in `src/components/ui`: | Component | Purpose | | --- | --- | | `Button` | Consistent variants, sizes, loading state, and focus-visible treatment. | | `IconButton` | Square accessible icon action with required ARIA labelling. | | `Badge` | Category, difficulty, release phase, and status labels. | | `Input` | Labelled search/text input with hint/error descriptions and left/right slots. | | `Select` | Native select wrapper for accessible sorting controls. | | `Panel` | Glass/solid/elevated section surface. | | `Skeleton` / `SkeletonText` | Stable loading placeholders with shimmer. | | `ToggleSwitch` | ARIA `switch` control for binary preferences. | | `SegmentedControl` | Keyboard-accessible button group for view mode selection. | | `Tooltip` | Lightweight CSS tooltip for non-essential hover hints. | All primitives accept `className` for composition but own the baseline visual language. ## Catalogue behaviours - Search scans title, subtitle, category, difficulty, tags, keywords, descriptions, applications, facts, and part names. - Filters support category, difficulty, release phase, and favourites-only mode. - Sort supports name, newest, and complexity. - View modes support comfortable and compact cards. - Results animate with Framer Motion while preserving semantic list structure. - Empty states include the active query and a clear-filters action. - Skeleton cards match the grid dimensions to prevent layout shift. ## Accessibility Accessibility decisions included in the shell: - A skip link appears on focus and jumps to `#main-content`. - Interactive chips use `aria-pressed`. - Favourite buttons use `aria-pressed` and machine-specific labels. - The theme button announces the current and next theme state. - Search inputs have visible labels or accessible labels. - Native inputs/selects are preferred where possible. - `*:focus-visible` receives a high-contrast accent outline. - Status updates use semantic text and avoid animation-only communication. - Reduced motion disables smooth scrolling and shortens loading skeleton timing. ## Responsive breakpoints The shell is designed around these target widths: - Mobile: 375, 390, 430 - Tablet: 768, 1024 - Desktop: 1280, 1440+ Tailwind utility breakpoints are used for layout changes. Card internals use flexible wrapping and min-height constraints so metadata never overlaps controls. ## Extending the shell When adding a new view: 1. Add route metadata through `usePageMetadata`. 2. Render within `AppShell` so skip links, navigation, and status bar stay consistent. 3. Use shared primitives before creating a new one-off control. 4. Store durable preferences in Zustand; keep transient hover/open state local. 5. Use the machine registry rather than duplicating catalogue metadata.