# Border System

## Objective

Give borders defined jobs so structure, focus, and selection never look the same.

A set of border tokens covering structural dividers, interactive outlines, focus rings, selection, and error emphasis.

## 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. Audit every border in the app and sort it into one of a few jobs: separating content, outlining a control, marking focus, marking selection, or signalling an error. Anything that does not fit a job is decoration that should be removed rather than tokenised.
2. Keep structural borders and interactive borders visually distinct. A divider between table rows and the outline of a text input should not share a colour, or users will read inert content as clickable.
3. Define focus separately from selection and from hover. Focus follows the keyboard, selection follows intent, and a control that is both focused and selected must show both without one hiding the other.
4. Give the dark theme its own border values. A border that reads as a subtle grey on white becomes invisible on a near-black surface, and raising its opacity is not the same as picking the right colour.
5. Do not use a border token to imply elevation or stacking order. Boundaries are this feature's job, elevation belongs to Shadow Scale, and paint order belongs to Elevation Layer Map.

## 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

- Decorative dividers and interactive outlines must remain separable at a glance, otherwise a non-clickable panel edge is mistaken for a control and a real control loses its affordance.
- Subtle borders that work on a light background disappear on dark surfaces, so each token needs a dark-theme value chosen against the actual surface it will sit on, not derived by inverting the light one.
- Nesting a bordered component inside a bordered container produces a doubled two-pixel line at the shared edge. Decide which layer owns the boundary and have the inner element drop its border or collapse into the outer one.
- Hairline borders at high device pixel ratios round unpredictably and can render at zero width on some rows and full width on others, producing a striped table. Use a technique that survives fractional scaling rather than a fixed sub-pixel value.
- Focus rings must not be clipped by an ancestor that hides overflow, and must retain contrast against both the component and the page behind it.
- A border used to signal an error must not be the only signal, because colour alone fails for users who cannot distinguish it and for forced-colours mode.
- Rounded corners share the border radius scale, so a token change that alters width without accounting for radius will leave visible gaps at the corners of nested elements.

## 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 border in the app resolves to a token with a named job.
- [ ] Structural, interactive, focus, selection, and error borders are visually distinct from one another.
- [ ] Each token has a dark-theme value verified against the surface it appears on.
- [ ] No nested component renders a doubled border at a shared edge.
- [ ] Hairline borders render at consistent width across device pixel ratios.
- [ ] Focus rings are visible on every interactive element and are never clipped by an ancestor.
- [ ] 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.
