Auto — Diagnostic Report
An industrial diagnostic scan report for an auto shop, listing stored trouble codes such as P0301 and P0420 with severity rails, affected system, freeze-frame data, and a recommended fix plus labor cost. Customers and techs can expand any code for detail, filter by severity, and approve recommended repairs that roll up into a live work-order estimate with an authorize button. Animated health gauges summarize overall, engine, emissions, and electrical condition.
MCP
Code
:root {
--garage: #141518;
--garage-2: #1f2127;
--steel: #5b6470;
--steel-l: #8a929d;
--orange: #ff6a13;
--orange-d: #e2540a;
--orange-50: #fff0e6;
--ink: #16181c;
--ink-2: #3b4049;
--muted: #737a85;
--bg: #f3f4f6;
--surface: #ffffff;
--line: rgba(20, 21, 24, 0.1);
--line-2: rgba(20, 21, 24, 0.18);
--ok: #2f9e6f;
--warn: #e0962a;
--danger: #d4493e;
--info: #2b7fff;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 18px;
--shadow-sm: 0 1px 2px rgba(20, 21, 24, 0.06), 0 1px 3px rgba(20, 21, 24, 0.05);
--shadow-md: 0 6px 20px rgba(20, 21, 24, 0.08);
--shadow-lg: 0 18px 48px rgba(20, 21, 24, 0.14);
}
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
font-family: "Inter", system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 22px 16px 48px;
}
.mono {
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum" 1;
letter-spacing: 0.01em;
}
.shell { max-width: 1180px; margin: 0 auto; }
/* Topbar */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
background: linear-gradient(135deg, var(--garage) 0%, var(--garage-2) 100%);
color: #fff;
border-radius: var(--r-lg);
padding: 16px 20px;
box-shadow: var(--shadow-md);
}
.brand { display: flex; align-items: center; gap: 13px; }
.brand-mark {
width: 44px; height: 44px;
border-radius: var(--r-sm);
background: var(--orange);
color: #141518;
display: grid; place-items: center;
font-weight: 800;
font-size: 17px;
letter-spacing: -0.02em;
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.14);
}
.brand-text { display: flex; flex-direction: column; }
.brand-name { font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.brand-sub { font-size: 12.5px; color: var(--steel-l); font-weight: 500; }
.topbar-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ro-chip, .scan-chip {
font-size: 12.5px;
font-weight: 600;
padding: 6px 12px;
border-radius: 999px;
}
.ro-chip {
background: rgba(255, 255, 255, 0.08);
color: #fff;
font-variant-numeric: tabular-nums;
border: 1px solid rgba(255, 255, 255, 0.16);
}
.scan-chip {
background: rgba(47, 158, 111, 0.16);
color: #7be3b6;
border: 1px solid rgba(47, 158, 111, 0.4);
}
/* Layout grid */
.layout {
margin-top: 18px;
display: grid;
grid-template-columns: 1.55fr 1fr;
grid-template-areas:
"vehicle vehicle"
"codes health"
"codes estimate";
gap: 18px;
align-items: start;
}
.vehicle { grid-area: vehicle; }
.health { grid-area: health; }
.codes { grid-area: codes; }
.estimate { grid-area: estimate; position: sticky; top: 16px; }
.panel {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
box-shadow: var(--shadow-sm);
padding: 18px;
}
.panel-title {
margin: 0 0 14px;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.02em;
text-transform: uppercase;
color: var(--ink-2);
}
/* Vehicle panel */
.vehicle {
display: grid;
grid-template-columns: 168px 1fr auto;
gap: 20px;
align-items: center;
}
.veh-photo {
position: relative;
height: 110px;
border-radius: var(--r-md);
background:
radial-gradient(120% 90% at 20% 10%, rgba(255, 255, 255, 0.18), transparent 60%),
linear-gradient(135deg, var(--garage-2), var(--steel));
overflow: hidden;
}
.veh-photo::after {
content: "";
position: absolute;
inset: auto -10% -40% auto;
width: 80%; height: 80%;
background: radial-gradient(circle, rgba(255, 106, 19, 0.4), transparent 70%);
filter: blur(8px);
}
.veh-photo-tag {
position: absolute;
top: 9px; left: 9px;
font-size: 11px;
font-weight: 600;
color: #fff;
background: rgba(20, 21, 24, 0.45);
padding: 3px 8px;
border-radius: 999px;
backdrop-filter: blur(4px);
}
.veh-title { margin: 0 0 2px; font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }
.veh-owner { margin: 0 0 12px; font-size: 13px; color: var(--muted); font-weight: 500; }
.veh-specs {
margin: 0;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 18px;
}
.veh-specs div { display: flex; flex-direction: column; }
.veh-specs dt { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--steel); font-weight: 600; }
.veh-specs dd { margin: 1px 0 0; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.veh-bay {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
padding: 12px 18px;
border-left: 1px solid var(--line);
}
.bay-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--steel); font-weight: 600; }
.bay-num { font-size: 38px; font-weight: 800; color: var(--orange); line-height: 1; font-variant-numeric: tabular-nums; }
.tech-tag { margin-top: 4px; font-size: 11.5px; color: var(--muted); font-weight: 500; }
/* Health gauges */
.gauges { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.gauge { margin: 0; text-align: center; }
.gauge-ring {
--val: 0;
--col: var(--ok);
width: 92px; height: 92px;
margin: 0 auto 8px;
border-radius: 50%;
display: grid; place-items: center;
background:
radial-gradient(closest-side, var(--surface) 70%, transparent 71% 100%),
conic-gradient(var(--col) calc(var(--val) * 1%), rgba(20, 21, 24, 0.08) 0);
transition: background 0.1s linear;
}
.gauge-num { font-size: 22px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.gauge figcaption { font-size: 12px; font-weight: 600; color: var(--muted); }
/* Codes */
.codes-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
margin-bottom: 14px;
}
.codes-head .panel-title { margin: 0; }
.filters { display: flex; gap: 6px; flex-wrap: wrap; }
.filter {
font: inherit;
font-size: 12.5px;
font-weight: 600;
padding: 6px 13px;
border-radius: 999px;
border: 1px solid var(--line-2);
background: var(--surface);
color: var(--ink-2);
cursor: pointer;
transition: all 0.15s ease;
}
.filter:hover { border-color: var(--steel); background: #fafafb; }
.filter.is-active { background: var(--garage); color: #fff; border-color: var(--garage); }
.filter:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.code-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.code {
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.code:hover { border-color: var(--line-2); box-shadow: var(--shadow-sm); }
.code.is-open { box-shadow: var(--shadow-md); border-color: var(--line-2); }
.code-head {
display: grid;
grid-template-columns: 6px auto 1fr auto;
align-items: center;
gap: 12px;
width: 100%;
padding: 13px 15px 13px 0;
background: var(--surface);
border: 0;
font: inherit;
text-align: left;
cursor: pointer;
}
.code-head:focus-visible { outline: 2px solid var(--orange); outline-offset: -2px; }
.sev-rail { width: 6px; align-self: stretch; }
.code[data-sev="critical"] .sev-rail { background: var(--danger); }
.code[data-sev="warning"] .sev-rail { background: var(--warn); }
.code[data-sev="info"] .sev-rail { background: var(--info); }
.code-id { font-size: 16px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
.code-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.code-desc { font-size: 14px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.code-system { font-size: 12px; color: var(--muted); font-weight: 500; }
.sev-badge {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 4px 10px;
border-radius: 999px;
white-space: nowrap;
}
.code[data-sev="critical"] .sev-badge { background: rgba(212, 73, 62, 0.12); color: var(--danger); }
.code[data-sev="warning"] .sev-badge { background: rgba(224, 150, 42, 0.14); color: #b97613; }
.code[data-sev="info"] .sev-badge { background: rgba(43, 127, 255, 0.12); color: var(--info); }
.code-right { display: flex; align-items: center; gap: 12px; padding-right: 4px; }
.chevron { width: 14px; height: 14px; color: var(--steel); transition: transform 0.2s ease; flex-shrink: 0; }
.code.is-open .chevron { transform: rotate(180deg); }
.code-body {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.25s ease;
background: #fbfbfc;
border-top: 1px solid transparent;
}
.code.is-open .code-body { grid-template-rows: 1fr; border-top-color: var(--line); }
.code-body-inner { overflow: hidden; }
.code-detail { padding: 15px 16px 16px 16px; }
.detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 14px; }
.detail-cell { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; }
.detail-cell dt { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--steel); font-weight: 600; }
.detail-cell dd { margin: 2px 0 0; font-size: 13px; font-weight: 600; color: var(--ink); }
.fix-block {
background: var(--orange-50);
border: 1px solid rgba(255, 106, 19, 0.25);
border-radius: var(--r-sm);
padding: 13px 14px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.fix-text { min-width: 0; }
.fix-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--orange-d); font-weight: 700; }
.fix-name { font-size: 14px; font-weight: 600; color: var(--ink); margin-top: 2px; }
.fix-meta { font-size: 12px; color: var(--muted); margin-top: 3px; }
.fix-action { display: flex; align-items: center; gap: 12px; }
.fix-cost { font-size: 17px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.btn-approve {
font: inherit;
font-size: 13px;
font-weight: 700;
padding: 9px 16px;
border-radius: var(--r-sm);
border: 1px solid var(--orange-d);
background: var(--orange);
color: #141518;
cursor: pointer;
transition: transform 0.12s ease, background 0.15s ease, box-shadow 0.15s ease;
white-space: nowrap;
}
.btn-approve:hover { background: var(--orange-d); color: #fff; box-shadow: var(--shadow-sm); }
.btn-approve:active { transform: translateY(1px); }
.btn-approve:focus-visible { outline: 2px solid var(--garage); outline-offset: 2px; }
.code.is-approved .btn-approve {
background: rgba(47, 158, 111, 0.14);
border-color: rgba(47, 158, 111, 0.5);
color: var(--ok);
cursor: default;
}
.code.is-approved .btn-approve:hover { box-shadow: none; }
.code.is-approved .fix-block { background: rgba(47, 158, 111, 0.08); border-color: rgba(47, 158, 111, 0.3); }
.empty { text-align: center; color: var(--muted); font-size: 13.5px; padding: 24px 0 6px; font-weight: 500; }
/* Estimate */
.est-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.est-empty { font-size: 13px; color: var(--muted); font-weight: 500; line-height: 1.45; }
.est-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding-bottom: 9px;
border-bottom: 1px dashed var(--line);
animation: rowIn 0.25s ease;
}
.est-row:last-child { border-bottom: 0; padding-bottom: 0; }
.est-row-text { display: flex; flex-direction: column; min-width: 0; }
.est-row-name { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.est-row-code { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.est-row-cost { font-size: 14px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
@keyframes rowIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.est-total {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 0;
border-top: 2px solid var(--garage);
font-weight: 700;
font-size: 14px;
color: var(--ink-2);
}
.est-amount { font-size: 22px; font-weight: 800; color: var(--ink); }
.btn-primary {
width: 100%;
font: inherit;
font-size: 14px;
font-weight: 700;
padding: 13px;
border-radius: var(--r-md);
border: 0;
background: var(--garage);
color: #fff;
cursor: pointer;
transition: background 0.15s ease, transform 0.12s ease, opacity 0.15s ease;
}
.btn-primary:hover:not(:disabled) { background: #000; }
.btn-primary:active:not(:disabled) { transform: translateY(1px); }
.btn-primary:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }
/* Toast */
.toast {
position: fixed;
left: 50%;
bottom: 24px;
transform: translateX(-50%) translateY(20px);
background: var(--garage);
color: #fff;
font-size: 13.5px;
font-weight: 600;
padding: 12px 20px;
border-radius: var(--r-md);
box-shadow: var(--shadow-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.22s ease, transform 0.22s ease;
z-index: 50;
max-width: 90vw;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.ok { box-shadow: var(--shadow-lg), inset 4px 0 0 var(--ok); }
@media (max-width: 880px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas: "vehicle" "health" "codes" "estimate";
}
.estimate { position: static; }
.vehicle { grid-template-columns: 140px 1fr; }
.veh-bay { grid-column: 1 / -1; flex-direction: row; gap: 12px; border-left: 0; border-top: 1px solid var(--line); padding: 12px 0 0; justify-content: center; }
.bay-num { font-size: 28px; }
}
@media (max-width: 520px) {
body { padding: 14px 10px 40px; }
.vehicle { grid-template-columns: 1fr; }
.veh-photo { height: 130px; }
.veh-specs { grid-template-columns: repeat(2, 1fr); }
.gauges { grid-template-columns: repeat(2, 1fr); gap: 12px; }
.gauge-ring { width: 80px; height: 80px; }
.codes-head { flex-direction: column; align-items: stretch; }
.detail-grid { grid-template-columns: 1fr 1fr; }
.code-desc { white-space: normal; }
.fix-block { flex-direction: column; align-items: stretch; }
.fix-action { justify-content: space-between; }
}(function () {
"use strict";
/** @type {Array<object>} Scanned diagnostic trouble codes */
var CODES = [
{
id: "P0301",
severity: "critical",
desc: "Cylinder 1 Misfire Detected",
system: "Ignition / Fuel",
freezeRpm: "1,940 rpm",
coolant: "204 °F",
load: "61%",
status: "Confirmed",
fix: "Replace coil-on-plug & spark plug, cyl. 1",
fixMeta: "1.1 hr labor · OEM ignition coil + plug",
cost: 268.4,
},
{
id: "P0420",
severity: "warning",
desc: "Catalyst System Efficiency Below Threshold (Bank 1)",
system: "Emissions",
freezeRpm: "2,310 rpm",
coolant: "198 °F",
load: "44%",
status: "Confirmed",
fix: "Inspect & clean downstream O2 sensor, monitor catalyst",
fixMeta: "0.8 hr diagnostic · clean + retest cycle",
cost: 124.0,
},
{
id: "C0561",
severity: "critical",
desc: "System Configuration Mismatch — ABS Module",
system: "Brakes / Stability",
freezeRpm: "Idle",
coolant: "191 °F",
load: "12%",
status: "Active",
fix: "Reflash ABS controller & wheel-speed calibration",
fixMeta: "1.4 hr · module software update",
cost: 312.75,
},
{
id: "P0133",
severity: "warning",
desc: "O2 Sensor Slow Response (Bank 1, Sensor 1)",
system: "Fuel / Emissions",
freezeRpm: "1,620 rpm",
coolant: "200 °F",
load: "38%",
status: "Confirmed",
fix: "Replace upstream oxygen sensor",
fixMeta: "0.7 hr labor · OEM wideband sensor",
cost: 189.5,
},
{
id: "P0455",
severity: "info",
desc: "Evaporative Emission System — Large Leak",
system: "EVAP",
freezeRpm: "Idle",
coolant: "186 °F",
load: "9%",
status: "Pending",
fix: "Inspect fuel cap seal & EVAP lines",
fixMeta: "0.4 hr · smoke test if pending recurs",
cost: 48.0,
},
{
id: "B1342",
severity: "info",
desc: "ECU Internal Memory Fault — Stored",
system: "Body Control",
freezeRpm: "—",
coolant: "—",
load: "—",
status: "Stored / Inactive",
fix: "Clear code, recheck after road test",
fixMeta: "0.2 hr · monitor for recurrence",
cost: 0,
},
];
var approved = {}; // id -> true
/* ---------- helpers ---------- */
function money(n) {
return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
function sevLabel(s) {
return s === "critical" ? "Critical" : s === "warning" ? "Warning" : "Info";
}
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg, ok) {
toastEl.textContent = msg;
toastEl.classList.toggle("ok", !!ok);
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2400);
}
/* ---------- render codes ---------- */
var listEl = document.getElementById("codeList");
var emptyEl = document.getElementById("emptyState");
function chevronSvg() {
return '<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>';
}
function buildCode(c) {
var li = document.createElement("li");
li.className = "code";
li.dataset.sev = c.severity;
li.dataset.id = c.id;
var bodyId = "body-" + c.id;
var costLine = c.cost > 0
? '<span class="fix-cost mono">' + money(c.cost) + "</span>"
: '<span class="fix-cost mono">No charge</span>';
var approveBtn = c.cost > 0
? '<button class="btn-approve" data-approve type="button">Approve fix</button>'
: '<button class="btn-approve" data-approve type="button">Mark done</button>';
li.innerHTML =
'<button class="code-head" type="button" aria-expanded="false" aria-controls="' + bodyId + '">' +
'<span class="sev-rail" aria-hidden="true"></span>' +
'<span class="code-id mono">' + c.id + "</span>" +
'<span class="code-main">' +
'<span class="code-desc">' + c.desc + "</span>" +
'<span class="code-system">' + c.system + "</span>" +
"</span>" +
'<span class="code-right">' +
'<span class="sev-badge">' + sevLabel(c.severity) + "</span>" +
chevronSvg() +
"</span>" +
"</button>" +
'<div class="code-body" id="' + bodyId + '"><div class="code-body-inner"><div class="code-detail">' +
'<dl class="detail-grid">' +
'<div class="detail-cell"><dt>Status</dt><dd>' + c.status + "</dd></div>" +
'<div class="detail-cell"><dt>Freeze RPM</dt><dd class="mono">' + c.freezeRpm + "</dd></div>" +
'<div class="detail-cell"><dt>Coolant</dt><dd class="mono">' + c.coolant + "</dd></div>" +
'<div class="detail-cell"><dt>Engine Load</dt><dd class="mono">' + c.load + "</dd></div>" +
'<div class="detail-cell"><dt>System</dt><dd>' + c.system + "</dd></div>" +
'<div class="detail-cell"><dt>Severity</dt><dd>' + sevLabel(c.severity) + "</dd></div>" +
"</dl>" +
'<div class="fix-block">' +
'<div class="fix-text">' +
'<div class="fix-label">Recommended fix</div>' +
'<div class="fix-name">' + c.fix + "</div>" +
'<div class="fix-meta">' + c.fixMeta + "</div>" +
"</div>" +
'<div class="fix-action">' + costLine + approveBtn + "</div>" +
"</div>" +
"</div></div></div>";
// toggle expand
var head = li.querySelector(".code-head");
head.addEventListener("click", function () {
var open = li.classList.toggle("is-open");
head.setAttribute("aria-expanded", open ? "true" : "false");
});
// approve
var btn = li.querySelector("[data-approve]");
btn.addEventListener("click", function (e) {
e.stopPropagation();
if (li.classList.contains("is-approved")) return;
li.classList.add("is-approved");
approved[c.id] = c;
btn.textContent = c.cost > 0 ? "Approved ✓" : "Done ✓";
renderEstimate();
toast(c.id + " — fix approved", true);
});
return li;
}
function renderCodes() {
listEl.innerHTML = "";
CODES.forEach(function (c) {
listEl.appendChild(buildCode(c));
});
}
/* ---------- severity filter ---------- */
var filterBtns = Array.prototype.slice.call(document.querySelectorAll(".filter"));
function applyFilter(sev) {
var visible = 0;
Array.prototype.forEach.call(listEl.children, function (li) {
var show = sev === "all" || li.dataset.sev === sev;
li.style.display = show ? "" : "none";
if (show) visible++;
});
emptyEl.hidden = visible !== 0;
}
filterBtns.forEach(function (b) {
b.addEventListener("click", function () {
filterBtns.forEach(function (x) {
x.classList.remove("is-active");
x.setAttribute("aria-pressed", "false");
});
b.classList.add("is-active");
b.setAttribute("aria-pressed", "true");
applyFilter(b.dataset.sev);
});
});
/* ---------- estimate panel ---------- */
var estList = document.getElementById("estList");
var estEmpty = document.getElementById("estEmpty");
var estTotalEl = document.getElementById("estTotal");
var authBtn = document.getElementById("authBtn");
function renderEstimate() {
var items = Object.keys(approved).map(function (k) { return approved[k]; });
estList.innerHTML = "";
if (!items.length) {
estList.appendChild(estEmpty);
estEmpty.hidden = false;
} else {
estEmpty.hidden = true;
}
var total = 0;
items.forEach(function (c) {
total += c.cost;
var li = document.createElement("li");
li.className = "est-row";
li.innerHTML =
'<span class="est-row-text">' +
'<span class="est-row-name">' + c.fix + "</span>" +
'<span class="est-row-code mono">' + c.id + " · " + c.system + "</span>" +
"</span>" +
'<span class="est-row-cost mono">' + (c.cost > 0 ? money(c.cost) : "—") + "</span>";
estList.appendChild(li);
});
estTotalEl.textContent = money(total);
authBtn.disabled = items.length === 0;
}
authBtn.addEventListener("click", function () {
var count = Object.keys(approved).length;
if (!count) return;
toast("Work order authorized · " + count + " repair" + (count > 1 ? "s" : "") + " sent to Bay 04", true);
});
/* ---------- health gauges (animated count-up) ---------- */
function gaugeColor(v) {
if (v >= 75) return "var(--ok)";
if (v >= 50) return "var(--warn)";
return "var(--danger)";
}
function animateGauges() {
var gauges = Array.prototype.slice.call(document.querySelectorAll(".gauge"));
gauges.forEach(function (g) {
var target = parseInt(g.dataset.value, 10) || 0;
var ring = g.querySelector(".gauge-ring");
var num = g.querySelector(".gauge-num");
ring.style.setProperty("--col", gaugeColor(target));
var cur = 0;
var start = performance.now();
var dur = 900;
function step(now) {
var t = Math.min(1, (now - start) / dur);
var eased = 1 - Math.pow(1 - t, 3);
cur = Math.round(eased * target);
ring.style.setProperty("--val", cur);
num.textContent = cur;
if (t < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
});
}
/* ---------- init ---------- */
renderCodes();
renderEstimate();
applyFilter("all");
// open the first critical code so the report opens informatively
var firstCritical = listEl.querySelector('.code[data-sev="critical"] .code-head');
if (firstCritical) firstCritical.click();
requestAnimationFrame(animateGauges);
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Diagnostic Report — Ridgeline Auto Works</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="shell">
<header class="topbar">
<div class="brand">
<div class="brand-mark" aria-hidden="true">RW</div>
<div class="brand-text">
<span class="brand-name">Ridgeline Auto Works</span>
<span class="brand-sub">Diagnostic Scan Report</span>
</div>
</div>
<div class="topbar-meta">
<span class="ro-chip">RO #48217</span>
<span class="scan-chip" id="scanChip">Scan complete · 6 codes</span>
</div>
</header>
<main class="layout">
<!-- Vehicle + health summary -->
<section class="panel vehicle" aria-labelledby="vehTitle">
<div class="veh-photo" aria-hidden="true">
<span class="veh-photo-tag">2019 · Sedan</span>
</div>
<div class="veh-info">
<h1 id="vehTitle" class="veh-title">2019 Maplewood Vantage SE</h1>
<p class="veh-owner">Owner — Dana Whitlock</p>
<dl class="veh-specs">
<div><dt>VIN</dt><dd class="mono">4MW9X2J71KC308714</dd></div>
<div><dt>Plate</dt><dd class="mono">8RTK·204</dd></div>
<div><dt>Odometer</dt><dd class="mono">86,412 mi</dd></div>
<div><dt>Engine</dt><dd class="mono">2.0L I4 Turbo</dd></div>
</dl>
</div>
<div class="veh-bay">
<span class="bay-label">Service Bay</span>
<span class="bay-num">04</span>
<span class="tech-tag">Tech · M. Okafor</span>
</div>
</section>
<section class="panel health" aria-labelledby="healthTitle">
<h2 id="healthTitle" class="panel-title">Vehicle Health Summary</h2>
<div class="gauges" id="gauges">
<figure class="gauge" data-value="62" data-label="Overall">
<div class="gauge-ring"><span class="gauge-num">--</span></div>
<figcaption>Overall</figcaption>
</figure>
<figure class="gauge" data-value="48" data-label="Engine">
<div class="gauge-ring"><span class="gauge-num">--</span></div>
<figcaption>Engine</figcaption>
</figure>
<figure class="gauge" data-value="71" data-label="Emissions">
<div class="gauge-ring"><span class="gauge-num">--</span></div>
<figcaption>Emissions</figcaption>
</figure>
<figure class="gauge" data-value="88" data-label="Electrical">
<div class="gauge-ring"><span class="gauge-num">--</span></div>
<figcaption>Electrical</figcaption>
</figure>
</div>
</section>
<!-- Trouble codes -->
<section class="panel codes" aria-labelledby="codesTitle">
<div class="codes-head">
<h2 id="codesTitle" class="panel-title">Scanned Trouble Codes</h2>
<div class="filters" role="group" aria-label="Filter by severity">
<button class="filter is-active" data-sev="all" aria-pressed="true">All</button>
<button class="filter" data-sev="critical" aria-pressed="false">Critical</button>
<button class="filter" data-sev="warning" aria-pressed="false">Warning</button>
<button class="filter" data-sev="info" aria-pressed="false">Info</button>
</div>
</div>
<ul class="code-list" id="codeList"></ul>
<p class="empty" id="emptyState" hidden>No codes match this filter.</p>
</section>
<!-- Estimate footer -->
<aside class="panel estimate" aria-labelledby="estTitle">
<h2 id="estTitle" class="panel-title">Approved Repairs</h2>
<ul class="est-list" id="estList">
<li class="est-empty" id="estEmpty">No fixes approved yet. Expand a code and approve its recommended repair.</li>
</ul>
<div class="est-total">
<span>Approved total</span>
<span class="est-amount mono" id="estTotal">$0.00</span>
</div>
<button class="btn-primary" id="authBtn" disabled>Authorize Work Order</button>
</aside>
</main>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Diagnostic Report
A status-forward diagnostic report panel for an auto repair shop. The header carries the repair-order number and scan summary, a vehicle card shows the VIN, plate, odometer, engine, and service bay, and four animated gauges score overall, engine, emissions, and electrical health on a count-up that colors itself green, amber, or red by value.
The trouble-code list reads like a real scan dump: each row shows the code (P0301, P0420, C0561, …), a colored severity rail, the affected system, and a severity badge. Expanding a code reveals freeze-frame data — RPM, coolant temp, engine load, status — alongside a highlighted recommended fix with labor breakdown and cost. Severity filter buttons narrow the list to critical, warning, or info.
Approving a fix marks the code done, drops a line item into the sticky estimate panel, and recalculates the approved total with tabular figures. Once anything is approved the Authorize Work Order button enables and dispatches the job to the bay via a toast. Everything is vanilla JS, keyboard-usable, and responsive down to a phone-width single column.
Illustrative UI only — fictional shop/dealership, not a real service system.