diff --git a/README.md b/README.md
index 85fb5a1..e98d84c 100644
--- a/README.md
+++ b/README.md
@@ -212,6 +212,14 @@ it is laid out along the length and turned before printing, which is what you wa
hangs from its short edge. Set it per site and check the bitmap preview — the two look very
different and only one will suit how you hang them.
+**Label stock** at the top of the badge settings is a shortcut that fills in the size, the roll
+type and the colour option. It is not itself a saved setting — the three fields it fills are what
+get stored, which is why it can appear to "revert" when the same dimensions describe two rolls.
+
+**Diagnostics.** The site card has a **Diagnostics** button showing exactly what would be sent,
+including the `brother_ql` command line, so it can be run by hand on the host. A failed test print
+shows the printer's own words rather than a summary.
+
**If the printer cannot be reached**, sign in still completes. The kiosk falls back to its own
browser print dialog, and the failure is shown against the site in **Admin → Sites** with the
reason. Admins can reprint any badge from the **On site** list.
diff --git a/public/css/admin.css b/public/css/admin.css
index 1cbdab1..80f45b9 100644
--- a/public/css/admin.css
+++ b/public/css/admin.css
@@ -400,3 +400,18 @@ tr.row-bad td { background: #fdf0f2; }
vertical-align: -2px;
margin-right: 2px;
}
+
+pre.raw {
+ margin: 0 0 14px;
+ padding: 12px;
+ background: var(--paper);
+ border: 1px solid var(--rule);
+ border-radius: 3px;
+ font-family: ui-monospace, Menlo, Consolas, monospace;
+ font-size: 12.5px;
+ line-height: 1.45;
+ white-space: pre-wrap;
+ word-break: break-word;
+ max-height: 320px;
+ overflow: auto;
+}
diff --git a/public/js/admin.js b/public/js/admin.js
index 08105ba..92bd151 100644
--- a/public/js/admin.js
+++ b/public/js/admin.js
@@ -689,6 +689,7 @@ async function loadSites() {
${s.printer.enabled ? `` : ''}
+ ${s.printer.enabled ? `` : ''}
`,
+ null,
+ { saveLabel: 'Close', hideCancel: true }
+ );
+ })
+ );
$$('[data-test-print]').forEach((btn) =>
btn.addEventListener('click', async () => {
btn.disabled = true;
@@ -748,7 +760,17 @@ async function loadSites() {
await api(`/sites/${btn.dataset.testPrint}/test-print`, { method: 'POST' });
toast('Sent to the printer.');
} catch (err) {
- toast(err.message, true);
+ // Show the printer's own words as well as the summary, because a refusal
+ // usually names the reason and the summary cannot cover every case.
+ const raw = err.payload?.raw;
+ openModal(
+ 'The printer refused the job',
+ `