diff --git a/frontend/src/components/NavSidebar.tsx b/frontend/src/components/NavSidebar.tsx
index a2e5d286..c78ca683 100644
--- a/frontend/src/components/NavSidebar.tsx
+++ b/frontend/src/components/NavSidebar.tsx
@@ -201,7 +201,8 @@ export default function NavSidebar({
// Layout slot: reserves only the slim footprint when unpinned, so the expanded rail (below)
// overlays content instead of pushing it. Pinned reserves the full width (in-flow).
// Slim icon rail, flush against the left viewport edge (only top/bottom margin), never grows.
-
+ // The slot is exactly the card's width so the filter tab/bar docks flush against its right edge.
+
box (which is inset by the rail, the header and the scrollbar
-// gutter). Removed on unmount / when disabled / when there's no art.
+// it. Painted on the app root (#root) — which is exactly the viewport and sits BEHIND the transparent
+// nav / header / content — so the art fills the whole page edge-to-edge (under the rail + floating
+// header too), not just the inset box. (A `position:fixed` layer at negative z-index does NOT
+// work here: the body's opaque background is painted over it, so it's invisible; #root's background,
+// being a real ancestor of the content, is the reliable full-viewport layer.) `attachment:fixed`
+// keeps it viewport-anchored while the content scrolls. Cleared on unmount / disable / no art.
export function useArtBackdrop(art: string | null | undefined, enabled: boolean) {
useLayoutEffect(() => {
- if (!enabled || !art) return;
- const el = document.createElement("div");
- el.setAttribute("data-plex-art-backdrop", "");
- el.style.cssText =
- "position:fixed;inset:0;z-index:-1;pointer-events:none;" +
- "background-size:cover;background-position:center 20%;background-repeat:no-repeat;";
- // The faint --bg overlay keeps it subtle and text-safe (same tuning the old paint used).
- el.style.backgroundImage =
- `linear-gradient(color-mix(in srgb, var(--bg) 60%, transparent), ` +
- `color-mix(in srgb, var(--bg) 64%, transparent)), url("${art}")`;
- document.body.appendChild(el);
- return () => el.remove();
+ const el = document.getElementById("root");
+ if (!el) return;
+ const s = el.style;
+ const clear = () => {
+ s.backgroundImage = "";
+ s.backgroundSize = "";
+ s.backgroundPosition = "";
+ s.backgroundRepeat = "";
+ s.backgroundAttachment = "";
+ };
+ if (enabled && art) {
+ // The faint --bg overlay keeps it subtle and text-safe (same tuning the old paint used).
+ s.backgroundImage =
+ `linear-gradient(color-mix(in srgb, var(--bg) 60%, transparent), ` +
+ `color-mix(in srgb, var(--bg) 64%, transparent)), url("${art}")`;
+ s.backgroundSize = "cover";
+ s.backgroundPosition = "center 20%";
+ s.backgroundRepeat = "no-repeat";
+ s.backgroundAttachment = "fixed";
+ } else {
+ clear();
+ }
+ return clear;
}, [art, enabled]);
}