* fix(web): make the plan chip a business-accent control at row height
The chip borrowed the warn-state pair for a plain mode flag, so it read as
a warning, and its 2px vertical padding left it 4px shorter than the + and
select controls beside it. It now uses the business accent pair, takes the
row's 28px height, and carries Chinese copy; the unused chip.off.*
dictionary entries had no surface and are dropped.
* docs(web): re-record the plan chip README pair
* docs(web): state the plan chip's close glyph and drop stale copy claims
The READMEs described the chip without the × the component renders, and the
zh side still quoted the English accessibility string after this branch gave
the namespace its own Chinese one.
* test(web): pin the plan chip's accent tokens, height, and Chinese copy
The lifecycle-chrome lane asserted the chip's warn pair; it now asserts the
business pair plus the 28px row height, and a zh plan-active golden records
the 「计划」 label the chip shows under the Chinese locale.
* fix(web): color claimed command tokens with the business accent
The draft's claimed token still used the warn label color while the plan chip
moved to the business pair, so a claimed /计划 read orange above a blue chip.
The claim decoration and the tests asserting its inline style now use
state-business-primary.
* fix(web): keep the composer control row on one line at narrow widths
The fixed-width mode chips and send circle left the row's 12px gaps deciding
between a slack first line and a wrapped trailing group: beside the plan chip,
a long model name moved the model trigger and send circle to a second line
while the first line still had room. Narrow rows now use 8px gaps, which holds
the row together down to the icon-only model trigger.
* fix(web): drop the context ring in the narrow composer row
With plan mode on and a long model name, the 28px occupancy ring plus its gap
was what pushed the trailing group onto a second line. The ring yields at the
same row width that already hides the access-mode label, so the fixed controls
keep one line; the reading stays reachable from a wider window.
---------
Co-authored-by: Turtle <[email protected]>
* feat(web): reveal a clipped sidebar session title on hover
A session title wider than its sidebar row is clipped with an ellipsis, so a
long parent title hides the `(1)` that distinguishes its fork. Hovering the row
now scrolls the title to its far edge and returns it to the start when the
pointer leaves. The title stays an `overflow: hidden` scrollport, so nothing
reflows and no scrollbar appears; `scroll-behavior: smooth` supplies the motion
(reduced motion keeps the jump), and the hovered row clips instead of
ellipsizing because a scrolled box still paints the ellipsis over the revealed
characters.
Covered by the row component spec, the stylesheet contract spec, and a new
keyless Chromium scenario that hovers a seeded clipped row in the assembled
application and asserts the reached scroll extent.
* fix(web): return the revealed session title in one step
Review follow-up on the hover reveal:
- Return the title to its start with `scrollTo({ behavior: 'instant' })` instead
of a smooth scroll. A smooth return carried the resting ellipsis and the
narrowing cell over the travelling text for its whole duration.
- Scope `scroll-behavior: smooth` to `.sessionRow .title` so Workspace rows are
untouched, and fold the reduced-motion reset into the file's existing block.
- Guard the hover-only `text-overflow: clip` with `@media (hover: hover)`: a
touch tap latches `:hover` after the title has already returned, which would
otherwise strand that row without its ellipsis.
- Pin the contract in the browser scenario: computed `scroll-behavior` is
`smooth` by default and `auto` under reduced motion, and the return lands
inside one step. Add the unit case for the explicit instant return.