feat: Worker portal Stage 1.5 — upgrade panel-state utility classes to 4 Askama-macro primitives

Description

Phase-1.5 follow-up to #485 (closed) (Stage 1 design system extraction). The original Stage 1 ships the 8 primitives (PanelFrameMoneyCell) plus four CSS-only panel-state utility classes (cy-pulse, .cy-skeleton, .cy-error-block, .cy-empty-state). Design has confirmed those four are first-class enough to be proper primitives — every panel renders all four states, source is dashboard/states.jsx in the 2026-05-14 design package.

This issue upgrades the four utility classes to four proper Askama-macro primitives with first-class props. Does not block #485 (closed); lands after.

Acceptance Criteria

  • Four new Askama-macro primitives at services/canopy-web/templates/_primitives/:
    • EmptyState: title + body + optional icon + optional cta (label + href). Centered, ~180 px min-height.
    • Skeleton: height + width + radius props; applies the cy-pulse keyframe animation.
    • SkeletonRow: composes Skeleton for table-shaped panels (avatar slot + N columns).
    • ErrorBlock: title + body + optional last_known_at (timestamp) + retry (htmx target) / status (link) buttons.
  • Rule documented + enforced via Askama-template lint or convention test: every panel template must render all four states (empty, loading, error, populated).
  • Existing four utility classes (cy-pulse keyframe stays; .cy-skeleton / .cy-error-block / .cy-empty-state) deprecated and removed once all callers migrate (within this MR).
  • At least one in-tree dashboard panel rewritten to use all four state primitives to validate the rule.
  • axe-core WCAG 2.1 AA clean for the validating panel
  • Playwright E2E: each state renders cleanly
  • CHANGELOG entry under === Changed

Context & References

  • Tracking issue: #460
  • Epic: &51
  • Plan: worker-portal-redesign.adoc, Stage 1.5
  • Source: dashboard/states.jsx from 2026-05-14 design package
  • Blocks: none in this epic (follow-up that runs in parallel with Stage 2 / Stage 3); strengthens the foundation for every Stage 5+ surface

Blocked by

  • #485 (closed) (Stage 1 ships first; this upgrades the four utility classes it leaves behind)

Labels

type::feature, priority::medium, program::infrastructure, service::web, workflow::ready, compliance::wcag-21-aa