diff --git a/docs/90_current_state.md b/docs/90_current_state.md
index 85b0ab0..8fb00c6 100644
--- a/docs/90_current_state.md
+++ b/docs/90_current_state.md
@@ -129,6 +129,10 @@ Last Updated: 2026-03-16
- `snapshot + start quality + recovery quality + completion quality + carry forward` 구조를 반영
- 기존 `focus-summary` 응답을 주간 review view model로 변환해서 사용
- recovery는 서버의 `pause 뒤 복귀` 집계를 사용하고, `자리 비움 뒤 복귀`만 limited note로 남긴다
+- `/stats` immersive review stage polish:
+ - `/stats`를 밝은 대시보드 카드 반복 화면에서 dark immersive review stage로 재구성했다
+ - 중앙 hero summary, snapshot metric rail, start/recovery/completion panel, carry-forward closure stage를 같은 glass family로 통일했다
+ - carry-forward ritual에 맞는 atmosphere 배경을 얇게 투영해 `/app`과 같은 제품군으로 보이게 정리했다
- `/app -> /stats` primary entry의 1차 연결:
- current session이 없고 최근 7일 데이터가 충분할 때 `/app`의 quiet secondary review dock에서 `Weekly Review` entry를 노출한다
- current session이 있으면 `/app` 자체가 `/space`로 이동하므로, `/app` review entry는 no-session entry shell 안에서만 다룬다
diff --git a/docs/screens/stats/current/14_weekly_review_reframe_spec.md b/docs/screens/stats/current/14_weekly_review_reframe_spec.md
index 919f831..fa7bcc7 100644
--- a/docs/screens/stats/current/14_weekly_review_reframe_spec.md
+++ b/docs/screens/stats/current/14_weekly_review_reframe_spec.md
@@ -147,6 +147,14 @@ VibeRoom의 review는 아래처럼 포지셔닝해야 한다.
Weekly Review는 `/stats` 안에서 아래 5개 구역으로 재구성한다.
+### 현재 visual shell 원칙
+
+- `/stats`는 밝은 factual dashboard가 아니라 dark immersive review stage로 간다
+- 배경은 carry-forward ritual과 연결되는 atmosphere를 얇게 투영한다
+- 상단은 quiet accessory만 두고, hero summary가 화면의 중심이 된다
+- snapshot metrics는 작은 glass tile rail로, start/recovery/completion은 같은 family의 review panel로 통일한다
+- 마지막 carry-forward CTA는 별도 버튼 묶음이 아니라 다음 세션 entry로 자연스럽게 이어지는 closure stage여야 한다
+
### Section A. Weekly Snapshot
목적:
diff --git a/docs/session_brief.md b/docs/session_brief.md
index ab3e7ac..53c56ce 100644
--- a/docs/session_brief.md
+++ b/docs/session_brief.md
@@ -107,6 +107,9 @@ Last Updated: 2026-03-16
- hero snapshot, start quality, recovery quality, completion quality, carry forward 구조를 사용한다.
- 기존 `focus-summary` 응답은 review view model로 변환해서 쓴다.
- recovery는 서버의 `pause 뒤 복귀` 집계를 사용하고, `away recovery`만 limited state로 남긴다.
+- `/stats` immersive review stage polish를 반영했다.
+ - dark atmosphere 배경 위에 중앙 hero summary, snapshot metric rail, review panel, carry-forward closure stage를 같은 glass family로 재구성했다.
+ - `/app`의 premium immersive tone과 같은 제품군으로 읽히도록 `/stats`의 위계와 재질을 다시 맞췄다.
- `/app`에서 `/stats`로 들어가는 primary path 1차가 생겼다.
- current session이 없을 때는 quiet review dock에서 `/stats`로 진입할 수 있다.
- review entry는 main start CTA보다 항상 낮은 강조를 유지한다.
diff --git a/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx b/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx
index dc692ce..fbf7e99 100644
--- a/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx
+++ b/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx
@@ -1,12 +1,52 @@
'use client';
import Link from 'next/link';
+import { useMemo } from 'react';
+import { useMediaCatalog, getSceneStageBackgroundStyle } from '@/entities/media';
import { usePlanTier } from '@/entities/plan';
+import { getSceneById, SCENE_THEMES } from '@/entities/scene';
import { useFocusStats } from '@/features/stats';
import { copy } from '@/shared/i18n';
import { cn } from '@/shared/lib/cn';
-const ReviewMetric = ({
+const glassPanelClass =
+ 'rounded-[2rem] border border-white/10 bg-[linear-gradient(160deg,rgba(8,12,18,0.46)_0%,rgba(8,12,18,0.2)_58%,rgba(8,12,18,0.52)_100%)] shadow-[0_24px_80px_rgba(3,7,18,0.28)] backdrop-blur-[24px]';
+const metricTileClass =
+ 'rounded-[1.45rem] border border-white/10 bg-[linear-gradient(145deg,rgba(255,255,255,0.08)_0%,rgba(255,255,255,0.04)_100%)] px-4 py-4 backdrop-blur-xl';
+
+const DEFAULT_STATS_SCENE_ID = getSceneById('forest')?.id ?? SCENE_THEMES[0].id;
+
+const reviewStageSceneByPreset = (presetId: string) => {
+ if (presetId.startsWith('forest')) {
+ return getSceneById('forest') ?? SCENE_THEMES[0];
+ }
+
+ return getSceneById(DEFAULT_STATS_SCENE_ID) ?? SCENE_THEMES[0];
+};
+
+const StatusAccessory = ({
+ label,
+ subtle = false,
+}: {
+ label: string;
+ subtle?: boolean;
+}) => {
+ return (
+
+
+ {label}
+
+ );
+};
+
+const SnapshotMetric = ({
label,
value,
hint,
@@ -16,10 +56,10 @@ const ReviewMetric = ({
hint: string;
}) => {
return (
-
-
{label}
-
{value}
-
{hint}
+
+
{label}
+
{value}
+
{hint}
);
};
@@ -30,35 +70,36 @@ const ReviewSection = ({
metrics,
availability,
note,
- toneClass,
+ accentClass,
}: {
title: string;
summary: string;
metrics: Array<{ id: string; label: string; value: string; hint: string }>;
availability: 'ready' | 'limited';
note?: string;
- toneClass: string;
+ accentClass: string;
}) => {
return (
-
-
-
+
+
+
-
-
{title}
-
{summary}
+
+
+ Weekly Review
+
+
+ {title}
+
+
{summary}
- {availability === 'limited' ? (
-
- Limited
-
- ) : null}
+ {availability === 'limited' ?
: null}
{metrics.length > 0 ? (
{metrics.map((metric) => (
-
+
{note}
) : null}
@@ -81,143 +122,179 @@ const ReviewSection = ({
export const StatsOverviewWidget = () => {
const { stats } = copy;
const { isPro } = usePlanTier();
+ const { sceneAssetMap } = useMediaCatalog();
const { review, isLoading, error, source, refetch } = useFocusStats();
+
+ const activeScene = useMemo(
+ () => reviewStageSceneByPreset(review.carryForward.presetId),
+ [review.carryForward.presetId],
+ );
+ const sourceLabel = source === 'api' ? stats.sourceApi : stats.sourceMock;
+ const syncLabel = error ? error : isLoading ? stats.loading : stats.synced;
const carryForwardCtaLabel = isPro ? stats.reviewCarryCtaPro : review.carryForward.ctaLabel;
return (
-
-
-
-
-
- {review.periodLabel}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{review.snapshotTitle}
+
+
+ {review.snapshotSummary}
+
+ {syncLabel}
+
+
-
-
-
- {copy.common.hub}
-
-
-
+
+ {review.snapshotMetrics.map((metric) => (
+
+ ))}
+
-
-
-
-
-
- {source === 'api' ? stats.sourceApi : stats.sourceMock}
-
-
- {review.snapshotSummary}
-
-
- {error ? error : isLoading ? stats.loading : stats.synced}
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Carry Forward
+
+
+ 다음 세션에 그대로 가져갈 흐름
+
+
+ {review.carryForward.keepDoing}
+
+
+
+ {isPro ?
: null}
-
- {review.snapshotMetrics.map((metric) => (
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {review.periodLabel}
-
-
- {stats.reviewCarryKeepTitle}
-
-
- {review.carryForward.keepDoing}
-
-
-
-
- {stats.reviewCarryTryTitle}
-
-
+
+
+
+ 다음 주에 바꿔볼 것
+
+
{review.carryForward.tryNext}
- {isPro ? (
-
-
- {stats.reviewCarryPresetLabel}
-
-
- {review.carryForward.presetLabel}
-
-
- ) : null}
+
+
+ Atmosphere
+
+
+ {review.carryForward.presetLabel}
+
+
+ 지금 가장 무리 없이 다시 들어갈 수 있는 기본 흐름입니다.
+
+
+
+
+
+
+ review는 지난 시간을 요약하는 화면이 아니라, 다음 세션을 더 가볍게 열기 위한
+ 출발점입니다.
+
{carryForwardCtaLabel}
-
-
-
-
+
+
+
+
);
};