diff --git a/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift b/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift index ae2ab37..ee776a1 100644 --- a/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift +++ b/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift @@ -34,18 +34,24 @@ struct SessionDetailView: View { TranscriptList(events: store.openEvents, scrollToBottomRequest: scrollToBottomRequest, isScrolledToBottom: $isScrolledToBottom) - // Measure the transcript's full height (the floating bar overlays it via safeAreaInset, - // so this frame is the whole screen area the card has to live within) and hand it to the - // action card so it can bound itself. + // The chat bar floats over the scrolling content on Liquid Glass instead of sitting + // in a boxed strip below it, so the transcript runs the full height of the screen. + .safeAreaInset(edge: .bottom) { actionArea } + // Measure the whole detail's height — the screen area the action card must fit within — + // and hand it to the card so it can cap itself and keep Allow/Deny (or Submit) on-screen. + // Measured *after* the safeAreaInset on purpose: this must be the fixed container height, + // not the transcript's inset-reduced height. The attention cards (approval / question) + // size themselves off `availableHeight` via `.frame(maxHeight:)`, so measuring it from the + // inset-reduced region fed the card's own height back into the value it was sized from — a + // layout cycle SwiftUI never resolved, pinning the main thread at 100% CPU during the push + // transition. It bit only the attention path (a card consumes this value; the plain + // composer doesn't), which is why a "Working" tap opened fine and an "attention" tap hung. .background { GeometryReader { proxy in Color.clear.preference(key: AvailableHeightKey.self, value: proxy.size.height) } } .onPreferenceChange(AvailableHeightKey.self) { availableHeight = $0 } - // The chat bar floats over the scrolling content on Liquid Glass instead of sitting - // in a boxed strip below it, so the transcript runs the full height of the screen. - .safeAreaInset(edge: .bottom) { actionArea } .navigationTitle(summary?.title ?? "Session") .navigationBarTitleDisplayMode(.inline) // With a session open the floating chat bar owns the bottom edge, so the compact