# Embedded Media Blocks

## Objective

Paste a video, map, or social link into content and get a proper embed instead of a URL.

Recognition of pasted media URLs in the editor, rendered as responsive embeds with a safe fallback.

## 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. Extend the app's existing Rich Text Editor or Markdown Editor with Preview to detect a pasted URL on its own line and offer to convert it to an embed. Do not add a separate embed editor beside the one authors already use.
2. Maintain an explicit allowlist of supported hosts. Resolve each pasted URL server-side into a stored block with a provider, an identifier, a title, a thumbnail, and an aspect ratio, so the published page does not depend on a live lookup.
3. Reuse the existing Media Aspect Ratio System to reserve the embed's space before it loads, and let the frame scale to the container width instead of a fixed pixel height.
4. Render a click-to-load placeholder showing the thumbnail and title, and only insert the third-party frame after the reader activates it or after consent is recorded through the existing Consent and Cookie Preferences.
5. Do not render an error when the host is unrecognised. Leave the URL as an ordinary link, since an author pasting a link to an unsupported site still meant it to be a link.

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

- An unsupported or unreachable host must degrade to a plain link with the URL as its text. An error box in the middle of a published article is worse than the link the author typed.
- Third-party embed scripts set cookies and fingerprint the reader the moment they load. Hold the frame behind a placeholder until consent exists, or the app is loading trackers it has promised not to load.
- Fixed-height embeds break on narrow screens, either cropping the content or forcing horizontal scroll. Size embeds by aspect ratio against the available width.
- A source that is deleted, made private, or geo-restricted leaves a blank frame with no explanation. Keep the stored title and thumbnail and show them with a note that the media is unavailable.
- A dozen embeds on one page each pull in their own scripts and delay first render badly. Load only the embeds near the viewport and keep the rest as placeholders.
- Embeds need an accessible name. Give each frame a title from the stored metadata so a screen reader does not announce a nameless frame.
- URL resolution happens against a user-supplied address, so it must be restricted to the allowlisted hosts and blocked from reaching internal addresses.
- A pasted URL inside a sentence is a link, not an embed. Only convert a URL that stands alone on its own line.

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

- [ ] Pasting a supported URL on its own line in the existing editor produces an embed block.
- [ ] Unsupported hosts render as plain links, never as errors.
- [ ] Embeds reserve their space by aspect ratio and cause no layout shift or horizontal scroll at 320px.
- [ ] No third-party script loads before the reader activates the embed or consent is recorded.
- [ ] Unavailable sources show the stored title and thumbnail with an explanation rather than an empty frame.
- [ ] A page with many embeds loads only those near the viewport.
- [ ] Every embed frame has an accessible title.
- [ ] 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.
