diff --git a/.planning/phases/08-engagement-user-profile-new/08-CONTEXT.md b/.planning/phases/08-engagement-user-profile-new/08-CONTEXT.md
new file mode 100644
index 0000000..4f57bc0
--- /dev/null
+++ b/.planning/phases/08-engagement-user-profile-new/08-CONTEXT.md
@@ -0,0 +1,167 @@
+# Phase 8: Engagement User Profile (NEW) - Context
+
+**Gathered:** 2026-05-07
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+A real, shareable per-employee profile page at `/mobile/engagement/[userId]` rendering identity → period selector → 4 hero metrics (2×2 grid) → categorized activity breakdown → two recent-items sections (time entries + meetings). Sourced from existing engagement endpoints (no new data). Replaces the desktop user-detail modal pattern on mobile only — desktop stays as-is.
+
+Scope anchor (from ROADMAP.md): tapping an Engagement overview row navigates to `/mobile/engagement/[userId]`; the profile is a real page so the device back gesture returns to the overview at the same scroll position; layout is single-column per ENG-06; reuses existing endpoints per ENG-08.
+
+
+
+
+## Implementation Decisions
+
+### Route, segment, and shell integration
+- **D-01:** New page at `app/mobile/engagement/[userId]/page.tsx`. The `EngagementUserRow` component (Phase 7, `components/mobile/EngagementUserRow.tsx`) already renders an entire-row `Link` to `/mobile/engagement/[graphUserId]` per Phase 7 D-19 — Phase 8 owns the destination. **Do NOT modify `EngagementUserRow.tsx`.**
+- **D-02:** `'use client'` + `useState` + `useEffect` + `fetch` (CLAUDE.md: no SWR/react-query, match Phase 7 pattern).
+- **D-03:** `[userId]` in the route segment is the `graph_users.id` (UUID-like string from Microsoft Graph), matching the existing `/api/engagement/user/[userId]` endpoint contract. Not the Better Auth `user.id`. Same convention used by Phase 7's `EngagementUserRow.graphUserId`.
+- **D-04:** Scroll restoration to overview: rely on Next.js App Router's default `scrollRestoration: true` — `Link` prefetch + browser back/forward restores scroll position automatically. No `sessionStorage` workaround needed unless the planner discovers the default doesn't hold. Treat as "verify in execution; if broken, then mitigate."
+
+### Identity header
+- **D-05:** Avatar source — Microsoft Graph photo with **initials fallback** when no photo is available. Use the existing `getMsgraphClient()` factory and a server-side photo fetch through a new thin endpoint (e.g. `/api/mobile/engagement/user/[userId]/photo` returning a small JPEG or 404). Initials computed via Phase 7's exported `getInitials(displayName)` helper from `EngagementUserRow.tsx`.
+- **D-06:** Fields under name (in this stacked order):
+ 1. **Job title** — `graph_users.job_title`
+ 2. **Department** — `graph_users.department` (omit row if NULL)
+ 3. **Email** — `graph_users.email`, rendered as `mailto:` link
+ 4. **Last active** — most recent of (`time_entries.entry_date`, last `engagement_snapshots` activity timestamp), formatted via `useUserTimezone()`. Display as relative if ≤7 days ("2 hours ago"), absolute if older ("2026-04-15"). Omit row if no signal.
+- **D-07:** Header card uses `Card` + `CardContent` with horizontal layout: avatar (left, ~56px) + identity stack (right). No subtitle, no role badge — the four rows above carry sufficient identity weight on a phone.
+
+### Period selector
+- **D-08:** Reuse Phase 7's `EngagementPeriodChips` component as-is. 3 chips: `7d` / `30d` / `90d` mapping to `D7`/`D30`/`D90`.
+- **D-09:** **Default period = `D30`** (matches Phase 7 overview default, preserves user's mental model carried from the previous screen).
+- **D-10:** Sticky behavior: same as Phase 7 — `sticky top-0 z-10 bg-background pt-2 pb-3 -mx-4 px-4` so chips run edge-to-edge while metrics scroll above. Header card scrolls under the chips.
+
+### Key metrics — 2×2 grid (4 hero metrics)
+- **D-11:** **Layout:** 2×2 grid of `Card` + `CardContent`, mirroring Phase 3 dashboard KPI grid. Each card: big number (`text-2xl font-semibold`), small label (`text-xs text-muted-foreground`), optional inline qualifier. `gap-3` between cards, no shadows (matches Phase 7 D-10).
+- **D-12:** **Hero metrics** (in reading order: top-left, top-right, bottom-left, bottom-right):
+ 1. **Hours worked** — sum of `time_entries.hours_worked` over the selected period
+ 2. **Billable hours** — sum where `billable = true`
+ 3. **Days worked** — distinct `entry_date` count
+ 4. **Meetings attended** — `teams_meetings_attended` summed over the period from `engagement_snapshots`
+- **D-13:** When the value is `0` or `NULL`, render `0` (not `—`). When the user has no activity at all, render the cards with zeros — empty-state messaging belongs at the recent-items section, not the metric grid.
+
+### Activity breakdown — categorized rows
+- **D-14:** Below the metric grid, a **single `Card`** with three labeled subsections in this order:
+ 1. **Time** — Hours worked / Billable hours / Days worked / utilization% (billable ÷ hours, if applicable)
+ 2. **Communication** — Teams messages (chat + private summed) / Emails sent / **After-hours: X% of messages, Y% of meetings** (the after-hours signal lives here, per D-15)
+ 3. **Meetings** — Meetings attended / Meetings organized / Total meeting duration (hours, from `meeting_duration_seconds`) / Zoom calls (only if `zoom` block in the response is non-null)
+- **D-15:** **After-hours** signal — single row inside Communication: `After-hours · {messagesPct}% messages, {meetingsPct}% meetings`. Tucked in, not callout-styled. Hide row when both are 0%.
+- **D-16:** Each subsection is a label (`text-sm font-medium text-muted-foreground`) followed by metric rows (label left, value right, `flex justify-between text-sm py-1.5`). No charts, no sparklines — keeps render light and matches DASH-04 / Phase 7 §6.5 ("no multi-series chart on mobile").
+- **D-17:** Hide a row entirely when its underlying field is `null` or `0` AND it's a "presence" signal (e.g. zoom calls when zoom not configured). For first-class metrics (hours, meetings) always render with `0`.
+
+### Recent items — two separate sections, tap-to-expand
+- **D-18:** Two separate sections rendered in this order (after activity breakdown):
+ 1. **Recent time entries** — last 10 from `recentEntries` (existing endpoint already returns these), sorted by `entry_date` descending. Each row collapsed shows: `entry_date` (formatted via `useUserTimezone()`), `hours_worked`, billable badge if applicable, ticket/project ref (if present), one-line notes preview. **Tap expands inline** to reveal: full notes, ticket title (if available), full project ref, exact timestamp.
+ 2. **Recent meetings** — last 10 from `recentTeamsMeetings`, sorted by `date` descending. Each row collapsed: subject, date (TZ-formatted), duration (from `meetingMins`), attendee count if available. **Tap expands inline** to reveal: matched time entries (the existing `matchedEntries` array), Zoom call linkage (if present), organizer.
+- **D-19:** **Bound to 10 each** (count-bounded, not date-bounded). Period selector does NOT affect recent-items count — it remains 10/10 regardless of D7/D30/D90. (Period changes the metrics + breakdown only.)
+- **D-20:** **Tap-to-expand mechanism:** local component state (`Set` of expanded entry IDs / meeting IDs). No URL state, no router push. Expanded rows animate via Tailwind `transition-all` + height; collapsed by default. Reuse shadcn `Collapsible` if it fits cleanly, else hand-roll.
+- **D-21:** Empty states — when `recentEntries` is empty: show "No time entries in the last 30 days" inline (one row). Same for meetings. Section header still renders.
+
+### Data fetching
+- **D-22:** Reuse `/api/engagement/user/[userId]?period={D7|D30|D90}` as-is per ENG-08. The endpoint already returns `user`, `hours`, `recentEntries`, `recentTeamsMeetings`, `dailyActivity`, `zoom`, `afterHours`, `peerMax` — Phase 8 ignores `peerMax` (radar/peer comparison is a desktop-only flourish) and `dailyActivity` (we render via metrics, no chart).
+- **D-23:** Single fetch on mount + on period change. Loading skeleton matches Phase 7 pattern: header skeleton + 4 metric-card skeletons + breakdown card skeleton + 2 recent-list skeletons.
+- **D-24:** Error handling: if 404 → "User not found" empty page with back link to `/mobile/engagement`. If 500 → toast (sonner) + retry button on the page body.
+
+### Avatar/photo endpoint
+- **D-25:** New thin route `/api/mobile/engagement/user/[userId]/photo` (server-side) — calls Microsoft Graph `/users/{id}/photo/$value` via `getMsgraphClient()`, returns the binary or 404. `requireAuth()` first. Cache headers: `Cache-Control: private, max-age=3600`. Browser caches the photo per-tab. Fallback to initials happens client-side when the `
` errors out.
+- **D-26:** Photo fetch is best-effort. If `MSGRAPH_*` env not configured, the endpoint returns 503 — the client treats any non-200 as "use initials." Phase 8 doesn't gate on Graph being configured.
+
+### Claude's Discretion
+- Exact card/row spacing, typography weights within Phase 7's established tokens (`text-2xl`, `text-xs`, `text-sm`, `space-y-3`, `gap-3`)
+- Whether to use `Collapsible` from shadcn or a hand-rolled disclosure for D-20
+- Skeleton component composition (use Phase 7 shapes as reference)
+- Toast wording for the 500 error case (D-24)
+- Whether to memoize the expand-state `Set` or use a plain object — implementation detail
+- The exact threshold for "Last active" relative-vs-absolute (D-06): treat ≤7d as relative as a starting heuristic; planner can refine
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Phase scope and requirements
+- `.planning/ROADMAP.md` §"Phase 8" — goal, depends-on, success criteria
+- `.planning/REQUIREMENTS.md` ENG-06, ENG-07, ENG-08 — single-column layout, real-page-not-modal, reuse existing endpoints
+
+### Prior-phase context this builds on
+- `.planning/phases/07-engagement-overview-new/07-CONTEXT.md` — period chip mapping (D-04..07), summary card visual tokens (D-10), sparkline pattern, list patterns; **D-19 establishes the row→`/mobile/engagement/[graphUserId]` link**
+- `.planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-SUMMARY.md` — `useUserTimezone()` hook signature, formatting pattern (`{ ...options, timeZone: tz }`)
+- `.planning/phases/02-mobile-shell-more-drawer/02-CONTEXT.md` — `/mobile` shell layout, sticky header pattern
+
+### Existing endpoints to reuse (no modification)
+- `app/api/engagement/user/[userId]/route.ts` — main data source (581 lines): returns `user`, `hours`, `recentEntries`, `recentTeamsMeetings`, `dailyActivity`, `zoom`, `afterHours`, `peerMax`, `snapshots`
+- `app/api/engagement/user/[userId]/history/route.ts` — monthly history (per-month metrics), **not used in Phase 8 v1**
+
+### Components to reuse from Phase 7
+- `components/mobile/EngagementPeriodChips.tsx` — chip component (D-08)
+- `components/mobile/EngagementUserRow.tsx` exports `getInitials()` (D-05)
+- `components/mobile/EngagementSummaryCard.tsx` — referenced as visual token source for metric cards
+- `components/ui/card.tsx`, `components/ui/skeleton.tsx`, `components/ui/collapsible.tsx`, `components/ui/badge.tsx` — shadcn primitives
+
+### Existing services and helpers
+- `lib/services/msgraph-factory.ts` — `getMsgraphClient()` for D-25 photo endpoint
+- `lib/hooks/use-user-timezone.ts` — TZ formatting (D-06, D-18)
+- `lib/auth-utils.ts` — `requireAuth()` for the photo endpoint
+
+### Desktop reference (do NOT replicate visuals)
+- `app/engagement/profile/page.tsx` — desktop modal pattern using recharts (`BarChart`, `RadarChart`); **kept as-is**, not deleted, not migrated. Phase 8 only adds the mobile real-page; desktop modal continues to serve desktop users.
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `components/mobile/EngagementPeriodChips.tsx` — drop-in for period selector (D-08)
+- `components/mobile/EngagementUserRow.tsx` exports `getInitials(displayName)` (D-05)
+- `lib/hooks/use-user-timezone.ts` — `useUserTimezone()` returns the user's IANA tz string (D-06, D-18)
+- `lib/services/msgraph-factory.ts` — `getMsgraphClient()` + `isMsgraphConfigured()` for the photo endpoint (D-25)
+- shadcn `Collapsible` — likely fit for the tap-to-expand recent rows (D-20)
+
+### Established Patterns
+- Mobile pages are `'use client'` + `useState` + `useEffect` + `fetch` (CLAUDE.md, Phase 7 D-03)
+- Sticky chips below H1 use `sticky top-0 z-10 bg-background pt-2 pb-3 -mx-4 px-4` (Phase 7 D-05)
+- Metric cards: big number `text-2xl font-semibold`, label `text-xs text-muted-foreground`, no shadow, just border (Phase 7 D-10)
+- TZ-formatted dates use `{ ...options, timeZone: tz }` from `useUserTimezone()` (Phase 7.1)
+- API routes return JSON; auth via `requireAuth()` from `lib/auth-utils.ts`; error response shape `{ error, message }`
+
+### Integration Points
+- Entry: `EngagementUserRow.tsx`'s existing `Link href="/mobile/engagement/{graphUserId}"` (Phase 7 wired this; Phase 8 only creates the destination page)
+- Data: `/api/engagement/user/[userId]` (existing) + new thin `/api/mobile/engagement/user/[userId]/photo` (D-25)
+- Auth/middleware: `/api/mobile/*` is whitelisted in `middleware.ts`; route handlers gate via `requireAuth()`
+- Navigation: Browser back gesture handled by Next.js App Router default scroll restoration (D-04) — no custom code unless verification reveals it's broken
+
+
+
+
+## Specific Ideas
+
+- "I want this to feel like the row card I just tapped — same avatar treatment, same identity weight" — header avatar reuses `getInitials()` and the visual rhythm of Phase 7 row cards
+- "When a manager opens this, they want to see the time numbers first" — 2×2 hero grid leads with Hours/Billable, then Days/Meetings; communication and meeting detail go below in the breakdown card
+- "Don't bury after-hours" — after-hours% gets a visible row inside Communication subsection rather than being hidden in a tooltip or collapsed section
+- Tap-to-expand is **inline** (no new page, no modal) — preserves the back-gesture-restores-scroll guarantee from SC#2
+
+
+
+
+## Deferred Ideas
+
+- **Peer comparison / radar chart** — desktop has `peerMax` data + a radar visualization; not on mobile v1. Could be a future "compare to team" toggle.
+- **Monthly history view** — `/api/engagement/user/[userId]/history` exists with 16 metrics × N months. Could power a "history" tab on the profile in a future phase. Not v1.
+- **`dailyActivity` chart** — the endpoint returns daily breakdown points; could render a single-series sparkline like Phase 7's `EngagementHoursSparkline`. Skipped for v1 to keep the page screen-bounded; reconsider if managers ask for it.
+- **Tap-to-open ticket/meeting** — D-20 picked tap-to-expand-inline. Future enhancement: an explicit "View ticket" button inside the expanded entry that deep-links to `/mobile/tickets/[id]`.
+- **D1 ("today") period chip** — Phase 7 D-07 deferred this; same applies here. Aggregate granularity is D7+ until a D1 sync lands.
+- **Zoom-only client-meeting filter** — desktop differentiates "client meetings" from total meetings using calendar metadata. Mobile v1 shows the totals; client-only breakdown is a future enhancement.
+
+
+
+---
+
+*Phase: 08-engagement-user-profile-new*
+*Context gathered: 2026-05-07*
diff --git a/.planning/phases/08-engagement-user-profile-new/08-DISCUSSION-LOG.md b/.planning/phases/08-engagement-user-profile-new/08-DISCUSSION-LOG.md
new file mode 100644
index 0000000..e4fbd18
--- /dev/null
+++ b/.planning/phases/08-engagement-user-profile-new/08-DISCUSSION-LOG.md
@@ -0,0 +1,152 @@
+# Phase 8: Engagement User Profile (NEW) - Discussion Log
+
+> **Audit trail only.** Do not use as input to planning, research, or execution agents.
+> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
+
+**Date:** 2026-05-07
+**Phase:** 08-engagement-user-profile-new
+**Areas discussed:** Identity header, Key metrics layout, Period default, Activity breakdown, Recent items
+
+---
+
+## Identity header
+
+### Avatar source
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Initials only (Recommended) | Reuse Phase 7's `getInitials()`. Zero external calls, consistent with overview row. | |
+| Graph photo with initials fallback | Fetch `user.photo` from Microsoft Graph; nicer visually if photos exist. | ✓ |
+| Graph photo only (no fallback) | Skip avatar entirely if no photo. | |
+
+**User's choice:** Graph photo with initials fallback
+**Notes:** Per D-25/D-26 — new thin endpoint at `/api/mobile/engagement/user/[userId]/photo` calls Graph; client falls back to initials on `
` error.
+
+### Fields under name (multi-select)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Job title | From `graph_users.job_title` — already on the row card | ✓ |
+| Email | Tap-to-email on phone (`mailto:`) | ✓ |
+| Department | From `graph_users.department` if populated | ✓ |
+| Last active timestamp | Most-recent activity (last time entry / last Teams message) | ✓ |
+
+**User's choice:** All four selected
+**Notes:** Renders in stacked order: title → department → email → last active. Department/last-active rows hide if NULL.
+
+---
+
+## Key metrics layout
+
+### Layout pattern
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| 2×2 grid — 4 hero metrics (Recommended) | Mirrors Phase 3 dashboard KPI grid | ✓ |
+| Stacked cards — 6 metrics | Mirrors Phase 7 overview summary cards | |
+| Compact strip — 6 in horizontal scroll | Saves vertical, breaks Pulse pattern | |
+
+**User's choice:** 2×2 grid
+
+### Default period
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| D30 — match overview default (Recommended) | Consistent with Phase 7 | ✓ |
+| D90 — detail-view convention | Heavier data load | |
+| D7 — most recent context | Spot-check oriented | |
+
+**User's choice:** D30
+
+### Top metrics for the 2×2 grid
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Hours worked + Billable hours + Days + Meetings | Time-focused set | ✓ |
+| Hours + Billable + Meetings + After-hours% | Time + workload signal | |
+| Hours + Meetings + Teams msgs + Emails | Activity-focused | |
+| Hours + Billable + Days + Meetings + Teams msgs + Emails (6 stacked) | Full picture, stacked | |
+
+**User's choice:** Hours worked + Billable hours + Days worked + Meetings attended
+
+---
+
+## Activity breakdown
+
+### Breakdown structure
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Categorized rows — Time / Communication / Meetings (Recommended) | Three labeled subsections, scannable, no charts | ✓ |
+| Single mixed list — all metrics flat | Simpler, loses grouping | |
+| Per-metric mini-sparklines | Visually rich but heavy | |
+| Daily activity timeline | Combined chart, less per-metric detail | |
+
+**User's choice:** Categorized rows
+
+### After-hours% placement
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Inside Communication section as a row (Recommended) | Tucked but visible | ✓ |
+| Standalone row above breakdown | Highlighted callout | |
+| Drop — not on mobile v1 | Skip for v1 | |
+
+**User's choice:** Inside Communication section
+
+---
+
+## Recent items
+
+### What gets shown
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Recent time entries only (Recommended) | Last ~10 from `recentEntries` | |
+| Recent meetings only | Last ~10 from `recentTeamsMeetings` | |
+| Mixed feed — interleaved by date | Single timeline | |
+| Two separate sections — Time entries + Meetings | Both, kept separate | ✓ |
+
+**User's choice:** Two separate sections
+
+### Scope
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Last 10 items (Recommended) | Bounded, fits one screen | ✓ |
+| Last 20 items | Fuller history | |
+| Last 7 days bounded by date | Time-bounded | |
+| Match selected period (D7/D30/D90) | Grows with period | |
+
+**User's choice:** Last 10 items (each section)
+
+### Tap behavior
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Read-only display, no tap action (Recommended) | Match Phase 7's read-only-on-mobile principle | |
+| Tap to open ticket / meeting detail | Adds nav surfaces | |
+| Tap to expand inline — show notes, attendees, full details | Stays on profile, reveals more rows | ✓ |
+
+**User's choice:** Tap to expand inline
+**Notes:** Local component state (`Set` of expanded IDs); no URL state.
+
+---
+
+## Claude's Discretion
+
+- Exact spacing/typography within Phase 7's established tokens
+- Whether to use shadcn `Collapsible` or hand-rolled disclosure
+- Skeleton component composition
+- Toast wording for 500 errors
+- Memoization detail of expand-state
+- "Last active" relative-vs-absolute threshold (started at ≤7d)
+
+## Deferred Ideas
+
+- Peer comparison / radar chart (desktop-only flourish)
+- Monthly history view (`/history` endpoint)
+- `dailyActivity` chart
+- Tap-to-open ticket/meeting deep links (future enhancement to inline expand)
+- D1 "today" period chip (Phase 7 deferral carries forward)
+- Zoom client-meeting filter (mobile v1 shows totals)