{"schemaVersion":"1.0.0","version":"1.1.0","updatedAt":"2026-10-13","name":"Cora Design System","description":"Public component library and machine-first design contract for Cora marketing and product development. Inspect visual recipes, reuse shared primitives, preserve shipped behavior and make deviations explicit.","canonicalUrl":"https://heycora.in/design-system/","endpoints":{"manifest":"/design-system/manifest.json","instructions":"/design-system/llms.txt","stylesheet":"/design-system/tokens.css"},"source":"cora-frontend/lib/design-system.ts","changelog":[{"version":"1.1.0","date":"2026-10-13","changes":["Add a public visual catalog of 24 source-backed specimens with variants, states, usage and structural examples.","Distinguish reusable production primitives from composition recipes; preserve all existing token semantics and export endpoints."]},{"version":"1.0.0","date":"2026-10-13","changes":["Consolidate the marketing and workspace design contract, semantic tokens, component rules, five reusable primitives and generated machine exports."]}],"governance":{"baseline":"Inherited monochromatic design direction and existing executable product patterns. This release consolidates them; it does not claim every historical implementation is compliant.","approval":"New accessible status colors, minimum target sizes, semantic tokens and reusable primitives are implementation recommendations introduced with this contract. Changes to brand direction require explicit owner approval.","precedence":["Current user instructions","Applicable repository instructions and accessibility requirements","This canonical contract and surface profile","Feature-local implementation and its documented exceptions","Legacy showcase and token files (historical only)"],"changeProtocol":["Read this manifest and the relevant profile before editing.","Inspect the existing feature, reuse its shell, and choose documented components.","Use named semantic tokens and reusable primitives; do not duplicate values.","If a new pattern is needed, update this source, component, states and rationale together.","Increment version: patch for corrections, minor for additive patterns, major for changed semantics.","Run check:design-system and build; inspect desktop, 390px mobile, keyboard and neighboring routes.","Document unresolved deviations; do not silently restyle unrelated modules."],"agentPrompt":"Before any Cora UI change, read cora-frontend/lib/design-system.ts (or /design-system/manifest.json and /design-system/llms.txt), choose marketing or workspace profile, reuse existing shells and documented primitives, preserve all states and mobile sheet rules, run npm run check:design-system in cora-frontend, and record any intentional design exception."},"profiles":[{"id":"marketing","name":"Marketing site","status":"existing-baseline","stack":"Next.js App Router / React / Tailwind","font":"--cora-font-marketing","canvas":"--cora-bg","description":"General Sans, expressive scale, white surfaces and monochromatic actions. Serif and handwritten accents belong to existing editorial hero treatments only. Do not add them to forms or data.","sources":["cora-frontend/styles/globals.css","cora-frontend/tailwind.config.ts","cora-frontend/app/layout.tsx"],"reuse":["components/layout/Navbar.tsx","components/layout/Footer.tsx","components/tools/ToolPageShell.tsx","components/tools/framework/ToolContainer.tsx"]},{"id":"workspace","name":"Product workspace","status":"existing-baseline","stack":"WordPress plugin / PHP / JavaScript / Tailwind","font":"--cora-font-workspace","canvas":"--cora-canvas","description":"Inter for operational UI, JetBrains Mono for identifiers, compact hierarchy and tonal selection. Current workspace canvas is cream; dark canvas is #0c0c0e. Mobile sheets slide vertically. Keep industry labels dynamic.","sources":["app/public/wp-content/plugins/cora-workspace/assets/css/admin-style.css","app/public/wp-content/plugins/cora-workspace/admin-dashboard.php",".agents/AGENTS.md"],"reuse":["window.coraShowToast","includes/workspace-header.php","Existing feature-local sheet and table markup"]}],"audit":{"method":"Repository source audit of marketing components, product views, styles, existing tokens, and instructions. The new route is browser-verified separately; this is not a claim that every existing product workflow has been visually tested.","frontendFiles":322,"findings":"287 distinct six-digit colors and 64 arbitrary max-width values appear in frontend source, including artwork and third-party logos. These counts demonstrate decentralization, not that every value is an error.","migration":"Migrate touched features incrementally. No global restyling or changes to authenticated workspace behavior are part of this release."},"featurePatterns":[{"name":"Shell, settings and permissions","sources":["admin-dashboard.php","views/view-feature-hub.php","views/view-cora-roles.php","views/view-settings-suite.php"],"rules":"Persistent navigation, profile popover, dynamic permissions, explicit unsaved-change save bar; no unscoped CSS."},{"name":"CRM, clients and pipeline","sources":["views/view-leads.php","views/view-clients.php"],"rules":"Shared filter state across table/board; industry-aware labels; labelled status and keyboard alternative to drag-and-drop."},{"name":"Tasks, projects and portfolio","sources":["views/view-client-task-manager.php","views/view-projects.php","cora-frontend/app/portfolio/"],"rules":"Consistent detail panels, checklists and activity; preserve confidentiality and selected-record context."},{"name":"Content, inbox and automation","sources":["views/view-content-suite.php","views/view-emails.php","views/view-inbox.php","views/view-automations.php"],"rules":"Separate draft, processing, published and failed states. Preserve editor content; show recoverable service errors."},{"name":"Media, proofing and galleries","sources":["views/view-media.php","views/view-media-editor.php","public-gallery-view.php"],"rules":"Aspect ratio presets 1:1 / 4:3 / 16:9, progressive previews, explicit selection and upload state; preserve image colors."},{"name":"Documents and signatures","sources":["views/view-vault.php","public-doc-view.php"],"rules":"Guided creation, labelled signature controls, audit state. Authored document fonts are content and remain outside interface typography restrictions."},{"name":"Canvas and visual builder","sources":["views/view-canvas.php","views/view-visual-builder.php"],"rules":"User-designed color and typography are an intentional exception; editor chrome stays neutral. Preserve autosave and selected-node context."},{"name":"Finance, inventory and scheduling","sources":["views/view-financials.php","views/view-equipment.php","views/view-crew-scheduler.php"],"rules":"Tabular values, explicit currency/tax/timezone, empty states and permissions; equipment/listing terminology derives from industry."},{"name":"Forms, reviews and client portals","sources":["views/view-forms.php","views/view-review-acquisition.php","public-form-view.php","public-client-portal.php"],"rules":"Visible labels and validation; client content retains its identity while functional controls follow the shared contract."},{"name":"Public marketing and knowledge","sources":["cora-frontend/components/hero/","cora-frontend/components/docs/","cora-frontend/components/tools/framework/"],"rules":"Reuse existing hero, editorial and tool shells. Neutral controls coexist with established scenic artwork and authentic brand logos."}],"primitiveApi":[{"name":"Sheet","import":"@/components/design-system/primitives","props":"open: boolean; onClose: () => void; title: string; placement?: sheet | modal | drawer (default: sheet); footer?: ReactNode; children: ReactNode","example":"<Sheet open={isOpen} onClose={() => setIsOpen(false)} title=\"Project details\" placement=\"drawer\">…</Sheet>","tokens":"--cora-bg, --cora-border, --cora-backdrop, --cora-radius-2xl, --cora-drawer-width"},{"name":"Button","import":"@/components/design-system/primitives","props":"variant?: primary | secondary | ghost | danger; loading?: boolean; all native button props","example":"<Button variant=\"primary\" loading={isSaving} onClick={save}>Save changes</Button>","tokens":"--cora-action, --cora-on-action, --cora-control-height, --cora-radius-lg"},{"name":"TextField","import":"@/components/design-system/primitives","props":"label: string; hint?: string; error?: string; id?: string; all native input props","example":"<TextField label=\"Project name\" hint=\"Visible to your team\" required />","tokens":"--cora-bg, --cora-border-strong, --cora-danger, --cora-text-body"},{"name":"Badge","import":"@/components/design-system/primitives","props":"tone?: neutral | success | warning | danger; children: ReactNode","example":"<Badge tone=\"success\">Active</Badge>","tokens":"--cora-selected, --cora-success, --cora-warning, --cora-danger"},{"name":"Card","import":"@/components/design-system/primitives","props":"all native div props; children: ReactNode","example":"<Card><h3>Project summary</h3><p>Ready for review.</p></Card>","tokens":"--cora-bg, --cora-border, --cora-radius-xl, --cora-space-6"}],"tokens":[{"name":"--cora-zinc-50","value":"#fafafa","category":"palette","usage":"Neutral reference 50; prefer semantic tokens in components."},{"name":"--cora-zinc-100","value":"#f4f4f5","category":"palette","usage":"Neutral reference 100; prefer semantic tokens in components."},{"name":"--cora-zinc-200","value":"#e4e4e7","category":"palette","usage":"Neutral reference 200; prefer semantic tokens in components."},{"name":"--cora-zinc-300","value":"#d4d4d8","category":"palette","usage":"Neutral reference 300; prefer semantic tokens in components."},{"name":"--cora-zinc-400","value":"#a1a1aa","category":"palette","usage":"Neutral reference 400; prefer semantic tokens in components."},{"name":"--cora-zinc-500","value":"#71717a","category":"palette","usage":"Neutral reference 500; prefer semantic tokens in components."},{"name":"--cora-zinc-600","value":"#52525b","category":"palette","usage":"Neutral reference 600; prefer semantic tokens in components."},{"name":"--cora-zinc-700","value":"#3f3f46","category":"palette","usage":"Neutral reference 700; prefer semantic tokens in components."},{"name":"--cora-zinc-800","value":"#27272a","category":"palette","usage":"Neutral reference 800; prefer semantic tokens in components."},{"name":"--cora-zinc-900","value":"#18181b","category":"palette","usage":"Neutral reference 900; prefer semantic tokens in components."},{"name":"--cora-zinc-950","value":"#09090b","category":"palette","usage":"Neutral reference 950; prefer semantic tokens in components."},{"name":"--cora-white","value":"#ffffff","category":"palette","usage":"Pure light surface / inverse text."},{"name":"--cora-cream","value":"#FBFAF7","category":"palette","usage":"Existing workspace canvas and editorial backdrop; never a colored action."},{"name":"--cora-workspace-dark","value":"#0c0c0e","category":"palette","usage":"Current dark workspace canvas; cards remain neutral raised surfaces."},{"name":"--cora-canvas","value":"#ffffff","category":"semantic","usage":"Surface-profile page canvas; workspace overrides this to cream or its dark canvas."},{"name":"--cora-bg","value":"#ffffff","category":"semantic","usage":"Page and control surface."},{"name":"--cora-surface","value":"#fafafa","category":"semantic","usage":"Secondary surface."},{"name":"--cora-selected","value":"#f4f4f5","category":"semantic","usage":"Tonal hover and selection."},{"name":"--cora-border","value":"#e4e4e7","category":"semantic","usage":"One-pixel structural borders."},{"name":"--cora-border-strong","value":"#71717a","category":"semantic","usage":"Accessible input boundary; never heavy card selection. Recommended for new controls."},{"name":"--cora-text","value":"#09090b","category":"semantic","usage":"Primary text."},{"name":"--cora-muted","value":"#52525b","category":"semantic","usage":"Supporting text on light surfaces."},{"name":"--cora-subtle","value":"#71717a","category":"semantic","usage":"Metadata; do not reduce opacity on small text."},{"name":"--cora-action","value":"#09090b","category":"semantic","usage":"Primary action / dark icon tile."},{"name":"--cora-on-action","value":"#ffffff","category":"semantic","usage":"Text on primary action."},{"name":"--cora-action-hover","value":"#27272a","category":"semantic","usage":"Primary action hover."},{"name":"--cora-focus","value":"#52525b","category":"semantic","usage":"Visible keyboard focus; accessibility exception to decorative outline prohibition."},{"name":"--cora-success","value":"#166534","category":"semantic","usage":"Legible success text; always include label or icon."},{"name":"--cora-success-bg","value":"#f0fdf4","category":"semantic","usage":"Success surface only."},{"name":"--cora-warning","value":"#854d0e","category":"semantic","usage":"Legible warning text; never the primary CTA."},{"name":"--cora-warning-bg","value":"#fefce8","category":"semantic","usage":"Warning surface only."},{"name":"--cora-danger","value":"#b91c1c","category":"semantic","usage":"Error / destructive text."},{"name":"--cora-danger-bg","value":"#fef2f2","category":"semantic","usage":"Error surface only."},{"name":"--cora-font-marketing","value":"'General Sans', var(--font-sans, Inter), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif","category":"typography","usage":"Marketing body and headings; retain current runtime font."},{"name":"--cora-font-workspace","value":"var(--font-sans, Inter), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif","category":"typography","usage":"Operational workspace text."},{"name":"--cora-font-ui","value":"var(--cora-font-marketing)","category":"typography","usage":"Active surface font. Override through data-cora-profile."},{"name":"--cora-font-code","value":"var(--font-mono, 'JetBrains Mono'), Menlo, Consolas, monospace","category":"typography","usage":"Code, identifiers, token values; use tabular figures for numeric data."},{"name":"--cora-text-caption","value":"0.75rem","category":"type scale","usage":"Role: caption. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-code","value":"0.8125rem","category":"type scale","usage":"Role: code. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-small","value":"0.875rem","category":"type scale","usage":"Role: small. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-body","value":"1rem","category":"type scale","usage":"Role: body. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-h3","value":"1.125rem","category":"type scale","usage":"Role: h3. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-h2","value":"1.5rem","category":"type scale","usage":"Role: h2. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-h1","value":"2rem","category":"type scale","usage":"Role: h1. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-text-display","value":"3rem","category":"type scale","usage":"Role: display. Base rem assumes 16px; respect browser zoom."},{"name":"--cora-space-0","value":"0px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-1","value":"4px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-2","value":"8px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-3","value":"12px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-4","value":"16px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-5","value":"20px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-6","value":"24px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-8","value":"32px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-10","value":"40px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-12","value":"48px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-16","value":"64px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-20","value":"80px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-space-24","value":"96px","category":"spacing","usage":"Four-pixel rhythm; choose by relationship, not arbitrary decoration."},{"name":"--cora-radius-sm","value":"6px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-radius-md","value":"8px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-radius-lg","value":"12px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-radius-xl","value":"16px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-radius-2xl","value":"24px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-radius-pill","value":"9999px","category":"radius","usage":"Controls: md/lg; cards: xl; sheets: 2xl; status: pill."},{"name":"--cora-shadow-sm","value":"0 1px 2px rgba(0,0,0,0.05)","category":"elevation","usage":"Subtle surface lift."},{"name":"--cora-shadow-sheet","value":"0 20px 50px rgba(0,0,0,0.12)","category":"elevation","usage":"Overlay elevation; do not apply to every card."},{"name":"--cora-backdrop","value":"rgba(9,9,11,0.45)","category":"elevation","usage":"Recommended modal backdrop, verify module behavior before replacing legacy overrides."},{"name":"--cora-duration-fast","value":"150ms","category":"motion","usage":"Hover and focus feedback."},{"name":"--cora-duration-normal","value":"200ms","category":"motion","usage":"Small transitions; no artificial wait."},{"name":"--cora-duration-sheet","value":"250ms","category":"motion","usage":"Sheet movement; disable for reduced motion."},{"name":"--cora-ease","value":"cubic-bezier(0.2, 0, 0, 1)","category":"motion","usage":"Calm deceleration."},{"name":"--cora-content-marketing","value":"1240px","category":"layout","usage":"Current main marketing container, observed across shipped components."},{"name":"--cora-content-editorial","value":"1100px","category":"layout","usage":"Current editorial and business-tool shell width."},{"name":"--cora-content-docs","value":"1440px","category":"layout","usage":"Current documentation shell width."},{"name":"--cora-content-workspace","value":"1280px","category":"layout","usage":"Operational content maximum from legacy token specification."},{"name":"--cora-content-reading","value":"720px","category":"layout","usage":"Recommended long-form prose width."},{"name":"--cora-control-height","value":"44px","category":"layout","usage":"Recommended minimum interactive target."},{"name":"--cora-drawer-width","value":"448px","category":"layout","usage":"Desktop panels only; mobile uses bottom sheet."},{"name":"--cora-z-menu","value":"40","category":"layer","usage":"Local menus within the feature stacking context."},{"name":"--cora-z-backdrop","value":"50","category":"layer","usage":"Local overlay backdrop."},{"name":"--cora-z-sheet","value":"60","category":"layer","usage":"Local sheet/dialog."},{"name":"--cora-z-toast","value":"70","category":"layer","usage":"Local feedback above sheets; bridge existing global z-index carefully."}],"themes":{"light":{"canvas":"#ffffff","bg":"#ffffff","surface":"#fafafa","selected":"#f4f4f5","border":"#e4e4e7","border-strong":"#71717a","text":"#09090b","muted":"#52525b","subtle":"#71717a","action":"#09090b","on-action":"#ffffff","action-hover":"#27272a","focus":"#52525b","success":"#166534","success-bg":"#f0fdf4","warning":"#854d0e","warning-bg":"#fefce8","danger":"#b91c1c","danger-bg":"#fef2f2"},"dark":{"canvas":"#09090b","bg":"#09090b","surface":"#18181b","selected":"#27272a","border":"#27272a","border-strong":"#71717a","text":"#fafafa","muted":"#d4d4d8","subtle":"#a1a1aa","action":"#fafafa","on-action":"#09090b","action-hover":"#e4e4e7","focus":"#a1a1aa","success":"#86efac","success-bg":"#14532d","warning":"#fde047","warning-bg":"#422006","danger":"#fca5a5","danger-bg":"#450a0a"}},"typography":[{"role":"Display","token":"--cora-text-display","weight":"600–700","lineHeight":"1.1","tracking":"-0.025em","usage":"Marketing hero; clamp to 32px on mobile; existing campaigns may use larger type."},{"role":"Page title","token":"--cora-text-h1","weight":"600–700","lineHeight":"1.2","tracking":"-0.02em","usage":"One h1 per page; operational headings may use 24px."},{"role":"Section title","token":"--cora-text-h2","weight":"600","lineHeight":"1.3","tracking":"-0.015em","usage":"Sections / sheet headings, semantic h2."},{"role":"Card title","token":"--cora-text-h3","weight":"600","lineHeight":"1.4","tracking":"-0.01em","usage":"Grouped content and card headings."},{"role":"Body","token":"--cora-text-body","weight":"400","lineHeight":"1.6","tracking":"-0.011em","usage":"Reading, forms on mobile; product dense rows use small (14px)."},{"role":"Small","token":"--cora-text-small","weight":"400–500","lineHeight":"1.5","tracking":"0","usage":"Supporting copy and product rows."},{"role":"Caption","token":"--cora-text-caption","weight":"400–500","lineHeight":"1.4","tracking":"0","usage":"Metadata; never essential input copy below 12px."},{"role":"Code","token":"--cora-text-code","weight":"400–500","lineHeight":"1.6","tracking":"0","usage":"Copyable code; horizontal scrolling confined to its own block."}],"principles":[{"id":"P01","title":"Quiet surfaces, clear hierarchy","detail":"Use Zinc, whitespace, typography and thin structural borders. No colored gradients, decorative emojis, heavy outlines or excessive shadows in operational UI."},{"id":"P02","title":"Meaning before decoration","detail":"Status color is reserved for success, warning and error. Always pair color with text or an icon. Brand artwork and editorial accents stay in their established marketing contexts."},{"id":"P03","title":"One source, two surfaces","detail":"Marketing and workspace share semantics and interaction principles while retaining their actual typography and canvas. Do not impose the marketing font on the product."},{"id":"P04","title":"Every state is a design decision","detail":"Specify default, hover, focus, selected, disabled, loading, empty, error and success before a feature is complete."},{"id":"P05","title":"Mobile is a first-class workflow","detail":"Use vertical sheets, explicit close controls, safe-area padding and reachable actions. Never force an off-canvas side drawer on a narrow screen."},{"id":"P06","title":"Preserve trust and privacy","detail":"Use fictional names and sample records in public examples. Do not expose owner names, credentials, internal account data or real customer information."}],"components":[{"id":"button","name":"Button","level":"Atom","implementation":"components/design-system/primitives.tsx → Button","rules":["Primary: solid monochrome; secondary: soft border; ghost: tonal hover; danger: text plus semantic surface.","44px minimum target; native button semantics; type=button unless submit is intentional.","Loading retains its label, disables repeat submissions and exposes aria-busy. Icon-only buttons need an accessible name."],"states":["default","hover","focus-visible","disabled","loading"],"status":"implemented"},{"id":"input","name":"Text field","level":"Atom","implementation":"components/design-system/primitives.tsx → TextField","rules":["Visible associated label, stable id, hint and error via aria-describedby.","Error uses aria-invalid and explanatory text. Do not use placeholder as label.","Mobile input text is 16px. Choose autocomplete, type and inputMode for the task."],"states":["default","focus-visible","disabled","error","required"],"status":"implemented"},{"id":"badge","name":"Status badge","level":"Atom","implementation":"components/design-system/primitives.tsx → Badge","rules":["Neutral is the default. Success, warning and danger only communicate state.","Include human-readable status; never rely on a colored dot alone."],"states":["neutral","success","warning","danger"],"status":"implemented"},{"id":"card","name":"Surface card","level":"Atom","implementation":"components/design-system/primitives.tsx → Card","rules":["Subtle one-pixel border, 16px radius, 24px padding.","A card is not clickable by default; put an explicit link or action inside."],"states":["default","selected (when selectable)","empty"],"status":"implemented"},{"id":"icons","name":"Iconography","level":"Foundation","implementation":"lucide-react in marketing / existing SVG product icons","rules":["Use SVG icons, typically 16/20/24px, consistent 1.8–2.2px stroke.","Decorative icons aria-hidden; icon actions need text equivalents. No emoji substitutions."],"states":["decorative","labelled"],"status":"existing-pattern"},{"id":"selection","name":"Checkbox / radio / switch","level":"Atom","implementation":"Existing feature controls; prefer native inputs","rules":["Label the input; preserve checked, disabled and keyboard behavior.","Use tonal filled selection and a check indicator; no heavy dark card border."],"states":["unchecked","checked","focus","disabled"],"status":"existing-pattern"},{"id":"tabs","name":"Tabs / segmented control","level":"Molecule","implementation":"Feature-local; no shared tab primitive yet","rules":["Use tabs only for same-page panels; use anchors for route navigation.","ARIA tablist/tab/tabpanel, selected state, roving focus and arrow keys required for custom tabs. Native radios are valid for settings."],"states":["selected","unselected","keyboard focus"],"status":"existing-pattern"},{"id":"select","name":"Select / combobox","level":"Atom","implementation":"Native select preferred; feature-local custom menus","rules":["Use native select for short lists. Custom searchable controls need full combobox keyboard behavior.","Mobile filters may open a bottom sheet. Maintain a visible label."],"states":["closed","open","selected","empty","disabled"],"status":"existing-pattern"},{"id":"toast","name":"Toast notification","level":"Molecule","implementation":"Marketing: components/ui/Toast.tsx; workspace: window.coraShowToast","rules":["Reuse the host notification API. No native alert, confirm or prompt.","Informational messages use role=status, urgent errors role=alert; actionable messages need a dismiss option.","Existing placement differs: marketing bottom center, workspace mobile top center / desktop bottom right. Do not create a third toast stack."],"states":["info","success","error","dismissed"],"status":"existing-pattern"},{"id":"sheet","name":"Sheet / dialog","level":"Organism","implementation":"components/design-system/primitives.tsx → Sheet; existing feature-local panels remain separate","rules":["Shared primitive: native dialog with modal focus containment, background inertness, Escape dismissal and focus return.","placement=sheet (default) preserves centred desktop geometry and bottom-sheet geometry at <=767px. placement=drawer is a right-edge full-height panel at >=1024px and a bottom sheet below 1024px. placement=modal remains centred at all widths.","Bottom sheets use a drag handle, 24px top corners, explicit close and safe-area inset. The handle is a visual affordance; dismiss with Close or Escape. All placements are modal; modeless inspectors retain their existing feature-local behavior.","Title is associated through aria-labelledby; protect unsaved work in the caller. Verify module backdrops before migration."],"states":["closed","open","submitting","validation error","unsaved"],"status":"implemented"},{"id":"table","name":"Data table","level":"Organism","implementation":"Workspace feature views / semantic HTML tables","rules":["Keep table headers, caption or accessible name and tabular numbers.","At narrow widths use labelled cards or a local scroll container; never clip actions.","Filters, sortable headers and pagination retain keyboard access and show empty/error states."],"states":["loading","populated","empty","filtered empty","error","selected"],"status":"existing-pattern"},{"id":"kanban","name":"Kanban board","level":"Organism","implementation":"Workspace CRM / lead views","rules":["Stages retain industry-aware labels. Provide non-drag move controls for keyboard and touch.","Confine horizontal board scroll; show stage counts and clear drop feedback."],"states":["empty stage","dragging","moved","save failure"],"status":"existing-pattern"},{"id":"stepper","name":"Guided workflow","level":"Molecule","implementation":"Document creation and signature flows","rules":["Existing contract sequence: Details → Terms → GST Math → E-Sign → Complete.","Use aria-current=step, validate before advancing, preserve entered values when going back.","On mobile show current step and progress without tiny overflowing labels."],"states":["current","completed","upcoming","blocked"],"status":"existing-pattern"},{"id":"upload","name":"File upload","level":"Molecule","implementation":"Media / vault / tools views","rules":["A dropzone includes a real labelled file input and keyboard alternative.","Show accepted types, size limit, progress, cancel, failure and retry. Never promise privacy beyond actual processing."],"states":["idle","drag-over","uploading","complete","rejected"],"status":"existing-pattern"},{"id":"dates","name":"Date / schedule controls","level":"Molecule","implementation":"Crew scheduler and booking views","rules":["Display timezone and local format explicitly. Native controls are preferred where practical.","Calendar grids need keyboard navigation, selected date labels and unavailable state."],"states":["available","selected","unavailable","invalid"],"status":"existing-pattern"},{"id":"empty","name":"Empty / error / skeleton","level":"Molecule","implementation":"Feature-local states","rules":["Distinguish no records, no filter matches, denied access and failed fetch.","Give one meaningful next action; use aria-busy for loading regions.","No artificial delays. Skeleton geometry matches final content; respect reduced motion."],"states":["loading","empty","error","retry"],"status":"existing-pattern"},{"id":"navigation","name":"Navigation shell","level":"Organism","implementation":"Marketing Navbar/Footer; workspace header/sidebar","rules":["Reuse the current shell and route-aware active states.","Workspace admin widget stays anchored at sidebar bottom with a profile popover.","Mobile navigation uses vertical sheet or in-flow menu; headings and skip links support keyboard navigation."],"states":["current","collapsed","expanded","mobile"],"status":"existing-pattern"},{"id":"search","name":"Search / filters","level":"Molecule","implementation":"Docs, tools and feature catalogs","rules":["Visible label, clear query, result count and useful no-results state.","Filters preserve query and communicate active state; URL state when sharable."],"states":["idle","results","no results","cleared"],"status":"existing-pattern"},{"id":"tooltip","name":"Tooltip / popover","level":"Molecule","implementation":"Feature-local contextual help","rules":["Help must be available on keyboard focus and touch, not hover alone.","Critical instructions belong in visible copy. Escape dismisses, focus remains stable."],"states":["closed","open","dismissed"],"status":"existing-pattern"},{"id":"hero","name":"Marketing hero","level":"Organism","implementation":"components/hero/Hero.tsx and page-specific heroes","rules":["One clear page promise, supporting copy and primary action.","Retain established artwork; stack copy and illustration on mobile.","Decorative imagery has empty alt text; informative imagery needs meaningful alt."],"states":["desktop","mobile","reduced motion"],"status":"existing-pattern"},{"id":"feature-grid","name":"Feature / industry grid","level":"Organism","implementation":"components/features and components/industry","rules":["Reuse domain data registry and existing card components.","One column on phone, two on tablet, three where readable; maintain heading order."],"states":["all","filtered","empty","detail"],"status":"existing-pattern"},{"id":"pricing","name":"Pricing / checkout","level":"Organism","implementation":"components/pricing/PricingSection.tsx and CheckoutSheet.tsx","rules":["Explain currency, billing period and limits in visible text.","Primary action remains monochrome; selected plan is tonal.","Payment sheets preserve loading/error states and mobile close behavior."],"states":["plan selected","billing switched","processing","failed","complete"],"status":"existing-pattern"},{"id":"editorial","name":"Docs / articles / guides","level":"Organism","implementation":"components/docs, components/blog, components/guides","rules":["Readable prose column, heading anchors, code overflow contained, mobile TOC.","Preserve current content schemas; provenance and updated dates remain visible."],"states":["reading","TOC open","searching"],"status":"existing-pattern"},{"id":"tool","name":"Micro-tool shell","level":"Organism","implementation":"components/tools/ToolPageShell.tsx; components/tools/framework/ToolContainer.tsx","rules":["Use the established shell for the tool family. Existing families differ; do not combine randomly.","Label every numeric input; show units, assumptions, rounding and result interpretation.","Primary calculation remains usable on mobile with output directly after input."],"states":["initial","valid result","invalid input","reset","export"],"status":"existing-pattern"},{"id":"ai","name":"AI input / execution feedback","level":"Organism","implementation":"components/hero/HeroAIInput.tsx and feature-local agent panels","rules":["Explain what an action will do, show processing state and allow cancellation when supported.","Never show simulated execution as a completed real action; expose recoverable errors.","Model and quota labels come from active configuration, not hardcoded historical models."],"states":["idle","composing","processing","result","failure"],"status":"existing-pattern"}],"catalogGuide":{"renderer":"cora-frontend/components/design-system/VisualCatalog.tsx","previews":"cora-frontend/components/design-system/CatalogPreviews.tsx","authority":"Each specimen links to existing component contracts by componentIds. Reuse the shared primitive API when status is shared-primitive. A reference-recipe demonstrates a composition, not a new shared component API or evidence of a completed legacy migration.","examples":"Examples are structural JSX fragments. Import Button, TextField, Card, Badge and Sheet from @/components/design-system/primitives when used. Caller variables and handlers are illustrative and must be implemented. Adapt behavior from the preview source and feature context; use semantic tokens for the feature stylesheet and verify its complete state matrix.","sources":"Catalog source paths resolve from the repository root. An existing pattern source establishes context; its legacy styles are not approved values to copy. Public samples use fictional records. File previews remain local demonstrations and do not perform an upload, payment, publication or destructive operation.","publishing":"The catalog lives on the existing /design-system route. JSON and plain text include the same records and version. Publish with the existing marketing site release; do not create a second project or duplicate registry."},"catalog":[{"id":"surface-card","category":"cards","name":"Surface card","status":"shared-primitive","componentIds":["card","badge"],"description":"The neutral container for related information, with clear hierarchy and an explicit inner action.","source":"cora-frontend/components/design-system/primitives.tsx","variants":["standard surface","tonal selection","compact content"],"states":["default","selected","empty","focus on inner action"],"usage":["Use Card as the common surface instead of redefining border, radius and padding.","Selection belongs to a labelled control and tonal fill. A div card is not a button.","Keep titles, supporting text and metadata in that order; use a link for navigation."],"example":"<Card><Badge>Draft</Badge><h3>Project overview</h3><p>Prepare the next delivery.</p><a href=\"/features/\">View features</a></Card>"},{"id":"feature-card","category":"cards","name":"Feature card","status":"reference-recipe","componentIds":["card","feature-grid","icons"],"description":"An icon, one concrete capability and supporting copy for a marketing feature or industry grid.","source":"cora-frontend/components/features/FeatureCards.tsx","variants":["icon and copy","capability list","visual feature"],"states":["default","link hover","focus-visible","grid stacked"],"usage":["Reuse the feature data registry and existing feature shell; preserve heading order.","Use a neutral icon tile for interface examples. Authentic brand artwork keeps its content colors.","Use one column on phones; add columns only while copy remains readable. Legacy colors in the source require scoped migration."],"example":"<Card><h3>Projects in one place</h3><p>Keep milestones, files and decisions together.</p><a href=\"/features/\">Explore features</a></Card>"},{"id":"project-card","category":"cards","name":"Project card","status":"reference-recipe","componentIds":["card","badge","button"],"description":"A workspace record with status, sample owner, due date, progress and an explicit details action.","source":"app/public/wp-content/plugins/cora-workspace/views/view-projects.php","variants":["active project","completed project","selected record"],"states":["default","selected","loading","empty","permission restricted"],"usage":["Keep selected-record context while opening details. Do not make a card with nested buttons a single clickable target.","Name progress with visible text and a labelled progress element; include the due date format.","Public examples use fictional owners. Actual industry terminology and permissions come from the host configuration."],"example":"<Card><Badge tone=\"success\">Active</Badge><h3>Studio refresh</h3><p>4 of 6 milestones complete</p><progress aria-label=\"Milestone completion\" value={4} max={6} /><Button variant=\"secondary\" onClick={openDetails}>View project</Button></Card>"},{"id":"metric-card","category":"cards","name":"Metric card","status":"reference-recipe","componentIds":["card","badge","table"],"description":"A labelled operational value with units, comparison period and an explanation of change.","source":"app/public/wp-content/plugins/cora-workspace/views/view-financials.php","variants":["count","currency","comparison"],"states":["populated","loading","no data","unavailable"],"usage":["Use tabular numbers and show currency or unit in visible copy.","Explain the comparison period and direction in text. A green number alone does not establish an improvement.","Never show unavailable data as zero; distinguish loading, no activity and fetch failure."],"example":"<Card><h3>Invoices paid</h3><p>₹48,000</p><p>Sample month · INR</p><Badge tone=\"success\">Up 8% from the previous month</Badge></Card>"},{"id":"pricing-card","category":"cards","name":"Pricing card","status":"reference-recipe","componentIds":["card","pricing","button","selection"],"description":"A sample plan with price, billing period, limits and a clear selection action.","source":"cora-frontend/components/pricing/PricingSection.tsx","variants":["monthly","annual","selected plan"],"states":["default","selected","billing switched","processing","failed"],"usage":["Catalog prices are fictional examples, never a replacement for active commercial plan configuration.","Display currency, billing period, tax treatment and limits before the action.","Selected plans use tonal fills and text indicators. Checkout uses the existing host flow."],"example":"<Card><h3>Sample plan</h3><p>₹999 / month · sample price</p><ul><li>5 sample projects</li></ul><Button onClick={selectPlan}>Choose sample plan</Button></Card>"},{"id":"blog-card","category":"cards","name":"Blog and article card","status":"reference-recipe","componentIds":["card","editorial","icons"],"description":"An editorial cover, topic, title, excerpt and reading metadata for a discoverable article.","source":"cora-frontend/components/blog/BlogArticleCard.tsx","variants":["article card","featured article","related guide"],"states":["default","image loading","image unavailable","link focus"],"usage":["Use the existing blog article schema and valid route. Keep published or updated dates accurate.","Use a 16:9 cover and meaningful alt text when it communicates article content; decorative covers use empty alt.","Prevent repeated links with ambiguous accessible names. This recipe documents structure while legacy editorial styles remain audited separately."],"example":"<Card><article><p>Guides · 5 min read</p><h3><a href=\"/blog/\">Planning a calmer workflow</a></h3><p>A sample article about keeping decisions visible.</p><p>Updated 13 October 2026</p></article></Card>"},{"id":"button-matrix","category":"controls","name":"Buttons and actions","status":"shared-primitive","componentIds":["button","icons"],"description":"Primary, secondary, ghost and destructive actions with loading, disabled and icon-label examples.","source":"cora-frontend/components/design-system/primitives.tsx","variants":["primary","secondary","ghost","danger","icon with label"],"states":["default","hover","focus-visible","disabled","loading"],"usage":["Use Button for actions and an anchor for navigation. Preserve the 44px target.","Loading disables repeated clicks while retaining a human-readable label and aria-busy.","Icon-only actions require an accessible name; decorative icons are hidden from assistive technology."],"example":"<><Button onClick={save}>Save changes</Button><Button variant=\"secondary\">Cancel</Button><Button variant=\"ghost\">More options</Button><Button variant=\"danger\">Remove sample</Button><Button loading>Saving changes</Button><Button disabled>Unavailable</Button></>"},{"id":"form-fields","category":"controls","name":"Form fields and validation","status":"shared-primitive","componentIds":["input","select","button"],"description":"Visible labels, supporting hints, required inputs, disabled controls and actionable field errors.","source":"cora-frontend/components/design-system/primitives.tsx","variants":["text","email","hint","required","error","disabled"],"states":["empty","entered","focus-visible","invalid","disabled"],"usage":["Use TextField so labels and description IDs stay associated. Placeholder text is never the label.","Choose input type, autocomplete and inputMode for the actual task; retain 16px text on mobile.","Preserve entered values on validation failure, identify the field and explain the correction."],"example":"<><TextField label=\"Project name\" hint=\"Visible to your team\" required /><TextField label=\"Email address\" type=\"email\" autoComplete=\"email\" error=\"Enter a complete email address.\" /><TextField label=\"Reference\" value=\"Assigned after creation\" disabled /></>"},{"id":"selection-controls","category":"controls","name":"Checkboxes, radios and switches","status":"reference-recipe","componentIds":["selection","select"],"description":"Native labelled selection for independent choices, exclusive options and a binary preference.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["checkbox","radio group","switch","native select"],"states":["unchecked","checked","focus-visible","disabled"],"usage":["Use native input behavior with visible labels and a fieldset legend for grouped choices.","Radio options in one group share a name. A switch exposes its checked state and a stable label.","Use tonal selection plus an indicator; do not introduce a heavy selected card outline."],"example":"<fieldset><legend>Delivery preference</legend><label><input type=\"radio\" name=\"delivery\" value=\"email\" defaultChecked /> Email</label><label><input type=\"radio\" name=\"delivery\" value=\"portal\" /> Client portal</label><label><input type=\"checkbox\" /> Include a summary</label></fieldset>"},{"id":"navigation-tabs","category":"controls","name":"Tabs and segmented navigation","status":"reference-recipe","componentIds":["tabs","navigation"],"description":"Same-page panels with selected state, matching panel relationships and keyboard navigation.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["panel tabs","segmented options"],"states":["selected","unselected","keyboard focus","panel visible"],"usage":["Use anchors for route navigation; tabs select same-page panels.","Implement roving tabindex, Arrow keys, Home and End with tablist/tab/tabpanel relationships.","Keep the active state tonal and readable. Use native radios when selecting a setting instead of switching content."],"example":"<><div role=\"tablist\" aria-label=\"Project views\"><button role=\"tab\" id=\"overview-tab\" aria-controls=\"overview-panel\" aria-selected={true}>Overview</button></div><section role=\"tabpanel\" id=\"overview-panel\" aria-labelledby=\"overview-tab\">Project overview</section></>"},{"id":"search-filter","category":"controls","name":"Search and filters","status":"reference-recipe","componentIds":["search","input","select","button"],"description":"A labelled query with clear action, result count and an explicit no-results response.","source":"cora-frontend/components/blog/BlogSearch.tsx","variants":["search input","category filter","clear query"],"states":["idle","results","no results","cleared"],"usage":["Name the collection being searched and announce changing result counts without moving focus.","Retain query when changing filters; use URL state for shareable views.","No results should offer Clear filters and distinguish absence from a service error."],"example":"<><TextField label=\"Search projects\" type=\"search\" value={query} onChange={e => setQuery(e.target.value)} /><Button variant=\"ghost\" onClick={() => setQuery('')}>Clear search</Button><p role=\"status\">{results.length} sample results</p></>"},{"id":"modal-dialog","category":"overlays","name":"Modal dialog","status":"shared-primitive","componentIds":["sheet","input","button"],"description":"A focused task with a labelled title, contained keyboard focus and explicit completion or cancellation.","source":"cora-frontend/components/design-system/primitives.tsx","variants":["centred modal","narrow-screen modal"],"states":["closed","open","submitting","validation error","dismissed"],"usage":["Reuse Sheet with placement=modal for a centred dialog at every width. The native dialog supplies background inertness and focus containment.","Escape and an explicit close action dismiss; return focus to the trigger.","Keep one clear task per modal and protect unsaved work in caller state. Use placement=sheet or drawer when mobile bottom-sheet geometry is appropriate."],"example":"<Sheet open={isOpen} onClose={() => setIsOpen(false)} placement=\"modal\" title=\"Create sample project\" footer={<Button onClick={createSample}>Create project</Button>}><TextField label=\"Project name\" required /></Sheet>"},{"id":"responsive-drawer","category":"overlays","name":"Drawer and mobile bottom sheet","status":"shared-primitive","componentIds":["sheet","card","button"],"description":"A contextual inspector positioned at the desktop edge and at the bottom of a narrow screen.","source":"cora-frontend/components/design-system/primitives.tsx","variants":["desktop side inspector","mobile bottom sheet"],"states":["closed","open","detail selected","unsaved","dismissed"],"usage":["Use Sheet placement=drawer for a full-height right-edge modal panel at >=1024px and a vertical bottom sheet below 1024px.","Preserve whether an existing feature inspector is modal or modeless. Do not silently replace a modeless inspector with this modal primitive.","The primitive supplies an associated title, explicit Close, Escape, focus containment/return and local scroll containment. Caller state preserves the selected record and protects unsaved changes."],"example":"<Sheet open={isOpen} onClose={() => setIsOpen(false)} placement=\"drawer\" title=\"Project details\"><p>Selected sample project</p></Sheet>"},{"id":"confirmation-dialog","category":"overlays","name":"Destructive confirmation","status":"reference-recipe","componentIds":["sheet","button"],"description":"A custom confirmation that identifies the affected sample record and the consequence of proceeding.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["remove record","discard changes"],"states":["closed","open","cancelled","confirming","failed"],"usage":["Use Sheet with clear consequence copy; never browser-native confirm or alert.","Offer a visible Cancel and a specifically labelled destructive action. Do not use an ambiguous Yes.","Preview confirmation updates fictional local state only. Production removal needs permission, pending state and recoverable failure."],"example":"<Sheet open={isConfirming} onClose={cancelRemoval} title=\"Remove sample project?\" footer={<><Button variant=\"secondary\" onClick={cancelRemoval}>Cancel</Button><Button variant=\"danger\" onClick={removeSample}>Remove sample project</Button></>}><p>The sample will disappear from this preview.</p></Sheet>"},{"id":"toast-feedback","category":"overlays","name":"Toast and inline feedback","status":"reference-recipe","componentIds":["toast","badge","button"],"description":"Status messages that announce a local outcome and offer an explicit dismissal or recovery action.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["informational","success","error","dismissible"],"states":["idle","visible","dismissed","retry available"],"usage":["Use the host notification API in real features. This inline reference does not create another global toast stack.","Use role=status for informational feedback and role=alert for urgent errors; do not move focus to routine messages.","Include text and a recovery action for failure; avoid relying on color or vanishing error messages."],"example":"<div role=\"status\"><p>Sample changes saved.</p><Button variant=\"ghost\" onClick={dismissMessage} aria-label=\"Dismiss saved message\">Dismiss</Button></div>"},{"id":"accordion","category":"content","name":"Accordion and disclosure","status":"reference-recipe","componentIds":["editorial","button"],"description":"Optional supporting information revealed through a named disclosure control.","source":"cora-frontend/components/blog/BlogFAQAccordion.tsx","variants":["single disclosure","FAQ group"],"states":["collapsed","expanded","keyboard focus"],"usage":["Prefer native details/summary when it suits the content; it supplies keyboard disclosure behavior.","Critical instructions and validation stay visible outside a collapsed disclosure.","For custom disclosure buttons associate aria-expanded and aria-controls; keep hidden content out of tab order."],"example":"<details><summary>How are project states used?</summary><p>Draft is editable; Ready for review awaits a decision; Complete records the final outcome.</p></details>"},{"id":"editorial-text","category":"content","name":"Typography and editorial structure","status":"reference-recipe","componentIds":["editorial","hero"],"description":"Readable headings, paragraph text, lists, quote, links and code inside a contained reading column.","source":"cora-frontend/components/blog/BlogBlockRenderer.tsx","variants":["article prose","documentation","inline code","quote"],"states":["reading","link focus","code overflow contained"],"usage":["Preserve General Sans in marketing and Inter in workspace; use the contract type roles.","Use sequential semantic headings and a reading width near --cora-content-reading. Long code scrolls locally.","Quotes need source context; publishing and updated dates remain visible when available."],"example":"<article><h2>Keep decisions visible</h2><p>A clear project record gives the team one place to find context.</p><ul><li>Define the outcome.</li><li>Assign the next action.</li></ul><blockquote><p>Write the decision beside the work.</p></blockquote><p>Use <code>--cora-text-body</code> for reading copy.</p></article>"},{"id":"empty-loading","category":"content","name":"Empty, loading and error states","status":"reference-recipe","componentIds":["empty","button","card"],"description":"Distinct treatments for a new collection, no filter matches, loading and a failed request.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["first use","filtered empty","loading skeleton","recoverable error"],"states":["loading","empty","error","retry","populated"],"usage":["First use offers one meaningful creation action; filtered empty offers Clear filters.","Use aria-busy on the loading region and a short status label; skeleton geometry matches the eventual content.","Failed requests show a recoverable explanation and Retry. Never simulate a successful service response."],"example":"<Card><h3>No projects yet</h3><p>Create a project to keep the next delivery organised.</p><Button onClick={openCreate}>Create sample project</Button></Card>"},{"id":"data-table","category":"data","name":"Data table","status":"reference-recipe","componentIds":["table","badge","button"],"description":"A semantic sample records table with clear column headers, statuses and explicit row actions.","source":"app/public/wp-content/plugins/cora-workspace/views/view-leads.php","variants":["records table","filtered table","mobile contained scroll"],"states":["populated","loading","empty","filtered empty","error","row action focus"],"usage":["Keep table caption, scope=col headers and text status labels; numeric data uses tabular figures.","On mobile keep wide tables inside a named local scroll region or provide labelled cards. Page overflow is forbidden.","Sorting, filters and pagination must remain keyboard accessible and reflect visible result counts."],"example":"<table><caption>Sample projects</caption><thead><tr><th scope=\"col\">Project</th><th scope=\"col\">Status</th></tr></thead><tbody><tr><th scope=\"row\">Studio refresh</th><td><Badge tone=\"success\">Active</Badge></td></tr></tbody></table>"},{"id":"kanban-board","category":"data","name":"Kanban board","status":"reference-recipe","componentIds":["kanban","card","select"],"description":"A stage-based sample board with counts and a non-drag way to move records.","source":"app/public/wp-content/plugins/cora-workspace/views/view-leads.php","variants":["stage columns","empty stage","keyboard move"],"states":["populated","empty stage","moving","moved","save failure"],"usage":["Resolve stage names from the active industry. Catalog stage labels are illustrative.","Provide a labelled move select or buttons for keyboard and touch; drag is optional.","Announce the new stage and preserve context. Constrain horizontal board scrolling to its region."],"example":"<section aria-label=\"Sample pipeline\"><h3>In progress · 1</h3><Card><h4>Studio refresh</h4><label>Move sample to<select value={stage} onChange={e => moveSample(e.target.value)}><option>Planned</option><option>In progress</option><option>Complete</option></select></label></Card></section>"},{"id":"workflow-stepper","category":"data","name":"Workflow stepper","status":"reference-recipe","componentIds":["stepper","button","input"],"description":"A guided workflow showing completed, current and upcoming steps with reachable next/back actions.","source":"app/public/wp-content/plugins/cora-workspace/views/view-vault.php","variants":["full sequence","mobile current step","blocked progression"],"states":["current","completed","upcoming","blocked"],"usage":["Use the documented document flow when building documents: Details → Terms → GST Math → E-Sign → Complete.","Set aria-current=step on the current item, validate before moving forward and preserve values when going back.","At narrow widths keep a readable current-step label and avoid tiny overflowing labels."],"example":"<nav aria-label=\"Document creation progress\"><ol><li aria-current=\"step\">Details</li><li>Terms</li><li>GST Math</li><li>E-Sign</li><li>Complete</li></ol></nav>"},{"id":"image-treatment","category":"media","name":"Images and avatars","status":"reference-recipe","componentIds":["hero","card","icons"],"description":"Editorial 16:9, gallery 4:3 and square/avatar image frames with captions and fallback treatment.","source":"app/public/wp-content/plugins/cora-workspace/views/view-media.php","variants":["16:9 editorial cover","4:3 gallery image","1:1 square image","avatar and initials"],"states":["loaded","loading","unavailable","selected"],"usage":["Image content preserves its original colors; interface borders and surrounding controls use semantic tokens.","Choose object-fit intentionally. Do not crop essential faces, document text or meaning; image captions retain attribution where needed.","Informative images need meaningful alt; decorative images use empty alt. Avatar labels identify the fictional sample user and provide initials fallback."],"example":"<figure><img src={sampleCoverSrc} alt=\"Illustrated sample project workspace\" width={640} height={360} /><figcaption>Sample editorial cover · 16:9</figcaption></figure>"},{"id":"file-upload","category":"media","name":"File upload","status":"reference-recipe","componentIds":["upload","input","button"],"description":"A labelled real file control with limits, local validation and explicit file-selection feedback.","source":"cora-frontend/components/design-system/CatalogPreviews.tsx","variants":["file picker","dropzone","file summary","rejected file"],"states":["idle","selected","drag-over","uploading","complete","rejected"],"usage":["The catalog selection demo validates file metadata locally and does not send a file to a server.","Show supported type and size limit in visible copy. Keep a keyboard-accessible real file input even if drag and drop is added.","Production upload must implement progress, cancellation, server validation, failure and retry. Never claim a local selection is an upload success."],"example":"<><label htmlFor=\"sample-file\">Choose sample image</label><input id=\"sample-file\" type=\"file\" accept=\"image/png,image/jpeg\" aria-describedby=\"sample-file-hint\" onChange={validateSampleFile} /><p id=\"sample-file-hint\">PNG or JPEG. Maximum 5 MB. Local preview only.</p></>"},{"id":"icon-library","category":"media","name":"Icons and meaningful labels","status":"reference-recipe","componentIds":["icons","button"],"description":"Consistent SVG glyphs for navigation, actions, files, media and status, paired with accessible names.","source":"cora-frontend/components/features/FeatureIcon.tsx","variants":["16px inline","20px control","24px tile","icon with label","icon-only action"],"states":["decorative","labelled","focus-visible","disabled"],"usage":["Use lucide-react or existing product SVGs; typically 16/20/24px with 1.8–2.2px stroke. Do not substitute emojis.","Keep decorative icons aria-hidden and name the containing action in human language.","Icon-only buttons need aria-label or visible accessible text. Status icons still require a readable state label."],"example":"<Button variant=\"secondary\" aria-label=\"Open project files\"><svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\"><path d=\"M3 7h6l2 2h10v11H3z\" /></svg></Button>"}],"responsive":[{"range":"< 640px","rule":"Phone: one-column forms and cards, 16px outer gutter, 44px targets, 16px input text, bottom sheets; local table/code overflow only."},{"range":"640–767px","rule":"Large phone / small tablet: grow gutters to 24px when space permits; do not assume desktop panel behavior."},{"range":"768–1023px","rule":"Tablet: two-column content where readable. Existing workspace sheets use <=1023px; preserve the module breakpoint."},{"range":">= 1024px","rule":"Desktop: persistent in-flow navigation, 24–32px gutters and content max width. Desktop panels only where the feature supports them."},{"range":"Zoom / safe area","rule":"Reflow at 320px and 200% zoom. Respect env(safe-area-inset-bottom). Never disable pinch zoom or hide essential overflow."}],"accessibility":["Normal text contrast at least 4.5:1; large text 3:1; necessary control boundaries / focus indicators 3:1. Verify each actual pairing, including dark mode.","Keyboard focus must remain clearly visible. A subtle focus outline is required even though heavy decorative outlines are forbidden.","Use semantic landmarks, sequential headings, associated labels, native controls and an accessible name for every icon action.","Announce asynchronous status without moving focus. Errors identify the field and explain how to recover.","Modal focus is contained and restored; Escape and an explicit close work. Never place hidden panels in the tab order.","Respect prefers-reduced-motion, browser zoom and touch input. No automatic marquee or smooth scrolling for reduced-motion users.","Status is conveyed by label or icon plus color. Do not use muted opacity for essential text."],"contentRules":["Use clear task language: Save changes, Create invoice, Move lead. Avoid technical infrastructure terms in customer workflows.","Use fictional sample identities and no real owner or customer data in public UI or fixtures.","Workspace labels resolve from active industry: equipment/property listings, shoots/showings, client/buyer leads. Do not hardcode industry names in shared views.","Show currency, tax assumptions, dates and timezone explicitly. Keep identifiers and financial numbers tabular.","Destructive actions explain the affected record and recovery limits; use custom confirmation surfaces."],"deviations":[{"id":"D01","scope":"Legacy token files","observed":"Root cora-design-tokens.js and frontend lib/cora-tokens.ts duplicate values and are not the executable source for current styling.","decision":"Historical references only. New UI consumes this contract and primitives; migrate a feature when touching it.","status":"migration-required","sources":["cora-design-tokens.js","cora-frontend/lib/cora-tokens.ts","cora-design-system.html"]},{"id":"D02","scope":"Typography","observed":"Old tokens and brand page specify Inter; marketing runtime loads General Sans.","decision":"Preserve General Sans on marketing and Inter in workspace. Reconcile brand documentation in a separate scoped edit.","status":"documented-exception","sources":["cora-frontend/styles/globals.css","cora-frontend/components/brand/BrandTypographySection.tsx"]},{"id":"D03","scope":"Color","observed":"Legacy WordPress Tailwind palette includes gold/bronze; status shades differ between brand and token files.","decision":"Zinc remains the inherited UI baseline. New status text tokens use darker legible colors; no gold action theme.","status":"migration-required","sources":["app/public/wp-content/plugins/cora-workspace/tailwind.config.js","cora-frontend/components/brand/BrandColorsSection.tsx"]},{"id":"D04","scope":"Mobile panels","observed":"Legacy tokens permit sliding drawers; workspace instructions require bottom sheets. CSS has overlapping 641px/1023px panel ranges.","decision":"Mobile vertical sheets take precedence. Audit the feature breakpoint and focus behavior before modifying a legacy panel.","status":"migration-required","sources":[".agents/AGENTS.md","app/public/wp-content/plugins/cora-workspace/assets/css/admin-style.css"]},{"id":"D05","scope":"Overlay backdrop","observed":"Workspace guidance calls for blurred dark backdrop; some runtime CSS makes backdrops transparent.","decision":"The dark backdrop token is recommended for new modal patterns. Preserve and investigate existing module overrides when migrating.","status":"documented-exception","sources":["app/public/wp-content/plugins/cora-workspace/assets/css/admin-style.css"]},{"id":"D06","scope":"Feedback","observed":"Marketing and workspace toast locations and z-index stacks differ.","decision":"Reuse host API and placement. The local layer scale applies to new isolated components, not a global z-index rewrite.","status":"documented-exception","sources":["cora-frontend/components/ui/Toast.tsx","app/public/wp-content/plugins/cora-workspace/assets/js/admin-script.js"]},{"id":"D07","scope":"Accessibility","observed":"Existing outline bans and animations can conflict with keyboard focus and reduced-motion needs.","decision":"Visible focus and reduced motion take precedence. New primitives implement focus and motion behavior; audit existing features on touch.","status":"migration-required","sources":[".agents/AGENTS.md","cora-frontend/components/providers/SmoothScrollProvider.tsx"]}],"verification":["Source contract and all machine exports stay synchronized.","No undocumented color/font literals in new design-system UI.","Button loading, field errors, theme contrast and search work with keyboard.","Inspect 390px and 1440px layouts and ensure no page-level horizontal overflow.","Confirm /docs, /tools and marketing homepage still render with unchanged host styles.","Build static export and confirm manifest.json, llms.txt and tokens.css exist in out/design-system."]}