diff --git a/src/app/notifications/page.tsx b/src/app/notifications/page.tsx
index ba17b08c5..f84bc2fbd 100644
--- a/src/app/notifications/page.tsx
+++ b/src/app/notifications/page.tsx
@@ -201,6 +201,7 @@ export default function NotificationsPage() {
title={t("notifications.title")}
description={t("notifications.subtitle")}
actions={headerActions}
+ stackActionsOnPhone
/>
{/* Desktop: table layout */}
diff --git a/src/components/ui/page-header.tsx b/src/components/ui/page-header.tsx
index e806e5294..c6e8ef28e 100644
--- a/src/components/ui/page-header.tsx
+++ b/src/components/ui/page-header.tsx
@@ -26,6 +26,15 @@ import { cn } from "@/lib/utils";
* shells hand-rolled the whole block to get the second copy, which is how
* they drifted apart from every module page in the first place.
*/
+/**
+ * A one-word German title ("Krankheitstagebuch") is wider than the column a
+ * phone leaves beside the actions, and without a break opportunity it ran
+ * underneath them. `hyphens-auto` breaks it by the page's `lang`; the
+ * `wrap-break-word` floor covers a word the hyphenation dictionary does not.
+ */
+const HEADING_CLASS =
+ "text-2xl font-bold tracking-tight hyphens-auto wrap-break-word";
+
export function PageHeader({
title,
titleId,
@@ -34,6 +43,7 @@ export function PageHeader({
backLink,
topSlot,
actions,
+ stackActionsOnPhone = false,
className,
}: {
title: ReactNode;
@@ -44,37 +54,65 @@ export function PageHeader({
/** Optional block above the title (e.g. a hub back-link the shell owns). */
topSlot?: ReactNode;
actions?: ReactNode;
+ /**
+ * Below `sm`, move the actions onto their own row under the description.
+ * For text-labelled actions (two outline links, say): beside the title they
+ * left the H1 a column narrower than its own word. Icon actions fit beside
+ * the title and leave this off.
+ */
+ stackActionsOnPhone?: boolean;
className?: string;
}) {
const heading =
headingAs === "div" ? (
-
+
{title}
) : (
-
+
{title}
);
+ // Title, description and actions share one grid. On a phone the
+ // description spans the full row under the title + actions: a header with
+ // three or four icon actions otherwise left the sentence a ~130 px column
+ // that wrapped five or six times. From `sm` up the actions span both rows,
+ // so the description sits beside them exactly as before.
return (
{backLink ?
: null}
{topSlot}
-
-
- {heading}
- {description ? (
-
{description}
- ) : null}
-
+
+
{heading}
{actions ? (
-
{actions}
+
+ {actions}
+
+ ) : null}
+ {description ? (
+
+ {description}
+
) : null}