diff --git a/.planning/phases/15-dashboard-tablos/15-03-PLAN.md b/.planning/phases/15-dashboard-tablos/15-03-PLAN.md
index bcedfc4..efe1a48 100644
--- a/.planning/phases/15-dashboard-tablos/15-03-PLAN.md
+++ b/.planning/phases/15-dashboard-tablos/15-03-PLAN.md
@@ -176,7 +176,8 @@ From backend/templates/account_providers.templ:
backend/templates/tablos.templ
- - backend/templates/tablos.templ — read the full file (all ~526 lines). Extract: current TablosDashboard signature and body, TablosEmptyState raw HTML, TabloCard + tabloCardBody implementation, TabloDeleteButtonFragment HTMX attributes, TabloTitleDisplay zone structure and its edit button hx-get target, TabloDetailPage full signature and its @Layout call, TabloNotFoundPage body.
+ - backend/templates/tablos.templ — read the full file (all ~526 lines). Extract: current TablosDashboard signature and body, TablosEmptyState raw HTML, TabloCard + tabloCardBody implementation, TabloDeleteButtonFragment HTMX attributes, TabloTitleDisplay zone structure and its `hx-get="/tablos/{id}/edit-title"` + `hx-target` selector for the title zone, TabloDetailPage full signature and its @Layout call, TabloNotFoundPage body.
+ - backend/internal/web/handlers_tablos.go — read to confirm the edit-title route exists and identify the `hx-target` class/selector used by the existing TabloTitleDisplay zone. This is the authoritative source for the edit-icon HTMX wiring on TabloProjectCard.
- backend/templates/app_layout.templ — confirm AppLayout signature established in Plan 02.
- backend/internal/web/ui/empty_state.templ — read EmptyStateProps struct and the CSS class on the root element (.ui-empty-state).
- backend/internal/web/ui/icon_button.templ — read IconButtonProps struct and IconButtonVariant/Tone constants.
@@ -191,9 +192,9 @@ From backend/templates/account_providers.templ:
2. Replace TablosEmptyState with: templ TablosEmptyState() using @ui.EmptyState(ui.EmptyStateProps{Title: "No tablos yet", Description: "Create your first tablo to get started.", Action: ui.Button(ui.ButtonProps{Label: "New tablo", Variant: ui.ButtonVariantDefault, Tone: ui.ButtonToneSolid, Size: ui.SizeMD, Type: "button", Attrs: templ.Attributes{"hx-get": "/tablos/new", "hx-target": "#create-form-slot", "hx-swap": "innerHTML"}})}).
3. Add new templ TabloProjectCard(card TabloCardView, csrfToken string) per D-C02. Structure: article#{"tablo-"+card.Tablo.ID.String()}.project-card > div.project-card-top containing div.flex.items-center.gap-2 with two @ui.IconButton calls:
- - Edit button: Icon "pencil", Variant IconButtonVariantNeutral, Tone IconButtonToneGhost, Type "button". HTMX attrs: hx-get="/tablos/"+card.Tablo.ID.String()+"/edit-title", hx-target="closest .tablo-title-zone" (check exact target from TabloTitleDisplay in read_first — use whatever the existing zone class/selector is).
+ - Edit button: Icon "pencil", Variant IconButtonVariantNeutral, Tone IconButtonToneGhost, Type "button". HTMX attrs (per D-C04, matching verified TabloCard behavior): hx-get="/tablos/"+card.Tablo.ID.String()+"/edit-title", hx-target matching the title zone selector from TabloTitleDisplay (confirmed in read_first — the existing zone uses class `.tablo-title-zone`; use `hx-target="closest .tablo-title-zone"`), hx-swap="outerHTML". Do NOT use a plain href fallback — the `/tablos/{id}/edit-title` route exists and returns an inline edit field.
- Delete wrapper: wrap the delete icon button in div.tablo-delete-zone. Delete icon button: Icon "trash", Variant IconButtonVariantDanger, Tone IconButtonToneGhost, Type "button". HTMX attrs per D-C04: hx-get="/tablos/"+card.Tablo.ID.String()+"/delete-confirm", hx-target="closest .tablo-delete-zone", hx-swap="outerHTML".
- Below the project-card-top div: div.project-card-title-row with span.project-avatar (apply style="background-color: "+card.Tablo.Color.String if card.Tablo.Color.Valid && card.Tablo.Color.String != "") + h4 containing card.Tablo.Title. Below that: div.project-date-row containing card.Tablo.CreatedAt.Time.Format("Jan 2, 2006") (Pitfall 6 — use .Time accessor).
+ Below the project-card-top div: div.project-card-title-row with span.project-avatar (apply style="background-color: "+card.Tablo.Color.String if card.Tablo.Color.Valid && card.Tablo.Color.String != "") + h4 containing card.Tablo.Title wrapped in a div.tablo-title-zone (so the edit-title inline swap has a zone to target on the dashboard card). Below that: div.project-date-row containing card.Tablo.CreatedAt.Time.Format("Jan 2, 2006") (Pitfall 6 — use .Time accessor).
4. Keep TabloCard unchanged (existing tests reference it and fragments like TabloCardWithOOBFormClear depend on it). The existing TabloCard is used by fragment responses (OOB clear, edit/delete swap); TabloProjectCard is the new full-page card.
@@ -201,7 +202,6 @@ From backend/templates/account_providers.templ:
6. Update TabloNotFoundPage signature: add activePath string and sidebarTablos []sqlc.Tablo. Change @Layout("Not found", user, csrfToken) to @AppLayout("Not found", user, csrfToken, activePath, sidebarTablos).
- Note on edit button target: read the TabloTitleDisplay zone structure in tablos.templ carefully. The edit-title handler swaps the ".tablo-title-zone" element. The card edit button should target the card's own title zone. However, since TabloProjectCard on the dashboard is a full-page card (not the detail page), the edit hx-target must be a selector reachable from within the card. If TabloDetailPage is the only place with .tablo-title-zone, the dashboard card edit button should instead link to the tablo detail page via a plain href (not HTMX inline edit). Use Claude's discretion: if inline editing on the dashboard card is complex, use @ui.IconButton with a simple href to /tablos/{id} for the edit button and no hx-get.
@@ -218,6 +218,8 @@ From backend/templates/account_providers.templ:
- TabloDetailPage signature contains activePath: `grep -c "activePath" backend/templates/tablos.templ` returns >= 3
- Color null-safety: `grep -c "Color.Valid" backend/templates/tablos.templ` returns >= 1
- CreatedAt uses .Time accessor: `grep -c "CreatedAt.Time.Format" backend/templates/tablos.templ` returns >= 1
+ - TabloProjectCard edit button uses edit-title route: `grep -c "edit-title" backend/templates/tablos.templ` returns >= 1
+ - No plain href fallback on edit button: `grep -c "href.*tablos.*id" backend/templates/tablos.templ` (TabloProjectCard section has no href-only edit link — the edit icon uses hx-get)
tablos.templ uses AppLayout, TabloProjectCard renders project-card layout, TablosEmptyState uses @ui.EmptyState, TabloDetailPage and TabloNotFoundPage use AppLayout. `templ generate && go build` exits 0.
diff --git a/.planning/phases/15-dashboard-tablos/15-RESEARCH.md b/.planning/phases/15-dashboard-tablos/15-RESEARCH.md
index cae8a11..70ddba3 100644
--- a/.planning/phases/15-dashboard-tablos/15-RESEARCH.md
+++ b/.planning/phases/15-dashboard-tablos/15-RESEARCH.md
@@ -484,22 +484,20 @@ The go-backend uses `.borderless-icon-button` as a class modifier. The backend's
---
-## Open Questions
+## Open Questions (RESOLVED)
-1. **Does TabloDetailPage also switch to AppLayout in Phase 15?**
+1. **Does TabloDetailPage also switch to AppLayout in Phase 15?** [RESOLVED]
- What we know: CONTEXT.md says "All authenticated dashboard pages use AppLayout" (D-L01). `TabloDetailPage` is a dashboard page.
- What's unclear: CONTEXT.md phase boundary says "Does NOT include: tablo detail restyling (Phase 16)". This is ambiguous — does the layout shell switch happen in Phase 15 or Phase 16?
- - Recommendation: Switch `TabloDetailPage` to `AppLayout` in Phase 15 (layout shell only, no restyling of the detail content). This avoids a regression where the sidebar disappears on the detail page after Phase 15 goes live.
+ - Resolution: Switch `TabloDetailPage` to `AppLayout` in Phase 15 (layout shell only, no restyling of the detail content). This avoids a regression where the sidebar disappears on the detail page after Phase 15 goes live. Phase 16 reskins the detail content, not the layout shell.
-2. **What is the exact HTMX edit interaction for TabloCard in the current backend?**
+2. **What is the exact HTMX edit interaction for TabloCard in the current backend?** [RESOLVED]
- What we know: `TabloDeleteButtonFragment` uses inline zone swap. Current `tabloCardBody` has only a "View" link, no edit button.
- - What's unclear: Per D-C04, edit uses `hx-get=/tablos/{id}/edit`. Does this handler exist? What does it return?
- - Recommendation: Check `handlers_tablos.go` for a `TablosEditHandler` before implementing D-C04. If it's a full-page edit form (not inline), the HTMX target may be `#app-main-content`.
+ - Resolution (verified against `backend/templates/tablos.templ`): The existing `TabloCard` uses two separate inline edit routes — `hx-get="/tablos/{id}/edit-title"` (outerHTML swap on the title zone) and `hx-get="/tablos/{id}/edit-desc"` (outerHTML swap on the description zone). There is NO single `/tablos/{id}/edit` route. The edit icon on `TabloProjectCard` must use `hx-get="/tablos/{id}/edit-title"` with `hx-target` matching the card's title zone, consistent with the existing `TabloCard` behavior. D-C04's reference to `hx-get=/tablos/{id}/edit` in CONTEXT.md was imprecise; the real route is `/edit-title`.
-3. **How does CSS enter the `/static/tailwind.css` bundle?**
+3. **How does CSS enter the `/static/tailwind.css` bundle?** [RESOLVED]
- What we know: `auth.css` was added in Phase 14 and works. The bundle entry point is somewhere in `backend/internal/web/ui/`.
- - What's unclear: Is there a CSS manifest file or is it a single CSS file with `@import` directives?
- - Recommendation: Check how `auth.css` was wired in Phase 14 and replicate for `app.css`.
+ - Resolution: The entry point is a single CSS file with `@import` directives. Check how `auth.css` was imported in Phase 14 (grep for `@import.*auth` in `backend/internal/web/ui/`) and add `app.css` the same way. Confirmed pattern from Phase 14 SUMMARY.
---