# Font Loading Strategy

## Objective

Load the custom fonts without invisible text, broken metrics, or a late reflow.

A defined loading, fallback, and failure path for every custom font the interface depends on.

## 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. List every font family, weight, and style the app actually renders, then check that list against what is being downloaded. Most apps ship weights nothing on the page uses.
2. Choose a fallback whose metrics are adjusted to match the custom face, so the text laid out before the font arrives occupies close to the same space and the swap does not reflow the page.
3. Preload only the faces needed for the first meaningful render. Preloading everything competes with the request for the content itself and delays the thing the user came for.
4. Define what happens when the font never arrives: blocked network, a failed request, an unsupported format. The page must remain fully readable in the fallback indefinitely rather than showing invisible text.
5. Do not solve a slow font by hiding text until it loads. Blank text on a working page is a worse failure than a brief change of typeface, and it is the failure users report as the site being broken.

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

- The fallback must be metric-compatible or metric-adjusted, otherwise the swap shifts every line of text and the layout jumps after the page appeared finished.
- Preloading more than the critical faces steals bandwidth from the first render, so the preload list needs to be short and justified rather than generated from the whole family.
- Variable fonts change the calculation — one file may replace six, but only if the app actually uses the axes it carries, and language subsets need their own decision about which are fetched eagerly.
- A complete font failure must leave the page readable in the fallback rather than blank, which means the invisible-text period has to be bounded and short.
- Fonts loaded conditionally for a script the user's content requires must not arrive so late that the text has already been measured and laid out with a wrong-width fallback.
- Icon fonts fail differently from text fonts: an unloaded icon face renders as boxes or as unrelated characters, which is why icons belong in the Icon System rather than in a font.
- Reserving space for text that has not rendered is shared ground with Layout Shift Guard; this feature owns the font metrics and swap behaviour, and that feature owns detecting the movement when it happens anyway.

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

- [ ] Text is readable throughout loading and never invisible for a prolonged period.
- [ ] Fallback metrics are adjusted so the swap produces no visible reflow.
- [ ] Only the faces required for first render are preloaded.
- [ ] Every weight and style downloaded is one the app actually renders.
- [ ] A total font failure leaves the interface fully usable in the fallback.
- [ ] Variable font axes and language subsets are loaded deliberately rather than wholesale.
- [ ] No icon or symbol rendering depends on a custom font loading successfully.
- [ ] 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.
