# Viewport Height Utility

## Objective

Stop full-height screens from jumping or hiding their controls on mobile browsers.

A single shared height primitive that resolves to the real usable viewport on every device and browser mode.

## 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 place the app assumes the viewport is a fixed height — full-bleed heroes, sidebars, drawers, editor shells, scroll containers with a hard height — and route them all through one shared height primitive rather than repeating the same measurement in a dozen components.
2. Distinguish the three heights that matter and pick deliberately per surface: the smallest height the viewport takes when browser chrome is fully expanded, the largest when it is retracted, and the height right now. A fixed sidebar wants the small height so its footer is never cut off; a decorative hero can take the large height.
3. Always pair the viewport height with a content minimum. A panel that collapses to the height of a short phone in landscape must still be tall enough to show its own controls, and must scroll rather than crush its contents.
4. Verify the behaviour in a normal browser tab, in a home-screen installed session with no browser chrome at all, and in landscape, because each resolves the same declaration to a different number and only one of them is usually tested.
5. Do not measure the window in script and write a pixel height on resize. That approach fires late, flashes the wrong height on first paint, fights browser chrome that animates in and out during a scroll, and has to be re-run for every orientation and keyboard event.

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

- Mobile browsers change their visible height as the address bar retracts and expands during a scroll, so a naive full-height value is correct at rest and wrong mid-scroll. Choose the small or large viewport variant explicitly per surface rather than accepting whichever the browser reports at the moment of layout.
- When the on-screen keyboard opens, the usable area shrinks dramatically and any element sized to the full viewport will push its own footer and primary action underneath the keyboard. Decide per surface whether it tracks the shrunken viewport or holds still, and never let a submit control end up unreachable.
- A viewport height must never become a content ceiling. If the content is taller than the resolved height — a long form, a translated label that wraps to three lines, a large accessibility text size — the container must scroll instead of clipping, so enforce a minimum height alongside the viewport height.
- The same declaration resolves differently in a browser tab, in a home-screen standalone session, and inside an in-app webview, because each has a different amount of surrounding chrome. All three need checking, and standalone mode also has to clear the device safe-area insets at the top and bottom.
- Rotating the device changes both the height and the amount of chrome at once, and some browsers report the old value for a frame or two afterwards. The layout must settle correctly without the user needing to scroll to trigger a reflow.
- Nested full-height containers compound the error: a panel that is one full viewport tall inside another that is also one full viewport tall produces a page twice the screen height with no visible scroll cue.
- Height changes must not be animated by default. A container that eases between the small and large viewport height turns ordinary scrolling into a wobbling layout.

## 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 full-height surface in the app resolves its height through one shared primitive rather than a locally repeated calculation.
- [ ] Scrolling on a mobile browser does not resize, jump, or reflow full-height layouts as the address bar retracts.
- [ ] No primary action or footer control is pushed out of reach when the on-screen keyboard is open.
- [ ] Full-height containers scroll rather than clip when their content exceeds the resolved height.
- [ ] The layout is correct in a browser tab, in a home-screen standalone session, and after rotating the device.
- [ ] Safe-area insets are respected at the top and bottom in standalone mode.
- [ ] 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.
