From ca067bfe3dbeb2d09601952c6370d36455c8571f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?=
Date: Tue, 30 Jun 2026 12:29:17 +0200
Subject: [PATCH] fix(ui): conform the wellbeing card and fill lone grid items
full-width
The mental-wellbeing instrument card carried a font-medium title and a
gap-4 body, drifting from the medication card it should mirror; bring its
title to text-lg font-semibold and its body to the shared space-y-3.5
rhythm.
Several insight grids left a lone trailing tile stranded at half width
with an empty column beside it. Gate each multi-column grid on having
more than one item so a single tile spans the full row, and give the
fixed five-card mood-correlation grid a trailing-card span so it no
longer orphans on the two-up breakpoint.
Add a little bottom breathing room to the device-score tile so its
rolling-average line no longer reads flush against the card edge.
---
.../insights/derived/vitals-dashboard.tsx | 16 ++++++++++++++--
src/components/insights/device-score-tile.tsx | 2 +-
.../insights/mood/mood-correlation-cards.tsx | 18 ++++++++++++++++--
.../insights/mood/mood-narrative-feed.tsx | 8 +++++++-
.../insights/sleep/sleep-quality-section.tsx | 10 +++++++++-
src/components/labs/lab-list.tsx | 10 +++++++++-
.../mental-health/instrument-card.tsx | 4 ++--
7 files changed, 58 insertions(+), 10 deletions(-)
diff --git a/src/components/insights/derived/vitals-dashboard.tsx b/src/components/insights/derived/vitals-dashboard.tsx
index 76f0c1394..ce6169597 100644
--- a/src/components/insights/derived/vitals-dashboard.tsx
+++ b/src/components/insights/derived/vitals-dashboard.tsx
@@ -784,7 +784,14 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
aria-label={
isLoading ? t("insights.derived.vitals.loadingLabel") : undefined
}
- className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3"
+ className={cn(
+ "grid grid-cols-1 gap-3",
+ // Multi-column only when the skeleton row or more than one tile
+ // fills it; a lone tile spans the full width rather than sitting
+ // in a one-third column with dead space beside it.
+ (isLoading || vitalTiles.length > 1) &&
+ "sm:grid-cols-2 lg:grid-cols-3",
+ )}
>
{isLoading
? Array.from({ length: 6 }).map((_, i) => (
@@ -806,7 +813,12 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
/>
1 && "sm:grid-cols-2 lg:grid-cols-3",
+ )}
>
{mobilityTiles.map((tile) => tile.node)}
diff --git a/src/components/insights/device-score-tile.tsx b/src/components/insights/device-score-tile.tsx
index 178617bb1..40a10fd9c 100644
--- a/src/components/insights/device-score-tile.tsx
+++ b/src/components/insights/device-score-tile.tsx
@@ -121,7 +121,7 @@ export function DeviceScoreTile({
) : null}
-
+
{isLearning ? (
= {
function MoodCorrelationCard({
kind,
data,
+ className,
}: {
kind: MetricKind;
data: MoodMetricCorrelationData;
+ className?: string;
}) {
const { t } = useTranslations();
const hasResult = data.result != null && data.n >= 5;
return (
-
+
@@ -165,7 +171,15 @@ export function MoodCorrelationCards({
-
+ {/* Five fixed cards: on the two-up sm grid the trailing card lands
+ alone in its row, so it spans full width there; the three-up lg
+ grid leaves it paired (row of 3 + row of 2) and it stays one
+ column. */}
+
);
}
diff --git a/src/components/insights/mood/mood-narrative-feed.tsx b/src/components/insights/mood/mood-narrative-feed.tsx
index 2e53c899d..6560ce81d 100644
--- a/src/components/insights/mood/mood-narrative-feed.tsx
+++ b/src/components/insights/mood/mood-narrative-feed.tsx
@@ -14,6 +14,7 @@ import {
import type { ComponentType } from "react";
import { useTranslations } from "@/lib/i18n/context";
+import { cn } from "@/lib/utils";
/**
* v1.8.6 — narrative takeaway feed.
@@ -69,7 +70,12 @@ export function MoodNarrativeFeed({ items }: { items: MoodNarrativeItem[] }) {
// ladder. Lay them two-up on anything wider than a phone; a lone
// takeaway still spans the row rather than orphaning half of it.
1 && "sm:grid-cols-2",
+ )}
data-slot="mood-narrative-feed"
aria-label={t("insights.mood.narrative.title")}
>
diff --git a/src/components/insights/sleep/sleep-quality-section.tsx b/src/components/insights/sleep/sleep-quality-section.tsx
index 7813c07d2..b471c092f 100644
--- a/src/components/insights/sleep/sleep-quality-section.tsx
+++ b/src/components/insights/sleep/sleep-quality-section.tsx
@@ -4,6 +4,7 @@ import { Activity, Gauge, Moon, Repeat, Target, Waves } from "lucide-react";
import { useInsightsAnalytics } from "@/hooks/use-insights-analytics";
import { useTranslations } from "@/lib/i18n/context";
+import { cn } from "@/lib/utils";
import { SectionHeading } from "@/components/insights/section-heading";
import { DeviceScoreTile } from "@/components/insights/device-score-tile";
import { DeviceScoreGridSkeleton } from "@/components/insights/device-score-tile-skeleton";
@@ -111,7 +112,14 @@ export function SleepQualitySection({ enabled }: { enabled: boolean }) {
}
/>
-
+
1 && "sm:grid-cols-2",
+ )}
+ >
{present.map((tile) => (
void } = {}) {
// the line-1 chip, the panel as the category badge. v1.18.10 (#3) — no delete
// control on the tile; the trash icon lives only on the value detail view.
return (
-
+ 1 && "sm:grid-cols-2",
+ )}
+ >
{truncated ? (
-
diff --git a/src/components/mental-health/instrument-card.tsx b/src/components/mental-health/instrument-card.tsx
index be9204a70..2b24cf69b 100644
--- a/src/components/mental-health/instrument-card.tsx
+++ b/src/components/mental-health/instrument-card.tsx
@@ -36,9 +36,9 @@ export function InstrumentCard({
return (
-
+
-
+
{t(`mentalHealth.instrument.${key}`)}