---
phase: 16-tablo-detail
plan: 02
type: execute
wave: 2
depends_on:
  - 16-01
files_modified:
  - backend/templates/tablos.templ
autonomous: true
requirements:
  - DETAIL-01

must_haves:
  truths:
    - "Tablo detail page header uses .project-card-top layout with color avatar, inline-editable title zone, and action controls"
    - "Action controls use @ui.IconButton for Discussion and Delete, @ui.Button for Invite Member — no hardcoded #804EEC hex"
    - "Metadata row uses .tablo-metadata-row with created date, @ui.Badge status pill, and .project-progress-track/bar"
    - "Tab nav uses .tab-nav / .tab-nav-item / .tab-nav-item.is-active classes replacing hardcoded Tailwind hex classes"
    - "Description zone renders inside TabloOverviewTabFragment (not in the persistent header)"
    - "EtapeStrip is no longer called from TasksTabFragment (KanbanBoard call site update deferred to Plan 03 where signature change also happens)"
    - "All existing tablo handler tests pass unchanged"
  artifacts:
    - path: backend/templates/tablos.templ
      provides: Restyled TabloDetailPage header, tab nav, overview tab, TasksTabFragment EtapeStrip removal
      contains: ".project-card-top"
    - path: backend/templates/tablos_templ.go
      provides: Generated Go from restyled tablos.templ
      exports: []
  key_links:
    - from: backend/templates/tablos.templ TabloDetailPage
      to: backend/internal/web/ui/app.css .project-card-top
      via: CSS class on div element
      pattern: "project-card-top"
    - from: backend/templates/tablos.templ TabloOverviewTabFragment
      to: TabloDescDisplay / TabloDescEditFragment
      via: "@TabloDescDisplay(tablo, csrfToken)" call inside overview tab
      pattern: "TabloDescDisplay"
    - from: backend/templates/tablos.templ TasksTabFragment
      to: KanbanBoard
      via: "@KanbanBoard(tablo.ID, csrfToken, tasks, filter)" — etapes parameter added in Plan 03 simultaneously with KanbanBoard signature change
      pattern: "KanbanBoard"
---

<objective>
Restyle `TabloDetailPage` header area (project-card-top layout, color avatar, action controls), metadata row, tab nav bar, and overview tab content. Move the description zone from the persistent header into `TabloOverviewTabFragment`. Remove the `@EtapeStrip` call from `TasksTabFragment`. The `KanbanBoard` call site update (adding `etapes` parameter) is deferred to Plan 03, where the signature change and all three call sites are updated atomically to keep the build clean at every wave boundary. All HTMX wiring, inline-edit zones, delete flow, and tab routing are preserved unchanged.

Purpose: Deliver DETAIL-01 — the tablo detail header matches the project-card-top design.
Output: Restyled `tablos.templ` with no hardcoded hex values in the detail page section.
</objective>

<execution_context>
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/workflows/execute-plan.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/ROADMAP.md
@.planning/phases/16-tablo-detail/16-CONTEXT.md
@.planning/phases/16-tablo-detail/16-RESEARCH.md
@.planning/phases/16-tablo-detail/16-PATTERNS.md
@.planning/phases/16-tablo-detail/16-UI-SPEC.md
@.planning/phases/16-tablo-detail/16-01-SUMMARY.md

<interfaces>
<!-- Critical contracts and current patterns the executor must know. -->

From backend/templates/tablos.templ (current state — read the file before editing):

TabloDetailPage signature (line ~200):
  templ TabloDetailPage(tablo sqlc.Tablo, tasks []sqlc.Task, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, csrfToken string, activeTab string, user auth.User)

Current header structure uses raw inline Tailwind classes with hardcoded #804EEC hex. Replace with design token classes.

Color avatar pattern from TabloProjectCard (lines ~103–112) — reuse for detail header, adding first-character text:
  if tablo.Color.Valid && tablo.Color.String != "" {
      span class="project-avatar" style="background-color: {tablo.Color.String}"
          if len(tablo.Title) > 0 { string([]rune(tablo.Title)[0:1]) }
  } else {
      span class="project-avatar"
          if len(tablo.Title) > 0 { string([]rune(tablo.Title)[0:1]) }
  }

Tab nav active state — current pattern (lines ~306–325) uses inline Tailwind hex classes per-tab. Replace ALL 5 tabs (overview, tasks, files, discussion, events):
  if activeTab == "overview" || activeTab == "" { class="tab-nav-item is-active" } else { class="tab-nav-item" }

EtapeStrip call in TasksTabFragment (line ~412): DELETE this call
  @EtapeStrip(tablo.ID, etapes, counts, filter, csrfToken, false)

KanbanBoard call in TasksTabFragment (line ~413): UPDATE to add etapes parameter
  @KanbanBoard(tablo.ID, csrfToken, tasks, filter)
  → @KanbanBoard(tablo.ID, csrfToken, tasks, filter, etapes)

Delete button in detail header — per Pitfall 6: do NOT modify TabloDeleteButtonFragment (used by dashboard cards).
Create an INLINE IconButton inside a .tablo-delete-zone div in TabloDetailPage header:
  div class="tablo-delete-zone"
    @ui.IconButton(ui.IconButtonProps{Label: "Delete tablo", Icon: "trash", Variant: ui.IconButtonVariantDanger, Tone: ui.IconButtonToneGhost, Type: "button", Attrs: templ.Attributes{"hx-get": "/tablos/{id}/delete-confirm", "hx-target": "closest .tablo-delete-zone", "hx-swap": "outerHTML"}})

Discussion action in header: use a semantic <a> tag wrapping @ui.IconButton. Do NOT use an hx-get on the IconButton itself — the <a> tag handles navigation:
  <a href="/tablos/{id}/discussion" hx-get="/tablos/{id}/discussion" hx-target="#tab-content" hx-swap="innerHTML" hx-push-url="true">
    @ui.IconButton(ui.IconButtonProps{Icon: "chat", Tone: ui.IconButtonToneGhost, Attrs: templ.Attributes{"aria-label": "Discussion"}})
  </a>

Invite button: use ButtonToneSoft + ButtonVariantDefault (NOT ButtonVariantGhost — @ui.Button has no Ghost tone; ButtonTone only has ButtonToneSolid and ButtonToneSoft; .ui-button-soft.ui-button-default renders a soft/outlined button matching the current bordered style):
  @ui.Button(ui.ButtonProps{Label: "Invite Member", Variant: ui.ButtonVariantDefault, Tone: ui.ButtonToneSoft, Size: ui.SizeMD, Type: "button"})

Metadata row:
  div class="tablo-metadata-row"
    div class="tablo-metadata-date"
      [calendar SVG 1rem aria-hidden]
      span "Created"
      span { tablo.CreatedAt.Time.Format("Jan 2, 2006") }
    @ui.Badge(ui.BadgeProps{Label: "In progress", Variant: ui.BadgeVariantPrimary})
    div class="project-progress-track"
      div class="project-progress-bar" style="width: 0%;"

Overview tab (TabloOverviewTabFragment): move the tablo-desc-zone call here (currently in persistent header). The component already exists — just relocate the @TabloDescDisplay(tablo, csrfToken) call inside a div class="tablo-desc-zone" inside TabloOverviewTabFragment.

Tab nav wrapper: change the outer div for the tab links to div class="tab-nav" (replaces existing raw flex Tailwind classes).

ui package variant identifiers (from backend/internal/web/ui/variants.go):
  ui.ButtonVariantDefault, ui.ButtonToneSoft, ui.ButtonToneSolid
  ui.IconButtonVariantDanger, ui.IconButtonVariantNeutral, ui.IconButtonToneGhost
  ui.BadgeVariantPrimary, ui.BadgeVariantInfo
  ui.SizeMD
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Restyle TabloDetailPage header, metadata row, and tab nav</name>
  <files>backend/templates/tablos.templ</files>
  <read_first>
    - backend/templates/tablos.templ (read the FULL file before editing — you need to understand the current header structure, tab nav structure, action control positions, and the persistent desc zone location; the file is ~650 lines)
    - backend/internal/web/ui/variants.go (read to confirm exact Go identifiers for variants/tones: ButtonVariantGhost, IconButtonVariantDanger, IconButtonToneGhost, BadgeVariantPrimary, SizeMD — use these exact names)
    - .planning/phases/16-tablo-detail/16-PATTERNS.md (section "backend/templates/tablos.templ" — color avatar pattern, tab nav pattern, IconButton for delete, metadata row pattern, description zone relocation)
  </read_first>
  <action>
    Edit `backend/templates/tablos.templ` to restyle `TabloDetailPage`. Make the following targeted changes:

    1. HEADER — replace the current header div (which uses inline Tailwind flex classes with #804EEC) with a `.project-card-top` layout:
       - Outer div: `class="project-card-top"`
       - Left: `div class="project-card-title-row"` containing the project-avatar span (with tablo color + first char of title per PATTERNS.md color avatar pattern) followed by the existing `.tablo-title-zone` inline-edit zone (`@TabloTitleDisplay(tablo, csrfToken)` preserved as-is)
       - Right: action controls row with gap, containing: (a) Discussion `@ui.IconButton` with `Icon: "chat"`, `Label: "Discussion"`, ghost/neutral variant, wrapped so it navigates to the discussion tab (use hx-get="/tablos/{id}/discussion" hx-target="#tab-content" hx-swap="innerHTML" hx-push-url="true" as Attrs); (b) `@ui.Button` for "Invite Member" with `ButtonToneSoft + ButtonVariantDefault` (see interfaces section — Ghost tone does not exist); (c) a `.tablo-delete-zone` div containing the trash `@ui.IconButton` (DO NOT use or modify `@TabloDeleteButtonFragment`)

    2. METADATA ROW — replace the current metadata span/div elements (which use hardcoded color classes) with `div class="tablo-metadata-row"` containing: tablo-metadata-date div (calendar SVG + "Created" + formatted date), `@ui.Badge` for "In progress" with `BadgeVariantPrimary`, and the progress track/bar divs using `.project-progress-track` + `.project-progress-bar` CSS classes (per PATTERNS.md metadata row pattern)

    3. TAB NAV — change the outer container of the 5 tab links to `div class="tab-nav"`. For each of the 5 tabs (overview, tasks, files, discussion, events): replace the long inline Tailwind class strings (which contain `text-[#804EEC]`, `border-[#804EEC]`, etc.) with the simple conditional: `if activeTab == "{tab}" { class="tab-nav-item is-active" } else { class="tab-nav-item" }`. Preserve all `hx-get`, `hx-target`, `hx-swap`, `hx-push-url`, and `href` attributes on each tab link unchanged.

    4. DESCRIPTION ZONE RELOCATION — Remove the `tablo-desc-zone` div (containing `@TabloDescDisplay`) from the persistent header area (above the tab nav). Move it into `TabloOverviewTabFragment` as the first element inside that component. The `TabloDescDisplay` and `TabloDescEditFragment` components themselves are not modified — only the call site location changes.

    After editing, run: `just generate` to regenerate `tablos_templ.go`.
  </action>
  <verify>
    <automated>grep -c "project-card-top" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/templates/tablos.templ && grep -c "tab-nav-item is-active" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/templates/tablos.templ && grep -c "tablo-metadata-row" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/templates/tablos.templ && grep -c "804EEC" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/templates/tablos.templ && cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source && go test ./backend/internal/web/... -run TestTablos -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `tablos.templ` contains `class="project-card-top"` in TabloDetailPage header
    - `tablos.templ` contains `class="tab-nav-item is-active"` (applied conditionally to the active tab)
    - `tablos.templ` contains `class="tablo-metadata-row"`
    - `tablos.templ` contains `@ui.Badge(ui.BadgeProps{Label: "In progress", Variant: ui.BadgeVariantPrimary})`
    - `tablos.templ` contains `.project-progress-track` and `.project-progress-bar` class references
    - `grep -c "#804EEC" backend/templates/tablos.templ` returns 0 (all hardcoded hex removed from detail page)
    - `tablos.templ` contains `@TabloDescDisplay` call inside `TabloOverviewTabFragment` (not in the persistent header)
    - `go test ./backend/internal/web/... -run TestTablos -count=1` passes
    - `TabloDeleteButtonFragment` function body is unchanged (grep its content to confirm)
  </acceptance_criteria>
  <done>TabloDetailPage header uses project-card-top layout; tab nav uses design token classes; description is in overview tab; no hardcoded hex values remain in the detail page header/nav section.</done>
</task>

<task type="auto">
  <name>Task 2: Remove EtapeStrip call from TasksTabFragment</name>
  <files>backend/templates/tablos.templ</files>
  <read_first>
    - backend/templates/tablos.templ (already read in Task 1 — find TasksTabFragment, line ~407–420; confirm EtapeStrip call position)
    - .planning/phases/16-tablo-detail/16-RESEARCH.md (Pattern 4: EtapeStrip Removal and OOB Impact — this task handles Site 1 only; Sites 2 and 3 in tasks.templ are handled in Plan 03)
  </read_first>
  <action>
    In `TasksTabFragment` inside `tablos.templ`:

    DELETE the line: `@EtapeStrip(tablo.ID, etapes, counts, filter, csrfToken, false)` — remove this entire call (per D-E01; the EtapeStrip UI strip is removed from the tasks tab). Also remove any surrounding `div id="etape-strip"` wrapper if one exists.

    DO NOT modify the `@KanbanBoard(tablo.ID, csrfToken, tasks, filter)` call in this task. The KanbanBoard signature change (adding the `etapes` parameter) and ALL THREE call site updates happen atomically in Plan 03, Task 1 (tasks.templ) and Plan 03, Task 2 (handlers_tasks.go + tablos.templ). Splitting the call site update across plans would leave the build broken at the wave boundary.

    After editing, run: `just generate` to regenerate `tablos_templ.go`. Then confirm the build is clean.
  </action>
  <verify>
    <automated>grep -c "EtapeStrip" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/templates/tablos.templ && go build ./backend/... && go test ./backend/internal/web/... -run TestTablos -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `grep "EtapeStrip" backend/templates/tablos.templ` returns 0 (the EtapeStrip call is gone from TasksTabFragment)
    - `go build ./backend/...` exits 0 (build is clean — no compile errors)
    - `go test ./backend/internal/web/... -run TestTablos -count=1` passes
  </acceptance_criteria>
  <done>EtapeStrip is not called from TasksTabFragment; templ generate exits 0; go build ./backend/... exits 0.</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Go template → HTML response | tablos.templ renders tablo data from DB into HTML; existing ownership guard (`loadOwnedTablo`) unchanged |
| HTMX GET requests | hx-get endpoints for tab fragments are authenticated routes; no change to auth middleware |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-16-02-01 | Tampering | TabloDetailPage inline-edit zones | accept | tablo-title-zone and tablo-desc-zone HTMX endpoints validate CSRF token and ownership — unchanged; only CSS classes change |
| T-16-02-02 | Spoofing | Discussion/Delete action controls | accept | Auth middleware on all /tablos/{id}/* routes unchanged; restyling does not change route protection |
| T-16-02-03 | Information Disclosure | tablo.Color inline style | accept | tablo.Color is user-supplied but rendered as a CSS value in a style attribute; no script injection possible via `background-color: {value}` — browsers do not execute style values as JS |
</threat_model>

<verification>
```bash
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source
go test ./backend/internal/web/... -count=1
```
All existing tablo tests pass. No hardcoded #804EEC hex in tablos.templ for the detail page section.
</verification>

<success_criteria>
- `tablos.templ` header uses `.project-card-top`, `.project-avatar` (with first char), `.tablo-title-zone`
- All 5 tab nav items use `.tab-nav-item` / `.tab-nav-item.is-active` (no hardcoded hex)
- Description zone is inside `TabloOverviewTabFragment`
- `EtapeStrip` is not called from `TasksTabFragment`
- `KanbanBoard` call passes `etapes`
- `go test ./backend/internal/web/... -count=1` passes
</success_criteria>

<output>
After completion, create `.planning/phases/16-tablo-detail/16-02-SUMMARY.md` using the summary template.
</output>
