### Description
Community report: in the **Devices** widget editor, the "Add a …device" select at the bottom of the panel opens a menu whose bottom is cut off by the edge of the screen, and the options down there cannot be selected.
**Root cause.** The 8 dashboard widget editors (devices, device-in-room, chart, gauge, energy consumption, music, scene, user presence) plus `SelectDeviceFeature`, `RoomSelector` and `MigrateDeviceModal` imported `react-select` directly, so they never got the `menuPosition: 'fixed'` that #3037 added to the shared `components/form/Select` wrapper: their portaled menus were placed against the *document* rather than the viewport, and react-select scrolled the page to make room, which `closeMenuOnScroll` turned into an immediate close. Beyond that, react-select 4's own placement is computed exactly **once**, when the menu mounts, by measuring the menu against `window.innerHeight`, which leaves the menu out of reach whenever:
- the option list grows while the menu is open (the user erases part of the filter): a menu opened short fit below, then grew past the bottom of the viewport — the exact symptom of the screenshot;
- the soft keyboard slides up right after the tap that opened the menu and the viewport shrinks under it; on iOS (and some Android WebViews) only the *visual* viewport shrinks, `innerHeight` never does, so even a fresh react-select placement would sit under the keys;
- and a pre-existing quirk: under preact/compat, emotion inserts a first-seen style in a layout effect, *after* refs are attached, so the very first menu opened on a page was measured unstyled (an in-flow `div` at the end of `<body>` with every option visible) and placed on garbage — usually flipped above its control whether or not there was room there.
**Fix.**
- Every portaled select goes through the shared wrapper; the now-redundant `menuPlacement` / `menuPortalTarget` / `closeMenuOnScroll` props are dropped from the callers.
- **The wrapper owns the placement.** Its own `MenuPortal` decides the side (below the control while at least `minMenuHeight` fits there, above otherwise — react-select's own policy) and the max height (never more than the room there is) from the control's rectangle and the **visible viewport** (`visualViewport`, falling back to `innerHeight`), on every render and on every `resize` / `visualViewport` `resize` + `scroll`, and hands them to `Menu` and `MenuList` through a context. react-select's `MenuPlacer` is not given the menu ref, so it never measures, never scrolls the page, and the emotion timing quirk is moot. Because the side depends on the control and the viewport alone, a list that grows while the menu is open cannot push it off screen.
- Spec A.3 (`docs/specs/dashboard-flexible-layout-and-widgets.md`) updated accordingly.
- New Cypress spec `DashboardDevicesBoxSelect.cy.js`: a Devices widget with an 8-feature device, a control near the bottom of a short screen, the menu opened short (no match) and the filter erased — the whole menu must stay on screen and the option at the end of the list must be selectable. Cypress cannot shrink the visual viewport independently of `innerHeight`, so that branch is covered by reading only.
**Verified** with Playwright against the demo dashboard editor (desktop side panel, 1280px wide), before → after:
| Scenario | Before | After |
|---|---|---|
| First menu of the page, control high in the panel | flipped above the control (accidental, cut off when there is no room above) | placed below |
| Control at the bottom of the panel, 600px viewport | flips above | flips above (unchanged) |
| Opened with room below, then viewport shrinks (soft keyboard) | menu stays where it was | menu re-placed above the control |
| Opened with a short filtered list, filter erased | menu grows to 220px and overflows the viewport bottom (bottom 835px for a 720px viewport) — the reported bug | menu flips above the control |
`npm run eslint` and `npm run prettier-check` pass on the changed files; `vite build` succeeds.
## Forum
Forum: https://community.gladysassistant.com/t/bug-sur-selecteur-en-bas-de-page/10749
### Checklist
- [x] Tests pass: front-only change, no server code touched; a Cypress spec was added for the reported scenario (Cypress is run by CI, it needs a running server)
- [x] Linter and prettier pass on both front and server (`npm run eslint`, `npm run prettier`)
- [x] No undocumented breaking change
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Bg7EqaUKQH4zonmn4bcmdg
## Summary by CodeRabbit
* **Bug Fixes**
* Improved dropdown behavior across chart, device, energy, gauge, music, scene, presence, migration, and room-selection screens.
* Menus now remain within the visible screen and adjust their position and height during resizing, scrolling, and on-screen keyboard use.
* Space-constrained menus remain scrollable, allowing all options to be accessed without overflowing the screen.
* Selection controls now provide a more consistent experience throughout the app.