.row { position: relative; padding: 5px 0; } .toolGroupSpacing { padding: 8px 0; } /* * Anchored inside the message row rather than floating above it: the message * list (`.list`) is `overflow-y: auto`, so a tooltip spilling outside the row * box would be clipped or trigger a scrollbar. Staying within the row keeps it * visible at the scroll edges. `pointer-events: none` lets clicks and inner * hover interactions (tool expand, links) pass through. * * Anchored at the BOTTOM-right, and fully opaque. Both halves matter, and the * position is the load-bearing one. * * At the top-right the chip's lower edge cuts horizontally through the first * line of the message, and the first line of a wrapped block is the one that * runs the full column width. It does not hide the last word so much as * decapitate it: the chip removes a letter's ascender while its bowl stays * visible below, so "finished." reads as "finisheu." -- the shape that kept * being reported as a corrupted error message in web-shell previews. Making * the background opaque alone does NOT fix that; it erases the faint remnant * of the ascender and leaves the letter looking even more like a "u". Moving * the chip off the text is what fixes it. The last line of a wrapped block is * a ragged remainder, and rows carrying an action bar (the turn-error Copy * button) leave that corner empty outright. * * Opacity still matters on its own: at 92% a glyph beneath any overlay bleeds * through it, which reads as broken text rather than as a chip. `.chatTip` and * `.copyButton` sit over content too (`.chatActions` pulls itself up by -24px) * and carry the same fix. So does `.toolTimeTip` in SubAgentPanel.module.css, * which mirrors this chip over a sub-tool line and had no `background` at all * -- but only its background: that row cannot wrap and is about as tall as the * chip, so it has no slack to move into. `visual-capture-contracts.test.ts` * pins these, because no test reads this geometry: reverting the anchor or the * background keeps every suite green. * * Overlap is now rare, not impossible -- a message whose last block is a * full-width code block or table still gets the chip in its corner. Reserving * space in flow was rejected: hover-time padding reflows the transcript, and a * permanent float notch shrinks every code block that establishes its own * formatting context. */ .tip { position: absolute; bottom: 2px; right: 4px; z-index: 5; color: var(--muted-foreground); background: var(--background); border: 1px solid var(--border); border-radius: 4px; padding: 1px 4px; font-size: 11px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.12s ease; } .row:hover > .tip { opacity: 1; } /* Chat mode: timestamp shown at bottom-right on hover */ .chatRow { position: relative; display: flex; width: 100%; flex-direction: column; align-items: flex-end; } .chatTip { color: var(--muted-foreground); background: var(--background); border-radius: 4px; padding: 1px 4px; font-size: 11px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.12s ease; } .chatActions { display: inline-flex; align-items: center; gap: 4px; margin-top: -24px; margin-right: 4px; z-index: 5; opacity: 0; transition: opacity 0.12s ease; } .chatActions .chatTip { opacity: 1; } .copyButton { display: inline-flex; width: 20px; height: 20px; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 5px; background: var(--background); color: var(--muted-foreground); cursor: pointer; } .copyButton:hover, .copyButton:focus-visible { color: var(--muted-foreground); outline: none; } .copyButton svg { width: 14px; height: 14px; } .chatRow:hover > .chatActions, .chatRow:focus-within > .chatActions, .chatActions[data-menu-open='true'] { opacity: 1; }