DIY — Repair Guide
An iFixit-style step-by-step repair guide page for a fictional Volta X2 headphone battery swap, drawn in a blueprint maker aesthetic. It packs a CSS-illustrated device hero with difficulty and time badges, a tools-and-parts strip, eight SVG-illustrated steps with color-matched screw callouts and danger/caution boxes, a sticky IntersectionObserver progress rail, localStorage-persisted completion checkboxes feeding a meter, and a stamped success state once every step is checked off.
MCP
Code
:root {
--blueprint: #0f2a4a;
--blueprint-d: #0a1e36;
--blueprint-l: #16385f;
--grid: rgba(140, 180, 220, 0.14);
--grid-major: rgba(140, 180, 220, 0.26);
--orange: #ff6b35;
--orange-d: #e0521f;
--orange-soft: #ffe3d6;
--kraft: #d9c7a7;
--kraft-l: #efe6d4;
--ink: #1c2733;
--ink-2: #3d4a57;
--muted: #6b7885;
--bg: #f4f1ea;
--white: #ffffff;
--line: rgba(28, 39, 51, 0.12);
--line-2: rgba(28, 39, 51, 0.2);
--ok: #2f9e6f;
--warn: #d98a2b;
--danger: #d4503e;
--r-sm: 6px;
--r-md: 12px;
--r-lg: 18px;
--shadow-sm: 0 1px 3px rgba(28, 39, 51, 0.08);
--shadow-md: 0 6px 24px rgba(28, 39, 51, 0.12);
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
color: var(--ink);
background: var(--bg);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.mono {
font-family: "JetBrains Mono", ui-monospace, monospace;
}
img,
svg {
max-width: 100%;
display: block;
}
/* ============ HERO ============ */
.hero {
background-color: var(--blueprint);
background-image:
linear-gradient(var(--grid) 1px, transparent 1px),
linear-gradient(90deg, var(--grid) 1px, transparent 1px),
linear-gradient(var(--grid-major) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-major) 1px, transparent 1px);
background-size: 8px 8px, 8px 8px, 80px 80px, 80px 80px;
color: var(--white);
border-bottom: 4px solid var(--orange);
}
.hero-inner {
max-width: 1100px;
margin: 0 auto;
padding: 48px 24px 56px;
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 40px;
align-items: center;
}
.crumbs {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.6);
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 18px;
}
.crumbs a {
color: rgba(255, 255, 255, 0.75);
text-decoration: none;
}
.crumbs a:hover,
.crumbs a:focus-visible {
color: var(--orange-soft);
text-decoration: underline;
}
.crumbs [aria-current] {
color: var(--white);
font-weight: 600;
}
.guide-no {
font-family: "JetBrains Mono", ui-monospace, monospace;
font-size: 0.75rem;
letter-spacing: 0.14em;
color: var(--kraft);
margin: 0 0 10px;
}
.hero h1 {
font-size: clamp(1.7rem, 4vw, 2.6rem);
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.03em;
line-height: 1.12;
margin: 0 0 14px;
}
.hero .accent {
color: var(--orange);
}
.hero-sub {
color: var(--kraft-l);
max-width: 46ch;
margin: 0 0 22px;
}
.hero-meta {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.meta-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 7px 12px;
border: 1px solid rgba(140, 180, 220, 0.35);
border-radius: 999px;
font-size: 0.8rem;
color: var(--kraft-l);
background: rgba(10, 30, 54, 0.55);
}
.meta-chip .mono {
font-size: 0.78rem;
font-weight: 600;
color: var(--white);
letter-spacing: 0.06em;
}
.meta-chip.diff {
border-color: var(--orange);
color: var(--orange-soft);
font-weight: 600;
}
.pips {
display: inline-flex;
gap: 3px;
}
.pips i {
width: 7px;
height: 7px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
}
.pips i.on {
background: var(--orange);
}
/* Device illustration */
.device {
margin: 0;
text-align: center;
}
.device-stage {
position: relative;
height: 260px;
border: 1px dashed var(--grid-major);
border-radius: var(--r-lg);
background: rgba(10, 30, 54, 0.4);
}
.hp-band {
position: absolute;
top: 26px;
left: 50%;
transform: translateX(-50%);
width: 170px;
height: 90px;
border: 14px solid var(--kraft);
border-bottom: none;
border-radius: 100px 100px 0 0;
}
.hp-yoke {
position: absolute;
top: 108px;
width: 10px;
height: 46px;
background: var(--kraft);
border-radius: 5px;
}
.hp-yoke-l { left: calc(50% - 90px); }
.hp-yoke-r { right: calc(50% - 90px); }
.hp-cup {
position: absolute;
top: 142px;
width: 74px;
height: 92px;
background: var(--blueprint-l);
border: 3px solid #8cb4dc;
border-radius: 34px;
}
.hp-cup-l { left: calc(50% - 122px); }
.hp-cup-r { right: calc(50% - 122px); }
.hp-pad {
position: absolute;
inset: 10px;
border: 2px dashed rgba(140, 180, 220, 0.45);
border-radius: 26px;
}
.hp-led {
position: absolute;
right: -2px;
top: 38px;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--orange);
box-shadow: 0 0 8px var(--orange);
animation: led-pulse 1.8s ease-in-out infinite;
}
@keyframes led-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.35; }
}
.callout-tag {
position: absolute;
right: 12px;
bottom: 12px;
padding: 6px 10px;
background: var(--orange);
color: var(--blueprint-d);
font-size: 0.72rem;
font-weight: 700;
border-radius: var(--r-sm);
}
.callout-tag .mono {
letter-spacing: 0.08em;
}
.device figcaption {
margin-top: 10px;
font-size: 0.7rem;
letter-spacing: 0.12em;
color: rgba(255, 255, 255, 0.5);
}
/* ============ KIT STRIP ============ */
.kit-strip {
background: var(--kraft-l);
background-image:
linear-gradient(rgba(28, 39, 51, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(28, 39, 51, 0.05) 1px, transparent 1px);
background-size: 20px 20px;
border-bottom: 1px solid var(--line-2);
}
.kit-inner {
max-width: 1100px;
margin: 0 auto;
padding: 22px 24px;
display: flex;
flex-wrap: wrap;
gap: 28px;
align-items: flex-start;
}
.kit-group {
flex: 1 1 260px;
}
.kit-title {
margin: 0 0 10px;
font-size: 0.78rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--ink-2);
}
.kit-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
}
.kit-list li {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 0.86rem;
color: var(--ink);
background: var(--white);
border: 1px solid var(--line);
border-radius: 999px;
padding: 6px 12px 6px 9px;
box-shadow: var(--shadow-sm);
}
.kit-ico {
font-size: 0.9rem;
}
.badge {
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.05em;
color: var(--blueprint);
background: rgba(15, 42, 74, 0.08);
border: 1px solid rgba(15, 42, 74, 0.18);
border-radius: 4px;
padding: 1px 6px;
}
.kit-cta {
margin-left: auto;
align-self: center;
font: inherit;
font-weight: 700;
font-size: 0.9rem;
color: var(--white);
background: var(--orange);
border: none;
border-radius: var(--r-md);
padding: 12px 20px;
cursor: pointer;
box-shadow: 0 3px 0 var(--orange-d);
transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.kit-cta:hover { background: var(--orange-d); }
.kit-cta:active {
transform: translateY(3px);
box-shadow: 0 0 0 var(--orange-d);
}
.kit-cta:focus-visible {
outline: 3px solid var(--blueprint);
outline-offset: 2px;
}
/* ============ GUIDE LAYOUT ============ */
.guide-wrap {
max-width: 1100px;
margin: 0 auto;
padding: 40px 24px 80px;
display: grid;
grid-template-columns: 230px 1fr;
gap: 40px;
align-items: start;
}
/* Rail */
.rail {
position: sticky;
top: 20px;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 18px;
box-shadow: var(--shadow-sm);
}
.rail-meter-head {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 8px;
}
#meterPct {
font-size: 1.3rem;
font-weight: 700;
color: var(--blueprint);
}
.rail-meter-label {
font-size: 0.78rem;
color: var(--muted);
}
.meter-track {
height: 10px;
border-radius: 999px;
background: rgba(28, 39, 51, 0.08);
overflow: hidden;
margin-bottom: 16px;
}
.meter-fill {
height: 100%;
width: 0%;
border-radius: inherit;
background: linear-gradient(90deg, var(--orange), var(--orange-d));
transition: width 0.35s ease;
}
.meter-fill.full {
background: linear-gradient(90deg, var(--ok), #237c56);
}
.rail-list {
list-style: none;
margin: 0 0 16px;
padding: 0;
display: grid;
gap: 2px;
}
.rail-link {
display: flex;
align-items: center;
gap: 10px;
padding: 7px 8px;
border-radius: var(--r-sm);
text-decoration: none;
color: var(--ink-2);
font-size: 0.84rem;
border-left: 3px solid transparent;
transition: background 0.15s ease, border-color 0.15s ease;
}
.rail-link:hover,
.rail-link:focus-visible {
background: rgba(15, 42, 74, 0.06);
}
.rail-link.active {
background: rgba(255, 107, 53, 0.1);
border-left-color: var(--orange);
color: var(--ink);
font-weight: 600;
}
.rail-dot {
flex: none;
width: 22px;
height: 22px;
display: grid;
place-items: center;
font-size: 0.7rem;
font-weight: 700;
color: var(--blueprint);
background: rgba(15, 42, 74, 0.08);
border: 1px solid rgba(15, 42, 74, 0.2);
border-radius: 50%;
transition: background 0.2s ease, color 0.2s ease;
}
.rail-link.done .rail-dot {
background: var(--ok);
border-color: var(--ok);
color: var(--white);
}
.rail-link.done .rail-txt {
text-decoration: line-through;
text-decoration-color: rgba(28, 39, 51, 0.35);
color: var(--muted);
}
.rail-reset {
width: 100%;
font: inherit;
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
background: none;
border: 1px dashed var(--line-2);
border-radius: var(--r-sm);
padding: 8px;
cursor: pointer;
transition: color 0.15s ease, border-color 0.15s ease;
}
.rail-reset:hover,
.rail-reset:focus-visible {
color: var(--danger);
border-color: var(--danger);
}
/* Steps */
.steps {
display: grid;
gap: 36px;
min-width: 0;
}
.step {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--shadow-sm);
transition: box-shadow 0.2s ease, border-color 0.2s ease;
scroll-margin-top: 20px;
}
.step:hover {
box-shadow: var(--shadow-md);
}
.step.is-done {
border-color: rgba(47, 158, 111, 0.5);
}
.step-head {
display: flex;
align-items: center;
gap: 14px;
padding: 18px 24px 14px;
}
.step-num {
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.14em;
color: var(--white);
background: var(--blueprint);
border-radius: var(--r-sm);
padding: 5px 10px;
}
.step.is-done .step-num {
background: var(--ok);
}
.step-head h2 {
margin: 0;
font-size: 1.25rem;
font-weight: 700;
letter-spacing: 0.01em;
}
.step-media {
margin: 0 24px;
border-radius: var(--r-md);
overflow: hidden;
border: 1px solid var(--line);
}
.step-svg {
width: 100%;
height: auto;
}
.step-body {
padding: 18px 24px 22px;
}
.step-notes {
margin: 0 0 16px;
padding: 0;
list-style: none;
display: grid;
gap: 10px;
}
.step-notes li {
position: relative;
padding-left: 22px;
font-size: 0.95rem;
color: var(--ink-2);
}
.step-notes li::before {
content: "";
position: absolute;
left: 4px;
top: 0.55em;
width: 8px;
height: 8px;
border-radius: 2px;
background: var(--orange);
transform: rotate(45deg);
}
.step-notes strong { color: var(--ink); }
/* Screw / part callout badges */
.screw {
display: inline-block;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.06em;
border-radius: 4px;
padding: 2px 8px;
border: 1px solid;
white-space: nowrap;
}
.screw-orange {
color: var(--orange-d);
background: var(--orange-soft);
border-color: rgba(224, 82, 31, 0.4);
}
.screw-green {
color: #1e7a52;
background: rgba(47, 158, 111, 0.12);
border-color: rgba(47, 158, 111, 0.4);
}
.screw-red {
color: #a83526;
background: rgba(212, 80, 62, 0.1);
border-color: rgba(212, 80, 62, 0.4);
}
.screw-kraft {
color: var(--ink-2);
background: var(--kraft-l);
border-color: var(--kraft);
}
/* Callouts */
.callout {
border-radius: var(--r-md);
border: 1px solid;
border-left-width: 5px;
padding: 12px 16px;
margin: 0 0 16px;
}
.callout p {
margin: 6px 0 0;
font-size: 0.88rem;
color: var(--ink-2);
}
.callout-tag-txt {
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.12em;
}
.callout.danger {
background: rgba(212, 80, 62, 0.07);
border-color: rgba(212, 80, 62, 0.45);
}
.callout.danger .callout-tag-txt { color: var(--danger); }
.callout.warn {
background: rgba(217, 138, 43, 0.08);
border-color: rgba(217, 138, 43, 0.5);
}
.callout.warn .callout-tag-txt { color: #a8681a; }
.callout.info {
background: rgba(15, 42, 74, 0.05);
border-color: rgba(15, 42, 74, 0.3);
}
.callout.info .callout-tag-txt { color: var(--blueprint); }
/* Done checkbox */
.done-check {
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 0.9rem;
font-weight: 600;
color: var(--ink-2);
cursor: pointer;
padding: 8px 14px 8px 10px;
border: 1px dashed var(--line-2);
border-radius: var(--r-md);
user-select: none;
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.done-check:hover {
border-color: var(--ok);
color: var(--ink);
}
.done-check input {
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
}
.done-check .box {
flex: none;
width: 22px;
height: 22px;
border: 2px solid var(--line-2);
border-radius: var(--r-sm);
background: var(--white);
display: grid;
place-items: center;
transition: background 0.15s ease, border-color 0.15s ease;
}
.done-check .box::after {
content: "✓";
font-size: 0.85rem;
font-weight: 800;
color: var(--white);
opacity: 0;
transform: scale(0.4);
transition: opacity 0.15s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.done-check input:checked + .box {
background: var(--ok);
border-color: var(--ok);
}
.done-check input:checked + .box::after {
opacity: 1;
transform: scale(1);
}
.done-check input:focus-visible + .box {
outline: 3px solid var(--orange);
outline-offset: 2px;
}
.done-check:has(input:checked) {
border-style: solid;
border-color: rgba(47, 158, 111, 0.5);
background: rgba(47, 158, 111, 0.07);
color: #1e7a52;
}
/* ============ FINISH ============ */
.finish-card {
background-color: var(--blueprint);
background-image:
linear-gradient(var(--grid) 1px, transparent 1px),
linear-gradient(90deg, var(--grid) 1px, transparent 1px),
linear-gradient(var(--grid-major) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-major) 1px, transparent 1px);
background-size: 8px 8px, 8px 8px, 80px 80px, 80px 80px;
color: var(--kraft-l);
border-radius: var(--r-lg);
padding: 36px 32px;
text-align: center;
border: 1px solid var(--blueprint-l);
}
.finish-title {
margin: 0 0 12px;
font-size: 1.5rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--white);
}
.finish-note {
max-width: 56ch;
margin: 0 auto 10px;
font-size: 0.95rem;
}
.finish-note.dim {
color: rgba(255, 255, 255, 0.55);
font-size: 0.85rem;
}
.finish-note .screw-green {
background: rgba(47, 158, 111, 0.25);
color: #9be8c4;
}
.success-stamp {
display: inline-block;
font-size: 1.1rem;
font-weight: 700;
letter-spacing: 0.2em;
color: var(--ok);
border: 3px solid var(--ok);
border-radius: var(--r-sm);
padding: 8px 18px;
margin-bottom: 18px;
transform: rotate(-4deg);
animation: stamp-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes stamp-in {
from { transform: rotate(-4deg) scale(2); opacity: 0; }
to { transform: rotate(-4deg) scale(1); opacity: 1; }
}
.finish-actions {
display: flex;
justify-content: center;
gap: 12px;
margin-top: 20px;
flex-wrap: wrap;
}
.btn-primary,
.btn-ghost {
font: inherit;
font-weight: 700;
font-size: 0.9rem;
border-radius: var(--r-md);
padding: 12px 22px;
cursor: pointer;
transition: transform 0.12s ease, background 0.15s ease, color 0.15s ease;
}
.btn-primary {
color: var(--white);
background: var(--orange);
border: none;
box-shadow: 0 3px 0 var(--orange-d);
}
.btn-primary:hover { background: var(--orange-d); }
.btn-primary:active { transform: translateY(3px); box-shadow: none; }
.btn-ghost {
color: var(--kraft-l);
background: transparent;
border: 1px solid rgba(140, 180, 220, 0.45);
}
.btn-ghost:hover {
color: var(--white);
border-color: var(--white);
}
.btn-primary:focus-visible,
.btn-ghost:focus-visible {
outline: 3px solid var(--kraft);
outline-offset: 2px;
}
/* ============ FOOTER / TOAST ============ */
.foot {
border-top: 1px solid var(--line);
padding: 26px 24px 40px;
text-align: center;
font-size: 0.82rem;
color: var(--muted);
}
.foot .mono {
letter-spacing: 0.1em;
color: var(--ink-2);
}
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 20px);
background: var(--ink);
color: var(--kraft-l);
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.04em;
padding: 12px 20px;
border-radius: var(--r-md);
border-left: 4px solid var(--orange);
box-shadow: var(--shadow-md);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
max-width: min(90vw, 420px);
z-index: 50;
}
.toast.show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ============ RESPONSIVE ============ */
@media (max-width: 900px) {
.hero-inner {
grid-template-columns: 1fr;
padding-bottom: 40px;
}
.device-stage { max-width: 420px; margin: 0 auto; }
.guide-wrap {
grid-template-columns: 1fr;
gap: 24px;
}
.rail {
position: static;
display: grid;
grid-template-columns: 1fr auto;
gap: 12px 18px;
align-items: center;
}
.rail-list { display: none; }
.rail-meter { grid-column: 1; }
.rail-reset { grid-column: 2; width: auto; }
.meter-track { margin-bottom: 0; }
}
@media (max-width: 520px) {
.hero-inner { padding: 32px 18px 36px; }
.kit-inner { padding: 18px; gap: 18px; }
.kit-cta { margin-left: 0; width: 100%; }
.guide-wrap { padding: 24px 14px 60px; }
.step-head { padding: 14px 16px 12px; flex-wrap: wrap; gap: 10px; }
.step-head h2 { font-size: 1.05rem; }
.step-media { margin: 0 12px; }
.step-body { padding: 14px 16px 18px; }
.finish-card { padding: 26px 18px; }
.done-check { width: 100%; justify-content: center; }
}/* Volta X2 battery replacement — guide interactions
- IntersectionObserver highlights the current step in the sticky rail
- "Mark step complete" checkboxes persist to localStorage
- Completion meter + success state when all 8 steps are done
- toast(msg) helper for micro-feedback */
(function () {
"use strict";
var STORAGE_KEY = "fixshop.vx2-bat-011.progress";
var TOTAL_STEPS = 8;
var checkboxes = Array.prototype.slice.call(
document.querySelectorAll(".step-done")
);
var railLinks = Array.prototype.slice.call(
document.querySelectorAll(".rail-link")
);
var steps = Array.prototype.slice.call(document.querySelectorAll(".step"));
var meterFill = document.getElementById("meterFill");
var meterBar = document.getElementById("meterBar");
var meterPct = document.getElementById("meterPct");
var finishDefault = document.getElementById("finishDefault");
var finishSuccess = document.getElementById("finishSuccess");
var finishCount = document.getElementById("finishCount");
var toastEl = document.getElementById("toast");
/* ---------- toast ---------- */
var toastTimer = null;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2400);
}
/* ---------- persistence ---------- */
function loadProgress() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
var parsed = raw ? JSON.parse(raw) : [];
return Array.isArray(parsed) ? parsed : [];
} catch (e) {
return [];
}
}
function saveProgress(list) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
} catch (e) {
/* private mode — session-only progress */
}
}
function completedSteps() {
return checkboxes
.filter(function (cb) {
return cb.checked;
})
.map(function (cb) {
return cb.getAttribute("data-step");
});
}
/* ---------- render ---------- */
var wasComplete = false;
function render() {
var done = completedSteps();
var pct = Math.round((done.length / TOTAL_STEPS) * 100);
meterFill.style.width = pct + "%";
meterFill.classList.toggle("full", pct === 100);
meterPct.textContent = pct + "%";
meterBar.setAttribute("aria-valuenow", String(pct));
finishCount.textContent = done.length + " / " + TOTAL_STEPS;
steps.forEach(function (stepEl) {
var n = stepEl.getAttribute("data-step");
stepEl.classList.toggle("is-done", done.indexOf(n) !== -1);
});
railLinks.forEach(function (link) {
var n = link.getAttribute("data-step");
var isDone = done.indexOf(n) !== -1;
link.classList.toggle("done", isDone);
var dot = link.querySelector(".rail-dot");
dot.textContent = isDone ? "✓" : n;
});
var complete = done.length === TOTAL_STEPS;
finishDefault.hidden = complete;
finishSuccess.hidden = !complete;
if (complete && !wasComplete) {
toast("All 8 steps complete — nice fix!");
document
.getElementById("finish")
.scrollIntoView({ behavior: "smooth", block: "center" });
}
wasComplete = complete;
}
/* ---------- restore + wire checkboxes ---------- */
var saved = loadProgress();
checkboxes.forEach(function (cb) {
cb.checked = saved.indexOf(cb.getAttribute("data-step")) !== -1;
cb.addEventListener("change", function () {
var done = completedSteps();
saveProgress(done);
render();
if (done.length < TOTAL_STEPS) {
toast(
cb.checked
? "Step " + cb.getAttribute("data-step") + " done — " +
(TOTAL_STEPS - done.length) + " to go"
: "Step " + cb.getAttribute("data-step") + " unchecked"
);
}
});
});
/* ---------- reset ---------- */
document.getElementById("resetBtn").addEventListener("click", function () {
checkboxes.forEach(function (cb) {
cb.checked = false;
});
saveProgress([]);
wasComplete = false;
render();
toast("Progress reset — back to step 1");
document
.getElementById("step-1")
.scrollIntoView({ behavior: "smooth", block: "start" });
});
/* ---------- sticky rail: current step via IntersectionObserver ---------- */
var activeStep = null;
function setActive(n) {
if (n === activeStep) return;
activeStep = n;
railLinks.forEach(function (link) {
link.classList.toggle(
"active",
link.getAttribute("data-step") === n
);
});
}
if ("IntersectionObserver" in window) {
var visible = {};
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
var n = entry.target.getAttribute("data-step");
visible[n] = entry.isIntersecting ? entry.intersectionRatio : 0;
});
var best = null;
var bestRatio = 0;
Object.keys(visible).forEach(function (n) {
if (visible[n] > bestRatio) {
bestRatio = visible[n];
best = n;
}
});
if (best) setActive(best);
},
{ rootMargin: "-15% 0px -35% 0px", threshold: [0, 0.25, 0.5, 0.75, 1] }
);
steps.forEach(function (stepEl) {
observer.observe(stepEl);
});
} else {
setActive("1");
}
/* rail links: smooth scroll */
railLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
var target = document.querySelector(link.getAttribute("href"));
if (target) {
target.scrollIntoView({ behavior: "smooth", block: "start" });
setActive(link.getAttribute("data-step"));
}
});
});
/* ---------- misc buttons ---------- */
document.getElementById("kitBtn").addEventListener("click", function () {
toast("Fix kit VX2-CELL-620 + tools added to cart");
});
var shareBtn = document.getElementById("shareBtn");
if (shareBtn) {
shareBtn.addEventListener("click", function () {
toast("Fix report shared with the Fixshop community");
});
}
var anotherBtn = document.getElementById("anotherBtn");
if (anotherBtn) {
anotherBtn.addEventListener("click", function () {
toast("Loading more Volta X2 guides…");
});
}
/* ---------- init ---------- */
render();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Volta X2 Battery Replacement — Fixshop Guide</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&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ============ HERO ============ -->
<header class="hero" role="banner">
<div class="hero-inner">
<div class="hero-copy">
<nav class="crumbs" aria-label="Breadcrumb">
<a href="#">Fixshop</a><span aria-hidden="true">/</span>
<a href="#">Audio</a><span aria-hidden="true">/</span>
<a href="#">Volta X2</a><span aria-hidden="true">/</span>
<span aria-current="page">Battery</span>
</nav>
<p class="guide-no">GUIDE VX2-BAT-011 · REV C</p>
<h1>Volta X2 Headphone<br /><span class="accent">Battery Replacement</span></h1>
<p class="hero-sub">
Swap the worn 620 mAh cell in your Volta X2 over-ears and get back to
30-hour listening sessions. Written and torn down by the Fixshop community.
</p>
<div class="hero-meta" role="list">
<span class="meta-chip diff" role="listitem">
<span class="pips" aria-hidden="true"><i class="on"></i><i class="on"></i><i class="on"></i><i></i><i></i></span>
Moderate
</span>
<span class="meta-chip" role="listitem"><span class="mono">25–40 MIN</span></span>
<span class="meta-chip" role="listitem"><span class="mono">8 STEPS</span></span>
<span class="meta-chip" role="listitem"><span class="mono">4,218</span> completed</span>
</div>
</div>
<!-- CSS device illustration -->
<figure class="device" aria-label="Illustration of the Volta X2 headphone">
<div class="device-stage">
<div class="hp-band"></div>
<div class="hp-cup hp-cup-l"><div class="hp-pad"></div></div>
<div class="hp-cup hp-cup-r"><div class="hp-pad"></div><div class="hp-led"></div></div>
<div class="hp-yoke hp-yoke-l"></div>
<div class="hp-yoke hp-yoke-r"></div>
<div class="callout-tag"><span class="mono">RIGHT CUP</span> houses battery</div>
</div>
<figcaption class="mono">FIG. 00 — VOLTA X2 · EXPLODED SIDE VIEW</figcaption>
</figure>
</div>
</header>
<!-- ============ TOOLS / PARTS STRIP ============ -->
<section class="kit-strip" aria-label="Tools and parts required">
<div class="kit-inner">
<div class="kit-group">
<h2 class="kit-title">Tools</h2>
<ul class="kit-list">
<li><span class="kit-ico" aria-hidden="true">🪛</span>P00 Phillips driver <span class="mono badge">FS-P00</span></li>
<li><span class="kit-ico" aria-hidden="true">🔧</span>T5 Torx driver <span class="mono badge">FS-T5</span></li>
<li><span class="kit-ico" aria-hidden="true">🎸</span>Opening picks ×2 <span class="mono badge">FS-PICK</span></li>
<li><span class="kit-ico" aria-hidden="true">🥄</span>Nylon spudger <span class="mono badge">FS-SPG</span></li>
<li><span class="kit-ico" aria-hidden="true">🤏</span>ESD tweezers <span class="mono badge">FS-TWZ</span></li>
</ul>
</div>
<div class="kit-group">
<h2 class="kit-title">Parts</h2>
<ul class="kit-list">
<li><span class="kit-ico" aria-hidden="true">🔋</span>Volta X2 battery 620 mAh <span class="mono badge">VX2-CELL-620</span></li>
<li><span class="kit-ico" aria-hidden="true">🩹</span>Adhesive strip set <span class="mono badge">VX2-ADH-KIT</span></li>
</ul>
</div>
<button class="kit-cta" id="kitBtn" type="button">Add fix kit — $24.90</button>
</div>
</section>
<!-- ============ GUIDE BODY ============ -->
<div class="guide-wrap">
<!-- Sticky progress rail -->
<aside class="rail" aria-label="Guide progress">
<div class="rail-meter">
<div class="rail-meter-head">
<span class="mono" id="meterPct">0%</span>
<span class="rail-meter-label">complete</span>
</div>
<div class="meter-track" role="progressbar" aria-label="Guide completion" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" id="meterBar">
<div class="meter-fill" id="meterFill"></div>
</div>
</div>
<ol class="rail-list" id="railList">
<li><a href="#step-1" class="rail-link" data-step="1"><span class="rail-dot mono">1</span><span class="rail-txt">Power down</span></a></li>
<li><a href="#step-2" class="rail-link" data-step="2"><span class="rail-dot mono">2</span><span class="rail-txt">Remove ear cushion</span></a></li>
<li><a href="#step-3" class="rail-link" data-step="3"><span class="rail-dot mono">3</span><span class="rail-txt">Driver plate screws</span></a></li>
<li><a href="#step-4" class="rail-link" data-step="4"><span class="rail-dot mono">4</span><span class="rail-txt">Lift driver plate</span></a></li>
<li><a href="#step-5" class="rail-link" data-step="5"><span class="rail-dot mono">5</span><span class="rail-txt">Disconnect battery</span></a></li>
<li><a href="#step-6" class="rail-link" data-step="6"><span class="rail-dot mono">6</span><span class="rail-txt">Remove old cell</span></a></li>
<li><a href="#step-7" class="rail-link" data-step="7"><span class="rail-dot mono">7</span><span class="rail-txt">Seat new cell</span></a></li>
<li><a href="#step-8" class="rail-link" data-step="8"><span class="rail-dot mono">8</span><span class="rail-txt">Reconnect & test</span></a></li>
</ol>
<button class="rail-reset" id="resetBtn" type="button">Reset progress</button>
</aside>
<!-- Steps -->
<main class="steps" id="steps">
<!-- STEP 1 -->
<article class="step" id="step-1" data-step="1">
<header class="step-head">
<span class="step-num mono">STEP 1</span>
<h2>Power down & discharge</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Power button held on the right ear cup">
<rect x="0" y="0" width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<ellipse cx="320" cy="185" rx="150" ry="120" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<ellipse cx="320" cy="185" rx="105" ry="82" fill="#0a1e36" stroke="rgba(140,180,220,.4)" stroke-width="2" stroke-dasharray="6 6"/>
<rect x="452" y="160" width="26" height="52" rx="12" fill="#ff6b35"/>
<text x="500" y="175" fill="#ffe3d6" font-family="JetBrains Mono, monospace" font-size="15">PWR — hold 5s</text>
<path d="M465 130 q10 -26 -6 -44" stroke="#ffe3d6" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="459" cy="82" r="5" fill="#ffe3d6"/>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 01 — RIGHT CUP, POWER SIDE</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Hold the <strong>power button</strong> on the right cup for 5 seconds until the status LED goes dark.</li>
<li>Play audio at low volume for a few minutes beforehand if the battery is above 50% — a partially drained cell is safer to handle.</li>
<li>Unplug any USB-C or 3.5 mm cables.</li>
</ul>
<div class="callout danger" role="note">
<span class="callout-tag-txt mono">⚠ BATTERY SAFETY</span>
<p>Never work on a charging device. Lithium-polymer cells can vent or ignite if punctured while energised.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="1" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 2 -->
<article class="step" id="step-2" data-step="2">
<header class="step-head">
<span class="step-num mono">STEP 2</span>
<h2>Remove the right ear cushion</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Ear cushion being twisted off its bayonet mount">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<ellipse cx="250" cy="185" rx="130" ry="105" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<ellipse cx="250" cy="185" rx="88" ry="68" fill="#0a1e36"/>
<ellipse cx="455" cy="170" rx="95" ry="80" fill="none" stroke="#ffe3d6" stroke-width="4" stroke-dasharray="10 8" transform="rotate(-12 455 170)"/>
<path d="M395 92 a95 80 0 0 1 120 8" stroke="#ff6b35" stroke-width="6" fill="none" stroke-linecap="round"/>
<path d="M515 100 l14 -18 M515 100 l-22 -4" stroke="#ff6b35" stroke-width="6" fill="none" stroke-linecap="round"/>
<text x="392" y="290" fill="#ffe3d6" font-family="JetBrains Mono, monospace" font-size="15">TWIST CCW 15°</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 02 — BAYONET MOUNT</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Grip the cushion at the 3 and 9 o'clock positions and rotate it <strong>counter-clockwise about 15°</strong> until the bayonet tabs release.</li>
<li>Lift the cushion straight off. No tools needed — it should release with light force.</li>
<li>Set it fabric-side up so the memory foam keeps its shape.</li>
</ul>
<div class="callout info" role="note">
<span class="callout-tag-txt mono">ℹ PRO TIP</span>
<p>Photograph the cushion orientation before removal — the oval pad only reseats correctly one way.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="2" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 3 -->
<article class="step" id="step-3" data-step="3">
<header class="step-head">
<span class="step-num mono">STEP 3</span>
<h2>Remove the driver plate screws</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Driver plate with color-coded screw locations">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<ellipse cx="320" cy="180" rx="160" ry="128" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<ellipse cx="320" cy="180" rx="70" ry="70" fill="#0a1e36" stroke="rgba(140,180,220,.35)" stroke-width="2"/>
<circle cx="320" cy="180" r="34" fill="none" stroke="rgba(140,180,220,.35)" stroke-width="2"/>
<!-- orange screws P00 -->
<circle cx="320" cy="70" r="12" fill="#ff6b35" stroke="#0a1e36" stroke-width="3"/>
<circle cx="200" cy="238" r="12" fill="#ff6b35" stroke="#0a1e36" stroke-width="3"/>
<circle cx="440" cy="238" r="12" fill="#ff6b35" stroke="#0a1e36" stroke-width="3"/>
<!-- green screw T5 -->
<circle cx="320" cy="288" r="12" fill="#2f9e6f" stroke="#0a1e36" stroke-width="3"/>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 03 — DRIVER PLATE FASTENERS</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li><span class="screw mono screw-orange">3× P00 4.2 MM</span> around the plate rim — <em>orange</em> dots in the figure.</li>
<li><span class="screw mono screw-green">1× T5 6.0 MM</span> at the hinge side — <em>green</em> dot. This one is longer; keep it separate.</li>
<li>Park screws on a magnetic mat in the same layout as the cup so nothing gets swapped.</li>
</ul>
<div class="callout warn" role="note">
<span class="callout-tag-txt mono">⚠ CAUTION</span>
<p>The P00 heads strip easily. Press down firmly and turn slowly — if a screw resists, re-seat the driver rather than forcing it.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="3" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 4 -->
<article class="step" id="step-4" data-step="4">
<header class="step-head">
<span class="step-num mono">STEP 4</span>
<h2>Lift the driver plate</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Opening pick freeing the driver plate, ribbon cable still attached">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<ellipse cx="300" cy="220" rx="150" ry="100" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<ellipse cx="330" cy="130" rx="140" ry="60" fill="#1e4a7a" stroke="#8cb4dc" stroke-width="3" transform="rotate(-8 330 130)"/>
<path d="M370 175 q-20 30 -30 55" stroke="#ffd166" stroke-width="5" fill="none" stroke-dasharray="2 7" stroke-linecap="round"/>
<text x="392" y="205" fill="#ffd166" font-family="JetBrains Mono, monospace" font-size="14">RIBBON — DO NOT PULL</text>
<path d="M118 210 l60 -30 l14 22 l-60 30 z" fill="#ff6b35"/>
<text x="60" y="270" fill="#ffe3d6" font-family="JetBrains Mono, monospace" font-size="14">PICK, <3MM DEEP</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 04 — PLATE HINGED OPEN</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Slide an <strong>opening pick</strong> into the seam near the USB-C port and work around the rim to free the friction clips — four soft clicks.</li>
<li>Hinge the plate open like a book <strong>toward the headband</strong>. A short ribbon cable still ties it to the driver.</li>
<li>Rest the plate against the yoke; do not let it dangle by the ribbon.</li>
</ul>
<div class="callout warn" role="note">
<span class="callout-tag-txt mono">⚠ PRY GENTLY</span>
<p>Insert the pick no deeper than 3 mm — the driver surround sits just inside the rim and tears easily. Never pry with metal.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="4" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 5 -->
<article class="step" id="step-5" data-step="5">
<header class="step-head">
<span class="step-num mono">STEP 5</span>
<h2>Disconnect the battery</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Spudger lifting the battery connector from its socket">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<rect x="150" y="120" width="340" height="150" rx="14" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<rect x="180" y="150" width="180" height="90" rx="8" fill="#0a1e36" stroke="#d4503e" stroke-width="3"/>
<text x="196" y="202" fill="#ffb4a8" font-family="JetBrains Mono, monospace" font-size="15">CELL 620mAh</text>
<rect x="396" y="176" width="52" height="34" rx="6" fill="#d4503e"/>
<path d="M448 193 h60" stroke="#ffd166" stroke-width="5"/>
<path d="M508 193 l-40 -70" stroke="#efe6d4" stroke-width="8" stroke-linecap="round"/>
<text x="472" y="96" fill="#efe6d4" font-family="JetBrains Mono, monospace" font-size="14">SPUDGER — LIFT UP</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 05 — BTB CONNECTOR J4</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Locate connector <span class="screw mono screw-red">J4 · BTB 4-PIN</span> on the edge of the logic board, marked red in the figure.</li>
<li>Slip the flat end of a <strong>nylon spudger</strong> under the connector and lever it <strong>straight up</strong> — it pops off like a snap button.</li>
<li>With the battery isolated, the rest of the repair is de-energised.</li>
</ul>
<div class="callout danger" role="note">
<span class="callout-tag-txt mono">⚠ DANGER — SHORT RISK</span>
<p>Do not touch the board with metal tools while the battery is connected. Bridging the J4 pads can destroy the charge controller.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="5" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 6 -->
<article class="step" id="step-6" data-step="6">
<header class="step-head">
<span class="step-num mono">STEP 6</span>
<h2>Remove the old cell</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Adhesive pull tab being drawn out from under the battery">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<rect x="180" y="130" width="200" height="110" rx="10" fill="#0a1e36" stroke="#d4503e" stroke-width="3"/>
<text x="204" y="192" fill="#ffb4a8" font-family="JetBrains Mono, monospace" font-size="15">OLD CELL</text>
<path d="M200 240 q-40 60 -110 58" stroke="#efe6d4" stroke-width="8" fill="none" stroke-linecap="round"/>
<path d="M96 296 l-24 4 M96 296 l10 -22" stroke="#efe6d4" stroke-width="6" fill="none" stroke-linecap="round"/>
<text x="60" y="256" fill="#efe6d4" font-family="JetBrains Mono, monospace" font-size="14">PULL TAB — LOW & SLOW</text>
<text x="420" y="150" fill="#ffd166" font-family="JetBrains Mono, monospace" font-size="14">NO METAL</text>
<text x="420" y="172" fill="#ffd166" font-family="JetBrains Mono, monospace" font-size="14">UNDER CELL</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 06 — STRETCH-RELEASE ADHESIVE</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Find the white <strong>stretch-release pull tab</strong> at the bottom edge of the cell.</li>
<li>Grip it with tweezers and pull <strong>slowly and parallel to the cup</strong> — the strip stretches to ~10× its length before releasing.</li>
<li>If the tab snaps, wick a drop of isopropyl alcohol under the cell, wait 60 seconds, and lift with a <em>plastic</em> pick from the tab edge.</li>
</ul>
<div class="callout danger" role="note">
<span class="callout-tag-txt mono">⚠ DANGER — PUNCTURE</span>
<p>Never bend, crease, or lever against the pouch cell. If the old battery is swollen, stop and take the unit to a battery recycler.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="6" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 7 -->
<article class="step" id="step-7" data-step="7">
<header class="step-head">
<span class="step-num mono">STEP 7</span>
<h2>Seat the new cell</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="New battery aligned over fresh adhesive strips">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<rect x="180" y="150" width="200" height="110" rx="10" fill="none" stroke="#8cb4dc" stroke-width="3" stroke-dasharray="8 8"/>
<rect x="196" y="176" width="168" height="16" rx="4" fill="#efe6d4"/>
<rect x="196" y="226" width="168" height="16" rx="4" fill="#efe6d4"/>
<rect x="210" y="60" width="200" height="110" rx="10" fill="#0a1e36" stroke="#2f9e6f" stroke-width="3" transform="rotate(6 310 115)"/>
<text x="248" y="122" fill="#9be8c4" font-family="JetBrains Mono, monospace" font-size="15" transform="rotate(6 310 115)">NEW CELL</text>
<path d="M430 140 l-30 44" stroke="#2f9e6f" stroke-width="5" stroke-linecap="round"/>
<path d="M400 184 l4 -24 M400 184 l22 -8" stroke="#2f9e6f" stroke-width="5" fill="none" stroke-linecap="round"/>
<text x="430" y="240" fill="#9be8c4" font-family="JetBrains Mono, monospace" font-size="14">LEAD SIDE → J4</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 07 — ADHESIVE LAYOUT</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Clean the recess with isopropyl alcohol and let it flash off.</li>
<li>Lay the two new strips from kit <span class="screw mono screw-kraft">VX2-ADH-KIT</span> inside the dashed outline, then peel the top liners.</li>
<li>Orient the new <span class="screw mono screw-green">VX2-CELL-620</span> with its <strong>lead toward J4</strong>, lower it in, and press for 10 seconds.</li>
</ul>
<div class="callout info" role="note">
<span class="callout-tag-txt mono">ℹ CHECK FIRST</span>
<p>Dry-fit the cell before peeling the liners — the adhesive grabs on first contact and repositioning weakens it.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="7" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- STEP 8 -->
<article class="step" id="step-8" data-step="8">
<header class="step-head">
<span class="step-num mono">STEP 8</span>
<h2>Reconnect & test</h2>
</header>
<div class="step-media" aria-hidden="true">
<svg viewBox="0 0 640 360" class="step-svg" role="img" aria-label="Connector pressed home and LED showing green">
<rect width="640" height="360" fill="var(--blueprint)"/>
<g opacity="0.5" stroke="rgba(140,180,220,0.2)" stroke-width="1">
<path d="M0 90H640M0 180H640M0 270H640M160 0V360M320 0V360M480 0V360"/>
</g>
<rect x="150" y="130" width="340" height="140" rx="14" fill="#16385f" stroke="#8cb4dc" stroke-width="3"/>
<rect x="396" y="182" width="52" height="34" rx="6" fill="#2f9e6f"/>
<path d="M422 150 v24" stroke="#9be8c4" stroke-width="5" stroke-linecap="round"/>
<path d="M422 174 l-10 -12 M422 174 l10 -12" stroke="#9be8c4" stroke-width="5" fill="none" stroke-linecap="round"/>
<text x="330" y="118" fill="#9be8c4" font-family="JetBrains Mono, monospace" font-size="14">PRESS UNTIL IT CLICKS</text>
<circle cx="540" cy="290" r="14" fill="#2f9e6f">
<animate attributeName="opacity" values="1;0.3;1" dur="1.6s" repeatCount="indefinite"/>
</circle>
<text x="420" y="296" fill="#9be8c4" font-family="JetBrains Mono, monospace" font-size="14">LED: OK</text>
<text x="42" y="330" fill="rgba(255,255,255,.55)" font-family="JetBrains Mono, monospace" font-size="13">FIG. 08 — POWER-ON TEST</text>
</svg>
</div>
<div class="step-body">
<ul class="step-notes">
<li>Align the <span class="screw mono screw-red">J4 · BTB 4-PIN</span> connector over its socket and press with a fingertip until it clicks flat.</li>
<li>Before closing anything, hold the power button — the LED should breathe <strong style="color:var(--ok)">green</strong>.</li>
<li>Power back off, then hinge the driver plate closed until every clip clicks.</li>
</ul>
<div class="callout warn" role="note">
<span class="callout-tag-txt mono">⚠ TEST BEFORE CLOSING</span>
<p>If the LED blinks amber twice, the connector is half-seated. Disconnect fully and press it home again — never force a misaligned BTB.</p>
</div>
<label class="done-check">
<input type="checkbox" class="step-done" data-step="8" />
<span class="box" aria-hidden="true"></span>
Mark step complete
</label>
</div>
</article>
<!-- FINISH -->
<section class="finish" id="finish" aria-live="polite">
<div class="finish-card" id="finishCard">
<div class="finish-default" id="finishDefault">
<h2 class="finish-title">Almost there</h2>
<p class="finish-note">
To reassemble your device, <strong>follow these instructions in reverse
order</strong> — screws in step 3 go back <em>last</em>, and the green
<span class="screw mono screw-green">1× T5 6.0 MM</span> returns to the hinge side only.
</p>
<p class="finish-note dim"><span class="mono" id="finishCount">0 / 8</span> steps checked off above.</p>
</div>
<div class="finish-success" id="finishSuccess" hidden>
<div class="success-stamp mono" aria-hidden="true">FIXED ✓</div>
<h2 class="finish-title">Repair complete!</h2>
<p class="finish-note">
Nice work — your Volta X2 is back on a fresh 620 mAh cell. Give it one
full charge cycle before judging battery life, and drop the old cell at a
battery recycling point (never in household waste).
</p>
<div class="finish-actions">
<button class="btn-primary" id="shareBtn" type="button">Share your fix</button>
<button class="btn-ghost" id="anotherBtn" type="button">Browse more guides</button>
</div>
</div>
</div>
</section>
</main>
</div>
<footer class="foot">
<p><span class="mono">FIXSHOP.EXAMPLE</span> — community repair guides. Guide VX2-BAT-011, rev C, by <strong>Marisol Quintero</strong> & 12 contributors.</p>
</footer>
<div class="toast mono" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Repair Guide
A full teardown-style repair guide page in the blueprint/workshop design language: a navy grid hero introduces the fictional Volta X2 headphone with a pure-CSS device illustration, difficulty pips, a time estimate, and a kraft-paper strip listing every tool and part with mono part-number badges. Below, eight numbered steps each pair a hand-drawn SVG figure with bullet instructions, color-matched screw callouts (“3× P00 4.2 MM” in orange matching the orange dots in the figure), and danger/caution/info callout boxes for battery and prying hazards.
A sticky progress rail on the left tracks the step currently in view via IntersectionObserver and doubles as smooth-scroll navigation. Every step has a “Mark step complete” checkbox that persists to localStorage, fills the completion meter, strikes the step off the rail, and — once all eight are checked — swaps the “reassemble in reverse order” note for a stamped FIXED success card with share actions. A toast helper narrates each interaction, and a reset button clears progress.
The layout collapses gracefully: on tablets the rail becomes a compact meter bar above the steps, and everything remains usable down to 360px-wide viewports with keyboard-accessible checkboxes, buttons, and links throughout.
Illustrative UI only — always follow real safety guidance when working with tools, electronics, or repairs.