diff --git a/.agents/skills/frontend-design/reference/interaction-design.md b/.agents/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.agents/skills/frontend-design/reference/interaction-design.md
+++ b/.agents/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.claude/skills/frontend-design/reference/interaction-design.md b/.claude/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.claude/skills/frontend-design/reference/interaction-design.md
+++ b/.claude/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.codex/skills/frontend-design/reference/interaction-design.md b/.codex/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.codex/skills/frontend-design/reference/interaction-design.md
+++ b/.codex/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.cursor/skills/frontend-design/reference/interaction-design.md b/.cursor/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.cursor/skills/frontend-design/reference/interaction-design.md
+++ b/.cursor/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.gemini/skills/frontend-design/reference/interaction-design.md b/.gemini/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.gemini/skills/frontend-design/reference/interaction-design.md
+++ b/.gemini/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.kiro/skills/frontend-design/reference/interaction-design.md b/.kiro/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.kiro/skills/frontend-design/reference/interaction-design.md
+++ b/.kiro/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.opencode/skills/frontend-design/reference/interaction-design.md b/.opencode/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.opencode/skills/frontend-design/reference/interaction-design.md
+++ b/.opencode/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/.pi/skills/frontend-design/reference/interaction-design.md b/.pi/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/.pi/skills/frontend-design/reference/interaction-design.md
+++ b/.pi/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.
diff --git a/source/skills/frontend-design/reference/interaction-design.md b/source/skills/frontend-design/reference/interaction-design.md
index 10a77564b..19d6809a8 100644
--- a/source/skills/frontend-design/reference/interaction-design.md
+++ b/source/skills/frontend-design/reference/interaction-design.md
@@ -84,6 +84,78 @@ For tooltips, dropdowns, and non-modal overlays, use native popovers:
**Benefits**: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.
+## Dropdown & Overlay Positioning
+
+Dropdowns rendered with `position: absolute` inside a container that has `overflow: hidden` or `overflow: auto` will be clipped. This is the single most common dropdown bug in generated code.
+
+### CSS Anchor Positioning
+
+The modern solution uses the CSS Anchor Positioning API to tether an overlay to its trigger without JavaScript:
+
+```css
+.trigger {
+ anchor-name: --menu-trigger;
+}
+
+.dropdown {
+ position: fixed;
+ position-anchor: --menu-trigger;
+ position-area: block-end span-inline-end;
+ margin-top: 4px;
+}
+
+/* Flip above if no room below */
+@position-try --flip-above {
+ position-area: block-start span-inline-end;
+ margin-bottom: 4px;
+}
+```
+
+Because the dropdown uses `position: fixed`, it escapes any `overflow` clipping on ancestor elements. The `@position-try` block handles viewport edges automatically. **Browser support**: Chrome 125+, Edge 125+. Not yet in Firefox or Safari - use a fallback for those browsers.
+
+### Popover + Anchor Combo
+
+Combining the Popover API with anchor positioning gives you stacking, light-dismiss, accessibility, and correct positioning in one pattern:
+
+```html
+
+
+
+
+
+```
+
+The `popover` attribute places the element in the **top layer**, which sits above all other content regardless of z-index or overflow. No portal needed.
+
+### Portal / Teleport Pattern
+
+In component frameworks, render the dropdown at the document root and position it with JavaScript:
+
+- **React**: `createPortal(dropdown, document.body)`
+- **Vue**: ``
+- **Svelte**: Use a portal library or mount to `document.body`
+
+Calculate position from the trigger's `getBoundingClientRect()`, then apply `position: fixed` with `top` and `left` values. Recalculate on scroll and resize.
+
+### Fixed Positioning Fallback
+
+For browsers without anchor positioning support, `position: fixed` with manual coordinates avoids overflow clipping:
+
+```css
+.dropdown {
+ position: fixed;
+ /* top/left set via JS from trigger's getBoundingClientRect() */
+}
+```
+
+Check viewport boundaries before rendering. If the dropdown would overflow the bottom edge, flip it above the trigger. If it would overflow the right edge, align it to the trigger's right side instead.
+
+### Anti-Patterns
+
+- **`position: absolute` inside `overflow: hidden`** - The dropdown will be clipped. Use `position: fixed` or the top layer instead.
+- **Arbitrary z-index values** like `z-index: 9999` - Use a semantic z-index scale: `dropdown (100) -> sticky (200) -> modal-backdrop (300) -> modal (400) -> toast (500) -> tooltip (600)`.
+- **Rendering dropdown markup inline** without an escape hatch from the parent's stacking context. Either use `popover` (top layer), a portal, or `position: fixed`.
+
## Destructive Actions: Undo > Confirm
**Undo is better than confirmation dialogs**—users click through confirmations mindlessly. Remove from UI immediately, show undo toast, actually delete after toast expires. Use confirmation only for truly irreversible actions (account deletion), high-cost actions, or batch operations.