From 41cb6a5487a32acaaabb8e43e184a0ebce5f5743 Mon Sep 17 00:00:00 2001 From: Phil Merrell Date: Sun, 6 Sep 2026 09:41:40 -0600 Subject: [PATCH] fix(announcements): float the banner instead of occupying layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dismissing the banner pulled the whole view up by its height. It was a flex child of the shell's `
`, so appearing and disappearing reflowed everything below it — the jump was the bug, and reserving the space forever would have been a worse fix. It is now positioned `absolute` against a `relative` `
`: a rounded, shadowed pill floating over the content rather than a full-bleed strip displacing it. Measured before and after a dismissal, every content element — scroll container, greeting, composer — moves by exactly 0px in both axes. The overlay removes the reason anything had to know the banner's size, so this deletes more than it adds: - `--announcement-banner-height`, its `ResizeObserver`, the height signal, and the `DOCUMENT`/`ElementRef`/`DestroyRef` injections all go - `.chat-topnav-wrapper` goes back to `top: 0` - `.chat-container-empty.full-page` goes back to `inset: 0` - both floating sidenav control clusters go back to `top-4` `top-16` is the one constant that replaces all of it, and it is not arbitrary. On a chat route it lands the pill immediately below the fixed topnav — the placement §D1 asks for — and everywhere else it clears the shell's floating sidebar buttons, which sit at `top-4` and would otherwise be overlapped by a centred pill on any viewport narrow enough for the two to meet. Verified at 375px: the controls end at y=56 and the pill starts at y=64. The positioning strip spans the full content width, so it is `pointer-events-none` with `pointer-events-auto` on the pill alone — otherwise an invisible band would swallow clicks aimed at the topnav and the sidebar buttons beneath it. Verified: a click 30px outside the pill lands on the chat container, not the banner. `relative` on `
` is load-bearing. Without it the pill anchors to the viewport and drifts out from under the sidenav's padding transition. Browser-verified against dev data in light and dark and at 375px, with no horizontal overflow. Full frontend suite 2474 passed. Co-Authored-By: Claude Opus 5 --- frontend/ai.client/src/app/app.html | 19 ++-- .../announcement-banner.component.spec.ts | 90 ++++++++++--------- .../announcement-banner.component.ts | 71 +++++---------- .../chat-container.component.css | 14 +-- 4 files changed, 83 insertions(+), 111 deletions(-) diff --git a/frontend/ai.client/src/app/app.html b/frontend/ai.client/src/app/app.html index 136655fb..678a891a 100644 --- a/frontend/ai.client/src/app/app.html +++ b/frontend/ai.client/src/app/app.html @@ -41,9 +41,7 @@ @if (sidenavService.isCollapsed() && !chromeHidden()) { -