diff --git a/.agents/skills/migrate-container-queries/SKILL.md b/.agents/skills/migrate-container-queries/SKILL.md
new file mode 100644
index 000000000000..a0d88bd7cd32
--- /dev/null
+++ b/.agents/skills/migrate-container-queries/SKILL.md
@@ -0,0 +1,121 @@
+---
+name: migrate-container-queries
+description: Guide for migrating viewport media queries (@media, useMedia) to container queries in Sentry's frontend. Use when migrating responsive layout to container queries, replacing @media/useMedia, refactoring styled responsive components to Container/Flex/Grid primitives, or working on the DE container-query migration.
+---
+
+# Container Query Migration Guide
+
+Migrate viewport-based responsive logic (`@media` + `useMedia`) to container queries so components respond to their own available space instead of the raw viewport.
+
+> **Always do a visual check.** After every migration, resize the _element_ (not just the window) and confirm the layout is identical and flips at the intended width. A good way to narrow an element without touching the window is to open a resizable panel next to it — e.g. drag out the Seer explorer sidebar, which squeezes the middle content. The token scales differ, so a mechanical swap that compiles can still render wrong.
+
+## Approach: refactor first, swap second
+
+Stop at the first rung that fits. Prefer replacing hand-rolled CSS with primitives over a mechanical token swap.
+
+| Rung | When | Do |
+| ---------------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
+| 1. Primitive props | The `@media` only flips layout (`flex-direction`, `display`, `grid-template`, gap, visibility, width) | Delete the styled component; use `Container`/`Flex`/`Grid`/`Stack` responsive props (`direction={{xs: 'column', md: 'row'}}`) |
+| 2. `@container` swap | CSS can't be a prop (descendant selectors, pseudo-elements, `font-size`, complex `grid-template-areas`) | Keep the styled component; swap `@media` → `@container`, `theme.breakpoints.*` → `theme.container.*` |
+| 3. Container-scoped JS | Width is read in JS to branch rendering | Replace `useMedia(...)` with `useResponsivePropValue({...})` for a threshold boolean, or `useContainerBreakpoint()` to branch on the active key |
+| 4. Leave as `useMedia` | Genuine media feature, not width | Do nothing — these do not migrate |
+
+## ⚠️ Convert to the nearest container scale
+
+Breakpoint and container scales have **different keys and different pixel values** — this is not a rename. **MAP BY PIXEL VALUE, NOT BY KEY:** `breakpoints.sm` does NOT become `container.sm`. Reusing the same key is the #1 migration bug.
+
+`theme.breakpoints` (viewport / `@media`), base `2xs`:
+
+| `2xs` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` |
+| ----- | ----- | ----- | ----- | ------ | ------ | ------ |
+| 0px | 500px | 800px | 992px | 1200px | 1440px | 2560px |
+
+`theme.container` (container / `@container`), base `zero`:
+
+| `zero` | `3xs` | `2xs` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `3xl` | `4xl` | `5xl` |
+| ------ | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ------ | ------ | ------ |
+| 0px | 320px | 384px | 448px | 512px | 576px | 640px | 768px | 896px | 1024px | 1152px | 1280px |
+
+**Rule:** take the old breakpoint's pixel value and pick the `container` token whose pixel value is _nearest_ to it — not the token with the same name. `breakpoints.sm` is 800px, so it maps to `container.xl` (768px), not `container.sm` (512px). Then confirm with a visual check: the container is often narrower than the viewport, so the nearest-px token is a starting point, not a guarantee.
+
+## Genuine viewport width → `screen:` keys, not `useMedia`
+
+When layout truly must follow the _window_ (not the component's room), don't keep `useMedia` — use a `screen:`-prefixed responsive prop, which resolves against the viewport on the `theme.breakpoints` scale: `direction={{zero: 'column', 'screen:lg': 'row'}}`. Bare keys and `screen:` keys can mix on one prop. Prefer bare (container) keys; reach for `screen:` only when the viewport genuinely drives the layout.
+
+## Keep `useMedia` only for non-width media features
+
+Width — container or viewport — has a prop/hook path above. Leave `useMedia` in place only for:
+`prefers-color-scheme`, `prefers-reduced-motion`, `hover`, `pointer`, `max-height` / height-based, `resolution`, `print`.
+
+## container-type: only when no query container is in scope
+
+**Default: don't add one.** Bare keys and `@container` already resolve against the nearest ancestor container, and product views have one: `ContentStack` (`#main`, `views/organizationLayout/index.tsx`) wraps the routed `` with `containerType="inline-size"`; `topBar` and `#modal-portal` cover their own subtrees. Add `container-type` only when a subtree must respond to _its own_ width rather than the page's — then:
+
+- Use `inline-size` (width only). `size` also queries height, which collapses content unless height is set elsewhere.
+- In a reusable component that may already sit inside a container, make it conditional to avoid a redundant one — `containerType={hasParentQueryContainer ? 'normal' : 'inline-size'}` via `useHasContainerQuery()` (see `components/core/breadcrumbList/breadcrumbList.tsx`).
+
+## Examples
+
+### Rung 1 — styled `@media` → primitive props (preferred)
+
+```tsx
+// Old — delete the styled component
+const Row = styled('div')`
+ display: flex;
+ flex-direction: row;
+ gap: ${p => p.theme.space.md};
+ @media (max-width: ${p => p.theme.breakpoints.sm}) {
+ flex-direction: column;
+ }
+`;
+
+// New
+import {Flex} from '@sentry/scraps/layout';
+
+```
+
+### Rung 2 — `@media` → `@container` (when it can't be a prop)
+
+```tsx
+// Old
+@media (max-width: ${p => p.theme.breakpoints.md}) { ... }
+
+// New — swap at-rule AND scale; md breakpoint (992px) → nearest container token by px
+// is 3xl (1024px), NOT theme.container.md by matching key
+@container (max-width: ${p => p.theme.container['3xl']}) { ... }
+```
+
+### Rung 3 — `useMedia` (width) → container-scoped JS
+
+Both helpers below read the nearest query container (call from a descendant of one) and re-render as it crosses a breakpoint. A single `max-width` boolean is cleanest as a responsive value; reach for the active key only when you branch on the key itself.
+
+```tsx
+// Old
+const isNarrow = useMedia(`(max-width: ${theme.breakpoints.sm})`);
+
+// New — resolve a responsive boolean against the container, same mobile-first
+// cascade as CSS. A max-width query is "on by default, off past the threshold",
+// so name only the threshold key. Map by pixel value: breakpoints.sm (800px) →
+// nearest container token is xl (768px).
+import {useResponsivePropValue} from '@sentry/scraps/layout';
+
+const isNarrow = useResponsivePropValue({zero: true, xl: false});
+// below xl → true, at/above xl → false — one key on each side, nothing to enumerate.
+```
+
+Reach for `useContainerBreakpoint()` instead only when you branch on the key
+itself (e.g. picking one of several layouts), not a single threshold. It returns
+the container's active key (`'zero'` … `'5xl'`) — don't compare it with
+`=== 'zero'` for a max-width case: that fires only below 320px and drops the
+320–768px range the original query treated as narrow.
+
+## Migration Checklist
+
+Took the lowest rung that fits (above). Then verify the gotchas:
+
+- [ ] Mapped to the `container` token with the nearest pixel value, not the same name — e.g. `breakpoints.sm` → `container.xl`, not `container.sm`
+- [ ] For width read in JS, used `useResponsivePropValue({...})` for a threshold boolean; reserved `useContainerBreakpoint()` for branching on the key — never `=== 'zero'` to mean "narrow" (that's only <320px)
+- [ ] Routed genuine viewport-width cases to `screen:` keys; kept `useMedia` only for non-width media features
+- [ ] Added `container-type` only when a subtree needs its own; used `inline-size`
+- [ ] Confirmed a query-container ancestor exists (`@container` silently no-ops without one)
+- [ ] **Visual check:** resized the element and confirmed identical output flipping at the intended width
diff --git a/.agents/skills/migrate-container-queries/SPEC.md b/.agents/skills/migrate-container-queries/SPEC.md
new file mode 100644
index 000000000000..2ee3d628683f
--- /dev/null
+++ b/.agents/skills/migrate-container-queries/SPEC.md
@@ -0,0 +1,33 @@
+# Container Query Migration Guide Specification
+
+## Intent
+
+Provide a reliable, low-risk path for converting viewport-based responsive logic (`@media`, `useMedia`) to container queries, so components respond to their own available width instead of the raw viewport. The dominant failure mode this skill guards against is mapping a breakpoint token to the container token of the same name: the two scales share names but not pixel values.
+
+## Scope
+
+In scope: migrating `@media`/`useMedia` width logic to primitive props, `@container` CSS, `useContainerBreakpoint()`, or `screen:` keys, and deciding when to add `container-type`.
+
+Out of scope: non-width media features (`prefers-*`, `hover`, `pointer`, `resolution`, height-based, `print`) stay on `useMedia`; building the primitives or tokens themselves.
+
+## Non-negotiable Constraints
+
+- Map to the `container` token with the pixel value _nearest_ the old breakpoint's — never the same-named token.
+- Always visually verify by resizing the element (the container is often narrower than the viewport, so the nearest-px token is a starting point).
+- Route genuine viewport-width cases to `screen:` keys; keep `useMedia` only for non-width media features.
+
+## Sources
+
+- Scraps `Container` story, "Container Queries" section — authoritative for container vs. `screen:` keys, both token scales, `useContainerBreakpoint`, and `container-type` guidance.
+- Reference migration PR getsentry/sentry#120315 (trace-view).
+- `components/core/breadcrumbList/breadcrumbList.tsx` — conditional `container-type` pattern.
+
+## Known Limitations
+
+- The nearest-px token is only a starting point; the true reflow width needs a browser visual check the skill cannot perform.
+- `@container` silently no-ops without a query-container ancestor; the skill flags this but cannot detect it statically.
+
+## Maintenance
+
+- Update `SKILL.md` when token scales change, primitives gain/lose props, or a rung is added.
+- Update `SPEC.md` when intent, scope, the non-negotiable constraints, or the sources change.