Context
The pane-header action family under epic #13158 shipped its semantics this cycle — close, pin, maximize (#17952/#17953) and the overflow-as-first-action (#17960) — and #17956 shipped the ui: 'inline' | 'standalone' container variants with per-theme sheets. What never shipped, and was never ticketed, is the visual design of the actions themselves plus the theme values the inline variant reserved room for. The reference bar is the Qt-parity pane header: a compact cluster of flat monochrome glyphs sharing the strip's band, close at the corner — not a row of standalone buttons.
The Problem
Measured at Engine dev@9954179bb7 (post all four family merges):
- The only action-specific CSS in the entire tree is the focus-gating carrier (
.neo-toolbar-action-context-inactive, resources/scss/src/toolbar/Base.scss). Every projected header action renders as a stock neo-button in whatever the active theme's default button chrome is — in the neo themes that is a large filled rounded button, visually dominating the header band it sits in. Witnessed in the dock-maximize component fixture (neo-theme-neo-dark: filled square buttons for close/maximize) and in apps/workstation (the #17960 overflow control renders as a generic bordered button on the "Priority Alert Observatory" pane).
- The inline gradient hook has no values.
#17950 froze --tab-header-inline-background-image, consumed as background-image: var(--tab-header-inline-background-image, none) on .neo-tab-container-inline > .neo-tab-header-toolbar (resources/scss/src/tab/Container.scss:6) — and no theme value layer sets it, so the none default renders everywhere. The hook satisfied its ticket's ACs; the design (a subtle band gradient for dense pane headers) was deliberately left to a values pass that has no ticket.
apps/workstation never enables the engine actions. The engine's own showcase inherits the inline chrome (six inline containers render today) but projects no close/pin/maximize — so the chrome this ticket designs has no living witness in a public app until the flags turn on there.
The Architectural Reality
- Action items are addressable: every projected action carries
cls: 'neo-toolbar-action' and isToolbarAction: true (src/toolbar/Base.mjs:373,391); contributions add isToolbarActionContribution (#17960). The chrome selector is therefore .neo-tab-header-toolbar .neo-toolbar-action (scoped to tab headers so ordinary toolbars keep their button chrome), with the gating carrier already handling shown/hidden interactivity.
- The four theme value layers exist and already carry tab sheets (
resources/scss/theme-{light,dark,neo-light,neo-dark}/tab/Container.scss, extended by #17956) — the values land beside the variant styling they complete.
- The engine set is focus-gated by default; whatever hover/rest states the design chooses must keep the gated state's geometry-preserving discipline (the carrier toggles interactivity, not layout).
The Fix
One SCSS-plus-witness pass, no JS behavior changes:
- Action glyph chrome for
.neo-tab-header-toolbar .neo-toolbar-action in the structural sheet (compact hit target, transparent rest background, glyph-first) with per-theme values in all four theme layers (glyph color, hover/active surfaces, close-affordance accent if the theme language wants one). The Qt-parity read: actions share the header band, they do not sit on it as buttons.
- Inline gradient values: set
--tab-header-inline-background-image in the two neo themes (the dense-pane band the hook was frozen for); the classic themes may opt for none deliberately — a written choice, not an accident of the default.
apps/workstation enables enableDockCloseAction, enableDockPinAction, enableDockMaximizeAction — the engine's showcase becomes the living witness for the chrome across both neo themes and exercises the full frozen ordering: [overflow] → [engine set, focus-gated] → [close, always last].
Contract Ledger
| Target Surface |
Source of Authority |
Behavior |
Fallback |
Docs |
Evidence |
.neo-tab-header-toolbar .neo-toolbar-action |
src/toolbar/Base.mjs action marker + tab-header scope |
compact glyph-first chrome only inside tab headers; ordinary toolbars stay unchanged |
existing stock button chrome outside the selector |
structural SCSS intent comment |
selector-contract spec + per-theme visual receipt |
--tab-header-inline-background-image |
#17950 / merged #17956 hook |
real band gradient in both neo themes |
classic themes explicitly declare none |
per-theme inline-variant comment |
computed-style assertion in all four themes |
Workstation enableDockCloseAction / enableDockPinAction / enableDockMaximizeAction |
dashboard.dock.Workspace public configs |
showcase projects the frozen engine action set and ordering |
flags remain opt-in elsewhere |
Workstation config rationale |
dense-tour + action-order/focus-gating witness |
| gated action state |
neo-toolbar-action-context-inactive carrier |
geometry preserved; quiet and non-interactive under the new chrome |
existing hidden-carrier semantics |
no new public docs |
focused/unfocused rect stability + visual receipt |
The ledger changes visual/value and host opt-in surfaces only. It does not reopen action semantics. Classic-theme none is an explicit value, not reliance on the structural fallback.
Acceptance Criteria
Out of Scope
- Any action semantics, ordering, or gating behavior — all frozen and shipped by the family leaves.
- Redesigning the two
ui variants themselves (#17956 owns that shape); this ticket only supplies the values and the action chrome those variants were built to host.
- The private consumer workspaces — they inherit whatever the themes ship.
Related
Parent: #13158. Completes the design half of: #17950/#17956 (variants + hook), #17952 (pin), #17953 (maximize), #17960 (overflow-as-action). Reference precedent for gated-state mechanics: resources/scss/src/toolbar/Base.scss.
Origin Session ID: 914dffcd-0057-46a5-a0c6-9ca807fd5c91
Retrieval Hint: "dock header action glyph chrome four themes gradient values workstation witness"
— Vega (Fable 5, Claude Code) 🌿
Context
The pane-header action family under epic #13158 shipped its semantics this cycle —
close,pin,maximize(#17952/#17953) and the overflow-as-first-action (#17960) — and#17956shipped theui: 'inline' | 'standalone'container variants with per-theme sheets. What never shipped, and was never ticketed, is the visual design of the actions themselves plus the theme values the inline variant reserved room for. The reference bar is the Qt-parity pane header: a compact cluster of flat monochrome glyphs sharing the strip's band, close at the corner — not a row of standalone buttons.The Problem
Measured at Engine
dev@9954179bb7(post all four family merges):.neo-toolbar-action-context-inactive,resources/scss/src/toolbar/Base.scss). Every projected header action renders as a stockneo-buttonin whatever the active theme's default button chrome is — in the neo themes that is a large filled rounded button, visually dominating the header band it sits in. Witnessed in thedock-maximizecomponent fixture (neo-theme-neo-dark: filled square buttons for close/maximize) and inapps/workstation(the#17960overflow control renders as a generic bordered button on the "Priority Alert Observatory" pane).#17950froze--tab-header-inline-background-image, consumed asbackground-image: var(--tab-header-inline-background-image, none)on.neo-tab-container-inline > .neo-tab-header-toolbar(resources/scss/src/tab/Container.scss:6) — and no theme value layer sets it, so thenonedefault renders everywhere. The hook satisfied its ticket's ACs; the design (a subtle band gradient for dense pane headers) was deliberately left to a values pass that has no ticket.apps/workstationnever enables the engine actions. The engine's own showcase inherits the inline chrome (six inline containers render today) but projects no close/pin/maximize — so the chrome this ticket designs has no living witness in a public app until the flags turn on there.The Architectural Reality
cls: 'neo-toolbar-action'andisToolbarAction: true(src/toolbar/Base.mjs:373,391); contributions addisToolbarActionContribution(#17960). The chrome selector is therefore.neo-tab-header-toolbar .neo-toolbar-action(scoped to tab headers so ordinary toolbars keep their button chrome), with the gating carrier already handling shown/hidden interactivity.resources/scss/theme-{light,dark,neo-light,neo-dark}/tab/Container.scss, extended by#17956) — the values land beside the variant styling they complete.The Fix
One SCSS-plus-witness pass, no JS behavior changes:
.neo-tab-header-toolbar .neo-toolbar-actionin the structural sheet (compact hit target, transparent rest background, glyph-first) with per-theme values in all four theme layers (glyph color, hover/active surfaces, close-affordance accent if the theme language wants one). The Qt-parity read: actions share the header band, they do not sit on it as buttons.--tab-header-inline-background-imagein the two neo themes (the dense-pane band the hook was frozen for); the classic themes may opt fornonedeliberately — a written choice, not an accident of the default.apps/workstationenablesenableDockCloseAction,enableDockPinAction,enableDockMaximizeAction— the engine's showcase becomes the living witness for the chrome across both neo themes and exercises the full frozen ordering: [overflow] → [engine set, focus-gated] → [close, always last].Contract Ledger
.neo-tab-header-toolbar .neo-toolbar-actionsrc/toolbar/Base.mjsaction marker + tab-header scope--tab-header-inline-background-imagenoneenableDockCloseAction/enableDockPinAction/enableDockMaximizeActiondashboard.dock.Workspacepublic configsneo-toolbar-action-context-inactivecarrierThe ledger changes visual/value and host opt-in surfaces only. It does not reopen action semantics. Classic-theme
noneis an explicit value, not reliance on the structural fallback.Acceptance Criteria
.neo-tab-header-toolbar(regression spec on the cls contract).--tab-header-inline-background-imagevalue; the classic themes' choice is written in their sheets as a deliberate line (value or documentednone).apps/workstationprojects close, pin and maximize; the dense tour still passes; the focus-gating carrier's geometry-preserving behavior is unchanged (no layout shift when actions gate in/out).Out of Scope
uivariants themselves (#17956owns that shape); this ticket only supplies the values and the action chrome those variants were built to host.Related
Parent: #13158. Completes the design half of: #17950/
#17956(variants + hook),#17952(pin),#17953(maximize),#17960(overflow-as-action). Reference precedent for gated-state mechanics:resources/scss/src/toolbar/Base.scss.Origin Session ID: 914dffcd-0057-46a5-a0c6-9ca807fd5c91
Retrieval Hint: "dock header action glyph chrome four themes gradient values workstation witness"
— Vega (Fable 5, Claude Code) 🌿