# Scroll Containment Utility

## Objective

Stop the page scrolling behind an overlay without shifting the layout underneath.

A shared utility that locks background scrolling while an overlay is open and releases it cleanly when the overlay closes.

## 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 surface that currently locks or unlocks page scrolling on its own — modals, drawers, menus, mobile navigation, image viewers — and route all of them through one utility instead of each toggling styles directly.
2. Reserve the width the scrollbar occupied when scrolling is locked, so the page behind does not widen by the scrollbar's width and visibly shift at the moment the overlay appears.
3. Keep a count of active locks rather than a boolean. Closing one of two stacked overlays must not release the lock while the other is still open.
4. Record the exact styles and scroll offset in place before locking, and restore precisely those values on release rather than resetting to a hardcoded default.
5. Do not lock scrolling by fixing the document to the viewport as a first resort. On touch devices it discards the scroll position and snaps the user back to the top when the overlay closes; if you use that approach, capture and restore the offset explicitly.

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

- Locking scroll usually removes the scrollbar, and the page reflows into the reclaimed width. Compensate for that width on the document and on any fixed-position elements, or the whole layout jumps sideways each time an overlay opens.
- Touch scrolling on iOS ignores an overflow lock on the document and continues to scroll the page behind the overlay. Handle that platform explicitly rather than assuming an overflow rule is enough.
- Two or more overlays can be open at once — a dialog that opens a confirmation, a drawer containing a menu. Reference-count the locks so the last one to close is the one that releases.
- The utility must restore the original inline styles, overflow values, and scroll offset it found, not the values it assumed were there. Another feature may have set them first.
- A scroll container inside the overlay must remain scrollable while the background is locked, and reaching its end must not chain the scroll onto the page behind it.
- An overlay that unmounts abruptly — a route change, an error boundary, a hot reload in development — must still release the lock, or the app is left permanently unscrollable.
- Users who never see a scrollbar, because the pointer is a touchscreen or the platform overlays its scrollbars, must gain no compensating padding at all.

## 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 overlay in the app locks background scrolling through the same shared utility.
- [ ] Opening and closing an overlay causes no horizontal shift in the page behind it.
- [ ] Background scrolling is genuinely prevented on touch devices, not only with a mouse.
- [ ] Nested and simultaneous overlays release the lock only when the last one closes.
- [ ] Scroll position and the original styles are exactly as they were before the overlay opened.
- [ ] Scrollable regions inside an overlay still scroll, and do not chain to the page beneath.
- [ ] 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.
