diff --git a/.jules/palette.md b/.jules/palette.md
index 74cddb7ad..7a115b91b 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -19,3 +19,7 @@
## 2024-07-13 - CLI Debugging Stack Traces
**Learning:** Adding a `FAST_MLSIRM_DEBUG` bypass to user-friendly `try/except` blocks is crucial for DX. Otherwise, unexpected runtime errors during development will be swallowed into generic stderr messages, hiding the stack trace needed to actually fix the bug.
**Action:** When adding `try-except` blocks to Python CLI subcommands to improve Developer Experience (DX) by preventing raw tracebacks for users, include a debug bypass (e.g., `if os.environ.get("FAST_MLSIRM_DEBUG"): raise`) in *all* catch blocks (including `RuntimeError` and `Exception`) to ensure tracebacks aren't swallowed during local development and debugging.
+
+## 2026-07-28 - Table Row Header Accessibility
+**Learning:** When generating HTML data tables for reports, using `
` for the first identifying column improves screen reader accessibility by clearly associating the row header with its corresponding data cells. Additionally, applying `font-variant-numeric: tabular-nums;` ensures numbers align properly in columns for better visual tracking.
+**Action:** Always use ` | ` for the primary identifying cell in a table row, update base CSS selectors (like `thead th, tbody th, td`) to include the new tags to prevent visual regressions, and apply tabular-nums for numeric alignment in data-heavy tables.
diff --git a/python/fast_mlsirm/report.py b/python/fast_mlsirm/report.py
index 30ee4276b..c92abf6ad 100644
--- a/python/fast_mlsirm/report.py
+++ b/python/fast_mlsirm/report.py
@@ -317,11 +317,14 @@ def _table(rows: list[dict[str, Any]], *, label: str, limit: int = 12) -> str:
columns = _columns(rows)
body_rows = []
for row in rows[:limit]:
- cells = "".join(
- f" | {escape(_format_value(row.get(column, '')))} | "
- for column in columns
- )
- body_rows.append(f"{cells}
")
+ cells = []
+ for index, column in enumerate(columns):
+ val = escape(_format_value(row.get(column, "")))
+ if index == 0:
+ cells.append(f'{val} | ')
+ else:
+ cells.append(f"{val} | ")
+ body_rows.append(f"{''.join(cells)}
")
note = ""
described_by = ""
@@ -679,21 +682,28 @@ def _css() -> str:
border: 0;
}
-th,
+thead th,
+tbody th,
td {
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid var(--line);
white-space: nowrap;
+ font-variant-numeric: tabular-nums;
}
-th {
+thead th {
background: #f1f4ef;
color: #2f3437;
font-size: 0.8rem;
}
-tr:last-child td {
+tbody th {
+ font-weight: normal;
+}
+
+tr:last-child td,
+tr:last-child th {
border-bottom: 0;
}