---
phase: 19-tablo-list-revamp
plan: "02"
type: execute
wave: 2
depends_on: ["19-01"]
files_modified:
  - backend/templates/tablos.templ
  - backend/internal/web/ui/app.css
  - backend/static/tailwind.css          # regenerated by tailwindcss CLI
  - backend/templates/tablos_templ.go    # regenerated by templ generate
autonomous: true
requirements: [LIST-01, LIST-03]

must_haves:
  truths:
    - "TabloProjectCard shows a status badge (top-left) and delete button (top-right)"
    - "TabloProjectCard shows the tablo initial letter inside the colored avatar circle"
    - "TabloProjectCard shows a progress bar filled to card.Progress % with label 'Progression: X%'"
    - "Each tablo card renders both a .project-card element and a .tablo-list-row sibling"
    - "app.css contains .tablo-list-row, .project-card-progress-row, and [data-view='list'] CSS rules"
    - "go build and templ generate both exit 0 after changes"
  artifacts:
    - path: "backend/templates/tablos.templ"
      provides: "Revamped TabloProjectCard matching production screenshot"
      contains: "project-card-progress-row"
    - path: "backend/internal/web/ui/app.css"
      provides: "Progress row CSS + list row CSS + data-view toggle rules"
      contains: "tablo-list-row"
    - path: "backend/static/tailwind.css"
      provides: "Regenerated Tailwind output"
      contains: "tablo-list-row"
  key_links:
    - from: "TabloProjectCard template"
      to: "card.Progress (int, 0–100)"
      via: "inline style width: X% on .project-progress-bar"
      pattern: "project-progress-bar"
    - from: "TabloProjectCard template"
      to: "card.Tablo.Status (string)"
      via: "ui.Badge label"
      pattern: "ui.Badge"
    - from: ".project-card-progress-row CSS"
      to: ".project-progress-track / .project-progress-bar"
      via: "nested child selectors in app.css §20"
      pattern: "project-progress-track"
---

<objective>
Rebuild `TabloProjectCard` to match the production screenshot design — status badge, colored avatar initial, title, date, progress bar — and add both the new card CSS and the dual-element list row foundation.

Purpose: Delivers LIST-01 and the visual part of LIST-03. Plan 03 adds the toggle button that switches between the two elements rendered here.
Output: Revamped `TabloProjectCard` template + new CSS classes in app.css + regenerated tailwind.css.
</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>
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/ROADMAP.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/19-tablo-list-revamp/19-CONTEXT.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/19-tablo-list-revamp/19-RESEARCH.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/18-app-shell-navigation/18-03-SUMMARY.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/19-tablo-list-revamp/19-01-SUMMARY.md

Read before making visual decisions:
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/screenshots/Homepage.png
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/screenshots/ssidebar-header.png
</context>

<interfaces>
<!-- Key contracts the executor needs. Extracted from codebase. -->

From backend/templates/discussion_forms.go (after Plan 01):
```go
type TabloCardView struct {
    Tablo                 sqlc.Tablo    // .ID, .Title, .Color (pgtype.Text), .CreatedAt (pgtype.Timestamptz), .Status (string)
    DiscussionUnreadCount int64
    Progress              int           // 0–100
}
```

From backend/internal/web/ui/variants.go:
```go
type BadgeVariant string
const (
    BadgeVariantInfo    BadgeVariant = "info"
    BadgeVariantWarning BadgeVariant = "warning"
    BadgeVariantSuccess BadgeVariant = "success"
    BadgeVariantDanger  BadgeVariant = "danger"
    BadgeVariantPrimary BadgeVariant = "primary"   // ← use for "Active" status badge
)
```

From backend/internal/web/ui/badge.templ:
```go
type BadgeProps struct {
    Label   string
    Variant BadgeVariant
}
templ Badge(props BadgeProps) { ... }
// Usage: @ui.Badge(ui.BadgeProps{Label: "Active", Variant: ui.BadgeVariantPrimary})
```

From backend/templates/tablos.templ (current TabloProjectCard — root element is <article>):
```go
// Current root: <article id={"tablo-" + card.Tablo.ID.String()} class="project-card">
// HTMX OOB: TabloCardWithOOBFormClear calls TabloCard (NOT TabloProjectCard) for new tablo insertion.
// TabloProjectCard is rendered in the dashboard grid only.
// Safe to change its root element to a wrapper article with class="tablo-card-wrapper".
```

From backend/internal/web/ui/app.css (existing CSS — do NOT remove or rename):
```css
/* §14 */ .project-grid — 3-column grid, gap 1.25rem
/* §15 */ .project-card — card shell (border, radius 1rem, padding 1rem)
/* §16 */ .project-card-top — flex space-between, margin-bottom 1rem
/* §17 */ .project-card-title-row — flex, gap 0.75rem, margin-bottom 1rem
/* §17 */ .project-avatar — 3rem×3rem colored circle, background: var(--project-color, fallback)
/* §18 */ .project-date-row — flex, muted color, font-size 0.875rem, margin-bottom 1rem
/* §20 */ .project-progress-track — muted bg, border-radius 999px, height 0.5rem
/* §20 */ .project-progress-bar — background: var(--project-color, fallback), border-radius 999px, height 100%
```

Progress bar color note (Pitfall 3 from RESEARCH.md):
- .project-progress-bar uses var(--project-color, var(--color-project-fallback)).
- Per D-11: use var(--color-accent) for the progress bar on cards. Add a new class
  .project-card-progress-bar that overrides background to var(--color-accent) instead
  of var(--project-color). Use this class (not .project-progress-bar) on dashboard cards.
- Alternatively, set style="--project-color: var(--color-accent)" on the .project-card
  wrapper. Either approach is acceptable.

Initial letter pattern (from TabloDetailPage):
```go
// Confirmed pattern for avatar initial:
if card.Tablo.Color.Valid && card.Tablo.Color.String != "" {
    <span class="project-avatar" style={ "background-color: " + card.Tablo.Color.String }>
        if len(card.Tablo.Title) > 0 {
            { string([]rune(card.Tablo.Title)[0:1]) }
        }
    </span>
} else {
    <span class="project-avatar">
        if len(card.Tablo.Title) > 0 {
            { string([]rune(card.Tablo.Title)[0:1]) }
        }
    </span>
}
```

String import for Itoa (already in discussion_forms.go — NOT in tablos.templ yet):
```go
// tablos.templ needs: import "strconv" for strconv.Itoa(card.Progress)
// Add "strconv" to the import block in tablos.templ.
// strings.Title is deprecated — use strings.ToUpper(card.Tablo.Status[:1]) +
// card.Tablo.Status[1:] for title-casing, OR just pass "Active" as the badge label
// directly since Phase 19 only shows 'active' status. Recommended: title-case helper.
```

Tailwind rebuild command:
```bash
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend
./bin/tailwindcss -i tailwind.input.css -o static/tailwind.css --minify
```
</interfaces>

<tasks>

<task type="auto">
  <name>Task 1: Rebuild TabloProjectCard template with dual card+row output</name>
  <files>
    backend/templates/tablos.templ
  </files>
  <action>
    Read the production screenshot at screenshots/ssidebar-header.png before editing.
    The target layout (per D-10): status badge top-left, delete icon top-right, colored
    avatar circle with initial letter, title, creation date with calendar icon,
    "Progression: X%" label + progress bar.

    Rewrite the TabloProjectCard component in backend/templates/tablos.templ.

    1. Add "strconv" and "strings" to the import block at the top of tablos.templ.

    2. Replace the current TabloProjectCard body. The new structure:

       a. Outer wrapper article (same id, new class "tablo-card-wrapper") containing
          both the .project-card div and the .tablo-list-row div as siblings.
          This satisfies the dual-element approach (see RESEARCH.md pitfall 4) so that
          the HTMX OOB fragment remains a single root element.

       b. Inside .project-card:
          - .project-card-top: left side = status badge, right side = delete icon button
          - .project-card-title-row: avatar circle (with initial letter), title h4
          - .project-date-row: calendar SVG icon + formatted date
          - .project-card-progress-row: "Progression: X%" span + .project-progress-track
            containing .project-card-progress-bar (see Pitfall 3 note in interfaces)

       c. Inside .tablo-list-row (hidden by default via CSS, shown in list view):
          - Status badge
          - Title span
          - Date span
          - Progress label "X%"
          - Delete icon button
          (Full table-row layout is styled in Plan 03's CSS additions. This task
          renders the HTML structure; Plan 03 finalizes the toggle mechanism.)

    For the status badge label: title-case the Status string. Since strings.Title is
    deprecated, use a local helper in the template:
       { strings.ToUpper(card.Tablo.Status[:1]) + card.Tablo.Status[1:] }
    Guard against empty string: if len(card.Tablo.Status) > 0.

    For the progress bar: use class "project-card-progress-bar" (a new CSS class
    defined in Task 2 that uses var(--color-accent) instead of var(--project-color)).
    Set inline style for width: { strconv.Itoa(card.Progress) + "%" }

    For the delete icon button: keep the existing @ui.IconButton call with hx-get,
    hx-target, hx-swap identical to the current implementation.

    The edit-title pencil icon button from the current implementation can be removed
    per the production screenshot — the design shows only the delete button top-right.

    Do NOT rename or remove any other templ components in this file.

    3. Run templ generate:
       cd backend && templ generate ./...

    4. Run go build ./... to confirm the file compiles.
  </action>
  <verify>
    <automated>cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend && templ generate ./... && go build ./... 2>&1</automated>
  </verify>
  <done>
    - TabloProjectCard renders an outer article.tablo-card-wrapper containing .project-card and .tablo-list-row siblings
    - .project-card-top has status badge on left and delete button on right
    - .project-card-title-row has avatar with initial letter
    - .project-card-progress-row has "Progression: X%" label and .project-card-progress-bar
    - `templ generate` exits 0
    - `go build ./...` exits 0
  </done>
</task>

<task type="auto">
  <name>Task 2: Add progress-row and list-row CSS to app.css, rebuild Tailwind</name>
  <files>
    backend/internal/web/ui/app.css
    backend/static/tailwind.css
  </files>
  <action>
    Edit backend/internal/web/ui/app.css only (never edit static/tailwind.css directly).

    Append a new CSS section after Section 20 (progress track/bar). Call it
    "Section 20b — Dashboard card progress row and list-row":

    1. .project-card-progress-row — wrapper for the progress label + bar on cards:
       display: flex; flex-direction: column; gap: 0.35rem;

    2. .project-card-progress-label — "Progression: X%" text:
       color: var(--color-text-muted); font-size: 0.8rem;

    3. .project-card-progress-bar — accent-colored bar for dashboard cards (overrides
       the project-color var used in .project-progress-bar):
       background: var(--color-accent);
       border-radius: 999px;
       height: 100%;

    4. .tablo-card-wrapper — transparent grid item wrapper (so the grid layout still
       works when each slot contains a wrapper instead of a bare .project-card):
       display: contents;
       /* display:contents makes the wrapper invisible to layout — children
          (.project-card and .tablo-list-row) participate in the grid directly */

    5. .tablo-list-row — row layout for list view (hidden by default):
       display: none;
       align-items: center;
       gap: 1rem;
       padding: 0.75rem 1rem;
       border: 1px solid var(--color-border-subtle);
       border-radius: 0.75rem;
       background: var(--color-surface-default);

    6. .tablo-list-row-title — flex 1, font-weight 500

    7. .tablo-list-row-meta — muted color, font-size 0.875rem, flex items gap 0.5rem

    8. [data-view="list"] toggle rules (append at the end of the new section):

       #tablos-list[data-view="list"] {
         display: flex;
         flex-direction: column;
         gap: 0.5rem;
       }

       #tablos-list[data-view="list"] .project-card {
         display: none;
       }

       #tablos-list[data-view="list"] .tablo-list-row {
         display: flex;
       }

       Note on display:contents and list view: when data-view="list", the
       #tablos-list switches from grid to flex-column. The .tablo-card-wrapper
       wrappers (display:contents) are transparent to both layouts, so the switch
       works without overriding the wrapper.

    After editing app.css, rebuild Tailwind:
    cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend
    ./bin/tailwindcss -i tailwind.input.css -o static/tailwind.css --minify
  </action>
  <verify>
    <automated>cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend && grep -c "tablo-list-row" internal/web/ui/app.css && grep -c "project-card-progress-row" internal/web/ui/app.css && grep -c "tablo-list-row" static/tailwind.css</automated>
  </verify>
  <done>
    - app.css contains .tablo-card-wrapper (display: contents), .tablo-list-row, .project-card-progress-row, .project-card-progress-bar, and [data-view="list"] toggle rules
    - static/tailwind.css is regenerated and contains "tablo-list-row"
    - `go build ./...` still exits 0 after CSS changes
  </done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Template → DB value (Status) | Status string from DB is rendered as badge label; templ auto-escapes |
| Template → Progress int | Integer 0–100 from handler; rendered as inline style width and as text |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-19-02-01 | Information Disclosure | Status badge label | accept | Status value comes only from the authenticated user's own tablos; no cross-user leakage |
| T-19-02-02 | Tampering | Progress inline style | accept | Progress is server-computed int (0–100); rendered as `width: X%` via strconv.Itoa — no user input in path |
| T-19-02-03 | Elevation of Privilege | Delete button HTMX target | accept | hx-get /tablos/{id}/delete-confirm requires server-side ownership check (loadOwnedTablo); client-side rendering does not bypass this |
</threat_model>

<verification>
After both tasks complete:

```bash
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend
templ generate ./...
go build ./...
go test ./internal/web/... -run TestTablosDashboard_ProjectCards -v
grep -c "project-card-progress-row" internal/web/ui/app.css
grep -c "tablo-list-row" internal/web/ui/app.css
grep -c "tablo-card-wrapper" internal/web/ui/app.css
grep -c "tablo-list-row" static/tailwind.css
```

Expected: all greps return 1+; build exits 0; test passes or skips (no test DB).
</verification>

<success_criteria>
- `grep -c "project-card-progress-row" backend/internal/web/ui/app.css` returns 1
- `grep -c "tablo-list-row" backend/internal/web/ui/app.css` returns 1
- `grep -c "tablo-card-wrapper" backend/internal/web/ui/app.css` returns 1
- `grep -c "tablo-list-row" backend/static/tailwind.css` returns 1
- `grep -c "project-card-progress-row" backend/templates/tablos.templ` returns 1
- `grep -c "ui.Badge" backend/templates/tablos.templ` returns 1 (status badge)
- `cd backend && go build ./...` exits 0
- Visual: GET / shows cards with status badge, avatar initial, progress bar filled to correct %
</success_criteria>

<output>
After completion, create `/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/19-tablo-list-revamp/19-02-SUMMARY.md` following the summary template.
</output>
