# Komi Web Design System

Canonical design contract for humans and coding agents working on `komi-web`.

- Human reference: `https://komi-app.fr/design-system`
- Machine-readable reference: `https://komi-app.fr/design-system.md`
- Runtime proof: the existing components and scoped styles in `src/`

If this document and the running product disagree, inspect the owning surface before changing anything. Preserve working behavior, resolve the inconsistency in the smallest shared place, and update this document in the same change.

## 1. Operating contract for AI agents

Before editing a frontend surface:

1. Identify its visual scope from the table below.
2. Inspect the existing component, its callers, and the owning stylesheet.
3. Reuse an existing token, component, icon, and interaction pattern.
4. Keep business behavior, routing, permissions, analytics, and accessibility intact.
5. Implement the smallest coherent change.
6. Verify keyboard use, responsive behavior, reduced motion, type checking, tests, and production build.

Never:

- invent a new color when a semantic token already exists;
- copy a token value as a hexadecimal color into a component;
- move styles across scopes just to make one page easier to patch;
- add a component library or animation dependency for a local need;
- use color alone to communicate state;
- hide a missing action behind an inert call to action;
- claim a page is complete without checking its real rendered state.

Priority order when rules compete:

1. Correct behavior and accessible use.
2. Existing product contract and shared component behavior.
3. The rules in this document.
4. Local visual expression.

## 2. Brand principles

Komi should feel trustworthy without becoming cold, and lively without becoming noisy.

- Understand before impressing: hierarchy makes the next action obvious.
- Depth explains structure: shadows and materials indicate a real functional level.
- Accessibility is part of the first version, not a finishing pass.
- Personality stays controlled: coral, Unbounded, and fluid motion already sign the brand.
- If an element clarifies neither content, action, nor hierarchy, remove it.

## 3. Scope ownership

Do not treat the repository as one global visual surface.

| Scope | Surface | Primary source | Contract |
| --- | --- | --- | --- |
| `.km-site` | Public marketing site | `src/app/marketing.css` | Warm palette, editorial expression, Plus Jakarta Sans body copy |
| `.kr-site` | Public resources | `src/app/resources.css` | Long-form reading, search, editorial content |
| `.admin-shell` | Campus cockpit | `src/app/admin.css` | Dense decisions, lists, forms, and operational actions |
| `:root` | Member web application | `src/app/globals.css` | Functional tokens, light and dark themes, product components |
| `.km-design-system` | Design reference | `src/app/design-system.css` | Documentation specimens using the public Komi tokens |

Rules shared by every scope may be promoted only when they have at least three coherent uses or when a real cross-surface contract requires them. Otherwise keep them local.

## 4. Public color tokens

Use these variables inside `.km-site`. Select color by role, not preference.

| Token | Value | Use |
| --- | --- | --- |
| `--km-coral` | `#ff765d` | Expressive accent, illustration, and large decorative details |
| `--km-coral-deep` | `#c43d38` | Actions, links, focus details, and small foreground elements on light surfaces |
| `--km-coral-dark` | `#c43d38` | Compatibility alias for deep coral |
| `--km-orange` | `#ff9a57` | Secondary warmth and narrative accents |
| `--km-pink` | `#ff68a5` | Occasional secondary accent |
| `--km-rose` | `#ffd7df` | Soft surface and selection |
| `--km-cream` | `#fff8f2` | Main editorial background |
| `--km-sand` | `#f2e8df` | Media background and secondary region |
| `--km-white` | `#fffdfb` | Elevated surface and calm background |
| `--km-ink` | `#211e27` | Primary text and dark controls |
| `--km-dark` | `#17131c` | High-contrast surface and footer |
| `--km-night-soft` | `#2b222d` | Secondary dark surface |
| `--km-muted` | `#6e6670` | Secondary text on light surfaces |
| `--km-line` | `rgba(33, 30, 39, .11)` | Subtle boundary on light surfaces |
| `--km-line-light` | `rgba(255, 255, 255, .16)` | Subtle boundary on dark surfaces |

Contrast requirements:

- Use `--km-coral-deep` with light text for compact actions. White on deep coral measures approximately `5.08:1`.
- Do not use `--km-coral` for small text on white. Coral on warm white measures approximately `2.59:1`.
- Body text and control labels require at least `4.5:1`.
- Large text and meaningful component boundaries require at least `3:1`.
- Never lower meaningful foreground contrast through opacity.

## 5. Typography

### Unbounded

Use for identity-bearing headings, H1, H2, and deliberate brand moments.

- Weight: `650` to `720`.
- Heading letter spacing: `-0.018em` to `-0.038em`.
- A hero heading should normally stay within two lines on its intended viewport.
- Keep headings concise: 8 words recommended, 12 maximum.

### Plus Jakarta Sans

Use for public navigation, forms, marketing copy, and supporting UI text.

- Body size: `16px` to `19px`.
- Line height: `1.55` to `1.7`.
- Reading width: approximately `65` to `75` characters.

### Albert Sans

Use on the existing member application and cockpit surfaces where it is already the product typeface.

- Prefer useful density.
- Establish hierarchy with weight before increasing size.
- Do not migrate a product surface to a marketing font during an unrelated change.

Small text is `12px` minimum. Use at least `13px` when the information affects a decision or action.

## 6. Layout and spacing

- Public content container: `min(1240px, calc(100% - 48px))`.
- Desktop section spacing: `88px` to `148px`.
- Mobile section spacing: `68px` to `82px`.
- Desktop gutter: at least `24px`.
- Mobile gutter: at least `16px`.
- Align related content to a shared grid.
- Leave more space before a heading than after it.
- Use asymmetry only when it improves reading order or emphasis.
- Avoid repeated identical cards when an open list communicates the structure better.

Spacing values should come from the surrounding composition. Do not add an isolated value without a measurable layout reason.

## 7. Shape, elevation, and materials

| Token | Value | Use |
| --- | --- | --- |
| `--km-radius-sm` | `14px` | Inputs, controls, compact surfaces |
| `--km-radius` | `24px` | Functional cards and primary panels |
| `--km-radius-lg` | `36px` | Media and major editorial surfaces |
| `--km-shadow` | Existing CSS token | Default elevated surface |
| `--km-shadow-hover` | Existing CSS token | Interactive elevation change |
| `--km-page-shadow` | Existing CSS token | Major page-like surface |

Use pill shapes only for badges, filters, and compact actions. Do not make every container a rounded card. A boundary must explain grouping, interaction, or hierarchy.

## 8. Components

### Buttons and links

- Allow one primary action per visual region.
- Start labels with a clear verb and keep them on one line.
- Reuse `km-button`, `km-button-primary`, `km-button-outline`, and `km-button-light` on public pages.
- Use a link for navigation and a button for an in-place action.
- Interactive targets must measure at least `44px` on the touch axis.
- Provide visible rest, hover, focus, active, disabled, loading, success, and error states when applicable.
- If no action is available, show one concise reason and omit the inert call to action.

### Forms

- Keep the label visible.
- A placeholder never replaces a label.
- Place help before error feedback in the reading order.
- Put errors close to the affected field and explain how to recover.
- Preserve entered data after a recoverable error.
- Use native controls unless a real product requirement exceeds them.

### Informative surfaces

- A card must represent a meaningful group, level, or interaction.
- Prefer one information hierarchy: title, supporting detail, state, then next action.
- Do not decorate a card with icons, badges, or shadows that add no meaning.
- Empty and unavailable states must explain the real condition without implying success.

### Icons

- Reuse the installed `lucide-react` family.
- Use icons to improve recognition, not to replace essential labels.
- Decorative icons use `aria-hidden="true"`.
- Icon-only controls require an accessible name.

## 9. Motion

Motion confirms a relationship, state change, or consequence of an action.

- Entry: begin from a visibly related position and last about `180ms` to `400ms`.
- Interaction: respond immediately to pointer or keyboard input.
- Exit: follow the entry path in reverse and remain interruptible.
- Prefer `transform` and `opacity` for animation.
- Use `--km-ease-spring` for direct controls and `--km-ease-fluid` for composed transitions.
- Avoid decorative autoplay loops, exaggerated bounce, scroll hijacking, and delayed feedback.
- Under `prefers-reduced-motion: reduce`, remove translation and parallax. Preserve meaning with an instant state change or a short fade.

## 10. Responsive behavior

- Design from the content hierarchy, not from a fixed device mockup.
- Verify at `320px` width, common mobile widths, tablet, and desktop.
- Reflow before shrinking text below the minimum sizes.
- Horizontal scrolling is acceptable only for content whose structure requires it, such as a wide data table or explicit tab rail.
- Sticky elements must not cover the focused element or anchor target.
- Reserve media dimensions to prevent layout shift.
- At `200%` browser zoom, no information or action may be lost.

## 11. Accessibility

Every shipped interface must support:

- one H1 and a heading hierarchy without skipped levels;
- semantic landmarks and controls;
- keyboard access in a logical DOM order;
- a visible focus state on every interactive element;
- accessible names for controls and meaningful images;
- text alternatives that describe purpose, or an empty `alt` for decoration;
- status communicated with text rather than color alone;
- minimum contrast ratios from the color section;
- `44px` touch targets;
- reduced-motion behavior;
- comfortable use at `200%` zoom and `320px` width.

Do not add ARIA when native HTML already provides the correct role and behavior.

## 12. Content and interface writing

- Write in direct, plain language.
- State the real condition instead of reassuring without evidence.
- Prefer specific verbs: `Publier`, `Réessayer`, `Télécharger`, `Inviter`.
- Keep labels stable across pages when they trigger the same behavior.
- Error messages explain what happened and the next safe action.
- Do not use internal implementation vocabulary in public UI.
- Never invent demand, availability, price, success, or confidence.

## 13. Implementation workflow

For each frontend change:

1. Read this file and identify the owning scope.
2. Trace the complete user flow and inspect existing shared patterns.
3. List the states that can actually occur.
4. Reuse existing tokens and components.
5. Implement the smallest root-level change that serves all relevant callers.
6. Add one direct regression check for non-trivial behavior.
7. Verify the rendered page on mobile and desktop.
8. Run the relevant tests, `npm run typecheck`, and `npm run build`.
9. Report local validation, deployment, and publication as separate states.

## 14. Definition of done

A page is ready only when:

- its hierarchy and next action are immediately understandable;
- all realistic states are represented honestly;
- existing tokens and shared components are reused;
- every interactive state is present and keyboard accessible;
- the page works at `320px`, at `200%` zoom, and with reduced motion;
- images reserve their size and have correct alternatives;
- no duplicate token, component, or source of truth was introduced;
- tests, type checking, and production build pass;
- the real rendered surface has been inspected.

## 15. Governance

- Reuse first: search for an existing token, component, and pattern.
- Keep local: one-use geometry stays with its component.
- Promote carefully: create a token after three coherent uses or a demonstrated cross-surface contract.
- Remove duplicates in the same change.
- Document an exception before expanding the system around it.
- Update this contract whenever a deliberate design-system decision changes.


## 16. Retired partnerships

The former enterprise and partnership surfaces are removed. Legacy URLs return HTTP 410 with a clear withdrawal message and an accessible link to Komi. No active navigation, API or data dependency points to this domain. General campus showcases remain part of Komi.
