# Class Merge Helper

## Objective

Combine conditional classes in one place so the last one written actually wins.

A single helper every component uses to resolve base, conditional, and caller-supplied classes into one final list.

## Before You Begin

This feature is being added to an application that already exists and already
works. Do not scaffold a new project, and do not assume a blank slate.

Inspect the codebase first and establish:

- The existing application structure and where code of this kind already lives.
- The framework and version in use.
- The existing design system — colours, spacing, typography, and component conventions.
- Existing UI components you can reuse instead of writing new ones.
- The existing database structure, if this feature needs to persist anything.
- The existing authentication and authorization system, if this feature is user-scoped.
- Dependencies already installed, so you don't add a library that duplicates one.
- The existing test setup and conventions.

Only start writing code once you understand the above. If the application
already implements part of this feature, extend it rather than replacing it.

## Implementation Instructions

1. Find every component that currently builds a class string by hand and route all of them through one helper, so the resolution rules are identical everywhere.
2. Define the precedence plainly: the component's own base classes lose to its variant classes, and both lose to whatever the caller passed in. A caller that supplies a class expects it to take effect.
3. Accept the shapes calling code actually produces rather than forcing every call site to normalise first, and make the behaviour for absent and empty values explicit rather than incidental.
4. Detect and collapse conflicting utilities that set the same property, keeping the last one, so a caller adjusting one aspect of a component does not have to fight a base class that is still present.
5. Do not let this helper decide policy. Which utilities are permitted and when a pattern should be extracted belong to Utility Class Conventions; this helper only resolves what it is given.

## UI and UX Requirements

Match the application's existing design system exactly. Reuse its components,
spacing, and typography. This feature should look like it was always there.

## Responsive Requirements

Works on mobile, tablet, and desktop. Touch targets are large enough to hit on a
phone, and nothing overflows horizontally at 320px.

## Accessibility Requirements

- Fully keyboard navigable.
- Correct semantic elements and ARIA roles.
- Visible focus states.
- Meets WCAG AA contrast.
- Dynamic changes are announced to screen readers.
- Respects prefers-reduced-motion.

## Edge Cases

- A caller passing a class to change one property must win over the component's own class for that property. If the base class survives, the override silently does nothing and the caller will reach for importance flags instead.
- Values arriving as lists, as objects keyed by condition, and as absent or empty entries must all be handled without special-casing at the call site, and must never contribute stray separators or empty entries to the output.
- Conflicts between classes belonging to different systems — a utility framework class against a hand-written or component class targeting the same property — cannot be resolved by name matching alone. Define the resolution rule and state its limits.
- An invalid or misspelled class name must survive to the output unchanged rather than being quietly dropped, because a helper that swallows typos turns a visible styling bug into an invisible one.
- The helper runs on every render of every component, so its cost is multiplied by the size of the tree and must stay proportionate to the classes it is given.
- Ordering must be stable: the same inputs must produce the same output string every time, or server-rendered and client-rendered markup will disagree.

## Testing

Exercise the feature end to end in the running application. Cover every edge case
above, then run the existing test suite and confirm nothing regressed.

## Acceptance Criteria

- [ ] Every component composes classes through the single helper, with no hand-built class strings remaining.
- [ ] Caller-supplied classes reliably override the component's own classes for the same property.
- [ ] Lists, condition maps, and absent values are all accepted and produce no empty or duplicated entries.
- [ ] Conflicting utilities setting the same property collapse to the last one given.
- [ ] Unrecognised class names pass through unchanged.
- [ ] The same inputs always produce the same output string.
- [ ] The feature matches the existing design system.
- [ ] No existing functionality is broken.

## Adaptation Rules

- Match the existing design system. Do not introduce a new colour palette,
  spacing scale, or component library.
- Reuse existing components and utilities wherever they fit.
- Follow the naming, file layout, and code style already present.
- Do not upgrade, replace, or remove existing dependencies to make this
  feature fit. Adapt the feature to the app, not the app to the feature.
- Do not break existing functionality. If a change is genuinely required in
  existing code, make the smallest one that works and say so.
- If something in these instructions conflicts with how the application is
  built, follow the application and explain the deviation.

## Final Verification

Before you report the work as done:

1. Re-read the acceptance criteria above and check each one against what you
   actually built.
2. Run the application and exercise the feature end to end.
3. Run the existing test suite and confirm you have broken nothing.
4. Check the feature on mobile, tablet, and desktop widths.
5. Check keyboard navigation and focus handling.
6. Summarize what changed: files added, files modified, and anything you
   deliberately did differently because of how this application is built.

If any acceptance criterion is unmet, fix it before reporting completion.
