diff --git a/web/src/styles/app.css b/web/src/styles/app.css
index 644d479..ab5daea 100644
--- a/web/src/styles/app.css
+++ b/web/src/styles/app.css
@@ -1679,8 +1679,11 @@ select optgroup { background-color: var(--bg-elev); color: var(--fg); }
one that is open. The panel is positioned against the layout rather than the
scrolling content, so it stays put while the list scrolls under it.
========================================================================== */
-.admin-layout { position: relative; }
-.admin-content { max-width: 960px; }
+/* One column: the section list is in the folder pane (AdminNav), so the
+ table gets the width a second column would take. The height and scrolling
+ are what .settings-layout gave it. */
+.admin-layout { position: relative; height: 100%; min-height: 0; flex: 1; display: flex; flex-direction: column; }
+.admin-content { max-width: 1120px; flex: 1; min-height: 0; }
.admin-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.admin-head .grow { min-width: 220px; }
.admin-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
diff --git a/web/src/views/AppShell.tsx b/web/src/views/AppShell.tsx
index 396ad75..b5f169e 100644
--- a/web/src/views/AppShell.tsx
+++ b/web/src/views/AppShell.tsx
@@ -23,6 +23,7 @@ import { TranslateBoundary } from "@/ui/TranslateBoundary";
import { t } from "@/lib/i18n";
import { hasAdministration } from "@/lib/adminAccess";
import { usePermissions } from "./admin/usePermissions";
+import { AdminNav } from "./admin/AdminNav";
const PUSH_LABEL = {
connected: "Live updates connected",
@@ -213,7 +214,7 @@ export function AppShell({ children }: { children: ReactNode }) {
{section === "contacts" &&