diff --git a/bible-local/07-exporters.md b/bible-local/07-exporters.md
index a4c838e..00c2520 100644
--- a/bible-local/07-exporters.md
+++ b/bible-local/07-exporters.md
@@ -7,6 +7,7 @@
| `GET /api/export/csv` | CSV | Serial-number export |
| `GET /api/export/json` | raw-export ZIP bundle | Reopen and re-analyze later |
| `GET /api/export/reanimator` | JSON | Reanimator hardware payload |
+| `GET /chart/current?print=true` | HTML (auto-print) | Print/PDF version of the report — opens in new tab, calls `window.print()` |
| `POST /api/convert` | async ZIP artifact | Batch archive-to-Reanimator conversion |
## Raw export
diff --git a/internal/chart b/internal/chart
index 8105c7e..fddae50 160000
--- a/internal/chart
+++ b/internal/chart
@@ -1 +1 @@
-Subproject commit 8105c7ec08469cff523f2f2012921b59cf262707
+Subproject commit fddae50d64eefbd455d24eb2343e72078666bd16
diff --git a/internal/server/handlers.go b/internal/server/handlers.go
index 1e02678..5e3bc73 100644
--- a/internal/server/handlers.go
+++ b/internal/server/handlers.go
@@ -84,7 +84,10 @@ func (s *Server) handleChartCurrent(w http.ResponseWriter, r *http.Request) {
return
}
- html, err := chartviewer.RenderHTML(snapshotBytes, title)
+ printMode := r.URL.Query().Get("print") == "true"
+ html, err := chartviewer.RenderHTMLWithOptions(snapshotBytes, title, chartviewer.RenderOptions{
+ PrintMode: printMode,
+ })
if err != nil {
http.Error(w, "failed to render chart: "+err.Error(), http.StatusInternalServerError)
return
diff --git a/web/static/js/app.js b/web/static/js/app.js
index a630c75..0310ad4 100644
--- a/web/static/js/app.js
+++ b/web/static/js/app.js
@@ -1410,6 +1410,7 @@ async function loadData(vendor, filename) {
document.getElementById('clear-btn').classList.remove('hidden');
document.getElementById('header-raw-btn').classList.remove('hidden');
document.getElementById('header-reanimator-btn').classList.remove('hidden');
+ document.getElementById('header-pdf-btn').classList.remove('hidden');
document.getElementById('header-log-meta').classList.remove('hidden');
loadAuditViewer();
@@ -1509,6 +1510,10 @@ function exportData(format) {
window.location.href = `/api/export/${format}`;
}
+function printReport() {
+ window.open('/chart/current?print=true', '_blank');
+}
+
// Clear data
async function clearData() {
try {
@@ -1518,6 +1523,7 @@ async function clearData() {
document.getElementById('clear-btn').classList.add('hidden');
document.getElementById('header-raw-btn').classList.add('hidden');
document.getElementById('header-reanimator-btn').classList.add('hidden');
+ document.getElementById('header-pdf-btn').classList.add('hidden');
document.getElementById('header-log-meta').classList.add('hidden');
document.getElementById('upload-status').textContent = '';
const frame = document.getElementById('audit-viewer-frame');
diff --git a/web/templates/index.html b/web/templates/index.html
index 14edd73..c1e6912 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -18,6 +18,7 @@
+