Pages Medium
End-of-Shift Report
Printable X/Z shift report: net sales, tax, tips, voids, payment-method breakdown, cash drawer count, server-by-server tally. Print-ready with `@media print`.
Open in Lab
MCP
html css vanilla-js
Targets: JS HTML
Code
:root {
--cream: #f5f0e8;
--cream-2: #ece4d4;
--bone: #faf7f1;
--terracotta: #c1714a;
--terracotta-d: #a05a38;
--forest: #2d4a3e;
--forest-d: #1e3329;
--gold: #c9a84c;
--gold-light: #e6c97a;
--ink: #2c1a0e;
--ink-2: #4a3828;
--warm-gray: #7a6a58;
--success: #4f7a3a;
--danger: #b3432a;
--warning: #d99020;
--font-display: "Playfair Display", Georgia, serif;
--font-body: "Inter", system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-body);
background: var(--cream-2);
color: var(--ink);
min-height: 100vh;
-webkit-font-smoothing: antialiased;
display: flex;
flex-direction: column;
}
.toolbar {
background: var(--bone);
border-bottom: 1px solid rgba(44, 26, 14, 0.1);
padding: 14px 28px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.t-kicker {
font-size: 0.7rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--terracotta);
font-weight: 700;
}
.toolbar h1 {
font-family: var(--font-display);
font-weight: 800;
font-size: 1.4rem;
}
.t-tools {
display: flex;
gap: 8px;
align-items: center;
}
.seg {
background: var(--cream);
border: 1px solid rgba(44, 26, 14, 0.1);
border-radius: 999px;
padding: 3px;
display: inline-flex;
}
.seg-btn {
background: transparent;
border: none;
font-family: inherit;
font-size: 0.82rem;
font-weight: 700;
color: var(--ink-2);
padding: 7px 14px;
border-radius: 999px;
cursor: pointer;
}
.seg-btn.is-active {
background: var(--forest);
color: var(--bone);
}
.primary {
background: var(--forest);
color: var(--bone);
border: none;
border-radius: 999px;
padding: 9px 16px;
font-family: inherit;
font-size: 0.84rem;
font-weight: 700;
cursor: pointer;
}
.primary:hover {
background: var(--forest-d);
}
.paper {
padding: 28px 24px 64px;
display: flex;
justify-content: center;
}
.report {
width: 100%;
max-width: 860px;
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.1);
padding: 44px 56px 36px;
box-shadow: 0 14px 40px rgba(44, 26, 14, 0.14);
font-family: var(--font-mono);
font-size: 12.5px;
color: var(--ink);
line-height: 1.55;
}
.r-head {
text-align: center;
}
.r-brand {
font-family: var(--font-display);
font-weight: 800;
font-size: 1.7rem;
letter-spacing: 0.08em;
}
.r-addr {
font-size: 11px;
color: var(--ink-2);
}
.r-rule {
text-align: center;
letter-spacing: 0.4em;
color: var(--warm-gray);
margin: 14px 0 8px;
}
.head-meta {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px 24px;
font-size: 11.5px;
margin-top: 4px;
padding-top: 8px;
border-top: 1px dashed rgba(44, 26, 14, 0.3);
}
.head-meta div {
display: flex;
justify-content: space-between;
}
.head-meta dt {
color: var(--warm-gray);
letter-spacing: 0.04em;
}
.head-meta dd {
font-weight: 700;
}
.block {
margin-top: 28px;
}
.block h2 {
font-family: var(--font-display);
font-weight: 700;
font-size: 1.05rem;
margin-bottom: 12px;
border-bottom: 1px solid var(--terracotta);
padding-bottom: 4px;
}
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 36px;
}
@media (max-width: 720px) {
.grid-2 {
grid-template-columns: 1fr;
}
.report {
padding: 28px 24px;
}
}
.totals {
display: flex;
flex-direction: column;
gap: 4px;
}
.totals div {
display: flex;
justify-content: space-between;
font-size: 12.5px;
}
.totals dt {
color: var(--ink-2);
}
.totals dd {
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.totals .big {
border-top: 1px dashed rgba(44, 26, 14, 0.36);
margin-top: 4px;
padding-top: 6px;
font-size: 14px;
font-weight: 800;
}
.neg {
color: var(--danger);
}
.t {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.t th {
text-align: left;
padding: 6px 8px;
border-bottom: 1px solid rgba(44, 26, 14, 0.32);
color: var(--ink-2);
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 10px;
}
.t td {
padding: 6px 8px;
border-bottom: 1px dotted rgba(44, 26, 14, 0.18);
}
.t td:nth-child(n + 2) {
text-align: right;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.t .row-total td {
border-bottom: none;
font-weight: 800;
background: var(--cream);
border-top: 1px dashed rgba(44, 26, 14, 0.32);
}
.r-foot {
margin-top: 28px;
}
.sigs {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 36px;
margin-top: 24px;
}
.sig-line {
border-bottom: 1px solid var(--ink);
height: 26px;
}
.sig-label {
font-size: 11px;
margin-top: 4px;
color: var(--ink-2);
text-align: center;
}
.r-foot-note {
margin-top: 22px;
text-align: center;
font-size: 10.5px;
color: var(--warm-gray);
font-style: italic;
}
@media print {
body {
background: white;
}
.no-print {
display: none !important;
}
.paper {
padding: 0;
}
.report {
box-shadow: none;
border: none;
padding: 14mm 14mm;
max-width: 100%;
}
.block {
page-break-inside: avoid;
}
}const dateEl = document.getElementById("rDate");
const runEl = document.getElementById("rRun");
const typeEl = document.getElementById("rType");
const shiftEl = document.getElementById("rShift");
const fmt = (n) => String(n).padStart(2, "0");
const d = new Date();
dateEl.textContent = `${d.getFullYear()}-${fmt(d.getMonth() + 1)}-${fmt(d.getDate())}`;
runEl.textContent = `${fmt(d.getHours())}:${fmt(d.getMinutes())}`;
document.querySelectorAll(".seg-btn").forEach((b) =>
b.addEventListener("click", () => {
document.querySelectorAll(".seg-btn").forEach((x) => x.classList.toggle("is-active", x === b));
if (b.dataset.r === "x") {
typeEl.textContent = "X · INTERIM";
shiftEl.textContent = "19:00 – running";
} else {
typeEl.textContent = "Z · CLOSE";
shiftEl.textContent = "19:00 – 23:42";
}
})
);
document.getElementById("printBtn").addEventListener("click", () => {
window.print();
});<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;800&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600;700&display=swap"
/>
<link rel="stylesheet" href="style.css" />
<title>Shift report · Casa Olivar</title>
</head>
<body>
<div class="toolbar no-print">
<div>
<p class="t-kicker">Casa Olivar · POS</p>
<h1>End-of-shift report</h1>
</div>
<div class="t-tools">
<div class="seg">
<button class="seg-btn" type="button" data-r="x">X · interim</button>
<button class="seg-btn is-active" type="button" data-r="z">Z · close</button>
</div>
<button class="primary" type="button" id="printBtn">⎙ Print report</button>
</div>
</div>
<main class="paper">
<article class="report">
<header class="r-head">
<p class="r-brand">CASA OLIVAR</p>
<p class="r-addr">42 Calle del Olivar · Madrid · +34 910 555 042</p>
<p class="r-rule">— · —</p>
<dl class="head-meta">
<div><dt>Report</dt><dd id="rType">Z · CLOSE</dd></div>
<div><dt>Terminal</dt><dd>T-02</dd></div>
<div><dt>Shift</dt><dd id="rShift">19:00 – 23:42</dd></div>
<div><dt>Date</dt><dd id="rDate">—</dd></div>
<div><dt>Manager</dt><dd>Marco Reyes</dd></div>
<div><dt>Run at</dt><dd id="rRun">—</dd></div>
</dl>
</header>
<section class="block">
<h2>Sales summary</h2>
<dl class="totals">
<div><dt>Covers</dt><dd>38</dd></div>
<div><dt>Tickets</dt><dd>22</dd></div>
<div><dt>Avg check</dt><dd>$78.42</dd></div>
<div><dt>Gross sales</dt><dd>$2,884.00</dd></div>
<div><dt>Discounts</dt><dd class="neg">−$72.00</dd></div>
<div><dt>Net sales</dt><dd>$2,812.00</dd></div>
<div><dt>Tax (8.25%)</dt><dd>$231.99</dd></div>
<div><dt>Service (10%)</dt><dd>$281.20</dd></div>
<div class="big"><dt>Total taken</dt><dd>$3,325.19</dd></div>
</dl>
</section>
<section class="block">
<h2>Payment methods</h2>
<table class="t">
<thead><tr><th>Method</th><th>Count</th><th>Amount</th><th>%</th></tr></thead>
<tbody>
<tr><td>Cash</td><td>4</td><td>$362.10</td><td>10.9%</td></tr>
<tr><td>Visa / MC</td><td>13</td><td>$2,124.40</td><td>63.9%</td></tr>
<tr><td>Amex</td><td>2</td><td>$402.69</td><td>12.1%</td></tr>
<tr><td>Apple / Google Pay</td><td>2</td><td>$298.00</td><td>9.0%</td></tr>
<tr><td>Gift / house comp</td><td>1</td><td>$138.00</td><td>4.1%</td></tr>
<tr class="row-total"><td>Total</td><td>22</td><td>$3,325.19</td><td>100%</td></tr>
</tbody>
</table>
</section>
<section class="block grid-2">
<article>
<h2>Cash drawer</h2>
<dl class="totals">
<div><dt>Starting float</dt><dd>$150.00</dd></div>
<div><dt>+ Cash sales</dt><dd>$362.10</dd></div>
<div><dt>+ Cash tips paid out</dt><dd class="neg">−$48.00</dd></div>
<div><dt>= Expected</dt><dd>$464.10</dd></div>
<div><dt>Counted</dt><dd>$464.00</dd></div>
<div class="big">
<dt>Variance</dt>
<dd class="neg">−$0.10</dd>
</div>
</dl>
</article>
<article>
<h2>Tips & gratuity</h2>
<dl class="totals">
<div><dt>Service charge auto</dt><dd>$281.20</dd></div>
<div><dt>Card tips collected</dt><dd>$398.40</dd></div>
<div><dt>Cash tips declared</dt><dd>$48.00</dd></div>
<div><dt>Tip pool · 60% floor</dt><dd>$255.36</dd></div>
<div><dt>Tip pool · 30% kitchen</dt><dd>$127.68</dd></div>
<div class="big">
<dt>Total to staff</dt>
<dd>$727.60</dd>
</div>
</dl>
</article>
</section>
<section class="block">
<h2>Voids, comps & refunds</h2>
<table class="t">
<thead><tr><th>Type</th><th>Count</th><th>Amount</th><th>Reason</th></tr></thead>
<tbody>
<tr><td>Void</td><td>2</td><td>$48.00</td><td>Mistaken entry · table 4</td></tr>
<tr><td>Comp</td><td>1</td><td>$24.00</td><td>Birthday dessert · table 11</td></tr>
<tr><td>Refund</td><td>0</td><td>$0.00</td><td>—</td></tr>
</tbody>
</table>
</section>
<section class="block">
<h2>By server</h2>
<table class="t">
<thead>
<tr><th>Server</th><th>Tickets</th><th>Covers</th><th>Net sales</th><th>Tips</th></tr>
</thead>
<tbody>
<tr><td>Lina M.</td><td>8</td><td>14</td><td>$1,124.80</td><td>$184.40</td></tr>
<tr><td>Iria C.</td><td>6</td><td>10</td><td>$842.00</td><td>$132.80</td></tr>
<tr><td>Sofía R.</td><td>5</td><td>9</td><td>$612.20</td><td>$98.60</td></tr>
<tr><td>Theo K. (bar)</td><td>3</td><td>5</td><td>$233.00</td><td>$30.60</td></tr>
<tr class="row-total"><td>Total</td><td>22</td><td>38</td><td>$2,812.00</td><td>$446.40</td></tr>
</tbody>
</table>
</section>
<footer class="r-foot">
<p class="r-rule">— · —</p>
<div class="sigs">
<div>
<p class="sig-line"></p>
<p class="sig-label">Manager signature · Marco Reyes</p>
</div>
<div>
<p class="sig-line"></p>
<p class="sig-label">Counter-witness · Iria Costa</p>
</div>
</div>
<p class="r-foot-note">
End-of-shift Z report · system locks at midnight · keep one paper copy
in the safe for 7 days.
</p>
</footer>
</article>
</main>
<script src="script.js"></script>
</body>
</html>End-of-Shift Report
The Z-report a manager prints at close. Top header with restaurant, terminal, shift window and signature line. Body covers: net sales / tax / total · payment-method breakdown (cash, card, wallet, gift, comp) · gratuity split · void & comp count · cash drawer count (start, expected, counted, variance) · server-by-server tally. Footer prints the manager signature line. @media print strips the screen toolbar.