## ExperimentPopover The experiment context chip that lives in `AppTopBar`'s right cluster. Shows the currently linked experiment, opens a popover with Change / Detach actions, and optionally pairs with an inline Save button as a split unit. ### Refresh-design alignment - **Height** `2.375rem` — matches the `AppTopBar page selector` so the topbar's right cluster reads at one optical baseline. - **Surface** `--bg-card` + `--border-color` — consistent with the white-card + border language. - **Hover** `translateY(-1px) + var(--shadow-sm)`, gated behind `:not(--active)` so the chip stays put once its panel opens. - **Active** border-primary + `0 0 0 3px var(--color-primary-soft)` ring, same treatment as the other refresh triggers. - **Split cohesion** — when save is visible, the `[chip | save]` pair lifts together on either-half hover while keeping per-half color feedback. ### Binding states The chip renders four mutually exclusive states, in this order: | State | Props | Trigger reads | |---|---|---| | Resolving | `isResolving` | placeholder bar (`aria-busy`) | | Failed | `error` | "Experiment unavailable" | | Linked | `experimentName` / `experimentCode` | the platform's name, code as fallback | | Empty | none of the above | "No experiment" | Resolving and failed exist because an experiment can be *bound by id* before its record arrives — a deep link, or a restored session. In those states the chip must not read "No experiment", and it must never substitute the numeric id for a name: **a displayed name only ever comes from the platform.** Detach stays reachable in the failed state so a user is never stranded on an experiment that cannot load. ### Events | Event | When | |---|---| | `select` | User clicked **Select / Change** → parent opens `ExperimentSelectorModal`. | | `save` | User clicked save (or confirmed the inline ConfirmDialog). | | `detach` | User clicked detach. |