From b07d77cbfa88393c0f45e07393a6c8bc8b179fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 7 Jun 2026 17:53:45 +0200 Subject: [PATCH] feat(insights): premium polish for the wellness score detail view - carry the ring's per-metric tint onto the score-anatomy detail card so the tap-through reads as the same surface deepened, not a plain card - pad the hero ring so its bloom is no longer clipped top/bottom - lighten the detail card toward the bottom with a subtle theme-aware gradient - drop the "keine klinische Bewertung" footer line; the non-clinical framing stays behind the provenance explainer, the composition rows stay - move the info explainer from the card foot to the top-right corner at heading height; popover/sheet behaviour unchanged --- src/app/globals.css | 31 ++++++++ .../__tests__/score-anatomy-view.test.tsx | 22 +++++- .../derived/composite-score-anatomy.tsx | 17 +++++ .../insights/derived/score-anatomy-view.tsx | 72 +++++++++++++------ 4 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 254e94612..784f52bb8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -513,6 +513,37 @@ pointer-events: none; } +/* + * v1.15.12 (F1/F3) — `.wellness-detail-card` is the score-anatomy detail + * surface, deepened to match the dashboard ring tile the user tapped. + * + * F1 — carries the SAME per-metric `--tile-hue` mix over the theme `--card` + * as `.wellness-tile`, so the tap-through reads as the same surface + * rather than a plain bordered card. The hue is set inline per metric. + * F3 — a SUBTLE vertical gradient that lightens toward the BOTTOM: the top + * carries a touch more of the hue (16%) and it eases to 6% at the foot, + * giving the card a premium, lit-from-below depth. Theme-aware by + * construction — both stops mix over the theme `--card`, so it stays + * luminous on the white Alucard card and rich on the dark Dracula one. + * Kept minimal (a 10pp swing) so it never reads as a heavy slab. + * + * Static, no hover lift (it is a page surface, not a tap target) — so it + * needs no reduced-motion handling. + */ +.wellness-detail-card { + --tile-hue: var(--dracula-purple); + position: relative; + overflow: hidden; + background: linear-gradient( + 180deg, + color-mix(in srgb, var(--tile-hue) 16%, var(--card)) 0%, + color-mix(in srgb, var(--tile-hue) 6%, var(--card)) 100% + ); + border: 1px solid color-mix(in srgb, var(--tile-hue) 22%, transparent); + box-shadow: 0 12px 34px -28px + color-mix(in srgb, var(--tile-hue) 42%, transparent); +} + @media (hover: hover) { .wellness-tile:hover { transform: translateY(-2px); diff --git a/src/components/insights/derived/__tests__/score-anatomy-view.test.tsx b/src/components/insights/derived/__tests__/score-anatomy-view.test.tsx index ddca7518a..e5cd9ba76 100644 --- a/src/components/insights/derived/__tests__/score-anatomy-view.test.tsx +++ b/src/components/insights/derived/__tests__/score-anatomy-view.test.tsx @@ -53,7 +53,27 @@ describe("", () => { expect(html).toContain('data-contributor="respiratory"'); expect(html).toContain('data-present="false"'); expect(html).toContain('data-slot="provenance-explainer-trigger"'); - expect(html).toContain('data-slot="score-anatomy-disclaimer"'); + // v1.15.12 F4 — the "keine klinische Bewertung" footer line is removed; + // the non-clinical framing now lives behind the provenance explainer. + expect(html).not.toContain('data-slot="score-anatomy-disclaimer"'); + }); + + it("tints the card + leans the ring hue when a hue is passed (F1)", () => { + const html = render( + , + ); + expect(html).toContain('data-tinted="true"'); + expect(html).toContain("wellness-detail-card"); + expect(html).toContain("--tile-hue"); }); it("renders the insufficient state with the provisional ring + nudge", () => { diff --git a/src/components/insights/derived/composite-score-anatomy.tsx b/src/components/insights/derived/composite-score-anatomy.tsx index dd7bd263f..76c3585b3 100644 --- a/src/components/insights/derived/composite-score-anatomy.tsx +++ b/src/components/insights/derived/composite-score-anatomy.tsx @@ -12,6 +12,7 @@ import { ScoreAnatomyView, type AnatomyContributor, } from "./score-anatomy-view"; +import type { RingHue } from "./ring-hues"; import { METRIC_PROVENANCE } from "./standards"; /** @@ -51,6 +52,20 @@ export interface CompositeScoreAnatomyProps { className?: string; } +/** + * v1.15.12 F1 — each anatomy metric maps to the same ring hue its dashboard + * tile wears, so the detail card carries the matching tint + the ring arc + * leans the same colour (continuity from the tile tap). Mirrors the per-metric + * `hue` the wellness strip passes its `RingTile`s. + */ +const METRIC_HUE: Record = { + SLEEP_SCORE: "sleep", + READINESS: "readiness", + RECOVERY_SCORE: "recovery", + STRESS_SCORE: "stress", + STRAIN_SCORE: "strain", +}; + export function CompositeScoreAnatomy({ metric, className, @@ -117,6 +132,7 @@ export function CompositeScoreAnatomy({ + {/* v1.15.12 F5 — the ⓘ explainer is pinned TOP-right at heading height + (it used to trail the card at bottom-right). Absolute so it never + shifts the centred hero title; the trigger keeps its 44px touch + target + popover/sheet behaviour. */} +
+ +
+ {/* Hero: title + ring + caption */}

{title}

- + {/* v1.15.12 F2 — vertical breathing room so the ring's bloom/glow is + never clipped top/bottom by the hero container. */} +
+ +
{caption && !insufficient ? (

)} - {/* Provenance + cited standard + the non-clinical disclaimer */} -

-

- {t("insights.derived.anatomy.disclaimer")} -

- -
+ {/* v1.15.12 F4 — the "Richtwert — keine klinische Bewertung" footer line + is gone; the method + cited standard live behind the provenance + explainer (now top-right, F5), which carries the non-clinical framing + where it belongs. The composition (contributor rows above) stays. */} ); }