Context
Operator observation 2026-08-02, from the workstation demo: "cards at the right side, in case the window / main container is small look quite 'pressed'."
Reproduced and measured live at http://localhost:<dev>/apps/workstation/, dark theme, at two viewport sizes. Live latest-open sweep 2026-08-02T23:3xZ (newest #16419); A2A claim sweep over the last ~14 messages (newest 23:30Z) — no equivalent ticket and no in-flight claim. Neighbours checked: #16406 (tab-drag label-over-content — a FLIP paint artifact during drag, not static sizing), #16356 (Security pane zero-rect FLIP frame), #16336 (CLOSED — dock-rail label clipping). None owns card-internal sizing.
The Problem
The resident cards size their contents from the viewport and their box from the pane. Those two have no relationship, so a short pane keeps full-size type and silently shrinks a declared element to nothing.
Measured at viewport 1180x840 — every card reports the same metric font-size and padding, across a 2.3× spread in card height:
| card |
height |
metric font-size |
padding |
| Task Queue Pressure |
436px |
47.2px |
23.6px |
| Priority Alert Observatory |
436px |
47.2px |
23.6px |
| System Metrics |
188px |
47.2px |
23.6px |
| Commit Stream |
188px |
47.2px |
23.6px |
4vw of 1180 = 47.2. The type is keyed to the window; the box is keyed to the pane.
The unambiguous symptom — a declared element renders at zero. .workstation-resident-wave is declared height: 15px and carries the default flex-shrink: 1:
| card height |
used height |
| 436px |
15px |
| 436px |
15px |
| 188px |
0px |
| 188px |
0px |
The sparkline is not merely small — it is gone. The tall cards render their bars; the short ones render nothing, which is visible in the operator's screenshot and in a fresh capture.
The arithmetic, on a 188px card:
content box 140.8px (188 − 23.6 − 23.6 padding)
children 119px (kicker 12 + icon 24 + metric 45 + title 17 + footer 21 + wave 0)
margins 31px (title 8 + footer 14 + wave 9)
required 150px → −9.2px of slack
Negative slack, so flex shrinks the only shrinkable item to zero. At viewport 900x700 the same cards are 137px tall and the wave is still 0px, so this is not a single-breakpoint artifact — it scales with the layout.
The Architectural Reality
resources/scss/src/apps/workstation/Viewport.scss:
:239 .workstation-resident-card — display: flex; flex-direction: column; height: 100%; min-height: 0, padding: clamp(12px, 2vw, 24px)
:270 .workstation-resident-icon — font-size: clamp(18px, 2vw, 30px)
:278 .workstation-resident-metric — font-size: clamp(24px, 4vw, 58px)
:288 .workstation-resident-title — font-size: clamp(11px, 1.2vw, 16px)
:294 .workstation-resident-footer — margin-top: 14px; padding-top: 9px
:314 .workstation-resident-wave — height: 15px; margin-top: 9px, no flex-shrink
Every clamp() upper track is vw. In a dock/workstation layout the card's container is its pane, whose width and height are set by the dock split, not by the window. apps/workstation/view/Workspace.mjs:2245 renders the same markup for every resident, so each pane inherits sizing calibrated for a viewport it does not occupy.
The fixed margin-top values compound it: they are absolute while the type is viewport-relative, so the fixed and fluid parts of the card scale against different references.
The Fix
(Prescription — the ticket should choose deliberately rather than fold these together.)
Make the card's own box the sizing reference, and make degradation explicit rather than emergent.
- Container queries. Declare
container-type: size on .workstation-resident-card and move the clamp() upper tracks from vw to cqi / cqh. This is the root fix: the pane becomes the reference it already is visually. Cost: container-type: size requires the element's size to be independent of its contents, which holds here (height: 100%).
- A floor on the sparkline —
flex-shrink: 0 on .workstation-resident-wave, so a declared 15px element can never resolve to 0px unannounced.
- Explicit progressive disclosure — below a container-height threshold, hide the footer/wave deliberately rather than letting flex shrink them toward invisibility. A hidden element is a decision; a zero-height one is an accident.
My read is 1 + 2 + 3: (1) removes the cause, (2) converts a silent disappearance into a loud one during development, and (3) decides what a genuinely short card should drop. (2) alone is a trap — with negative slack it converts a vanishing sparkline into overflow, which is not better.
Acceptance Criteria
Out of Scope
- The tab-header overflow control and the active-tab indicator — now
#16424. My first reading of the screenshot was wrong: the … control is positioned correctly beside the tab label; what runs underneath it is the active-tab strip segment. My probe was wrong twice over — it tested clipping when the defect is overlap, and it walked the toolbar's children when src/tab/plugin/Overflow.mjs:17 roots the control at document.body. Both corrections came from the operator, not from re-reading. Split out because it lives in src/tab/, not in this app's SCSS.
#16406 — the tab-drag label paint artifact. Different mechanism (drag-time FLIP), different lane.
- The dock split algorithm that produces the short panes. The panes are legitimately short; the cards should cope.
- Any other app's cards. This sweep covered
apps/workstation only.
Avoided Traps
- "
vw is responsive, so this is already responsive." It is responsive — to the wrong thing. The code has fluid sizing and that sizing genuinely tracks the window, which is exactly why this survives review: nothing in it looks broken. The container simply is not the viewport. Reading the coarse reference when the finer one (the pane) is the actual container is the whole defect.
- Fixing it by shrinking the type constants. That trades a pressed large card for an undersized large one; the two card heights need different answers, which is the point of a container reference.
- Treating the zero-height sparkline as the bug. It is the loudest symptom. Pinning it with
flex-shrink: 0 while leaving vw sizing in place converts a silent disappearance into an overflow.
Related
#16406 — tab drag paints the tab header label over the content label (adjacent, different mechanism)
#16356 — Workstation Security pane zero-rect FLIP staging frame
#16336 — CLOSED; dock rail label clipping
apps/workstation/view/Workspace.mjs, resources/scss/src/apps/workstation/Viewport.scss
Decision Record impact: none — app-level presentation, no ADR authority touched. Agent OS structure-map gate: N/A (no ai/, MCP, Memory Core, or skill surface; no new or relocated .mjs).
Origin Session ID: 8c150fe3-e8a4-4475-8694-a6f92115dce9
Retrieval Hint: query_raw_memories("workstation resident card vw clamp viewport not container sparkline shrinks to zero short pane")
Context
Operator observation 2026-08-02, from the workstation demo: "cards at the right side, in case the window / main container is small look quite 'pressed'."
Reproduced and measured live at
http://localhost:<dev>/apps/workstation/, dark theme, at two viewport sizes. Live latest-open sweep 2026-08-02T23:3xZ (newest#16419); A2A claim sweep over the last ~14 messages (newest 23:30Z) — no equivalent ticket and no in-flight claim. Neighbours checked:#16406(tab-drag label-over-content — a FLIP paint artifact during drag, not static sizing),#16356(Security pane zero-rect FLIP frame),#16336(CLOSED — dock-rail label clipping). None owns card-internal sizing.The Problem
The resident cards size their contents from the viewport and their box from the pane. Those two have no relationship, so a short pane keeps full-size type and silently shrinks a declared element to nothing.
Measured at viewport
1180x840— every card reports the same metric font-size and padding, across a 2.3× spread in card height:4vwof 1180 = 47.2. The type is keyed to the window; the box is keyed to the pane.The unambiguous symptom — a declared element renders at zero.
.workstation-resident-waveis declaredheight: 15pxand carries the defaultflex-shrink: 1:15px15px0px0pxThe sparkline is not merely small — it is gone. The tall cards render their bars; the short ones render nothing, which is visible in the operator's screenshot and in a fresh capture.
The arithmetic, on a 188px card:
Negative slack, so flex shrinks the only shrinkable item to zero. At viewport
900x700the same cards are 137px tall and the wave is still0px, so this is not a single-breakpoint artifact — it scales with the layout.The Architectural Reality
resources/scss/src/apps/workstation/Viewport.scss::239.workstation-resident-card—display: flex; flex-direction: column; height: 100%; min-height: 0,padding: clamp(12px, 2vw, 24px):270.workstation-resident-icon—font-size: clamp(18px, 2vw, 30px):278.workstation-resident-metric—font-size: clamp(24px, 4vw, 58px):288.workstation-resident-title—font-size: clamp(11px, 1.2vw, 16px):294.workstation-resident-footer—margin-top: 14px; padding-top: 9px:314.workstation-resident-wave—height: 15px; margin-top: 9px, noflex-shrinkEvery
clamp()upper track isvw. In a dock/workstation layout the card's container is its pane, whose width and height are set by the dock split, not by the window.apps/workstation/view/Workspace.mjs:2245renders the same markup for every resident, so each pane inherits sizing calibrated for a viewport it does not occupy.The fixed
margin-topvalues compound it: they are absolute while the type is viewport-relative, so the fixed and fluid parts of the card scale against different references.The Fix
(Prescription — the ticket should choose deliberately rather than fold these together.)
Make the card's own box the sizing reference, and make degradation explicit rather than emergent.
container-type: sizeon.workstation-resident-cardand move theclamp()upper tracks fromvwtocqi/cqh. This is the root fix: the pane becomes the reference it already is visually. Cost:container-type: sizerequires the element's size to be independent of its contents, which holds here (height: 100%).flex-shrink: 0on.workstation-resident-wave, so a declared 15px element can never resolve to 0px unannounced.My read is 1 + 2 + 3: (1) removes the cause, (2) converts a silent disappearance into a loud one during development, and (3) decides what a genuinely short card should drop. (2) alone is a trap — with negative slack it converts a vanishing sparkline into overflow, which is not better.
Acceptance Criteria
.workstation-resident-wavenever resolves to a used height of0pxwhile it is in the DOM and its card is rendered. Either it renders at its declared height, or it is explicitly hidden by a stated rule.resources/scss/src/apps/workstation/.Out of Scope
#16424. My first reading of the screenshot was wrong: the…control is positioned correctly beside the tab label; what runs underneath it is the active-tab strip segment. My probe was wrong twice over — it tested clipping when the defect is overlap, and it walked the toolbar's children whensrc/tab/plugin/Overflow.mjs:17roots the control atdocument.body. Both corrections came from the operator, not from re-reading. Split out because it lives insrc/tab/, not in this app's SCSS.#16406— the tab-drag label paint artifact. Different mechanism (drag-time FLIP), different lane.apps/workstationonly.Avoided Traps
vwis responsive, so this is already responsive." It is responsive — to the wrong thing. The code has fluid sizing and that sizing genuinely tracks the window, which is exactly why this survives review: nothing in it looks broken. The container simply is not the viewport. Reading the coarse reference when the finer one (the pane) is the actual container is the whole defect.flex-shrink: 0while leavingvwsizing in place converts a silent disappearance into an overflow.Related
#16406— tab drag paints the tab header label over the content label (adjacent, different mechanism)#16356— Workstation Security pane zero-rect FLIP staging frame#16336— CLOSED; dock rail label clippingapps/workstation/view/Workspace.mjs,resources/scss/src/apps/workstation/Viewport.scssDecision Record impact:
none— app-level presentation, no ADR authority touched. Agent OS structure-map gate: N/A (noai/, MCP, Memory Core, or skill surface; no new or relocated.mjs).Origin Session ID: 8c150fe3-e8a4-4475-8694-a6f92115dce9
Retrieval Hint:
query_raw_memories("workstation resident card vw clamp viewport not container sparkline shrinks to zero short pane")