diff --git a/changelog.d/20261028-split-update-actions.md b/changelog.d/20261028-split-update-actions.md
new file mode 100644
index 0000000..c3a14f6
--- /dev/null
+++ b/changelog.d/20261028-split-update-actions.md
@@ -0,0 +1,7 @@
+---
+area: manager
+type: changed
+audience: admins
+title: Update and launch without updating share a divided button
+---
+Server and game client actions each use two adjacent segments of equal height. Both actions remain visible and keep their own availability checks.
diff --git a/changelog.d/20261028-window-density.md b/changelog.d/20261028-window-density.md
new file mode 100644
index 0000000..e987242
--- /dev/null
+++ b/changelog.d/20261028-window-density.md
@@ -0,0 +1,7 @@
+---
+area: manager
+type: fixed
+audience: admins
+title: Maximizing the window keeps text and controls at a comfortable size
+---
+The interface no longer enlarges with window width. System display scaling and browser zoom still work, and large action buttons use more compact spacing.
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index c9280ed..8511595 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -15,7 +15,7 @@ const buttonVariants = cva(
size: {
sm: "h-9 px-3 text-sm",
md: "h-11 px-5 text-[15px]",
- xl: "h-16 px-10 text-lg tracking-wide",
+ xl: "h-12 px-6 text-base",
},
},
defaultVariants: { variant: "secondary", size: "md" },
diff --git a/src/components/ui/split-button.tsx b/src/components/ui/split-button.tsx
new file mode 100644
index 0000000..023bd2e
--- /dev/null
+++ b/src/components/ui/split-button.tsx
@@ -0,0 +1,15 @@
+import { Button, type ButtonProps } from "./button";
+
+/** Two explicit actions, each with its own enabled state and keyboard focus. */
+export function SplitButton({ label, primary, secondary }: {
+ label: string;
+ primary: ButtonProps;
+ secondary: ButtonProps;
+}) {
+ return
+
+
+
;
+}
diff --git a/src/index.css b/src/index.css
index 13ef63c..8b4150b 100644
--- a/src/index.css
+++ b/src/index.css
@@ -16,10 +16,10 @@
--font-sans: "Segoe UI Variable Text", "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei", system-ui, sans-serif;
}
-/* Everything is sized in rem, so scaling the root font grows the whole interface with the window
- (16px up to about 1280px wide, then gradually larger; capped at 26px). */
+/* Window size changes layout, not UI density. Keep rem tied to the user's default
+ font size; browser zoom and operating-system display scaling still apply. */
html {
- font-size: clamp(16px, calc(0.75vw + 6.4px), 26px);
+ font-size: 100%;
}
html,
diff --git a/src/screens/Overview.tsx b/src/screens/Overview.tsx
index f1b6057..5185592 100644
--- a/src/screens/Overview.tsx
+++ b/src/screens/Overview.tsx
@@ -15,6 +15,7 @@ import { PublishRealmDialog } from "@/screens/PublishDialog";
import { useRegistryStatus } from "@/lib/registry";
import { usePublishRealms, type PublishRealm } from "@/lib/publishRealms";
import { useAutoRestart } from "@/lib/autoRestartPrefs";
+import { SplitButton } from "@/components/ui/split-button";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
@@ -410,32 +411,21 @@ export function Overview({ server, companions = true, onForget, onOpenUpdates, o
{running ? (
-
diff --git a/src/screens/RealmlistMenu.tsx b/src/screens/RealmlistMenu.tsx
index b230f94..faf8530 100644
--- a/src/screens/RealmlistMenu.tsx
+++ b/src/screens/RealmlistMenu.tsx
@@ -92,7 +92,7 @@ export function RealmlistMenu({ serverId, className }: { serverId: string; class
onClick={() => setOpen((v) => !v)}
aria-haspopup="menu"
aria-expanded={open}
- className="flex h-16 cursor-pointer items-center gap-3 rounded-md border border-line bg-card-2 px-4 text-left transition-colors hover:border-gold/50"
+ className="flex h-12 cursor-pointer items-center gap-3 rounded-md border border-line bg-card-2 px-4 text-left transition-colors hover:border-gold/50"
>
{t("realm.label")}
diff --git a/tools/overview-update-error.test.mjs b/tools/overview-update-error.test.mjs
index d5d52d0..eabc282 100644
--- a/tools/overview-update-error.test.mjs
+++ b/tools/overview-update-error.test.mjs
@@ -28,6 +28,7 @@ const bundle = await rolldown({
external: (id, importer) => id === "react/jsx-runtime" || id === "lucide-react" || (id === "react" && !importer?.endsWith("Overview.tsx")),
plugins: [{ name: "overview-test",
resolveId(id, importer) {
+ if (id === "@/components/ui/split-button") return fileURLToPath(new URL("../src/components/ui/split-button.tsx", import.meta.url));
if (id.startsWith("@/") || (id === "react" && importer?.endsWith("Overview.tsx"))) return "\0" + id;
},
load(id) {