` with `
Planning
` and the date range label below — matching the `.overview-section` pattern from tablos.templ.
+- **D-P02:** Add `PlanningShowDaySeparator(events []PlanningEventRow, index int) bool` helper in `planning_forms.go` — compares `events[index].DateLabel != events[index-1].DateLabel` (string comparison, returns true for index 0 or label change).
+- **D-P03:** Day separator element mirrors the discussion day separator style — a centered strip with the date label (e.g., `
`).
+- **D-P04:** `DateLabel` field is removed from `PlanningEventListItem` row body — it's now rendered in the separator. Event row shows: TimeRange → Title → TabloTitle + Location (existing right column).
+
+### Claude's Discretion
+
+- Exact `max-width` value for own message bubbles (recommend 70%)
+- Border-radius on bubbles (recommend `0.75rem` for all corners, or asymmetric: own `0.75rem 0.75rem 0.25rem 0.75rem`)
+- Exact opacity/alpha for the brand-primary bubble tint (recommend 10–15% — subtle, readable)
+- Divider between messages: keep `divide-y divide-slate-100` inside the card or drop it now that bubbles have their own visual weight (recommend dropping the divider)
+- Empty state for planning when no events: adopt `@ui.EmptyState(...)` to match Phase 16 files section (consistent with established pattern)
+- Navigation controls in planning heading: keep using `.ui-button` inline utility classes (no change needed)
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Locked Requirements
+- `.planning/phases/17-chat-planning/17-SPEC.md` — Locked requirements (6), boundaries, acceptance criteria — MUST read before planning
+
+### Product Scope
+- `.planning/ROADMAP.md` — Phase 17 goal, success criteria (4 criteria), requirements CHAT-UI-01, PLAN-UI-01
+- `.planning/REQUIREMENTS.md` — CHAT-UI-01 (card/surface design, own-vs-others), PLAN-UI-01 (overview-section layout)
+- `.planning/PROJECT.md` — v3.0 scope: visual polish only; no new data models or routes
+
+### Current Backend (files being changed)
+- `backend/templates/discussion.templ` — `DiscussionTabFragment`, `DiscussionMessageRow`, `DiscussionEmptyState`, `DiscussionDaySeparator`, `DiscussionComposer` — all being restyled
+- `backend/templates/discussion_forms.go` — `DiscussionMessageView` (add `IsOwn bool`), `DiscussionMessagesFromRows` (add `currentUserID uuid.UUID`), `DiscussionMessageFromRow` (returns `IsOwn: false`; handler sets `IsOwn: true` for HTMX path)
+- `backend/templates/planning.templ` — `PlanningPage`, `PlanningEventListItem` — adopt overview-section and day separators
+- `backend/templates/planning_forms.go` — add `PlanningShowDaySeparator` helper
+- `backend/internal/web/handlers_discussion.go` — `loadDiscussionTabData`, `DiscussionMessageCreateHandler` — thread `user.ID` through; set `IsOwn` for HTMX vs. SSE paths
+
+### Design System (Phase 13 — already in backend)
+- `backend/internal/web/ui/app.css` — receives new `.message-row`, `.message-own`, `.message-other`, `.message-bubble`, `.message-meta` CSS classes using design tokens
+- `backend/internal/web/ui/base.css` — design tokens; all new CSS uses `var(--...)` tokens. Key tokens: `--color-brand-primary`, `--color-surface-default`, `--color-border-subtle`, `--color-text-muted`, `--color-surface-muted-inverse`
+- `backend/internal/web/ui/card.templ` + `backend/internal/web/ui/card.css` — `.ui-card` class to apply to discussion message container
+- `backend/internal/web/ui/empty_state.templ` — `@ui.EmptyState(...)` for planning empty state (Claude's discretion)
+
+### Established Patterns (Phase 15–16)
+- `.planning/phases/16-tablo-detail/16-CONTEXT.md` — overview-section heading pattern, design token constraints, all-CSS-in-app.css rule
+- `.planning/phases/15-dashboard-tablos/15-CONTEXT.md` — AppLayout integration, sidebar tablos list pattern
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `backend/internal/web/ui/card.css` `.ui-card`: Apply to `#discussion-messages` container — swap `class="rounded border border-slate-200 bg-white"` with `class="ui-card"`
+- `backend/templates/discussion.templ` `DiscussionDaySeparator`: Day separator pattern already exists for discussion — use the same visual approach for planning day separators
+- `backend/internal/web/ui/empty_state.templ` `@ui.EmptyState(...)`: Ready for planning empty state to replace the current raw div
+
+### Established Patterns
+- All new CSS in `app.css` uses `var(--...)` tokens only — no hardcoded hex, no Tailwind inline in CSS files (Phases 13–16 convention)
+- Value-type Go structs: `DiscussionMessageView` is a struct (not pointer) — handler can mutate `.IsOwn` between SSE publish and HTMX render without affecting the published copy
+- `loadOwnedTablo` returns `tablo, user, ok` — `user.ID` is already available in all discussion handlers without additional queries
+
+### Integration Points
+- `backend/internal/web/handlers_discussion.go` `loadDiscussionTabData`: needs `userID uuid.UUID` as a new parameter; one caller (`TabloDiscussionTabHandler`) passes `user.ID`
+- `backend/internal/web/handlers_discussion.go` `DiscussionMessageCreateHandler`: sets `message.IsOwn = false` before SSE publish; `message.IsOwn = true` before HTMX render (line ~141)
+- `backend/templates/tablos.templ` `TabloDetailPage`: discussion tab passes `discussion DiscussionTabData` unchanged — no signature change needed at this level
+- All non-discussion handlers that pass empty `templates.DiscussionTabData{}` are unaffected — `IsOwn` defaults to `false` which is correct for empty data
+
+
+
+
+## Specific Ideas
+
+- Message bubble CSS: `.message-own .message-bubble { margin-left: auto; max-width: 70%; background: rgba(128, 78, 236, 0.10); border: 1px solid var(--color-border-subtle); border-radius: 0.75rem 0.75rem 0.25rem 0.75rem; }` — asymmetric radius gives the classic chat feel for own messages; others get `border-radius: 0.25rem 0.75rem 0.75rem 0.75rem`
+- `.message-meta` for own: `text-align: right; display: flex; justify-content: flex-end; gap: 0.5rem; margin-bottom: 0.25rem`
+- Planning day separator: reuse the `DiscussionDaySeparator` visual pattern — same gray-tinted strip (`bg-slate-50 px-4 py-2 text-center text-sm text-slate-500`) for visual consistency between the two restyled surfaces
+
+
+
+
+## Deferred Ideas
+
+- Hover-to-reveal timestamp (compact mode) — not in v3.0 requirements
+- Message edit or delete — not in v3.0 requirements
+- Sidebar collapse toggle (JS) — deferred since Phase 15; still deferred
+- Mobile-responsive kanban — still deferred (RESP-01 future)
+
+
+
+---
+
+*Phase: 17-chat-planning*
+*Context gathered: 2026-05-17*
diff --git a/.planning/phases/17-chat-planning/17-DISCUSSION-LOG.md b/.planning/phases/17-chat-planning/17-DISCUSSION-LOG.md
new file mode 100644
index 0000000..f77a762
--- /dev/null
+++ b/.planning/phases/17-chat-planning/17-DISCUSSION-LOG.md
@@ -0,0 +1,80 @@
+# Phase 17: Chat & Planning - 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-17
+**Phase:** 17-chat-planning
+**Areas discussed:** Chat bubble layout
+
+---
+
+## Chat Bubble Layout
+
+### Bubble Width and Alignment
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Full-width, background only | Own message fills full container width but has a tinted background. Others white/neutral. Simpler layout, no max-width clipping. Matches Slack highlight style. | |
+| Constrained bubble, right-aligned | Own message max-width ~70-75%, floated right. Others at full-width or left-constrained. Classic WhatsApp/iMessage style. Requires more CSS. | ✓ |
+
+**User's choice:** Constrained bubble, right-aligned
+
+---
+
+### Bubble Background Colors
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Brand primary tint for own, surface-default for others | Own: var(--color-brand-primary) at low opacity. Others: var(--color-surface-default) (white). Consistent with token palette. | ✓ |
+| Brand accent (blue) for own, neutral surface for others | Own: var(--color-brand-accent) (#3b82f6) tint. Others: var(--color-surface-muted). Blue accent, less "brand" than purple. | |
+
+**User's choice:** Brand primary tint (purple) for own, surface-default for others
+
+---
+
+### Author Label and Timestamp Position
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Above bubble, mirrored | Author + timestamp sit above bubble text, aligned to match bubble side. Own: right-aligned meta. Others: left-aligned meta. | ✓ |
+| Below bubble, timestamp only | No inline author label. Timestamp shown below bubble. Very compact. | |
+
+**User's choice:** Above bubble, mirrored — author + timestamp above, aligned to bubble side
+
+---
+
+### CSS Approach
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| New CSS classes in app.css using design tokens | Add .message-row, .message-own, .message-other, .message-bubble, .message-meta — all using var(--...) tokens. Consistent with Phase 13–16 pattern. | ✓ |
+| Inline Tailwind classes in templ | Conditional Tailwind classes directly in DiscussionMessageRow. Simpler to write, but mixes presentation into template and uses hardcoded colors. | |
+
+**User's choice:** New CSS classes in app.css with design tokens
+
+---
+
+## Areas NOT Selected
+
+The user was presented with three gray areas and selected only "Chat bubble layout":
+- **Composer + card integration** — not discussed; Claude's discretion (keep composer outside card, as currently)
+- **Planning event row layout after date removal** — not discussed; Claude's discretion (row shows TimeRange → Title → TabloTitle + Location)
+
+## Claude's Discretion
+
+- Exact max-width value for own bubbles (70%)
+- Border-radius on bubbles (asymmetric: own `0.75rem 0.75rem 0.25rem 0.75rem`, others `0.25rem 0.75rem 0.75rem 0.75rem`)
+- Exact opacity for brand-primary tint (10-15%)
+- Whether to keep `divide-y` inside the card or drop it now that bubbles have visual weight (recommend drop)
+- Composer placement (keep outside card, unchanged)
+- Planning day separator visual style (mirror discussion's `DiscussionDaySeparator` — gray strip, centered text)
+- Empty state for planning (adopt `@ui.EmptyState(...)` consistent with Phase 16)
+- Planning event row restructuring after removing DateLabel
+
+## Deferred Ideas
+
+- Hover-to-reveal timestamp (compact mode)
+- Message edit or delete functionality
+- Sidebar collapse toggle (JS interaction)
+- Mobile-responsive kanban layout