diff --git a/clients/apple/Sources/PunktfunkClient/Home/GamepadChrome.swift b/clients/apple/Sources/PunktfunkClient/Home/GamepadChrome.swift index 8391a3b1..44334423 100644 --- a/clients/apple/Sources/PunktfunkClient/Home/GamepadChrome.swift +++ b/clients/apple/Sources/PunktfunkClient/Home/GamepadChrome.swift @@ -385,15 +385,23 @@ struct GamepadTrayScrim: View { LinearGradient( stops: [ .init(color: .black, location: 0), - .init(color: .black.opacity(0.9), location: 0.5), + .init(color: .black.opacity(0.92), location: 0.55), .init(color: .clear, location: 1), ], startPoint: fromEdge, endPoint: toContent) } // Grow past the tray so the fade-to-clear happens OUTSIDE its bounds — the tray's own - // text always sits on the strong part, rows blur out before they reach it. - .padding(edge == .top ? .bottom : .top, -32) + // text always sits on the strong part, rows blur out before they reach it. The bottom + // gets the longer runway: its tray sits over SCROLLING rows plus the detail line, and + // the field verdict on the short reach was rows colliding visibly with the legend. + .padding(edge == .top ? .bottom : .top, edge == .top ? -44 : -72) .ignoresSafeArea() + // This view's geometry must NEVER animate: mounted inside a pushed shell layer, the + // full-bleed growth above (the negative padding and the safe-area expansion) rode the + // push's transaction, so the blur visibly entered at content bounds and grew into + // place — and `.geometryGroup()` on the layer does not reach safe-area resolution. + // The layer's own fade/slide still carries the scrim; only its SHAPE is pinned. + .transaction { $0.animation = nil } } } diff --git a/clients/apple/Sources/PunktfunkClient/Home/GamepadHomeView.swift b/clients/apple/Sources/PunktfunkClient/Home/GamepadHomeView.swift index 8c7a6eef..8a826ad1 100644 --- a/clients/apple/Sources/PunktfunkClient/Home/GamepadHomeView.swift +++ b/clients/apple/Sources/PunktfunkClient/Home/GamepadHomeView.swift @@ -124,10 +124,10 @@ struct GamepadHomeView: View { #if os(iOS) if let screen = topScreen { screenLayer(screen) - // Resolve the screen's internal layout (safe-area trays, the scrims' - // `.ignoresSafeArea()` full-bleed) BEFORE the insertion animates: without - // this the tray blurs entered at their content bounds and visibly grew to - // the screen edges mid-push. + // Settle the screen's internal layout before the insertion animates, so + // descendants never lerp from a half-resolved first frame. (Not sufficient + // for the tray blurs on its own — safe-area expansion resolves outside a + // geometry group; GamepadTrayScrim pins its own geometry too.) .geometryGroup() .zIndex(1) .id(screen.id) diff --git a/clients/apple/Sources/PunktfunkClient/Settings/GamepadSettingsView.swift b/clients/apple/Sources/PunktfunkClient/Settings/GamepadSettingsView.swift index b044af86..4358cddc 100644 --- a/clients/apple/Sources/PunktfunkClient/Settings/GamepadSettingsView.swift +++ b/clients/apple/Sources/PunktfunkClient/Settings/GamepadSettingsView.swift @@ -257,10 +257,12 @@ struct GamepadSettingsView: View { .padding(.vertical, 7) .background { // One shared capsule that MOVES between pills, rather than one per pill fading - // in and out — the highlight travels the way the press did. + // in and out — the highlight travels the way the press did. A Liquid Glass + // surface (accent-tinted through consoleGlass), so the strip wears the same + // material language as the rows it sits above. if selected { - Capsule() - .fill(ink.accent(0.85)) + Color.clear + .consoleGlass(Capsule(), tint: ink.accent(0.85)) .matchedGeometryEffect(id: "tab", in: tabHighlight) } }