Skip to content

fix(web): restore combined loading and syncing banners

MacroscopeApp / Macroscope - UI Consistency failed Aug 31, 2026 in 6m 55s

UI Consistency: 1 new finding, 6 prior findings open

New finding (commit 53c1702)

  • apps/web/src/components/chat/ComposerBanner.tsx — the new shared ComposerBanner / ComposerSurface primitives own the attachment seam, placement, per-variant outline/tint, stack-cap severity, tab/row semantics and the new width defaulting, but the PR deletes the four test files that pinned those behaviors (ComposerBannerStack.test.tsx, ComposerStashBadge.test.tsx, ComposerTasksBadge.test.tsx, ThreadSyncStatusPill.test.tsx) and trims assertions from ComposerCommandMenu.test.tsx / ComposerStashMenu.test.tsx. No test in apps/web renders either primitive. This commit adds a further untested contract: width="content" drops @container (so Row layout="wrap-actions" loses its container queries) and threadSyncPhase now suppresses task progress and takes the stack's attached slot.

Resolved since the last run

  • The thread sync status now composes ComposerBanner.Row / Icon / Content in ComposerActivityStatus.tsx, fixing the icon-column misalignment flagged on 4977016.

Prior findings still present at this head (not re-posted)

  • ComposerBanner.ToggleIcon inherits the whole buttonVariants base, including the pointer-coarse 44x44 ::after hit box, inside rows that are themselves buttons.
  • ComposerBanner.Body supplies only padding-inline-start, so pending-input option focus rings are clipped by the animating CollapsiblePanel.
  • The task list depends on implicit ul/li roles after Preflight's list-style: none, losing the list role and its aria-label in WebKit.
  • Notice descriptions render as a second row, so actions/dismiss align to the title line rather than the title + description block.
  • ComposerCommandMenuLayer still reads --chat-composer-drawer-inset, whose only declaration this PR removes from index.css.
  • ChatView's server-update notice uses a static InfoIcon for running, failed and idle states.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Method

  • Compared the merge base (8b817cb) diff with the incremental change in the newest commit (cfb3851...53c1702) to separate new work from already-reviewed code.
  • Read the head versions of ComposerBanner.tsx, ComposerBannerStack.tsx, ComposerSurface.tsx, ComposerTasksBadge.tsx, ComposerPendingUserInputPanel.tsx, ComposerActivityStatus.tsx, ChatComposer.tsx (banner dock, activity strip, command-menu layer) and index.css to confirm which earlier findings were addressed.
  • Verified the emitted-selector semantics of the migrated theme variants: @custom-variant dark (&:is(.dark, .dark *)) means dark:[html[data-theme-id]_&]:… resolves to html[data-theme-id] .cls:is(.dark, .dark *), matching the deleted global rules, so the theme bridge for the composer surfaces is preserved.
  • Traced attachment-sibling seam rules for the new width="content" sync banner: it only renders when no top drawer, tasks drawer or tasks tab can follow it, so the shared-outline rules are not broken by the narrower row.
  • Searched all apps/web tests for ComposerBanner / ComposerSurface / composer-banner usage; there are none, confirming the coverage gap.

Considered and not reported

  • Sync status taking the attached slot ahead of error/warning notices: the code comment and ChatView already null the sync phase when the environment is unavailable, so this reads as deliberate prioritization rather than a regression.
  • motion-safe:animate-spin on the sync spinner (previously static) and the loss of the non-functional data-thread-sync-drawer hook: no remaining consumers, and the motion guard is respected.

🔍 Agent activity — 20 tool calls

💭 I'm comparing the current PR head against prior reviewed commits to spot new issues without repeating past feedback. I notice ThreadSyncStatusPill.tsx has been removed and replaced by ComposerActivityStatus.tsx, which resolves an earlier comment about that component. Checking ComposerTasksBadge, it still uses a rendered list element without an explicit role="list" attribute, matching a previously flagged issue, so I won't repeat that. I want to verify whether the earlier concerns about ComposerBannerStack alignment, hardcoded inset values, missing test coverage for the iconless Thinking row, ToggleIcon pseudo-elements, and ComposerPendingUserInputPanel padding are still present at this head, and I also want to examine a new stash queue conditional in ChatComposer that decides whether to close the stash menu based on matching candidate IDs. Working through it, the closing logic is actually correct despite the double negative — it closes the menu only when no other entries remain in the queue. Other new additions like the tasks progress calculation and the server update dismissal tracking via WeakSet look fine. I still need to confirm whether the InfoIcon accessibility issue flagged in the prior run remains unaddressed in this new commit.

1. git_tools — cfb3851..53c1702

2. git_tools

💭 The git log shows the top commit as 4dcdd96 by maria-rcks, but HEAD points to 53c1702, which seems inconsistent — maybe that commit isn't in this repo clone. I'll just look at the files at HEAD directly instead.

3. browse_code — apps/web/src/components/chat/ComposerBanner.tsx

💭 The ToggleIcon and Attachment issues were already flagged in prior runs, so I shouldn't repeat them. I want to double-check whether the drawer-inset issue with ComposerCommandMenuLayer reading the CSS variable imperatively has actually been fixed at head by looking at ChatComposer.tsx around line 233.

4. git_tools — chat-composer-drawer-inset

💭 I'm confused by a discrepancy: the grep at that revision still shows the drawer-slot CSS present, but the diff I saw claims those same lines were deleted. That doesn't line up, so something about which revision I'm actually looking at must be off. I should double-check by searching for something unique to the current head, like whether a ComposerBanner file exists.

5. browse_code — apps/web/src/components/chat/Composer*.tsx

💭 I'm noticing a discrepancy — the diff claims those drawer-slot rules in index.css were removed, but the grep at head still shows them present around lines 869-885, so I need to re-check the actual line numbers in the file to reconcile this. Since git_grep's revision resolution might be unreliable given the earlier clone inconsistencies, I should just view the file directly through the GitHub tree URL for a more trustworthy read of lines 850-890.

6. browse_code — apps/web/src/index.css

💭 The composer CSS blocks are indeed removed at head, so git_grep must've used a stale revision earlier. That confirms ChatComposer.tsx still references the removed --chat-composer-drawer-inset declaration at line 173, matching what was flagged before. I want to double-check by viewing ChatComposer.tsx lines 150-260 directly at head since grep proved unreliable.

7. browse_code — apps/web/src/components/chat/ChatComposer.tsx

💭 That inset fallback issue was already flagged in a prior run, so no need to repeat it. Now I want to focus on identifying anything new introduced between the last reviewed commit and the current one, though I don't have direct diff access to the earlier commit, so I'll need to check via GitHub instead.

8. github_api_read_only — repos/{owner}/{repo}/compare/cfb3851...53c1702

💭 I see the new commit refactors the pill into ComposerActivityRow, splitting it into Row/Icon/Content components in response to my earlier feedback. Looking at the accessibility markup, the role="status" moved from the container to the inner span holding the label text, which still seems fine for screen readers. I notice ThreadSyncStatusPill's test was deleted but no new test was added for ComposerActivityStatus — a marginal gap worth flagging. The width logic switches between "content" and "fill" based on threadSyncPhase and drawer state, which changes the visual sizing from the old fill-width pill, though it's not clearly a regression. I'm also checking that activeTasksProgress and activeTaskSteps, now derived after destructuring, are still correctly used in the useEffect dependencies further down — that looks fine. I'm also verifying that when threadSyncPhase is active, activeTasksProgress correctly resolves to null so there's no conflict with ComposerActivityRow rendering, and confirming there's no duplicate role="status" element between the banner-stack path and the activity row. One thing that stands out: the sync pill used to have pointer-events-none so clicks passed through to the composer surface beneath it, but the new plain div lacks that — given the banner overlaps the composer surface by about 1rem, this could block clicks that previously worked. Non-interactive, so it's low signal either way. The labels are short fixed strings, so truncation shouldn't be an issue even with nowrap replacing the previous truncate behavior on narrow mobile widths — that's a minor difference worth noting but not concerning. There's a subtler issue with the adjacent-attachment border rules though: since the sync banner Root is now content-width rather than full-width within the ComposerBanner.Column, the next attachment that follows it (like the top drawer) will still lose its top border and rounded corners because it's treated as following an attachment regardless of that attachment's width — so the visual assumption behind those adjacency styles may not hold when the preceding banner is narrow instead of full-width. But I realize the width="content" case only fires when there's no top drawer and it's not collapsed mobile, so there's actually no following attachment in that scenario to worry about. I also need to check whether the tasks tab badge could follow, but that requires activeTasksProgress to be non-null, which it isn't during a sync phase — so no conflict there either. Now I need to trace whether ComposerBannerStack actually renders null when its items array is empty, checking how frontItem is derived from orderedItems. I'm also noticing the last-child override on the negative margin — the last attachment in the column removes the overlap that would otherwise let it bleed into the composer, since it's the Dock itself that handles that overlap at the outer level rather than each inner child. Now I'm scanning for other suspicious changes in the commit—checking whether width="content" attachment styling still works correctly, then considering the removal of the data-thread-sync-drawer="true" attribute, which might have downstream consumers like tests or other components relying on it that could break silently.

9. git_tools — thread-sync-drawer|data-composer-sync-status|ThreadSyncStatusPill|composer-activity-strip

10. browse_code — apps/web/src/components/chat/ComposerBannerStack.tsx

💭 I'm looking at how the ComposerBannerStack keys off the active thread and appends the activity item to the front of the banner items, so when sync phase is active and banners exist, the activity row sits attached at the top with notices stacked below. I'm now checking a potential accessibility gap: the activity row's status role sits on the inner label span rather than wrapping a persistent live-region container, which could mean screen readers miss the announcement when the sync text first mounts. Also flagging a design shift — the old sync pill deliberately avoided a spinning animation (a test explicitly checked for no "animate-" class), but the new ComposerActivityRow now includes motion-safe:animate-spin on its loader icon, which reverses that earlier intentional choice. Actually, checking the earlier commit, ThreadSyncStatusPill was already restored with the composed Row/Icon/Content structure, addressing my prior feedback there. Now I'm looking at a more concrete issue: the label span inside ComposerActivityRow has shrink-0 whitespace-nowrap while sitting in a min-w-0 flex container, which could cause overflow problems on narrow mobile widths where the row uses fill width. I'm also considering whether there's a duplicate role="status" conflicting with the tasks content, and thinking through how the width prop interacts differently when the sync banner is content-width versus full-width inside the Column — since the Column applies special width rules to Attachment children and has a last-child margin rule, I need to check how that affects seam alignment with the Main surface below. Checking how ComposerSurface.Main draws its outline when a banner is attached — it seems the outline becomes a full rounded rect around Main when any banner is attached, and the attached banner overlaps to mask its own bottom edge. With a narrow, content-width pill sitting on the composer's rounded top corner and overlapping by a fixed amount, I'm now working out whether that overlap actually conceals the seam correctly given the corner radius. I check whether container queries matter for the actions row layout and confirm they don't apply here since the default inline layout is used. I also note the dangling data-chat-composer-activity-strip attribute has no CSS consumer, but it's pre-existing so not a new issue worth flagging. Then I start looking at the removal of pointer-events-none and aria-label from the sync surface, comparing it to the previous version that had both an aria-label and text content. Now I'm considering whether there's a genuine new finding around how activeTasksProgress/activeTaskSteps gate on threadSyncPhase, specifically an effect that closes the tasks drawer when those values become null — I want to check if a transient sync phase could cause unwanted drawer closures during an active turn. Given the drawer state issue seems minor and docs note tasks controls return once the thread syncs, I want to verify the actual ChatComposer code around the banner stack and standalone sync strip to confirm they're mutually exclusive and don't render duplicate sync rows. I'm weighing an apparent conflict here: the instructions say to output exactly "All clear" when there are no findings, but the system prompt requires a JSON schema response. I'll resolve this by following the JSON schema and using "All clear" as the content within it, then deciding whether there are actual findings worth reporting by re-checking the ChatComposer activity strip code and the spin animation/truncate changes more carefully. I want to look at threadSyncLabel and confirm whether the activity row is the sole location for this, plus check whether a duplicate spinner exists elsewhere in the composer for consistency, so I'll pull up more of the ChatComposer file around those line ranges.

11. browse_code — apps/web/src/components/chat/ChatComposer.tsx

12. browse_code — apps/web/src/components/chat/ChatComposer.tsx

💭 I'm tracing through a potential conflict where the sync banner uses content width while another attachment tries to render alongside it. Checking the conditions, when width is "content" the top drawer is suppressed, so I need to verify whether the tasks drawer still renders correctly since it depends on activeTasksProgress being non-null, which isn't guaranteed during sync phase. I also notice that when the composer is collapsed on mobile during sync, the strip switches to fill width, so any top drawer attachment below shares a consistent full-width seam — that case works fine. The more interesting discrepancy is that when banner items are stacked, the activity row inherits the stack's default fill width, whereas the standalone path renders it as a narrow content-width pill — so the same sync status can look like a compact pill or a full-width band depending on context, which seems like an intentional visual distinction rather than a bug. Digging into the ComposerBanner.Row and Content components, I trace through how their grid columns and flex shrink behavior interact with a width="content" (w-fit) parent versus a full-width one, and it all seems to hold up correctly — the icon column stays fixed while the text column shrinks to fit content, with no overflow or layout breakage in either case. Given this, the newest commit doesn't reveal any new structural issues beyond what I've already catalogued. Checking the ComposerActivityRow implementation against my earlier review comment about composing Row/Icon/Content to share the icon column — it does exactly that now, and the animated spinner icon at 12px matches the sizing convention used elsewhere in the banner components. I'm now considering whether the motion-safe animate-spin addition conflicts with an existing test assertion that checks for the absence of animate- classes, and whether there's a broader repo convention around reduced-motion handling I should verify against.

13. git_tools — animate-spin

💭 I notice there's a shared Spinner primitive at that path using animate-spin, but the new ComposerActivityRow builds its own spinner with LoaderCircleIcon instead of reusing it — that's worth flagging as a case of reconstructing an existing UI primitive locally.

14. browse_code — apps/web/src/components/ui/spinner.tsx

💭 I'm weighing whether nesting a Spinner (which carries role="status") inside an aria-hidden Icon slot causes any accessibility conflict—since it's hidden, it seems fine—but I'm also noticing most of the codebase actually uses a raw LoaderIcon with animate-spin instead of the Spinner primitive, so that might be the more consistent choice. I'm double-checking that the sync and tasks banners are mutually exclusive, that ComposerActivityRow's role="status" isn't nested under any aria-hidden ancestor, and that this row is never rendered twice simultaneously in the two conditional locations—all of which check out fine. But I'm noticing something more concerning: previously the sync pill was a separate always-visible attachment, keeping urgent notices like error banners visible alongside it. Now with bannerPriority ordering, an active loading/sync phase becomes the front item while error or warning notices get pushed behind a 12px hover-only peek, meaning a live error or version-mismatch notice could be hidden from view during sync — a real regression compared to the prior commit where both were shown simultaneously. On touch devices the error notice's action buttons collapse behind a small peek requiring a tap to expand, so it's discoverable but demoted — likely intentional given the "Activity stays attached" design. Still, this behavior is specifically worsened by this commit since sync previously had its own attachment point and never fronted the stack, so it's arguably a pre-existing pattern the patch makes newly relevant. I'm weighing whether this counts as a concrete UI consistency violation worth flagging. The bigger concern is that visibility:hidden on the collapsed container removes those elements from the tab order entirely, meaning keyboard users can't reach the action buttons without first triggering the peek, even though it carries role="alert" and the peek button has proper aria-expanded/aria-controls attributes. Now I see the real issue: reusing the "activity" priority for the sync row means a passive, non-actionable status ends up fronting the stack ahead of actionable error or warning notices, hiding them behind the hover peek during every thread load or sync. That's a concrete, defensible finding worth flagging, and the smallest fix would be giving the sync row its own lower priority. The commit message explicitly says "restore combined loading and syncing banners," so this combination was deliberate, not accidental — that weakens my case for flagging it as an error since it reflects author intent rather than an oversight. I'm rereading the diff again, looking at how the sync phase suppresses the active tasks progress when it's active, to see if there's something more objective to point to. I trace whether the removed destructured names are still referenced elsewhere, like in memoized computations or mobile rendering, and they seem fine since they'd use the newly shadowed consts. There's a subtle UX quirk where the tasks drawer force-closes during sync via an effect, causing an expanded list to collapse once sync completes — but this is already documented behavior, so I won't flag it. I'm also considering whether there's an issue with how the width prop is conditioned. The width logic for the sync banner depends on drawer/collapsed-mobile flags, and mobile row height uses a fixed spacing token, which all checks out. I also confirm the inline tasks badge rendering is pre-existing and unrelated to this change. My overall read is that the new commit itself looks clean, though I need to decide whether prior unresolved findings should still count toward a failing check state. Since several previously flagged issues remain unfixed at head—the coarse-pointer toggle icon overlay, padding clipping focus rings, missing list role, description alignment, a dangling CSS variable read, and deleted test coverage—the check conclusion should be failure, but I need to avoid posting duplicate comments for things already flagged. I'm going through each one to verify it's still present at head before finalizing that failure conclusion: confirming the ToggleIcon issue persists, then moving to check the panel padding, list role, and banner stack alignment issues in turn.

15. browse_code — apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx

16. browse_code — apps/web/src/components/chat/ComposerTasksBadge.tsx

💭 Since both prior findings remain unresolved, the check should fail, but I need to avoid posting duplicates. I'm weighing whether there's a genuinely new finding worth flagging for this commit, considering how the sync status indicator now takes priority in the notice stack's visible slot. Comparing against the previous commit, the sync pill used to be a separate row below the notice stack, while the stack's front item was the highest-priority notice like an error. Now the sync status gets injected as the front item, hiding errors behind the collapsed peek — a concrete regression in the changed lines that seems fixable by keeping sync as its own attachment rather than giving it activity priority. Though I'm second-guessing this since the commit message mentions "restoring combined loading and syncing banners," which might mean the intent was deliberately to merge these into one band. I'm checking whether this is actually a real regression: while a thread loads, an important error banner like "Environment unavailable" with a Repair action could get hidden behind a hover peek showing only a spinner. But I notice ChatView already nulls out the sync phase specifically when the environment is unavailable, so that particular error can't be covered by this issue. I'm now considering other banner types — version mismatch, branch mismatch, woke notice, parked thread, resume-compaction — to see if any of those could still get hidden behind the sync indicator during loading. Checking candidate E: the last-child margin rule on the Column doesn't create issues here since the sync strip's Attachment is the final child, and the dock's overlap/negative margin logic stays consistent across all attachment types. Now checking the not-has-data-[composer-banner-surface=attached]:hidden behavior on the Dock -- with the sync row present, the Root has the attached surface attribute so the Dock displays correctly. Since prior review passes across five commits already produced eight comments covering most concerns, I want to double-check a few remaining risky areas that haven't been flagged yet, starting with how ComposerStashBadge migrates. I'm checking whether the head file preserved the data-prompt-stash-badge attribute, aria-label, and onPointerDown handler after the ComposerBanner.Row migration. I also notice ComposerStashMenu replaced the shared Command/CommandItem combobox primitive with hand-rolled ComposerBanner rows and manual keyboard navigation, including custom arrow-key handling and data-highlighted state -- this effectively reconstructs a primitive that was removed, which none of the earlier comments caught, though I need to consider whether the stash menu's keyboard-driven nature from the composer justifies the custom approach. I want to check whether the removed useEffect for resetting highlightedId when entries change causes arrow navigation to break after a deletion — I should look at how highlightedEntry is derived now in ComposerStashMenu. Also noting that ComposerSurface.tsx introduces a huge arbitrary Tailwind clip-path shape moved out of CSS, which seems like shifting complexity into inline utility classes just to shrink the stylesheet. Checking the earlier flagged issues, none of them touched this ownership question directly. This does feel like the biggest structural concern in the PR — moving composer glass composition and runtime theme variable overrides out of global CSS into long arbitrary Tailwind variants, which runs counter to the guidance about keeping behaviorally complex styling centralized. I want to verify by inspecting the actual emitted production CSS to confirm this isn't just a stylistic preference but a real regression risk. I'm working through how Tailwind's variant nesting order would interact here — whether dark combined with the bracket selector resolves correctly depends on whether .dark is applied on the html element itself, which affects whether the final selector chain still targets the right ancestor. Actually, nesting .dark & inside that selector would put .dark as an ancestor of html, which is also impossible unless the variant is actually defined as &:where(.dark, .dark *) rather than a simple ancestor combinator. I need to check how the dark variant is actually defined and where that class gets applied in the DOM.

17. git_tools — custom-variant (dark|light)

💭 I'm working through how Tailwind orders combined variants like dark mode with an arbitrary selector—figuring out whether the dark variant wraps the bracket selector or vice versa when generating the nested CSS output. That checks out for the dark-mode selector nesting. Now I'm scrutinizing the ComposerBanner surface where two before:bg-[...] utilities are stacked on the same pseudo-element—one using color-mix and one using linear-gradient—and I'm working through how Tailwind v4's type inference decides whether each maps to background-color versus background-image, since that determines whether they conflict or compose correctly. Now checking the fallback case when backdrop-filter isn't supported: the original CSS shorthand reset both background-image and background-color together to just the tint gradient plus solid surface, removing the seam gradient layer entirely. But in the Tailwind version, only background-color gets overridden, so the tint and seam gradient image layers could persist unintentionally in dark mode — I need to verify whether that discrepancy actually matters visually. Rather than chase this cascade specificity question further without being able to build and test it, I should step back and focus on what I actually need to deliver: I've already completed five prior review runs with eight total comments, and this run only introduces new code around the sync banner reference. That change addresses my prior comment well, and I don't see a new violation I'm confident about — the unresolved prior findings alone justify a failure state without adding new comments. One thing worth checking is whether ComposerActivityRow needs a test given the deleted ThreadSyncStatusPill test, since the sync status component's composition and behavior changed meaningfully, though I may have already covered this under an earlier test-deletion comment on MessagesTimeline. Actually the new commit introduces real width/defaulting logic and state transitions with zero test coverage, and it removed the only test that covered sync status rendering — that squarely matches the rule requiring focused tests for width/defaulting logic changes, so this is a defensible new finding worth an inline comment on ChatComposer.tsx. Since comments have to land on diff lines, I'm checking whether ComposerActivityStatus.tsx (a fully new file with no test) is a better spot than the ChatComposer width ternary hunk, since both appear in the diff. Confirming the width ternary is indeed part of the PR diff. I'm also weighing whether flagging missing test coverage is worthwhile here — the PR removed several test files covering banner-stack behaviors while introducing a new shared ComposerBanner primitive that has no tests of its own, which feels like a legitimate coverage regression worth calling out. I'll place a comment on ComposerBanner.tsx near the Root width-defaulting logic, since that file is entirely new and any line there falls within the diff. The comment should note that this shared primitive now owns behaviors previously covered by four deleted test files—banner stack cap variant, placement, dismiss semantics, tab rendering, sync status row—yet the new width defaulting and the sync/tasks swap logic in ChatComposer remain untested, and I'll ask for a focused render test. Before finalizing, I should double-check that no ComposerBanner.test.tsx or other test references the composer-banner attributes elsewhere in the codebase.

18. git_tools — composer-banner|ComposerBanner|ComposerSurface

19. browse_code — apps/web/src/components/chat/*.test.tsx

💭 I confirm there's no test coverage for the new ComposerBanner or ComposerSurface primitives, and that four test files covering replaced behaviors were deleted, along with assertions stripped from two others. I'll draft a comment flagging this gap, anchored on the width-defaulting logic in ComposerBanner's Root component, noting the untested attachment seam, variant tinting, and width/sync-row contracts, and suggesting a focused rendering test for attached vs floating placement and variant outlines. I'll keep this to one combined comment rather than splitting across files, and mark the overall status as a failure since prior unresolved findings persist alongside this new one, titled "UI Consistency: 1 new finding, prior findings unresolved." I'm settling on anchoring the inline comment near the width prop definition (around line 149) with a start line of 145, since that's the most precise spot for the width contract issue, then posting it.

20. modify_pr — Reviewed the composer banner/surface migration again against the new commit (53c1702, "restore combined loading and syncing banners"). The sync status now composes ComposerBanner.Row / Icon / Content (ComposerActivityStatus.tsx), which resolves the icon-column misalignment flagged on 4977016. One new finding below on the verification gate for the primitives this PR introduces. Findings raised on earlier commits that are still present at this head (not re-posted): - ComposerBanner.ToggleIcon inherits the full buttonVariants base, including the pointer-coarse 44x44 ::after hit box, inside rows that are themselves buttons. - ComposerBanner.Body supplies only padding-inline-start, so the pending-input option buttons' focus rings are clipped by the animating CollapsiblePanel. - The task list relies on implicit ul/li roles after Preflight's list-style: none, dropping the list role and its aria-label in WebKit. - Notice descriptions render as a second row, so actions/dismiss align to the title line instead of the whole block. - ComposerCommandMenuLayer still reads --chat-composer-drawer-inset, whose only declaration this PR deletes. - ChatView's server-update notice uses a static InfoIcon for running/failed/idle states.


Agent Credits: 287 credits

Token usage: 32 uncached input · 1,979,002 cache-read input · 167,410 cache-write input · 27,777 output
Agent Credits may also include non-token charges from external tools such as web research.