+ {/* v1.4.27 MB7 / CF-61 — drop `p-8` to `p-6 sm:p-8` so the
+ auth card breathes on Galaxy Fold / Pixel 5 without stealing
+ half the visible viewport with padding. Tablet+ keeps the
+ generous 32 px padding. */}
+
+ {/* v1.4.27 MB7 / CF-61 — drop `p-8` to `p-6 sm:p-8` so the
+ auth card breathes on Galaxy Fold / Pixel 5 without stealing
+ half the visible viewport with padding. Tablet+ keeps the
+ generous 32 px padding. */}
+
-
-
+ {/* v1.4.27 MB7 / MA2-F8 — `min-w-0` on the title
+ wrapper + `truncate` on the CardTitle keeps long
+ medication names (e.g. "Semaglutid Wegovy 0.5 mg
+ weekly") from pushing the streak badge off the
+ card on Galaxy Fold / Pixel 5. The Pill icon
+ + CardTitle pair shrinks to fit; the badge stays
+ on the right at its natural width. */}
+
+
+
+
{med.name}
{med.streak > 0 && (
-
+
{t("insights.dayStreak", { count: med.streak })}
)}
diff --git a/src/components/insights/daily-briefing.tsx b/src/components/insights/daily-briefing.tsx
index d01782af8..b375676a7 100644
--- a/src/components/insights/daily-briefing.tsx
+++ b/src/components/insights/daily-briefing.tsx
@@ -1,5 +1,6 @@
"use client";
+import Link from "next/link";
import {
Activity,
FileText,
@@ -30,6 +31,33 @@ import type {
DailyBriefingKeyFinding,
} from "@/lib/ai/schema";
+/**
+ * v1.4.27 MB7 / CF-68 — per-metric routing target for the briefing
+ * key findings. Maps the schema's `sourceMetric` discriminator to the
+ * sub-page slug that owns the deeper view. Metrics that don't have a
+ * dedicated routed sub-page yet (hrv, resting_hr, steps, …) fall
+ * through to `null` and render as a plain row (no link wrap).
+ */
+const METRIC_HREF: Record = {
+ bp: "/insights/blutdruck",
+ weight: "/insights/gewicht",
+ pulse: "/insights/puls",
+ mood: "/insights/stimmung",
+ compliance: "/insights/medikamente",
+ // Apple Health / GLP-1 additive metrics — no dedicated sub-page yet.
+ // They render as static rows; v1.4.28 can wire each as they ship.
+ hrv: null,
+ sleep: "/insights/schlaf",
+ resting_hr: null,
+ steps: null,
+ active_energy: null,
+ flights: null,
+ distance: null,
+ vo2_max: "/insights/puls",
+ body_temp: null,
+ glp1_plateau: "/insights/medikamente",
+};
+
/**
* v1.4.20 phase B1 — full-width Daily Briefing card.
*
@@ -128,11 +156,15 @@ function DeltaBadge({
function KeyFindingRow({ finding }: { finding: DailyBriefingKeyFinding }) {
const Icon = METRIC_ICON[finding.sourceMetric];
- return (
-
+ const href = METRIC_HREF[finding.sourceMetric];
+ // v1.4.27 MB7 / CF-68 — when the briefing's `sourceMetric` maps to
+ // a routed sub-page, wrap the entire row in a `` so the
+ // whole card is tappable on mobile instead of the user having to
+ // hit the small headline text. Hover + focus paint a subtle bg
+ // shift; metrics that don't have a sub-page yet render the
+ // original static row.
+ const rowContent = (
+ <>
);
}
diff --git a/src/components/insights/insights-tab-strip.tsx b/src/components/insights/insights-tab-strip.tsx
index d6882ec36..f9be8acfb 100644
--- a/src/components/insights/insights-tab-strip.tsx
+++ b/src/components/insights/insights-tab-strip.tsx
@@ -137,6 +137,13 @@ export function InsightsTabStrip({
data-slot="insights-tab-strip"
aria-label={t("insights.navAriaLabel")}
className={cn(
+ // v1.4.27 MB7 / CF-72 — relative wrapper hosts the right-edge
+ // fade overlay below so the user reads "there's more to
+ // scroll" when the pill row overflows. The fade is a tiny
+ // pointer-events-none pseudo-strip painted onto the inner
+ // strip via a sibling div; it sits only on `
+ {/* v1.4.27 MB7 / CF-72 — right-edge fade. The gradient
+ absolute-positions over the rightmost ~24 px of the strip
+ so the last visible pill softly fades into the background
+ colour, signalling "scroll for more" without a scrollbar.
+ Only paints on `
{onRegenerate && (
{WINDOW_DAYS.map((w) => (
diff --git a/src/components/insights/trends-row.tsx b/src/components/insights/trends-row.tsx
index 4ef8ec119..afd0304d3 100644
--- a/src/components/insights/trends-row.tsx
+++ b/src/components/insights/trends-row.tsx
@@ -105,13 +105,17 @@ export function TrendsRow({ annotations, confidence }: TrendsRowProps) {
v1.4.25 W3 — strengthen the equal-height contract with
`md:auto-rows-fr` + `md:items-stretch` on the grid and
`h-full` on each card so the tallest annotation still pins
- every row member to a single baseline. The `min-h-[300px]`
- floor stays in place for the single-column mobile view. */}
+ every row member to a single baseline.
+
+ v1.4.27 MB7 / CF-71 — drop the unconditional `min-h-[300px]`
+ floor to `md:min-h-[300px]` so mobile single-column doesn't
+ eat dead space below a short chart; the floor stays on `md+`
+ to preserve the equal-height baseline across the row. */}
-
+ {/* v1.4.27 MB7 / CF-46 — the filter row stacks the SelectTrigger
+ and the count caption vertically on `
)}
+ {/* v1.4.27 MB7 / CF-76 — bump the metadata
+ badges from `text-[10px]` to `text-[11px]`
+ so the legibility floor (12 px is the
+ mobile baseline; 11 px is the lowest
+ tolerated value for non-primary chrome)
+ holds across the row. The badge heights
+ stay at `h-5` / `h-4` since the type-
+ preface badge owns vertical real estate
+ inside the headline line. */}
{(m.type === "BLOOD_PRESSURE_SYS" ||
m.type === "BLOOD_PRESSURE_DIA") && (
{t(TYPE_LABEL_KEYS[m.type])}
@@ -519,7 +534,7 @@ export function MeasurementList({ onEdit, onAddFirst }: MeasurementListProps) {
{formatMeasurementSource(m.source, t)}
diff --git a/src/components/settings/account-section.tsx b/src/components/settings/account-section.tsx
index c40e98410..3cded990b 100644
--- a/src/components/settings/account-section.tsx
+++ b/src/components/settings/account-section.tsx
@@ -833,11 +833,17 @@ function PasskeyListSection({ isAuthenticated }: { isAuthenticated: boolean }) {
+ {/* v1.4.27 MB7 / CF-75 — promote the device-type from
+ plain text to an outline Badge so the mobile card
+ list reads consistent with the desktop table's
+ "Single-device / Multi-device" column. Sits on the
+ same chip row as the backup status and date so all
+ metadata reads as a single horizontal stride. */}