DIY — Retro Electronics Restoration Landing
A vintage-bench landing page for a fictional retro-electronics restoration shop, in plain HTML, CSS and vanilla JS. The hero is a chunky beveled CRT with scanlines, a vignette, phosphor-green boot text that types itself out, and a power knob playing a real tube-collapse animation. Below sit beveled service cards with price-from chips, a hover crossfade before/after gallery of CSS-drawn consoles and radios, a mono recap-kit table with an ESR note, a repair-log timeline, a toast-confirmed quote form and a seven-segment bench clock.
MCP
Code
:root{
/* retro-restoration palette */
--beige:#d8cdb6;
--beige-l:#e8e0cd;
--beige-d:#c2b498;
--bakelite:#3a3129;
--bakelite-d:#251f1a;
--bakelite-l:#4d4136;
--phosphor:#59f27a;
--phosphor-dim:#2f8f47;
--screen:#0b110c;
--amber:#ffab3d;
--amber-d:#d8862a;
--red:#b8483c;
--ink:#241e19;
--ink-2:#4a4038;
--muted:#7a6e60;
--bg:#efe8d8;
--white:#fffdf7;
--line:rgba(36,30,25,.14);
--line-2:rgba(36,30,25,.26);
--ok:#3f8f5e;
--warn:#d8862a;
--danger:#b8483c;
--r-sm:6px; --r-md:12px; --r-lg:18px;
--sh-1:0 1px 2px rgba(36,30,25,.10), 0 6px 18px rgba(36,30,25,.08);
--sh-2:0 2px 6px rgba(36,30,25,.14), 0 18px 40px rgba(36,30,25,.14);
--bevel: inset 1px 1px 0 rgba(255,255,255,.55), inset -2px -2px 0 rgba(0,0,0,.16);
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
margin:0;
font-family:Inter,system-ui,sans-serif;
line-height:1.5;
color:var(--ink);
background:var(--bg);
-webkit-font-smoothing:antialiased;
text-rendering:optimizeLegibility;
}
img{max-width:100%}
h1,h2,h3{line-height:1.15;margin:0;letter-spacing:-.02em}
p{margin:0}
.mono{font-family:"JetBrains Mono",ui-monospace,monospace}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.wrap{width:min(1180px,100% - 2.5rem);margin-inline:auto}
.skip{position:absolute;left:-9999px;top:0;background:var(--amber);color:var(--bakelite-d);padding:.6rem 1rem;border-radius:0 0 var(--r-sm) 0;font-weight:700;z-index:80}
.skip:focus{left:0}
:where(a,button,input,select,textarea,[tabindex]):focus-visible{
outline:3px solid var(--amber);
outline-offset:2px;
border-radius:var(--r-sm);
}
/* ---------- buttons ---------- */
.btn{
--btn-bg:var(--beige);
display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
padding:.72rem 1.15rem;border:1px solid var(--line-2);border-radius:var(--r-sm);
background:var(--btn-bg);color:var(--ink);
font-weight:700;font-size:.94rem;text-decoration:none;cursor:pointer;
box-shadow:var(--bevel), 0 2px 0 rgba(0,0,0,.18);
transition:transform .12s ease, box-shadow .12s ease, background .18s ease;
}
.btn:hover{transform:translateY(-1px);box-shadow:var(--bevel), 0 4px 0 rgba(0,0,0,.18)}
.btn:active{transform:translateY(1px);box-shadow:var(--bevel), 0 1px 0 rgba(0,0,0,.2)}
.btn-amber{--btn-bg:linear-gradient(#ffc169,var(--amber));border-color:var(--amber-d);color:#3a2607}
.btn-ghost{--btn-bg:transparent;color:var(--beige-l);border-color:rgba(216,205,182,.4);box-shadow:none}
.btn-ghost:hover{background:rgba(216,205,182,.12);box-shadow:none}
.btn-block{width:100%}
.chip{
display:inline-block;padding:.25rem .6rem;border-radius:999px;
background:var(--bakelite);color:var(--beige-l);
font-size:.74rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
}
.chip-green{background:rgba(63,143,94,.16);color:#2c6b45;border:1px solid rgba(63,143,94,.4)}
.card{
background:var(--white);
border:1px solid var(--line);
border-radius:var(--r-lg);
box-shadow:var(--sh-1);
}
/* ---------- topbar ---------- */
.topbar{position:sticky;top:0;z-index:60;background:rgba(58,49,41,.96);border-bottom:2px solid var(--bakelite-d);backdrop-filter:blur(8px)}
.topbar-in{display:flex;align-items:center;gap:1.2rem;min-height:66px}
.brand{display:flex;align-items:center;gap:.7rem;text-decoration:none;color:var(--beige-l);margin-right:auto}
.brand-tube{width:34px;height:26px;border-radius:5px;background:var(--screen);border:2px solid var(--beige-d);display:grid;place-items:center;box-shadow:inset 0 0 10px rgba(89,242,122,.35)}
.brand-tube i{width:10px;height:10px;border-radius:50%;background:var(--phosphor);box-shadow:0 0 8px var(--phosphor)}
.brand-txt strong{display:block;font-size:1.02rem;letter-spacing:-.01em}
.brand-txt em{display:block;font-style:normal;font-family:"JetBrains Mono",monospace;font-size:.68rem;color:rgba(216,205,182,.62);letter-spacing:.08em}
.nav{display:flex;gap:1.3rem}
.nav a{color:rgba(216,205,182,.82);text-decoration:none;font-size:.9rem;font-weight:500;padding:.3rem 0;border-bottom:2px solid transparent}
.nav a:hover{color:var(--amber);border-bottom-color:var(--amber)}
/* ---------- hero ---------- */
.hero{
position:relative;padding:4.2rem 0 4.6rem;color:var(--beige-l);
background:
radial-gradient(90% 70% at 12% 0%, rgba(255,171,61,.16), transparent 60%),
repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 2px, transparent 2px 4px),
linear-gradient(160deg,var(--bakelite-l),var(--bakelite-d));
}
.hero::after{content:"";position:absolute;inset:0;pointer-events:none;box-shadow:inset 0 -60px 80px -40px rgba(0,0,0,.6)}
.hero-in{position:relative;display:grid;grid-template-columns:1.05fr .95fr;gap:3rem;align-items:center}
.eyebrow{display:inline-block;font-family:"JetBrains Mono",monospace;font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;color:var(--amber);border:1px solid rgba(255,171,61,.4);border-radius:999px;padding:.3rem .8rem;margin-bottom:1.1rem}
.hero h1{font-size:clamp(2.1rem,4.6vw,3.5rem);font-weight:800}
.glow{color:var(--phosphor);text-shadow:0 0 18px rgba(89,242,122,.5)}
.lede{margin-top:1rem;max-width:52ch;color:rgba(216,205,182,.82);font-size:1.03rem}
.hero-cta{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:1.6rem}
.stats{display:flex;flex-wrap:wrap;gap:2rem;margin:2.2rem 0 0;padding-top:1.4rem;border-top:1px solid rgba(216,205,182,.18)}
.stats div{margin:0}
.stats dt{font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:rgba(216,205,182,.55)}
.stats dd{margin:.2rem 0 0;font-size:1.5rem;font-weight:700;color:var(--amber)}
/* CRT */
.crt-shell{display:flex;flex-direction:column;align-items:center;gap:.8rem}
.crt-bezel{
width:100%;max-width:460px;padding:20px 20px 14px;border-radius:22px;
background:linear-gradient(155deg,var(--beige-l),var(--beige) 40%,var(--beige-d));
box-shadow:
inset 2px 2px 0 rgba(255,255,255,.7),
inset -3px -4px 0 rgba(0,0,0,.22),
0 26px 50px rgba(0,0,0,.45);
position:relative;
}
.crt-screen{
position:relative;aspect-ratio:4/3;border-radius:16px/22px;overflow:hidden;
background:radial-gradient(120% 100% at 50% 40%, #16241a, var(--screen) 70%);
box-shadow:inset 0 0 0 6px #1b1611, inset 0 0 40px rgba(0,0,0,.9);
transition:filter .3s ease;
}
.crt-content{position:absolute;inset:0;padding:1.1rem 1.2rem;overflow:hidden}
.boot{
margin:0;font-size:.78rem;line-height:1.65;color:var(--phosphor);
text-shadow:0 0 6px rgba(89,242,122,.75);white-space:pre-wrap;word-break:break-word;
}
.boot .cursor{display:inline-block;width:.6em;height:1em;background:var(--phosphor);vertical-align:-.15em;animation:blink 1s steps(1,end) infinite}
@keyframes blink{50%{opacity:0}}
.scanlines{position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(0deg, rgba(0,0,0,.32) 0 1px, transparent 1px 3px);mix-blend-mode:multiply}
.vignette{position:absolute;inset:0;pointer-events:none;background:radial-gradient(75% 65% at 50% 50%, transparent 40%, rgba(0,0,0,.75) 100%)}
.collapse{position:absolute;inset:0;pointer-events:none;background:#eafff0;opacity:0;transform:scaleY(0);transform-origin:center}
.crt-screen[data-on="false"] .crt-content,
.crt-screen[data-on="false"] .scanlines{opacity:0;transition:opacity .12s ease}
.crt-screen[data-on="false"]{filter:brightness(.5)}
.crt-screen.collapsing .collapse{animation:crt-off .5s ease forwards}
.crt-screen.igniting .collapse{animation:crt-on .45s ease forwards}
@keyframes crt-off{
0%{opacity:.9;transform:scaleY(1) scaleX(1)}
45%{opacity:1;transform:scaleY(.02) scaleX(1)}
75%{opacity:1;transform:scaleY(.012) scaleX(.35)}
100%{opacity:0;transform:scaleY(.01) scaleX(0)}
}
@keyframes crt-on{
0%{opacity:1;transform:scaleY(.01) scaleX(0)}
35%{opacity:1;transform:scaleY(.02) scaleX(1)}
100%{opacity:0;transform:scaleY(1) scaleX(1)}
}
.crt-badge{position:absolute;left:26px;bottom:-2px;font-size:.6rem;letter-spacing:.14em;color:rgba(36,30,25,.5)}
.crt-panel{display:flex;align-items:center;gap:.9rem;margin-top:14px;padding-top:10px;border-top:1px solid rgba(0,0,0,.12)}
.knob{
width:46px;height:46px;border-radius:50%;padding:0;cursor:pointer;
border:2px solid rgba(0,0,0,.3);
background:conic-gradient(from 0deg, #4d4136, #2b241e 25%, #4d4136 50%, #2b241e 75%, #4d4136);
box-shadow:0 3px 0 rgba(0,0,0,.3), inset 0 0 0 3px rgba(255,255,255,.06);
display:grid;place-items:center;
}
.knob-face{width:30px;height:30px;border-radius:50%;background:radial-gradient(circle at 35% 30%, #6b5c4c, #322a23);display:grid;place-items:center;transition:transform .25s cubic-bezier(.34,1.56,.64,1)}
.knob-face i{width:3px;height:11px;border-radius:2px;background:var(--beige-l);transform:translateY(-6px)}
.knob[aria-checked="false"] .knob-face{transform:rotate(-42deg)}
.knob[aria-checked="true"] .knob-face{transform:rotate(42deg)}
.knob-label{display:flex;align-items:center;gap:.45rem;font-size:.66rem;letter-spacing:.14em;color:rgba(36,30,25,.6)}
.lamp{width:9px;height:9px;border-radius:50%;background:#6a5f50;box-shadow:inset 0 0 3px rgba(0,0,0,.5)}
.lamp.on{background:var(--red);box-shadow:0 0 10px rgba(184,72,60,.9)}
.sliders{display:flex;gap:.5rem;margin-left:auto}
.sliders span{width:9px;height:26px;border-radius:3px;background:linear-gradient(var(--bakelite-l),var(--bakelite-d));box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.vents{width:52px;height:26px;background:repeating-linear-gradient(90deg, rgba(0,0,0,.22) 0 3px, transparent 3px 7px);border-radius:3px}
.crt-caption{font-size:.7rem;letter-spacing:.14em;color:rgba(216,205,182,.5);text-transform:uppercase}
/* ---------- sections ---------- */
.section{padding:4.4rem 0}
.section-dark{background:linear-gradient(180deg,var(--bakelite),var(--bakelite-d));color:var(--beige-l)}
.sec-head{max-width:60ch;margin-bottom:2.2rem}
.sec-head h2{font-size:clamp(1.6rem,3vw,2.2rem);font-weight:800}
.sec-head p{margin-top:.55rem;color:var(--muted)}
.sec-head-dark p{color:rgba(216,205,182,.66)}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:1.2rem}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:1.4rem}
/* services */
.svc{padding:1.2rem;display:flex;flex-direction:column;gap:.6rem;position:relative;
box-shadow:var(--bevel), var(--sh-1);
border:1px solid var(--line-2);
background:linear-gradient(170deg,var(--white),#f7f2e6);
transition:transform .16s ease, box-shadow .16s ease;
}
.svc:hover{transform:translateY(-3px);box-shadow:var(--bevel), var(--sh-2)}
.svc h3{font-size:1.08rem}
.svc p{color:var(--ink-2);font-size:.92rem}
.svc-ill{position:relative;height:92px;border-radius:var(--r-md);overflow:hidden;background:radial-gradient(80% 90% at 50% 20%, #1d3a26, var(--screen));box-shadow:inset 0 0 0 2px rgba(0,0,0,.35)}
.svc-ill .pcb{position:absolute;inset:auto 0 0 0;height:26px;background:linear-gradient(#2b5a38,#1c3b25);box-shadow:0 -1px 0 rgba(89,242,122,.25)}
.svc-ill .cap{position:absolute;bottom:22px;width:16px;height:34px;border-radius:4px 4px 2px 2px;background:linear-gradient(#3b6fa8,#1e3c60);box-shadow:inset 0 -6px 0 rgba(0,0,0,.3), 0 0 10px rgba(89,242,122,.12)}
.svc-ill .c1{left:22%}.svc-ill .c2{left:44%;height:44px}.svc-ill .c3{left:66%;height:28px}
.svc-ill .tube{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:74px;height:56px;border-radius:10px;border:3px solid var(--beige-d);background:radial-gradient(circle at 50% 45%, rgba(89,242,122,.55), rgba(11,17,12,.9) 70%)}
.svc-ill .beam{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:6px;height:6px;border-radius:50%;background:var(--phosphor);box-shadow:0 0 22px 8px rgba(89,242,122,.6)}
.svc-ill .shell-a,.svc-ill .shell-b{position:absolute;width:70px;height:36px;border-radius:8px;background:linear-gradient(var(--beige-l),var(--beige-d));box-shadow:var(--bevel)}
.svc-ill .shell-a{left:14%;top:20%;transform:rotate(-8deg)}
.svc-ill .shell-b{right:14%;bottom:16%;transform:rotate(6deg);background:linear-gradient(#cbbb94,#a8956f)}
.svc-ill .bath{position:absolute;inset:auto 12% 12px 12%;height:44px;border-radius:0 0 10px 10px;background:linear-gradient(rgba(255,171,61,.5),rgba(255,171,61,.18));border:2px solid rgba(255,171,61,.5);border-top:none}
.svc-ill .bubble{position:absolute;bottom:18px;width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,.6);animation:rise 3.2s ease-in-out infinite}
.svc-ill .b1{left:30%}.svc-ill .b2{left:50%;animation-delay:.9s}.svc-ill .b3{left:68%;animation-delay:1.7s}
@keyframes rise{0%{transform:translateY(0);opacity:0}20%{opacity:.9}100%{transform:translateY(-34px);opacity:0}}
.ticks{list-style:none;margin:0;padding:0;display:grid;gap:.28rem;font-size:.76rem;color:var(--muted)}
.ticks li{padding-left:1.1rem;position:relative}
.ticks li::before{content:"";position:absolute;left:0;top:.45em;width:.5rem;height:.28rem;border-left:2px solid var(--ok);border-bottom:2px solid var(--ok);transform:rotate(-45deg)}
.ticks-lg{font-family:Inter,sans-serif;font-size:.9rem;gap:.5rem;color:var(--ink-2)}
.svc .chip{align-self:flex-start;margin-top:auto;background:var(--amber);color:#3a2607}
/* gallery */
.filters{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:1.6rem}
.pill{
padding:.42rem .9rem;border-radius:999px;cursor:pointer;
border:1px solid rgba(216,205,182,.32);background:transparent;color:rgba(216,205,182,.8);
font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;font-weight:600;
transition:background .16s ease,color .16s ease,border-color .16s ease;
}
.pill:hover{border-color:var(--amber);color:var(--amber)}
.pill.is-on{background:var(--amber);border-color:var(--amber);color:#3a2607}
.ba{border-radius:var(--r-lg);overflow:hidden;background:rgba(255,253,247,.05);border:1px solid rgba(216,205,182,.16);transition:transform .18s ease,border-color .18s ease}
.ba:hover,.ba:focus-visible{transform:translateY(-3px);border-color:rgba(255,171,61,.55)}
.ba.hide{display:none}
.ba-stage{position:relative;aspect-ratio:4/3;background:radial-gradient(90% 90% at 50% 20%, #2c241d, #17120f);overflow:hidden}
.ill{position:absolute;inset:0;display:grid;place-items:center;transition:opacity .5s ease}
.ill.restored{opacity:0}
.ba:hover .ill.restored,.ba:focus-visible .ill.restored{opacity:1}
.ba:hover .ill.yellowed,.ba:focus-visible .ill.yellowed{opacity:0}
.ba-tag{position:absolute;left:10px;top:10px;z-index:3;font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;background:rgba(11,17,12,.75);color:var(--phosphor);padding:.2rem .5rem;border-radius:999px;border:1px solid rgba(89,242,122,.35)}
.ba-body{padding:.9rem 1rem 1.1rem}
.ba-body h3{font-size:1rem;color:var(--beige-l)}
.meta{margin-top:.25rem;font-size:.72rem;color:rgba(216,205,182,.55)}
/* CSS illustrations, yellowed vs restored */
.ill.yellowed{--case:#c7b07a;--case-2:#a68e57;--face:#8f7a4a}
.ill.restored{--case:#e6dfcc;--case-2:#c9c0a8;--face:#b3a98f}
.ill-console{}
.ill-console::before{content:"";width:66%;height:34%;border-radius:10px;background:linear-gradient(var(--case),var(--case-2));box-shadow:var(--bevel),0 10px 18px rgba(0,0,0,.4)}
.ill-console .slot{position:absolute;top:38%;left:32%;width:36%;height:8px;border-radius:3px;background:rgba(0,0,0,.55)}
.ill-console .led{position:absolute;top:38%;left:26%;width:8px;height:8px;border-radius:50%;background:var(--red);box-shadow:0 0 8px rgba(184,72,60,.8)}
.ill-console .ridge{position:absolute;top:48%;left:32%;width:36%;height:14px;background:repeating-linear-gradient(90deg, rgba(0,0,0,.18) 0 3px, transparent 3px 8px)}
.ill-console.alt::before{background:linear-gradient(var(--face),var(--case-2));border-radius:6px}
.ill-radio::before{content:"";width:58%;height:46%;border-radius:14px 14px 8px 8px;background:linear-gradient(var(--case),var(--case-2));box-shadow:var(--bevel),0 10px 18px rgba(0,0,0,.4)}
.ill-radio .dial{position:absolute;top:36%;left:50%;transform:translateX(-50%);width:32%;height:16px;border-radius:8px;background:linear-gradient(#f6e6b8,#d9c48a);box-shadow:inset 0 0 6px rgba(255,171,61,.7)}
.ill-radio .needle{position:absolute;top:36%;left:52%;width:2px;height:16px;background:var(--red)}
.ill-radio .grille{position:absolute;top:50%;left:34%;width:32%;height:22px;background:repeating-linear-gradient(90deg, rgba(0,0,0,.3) 0 2px, transparent 2px 6px);border-radius:4px}
.ill-radio.alt::before{border-radius:50% 50% 8px 8px / 40% 40% 8px 8px}
.ill-computer::before{content:"";width:70%;height:30%;border-radius:6px 6px 12px 12px;background:linear-gradient(var(--case),var(--case-2));box-shadow:var(--bevel),0 10px 18px rgba(0,0,0,.4)}
.ill-computer .keys{position:absolute;top:41%;left:20%;width:60%;height:22px;background:repeating-linear-gradient(90deg, var(--face) 0 9px, transparent 9px 12px);opacity:.85;border-radius:3px}
.ill-computer .badge{position:absolute;top:36%;left:22%;width:26px;height:6px;border-radius:2px;background:var(--amber)}
.ill-handheld::before{content:"";width:32%;height:56%;border-radius:10px 10px 22px 10px;background:linear-gradient(var(--case),var(--case-2));box-shadow:var(--bevel),0 10px 18px rgba(0,0,0,.4)}
.ill-handheld .lcd{position:absolute;top:26%;left:50%;transform:translateX(-50%);width:22%;height:20%;border-radius:4px;background:linear-gradient(#7f9a5c,#5d7742);box-shadow:inset 0 0 0 3px rgba(0,0,0,.35)}
.ill-handheld .dpad{position:absolute;top:56%;left:41%;width:16px;height:16px;background:
linear-gradient(var(--face),var(--face)) center/6px 16px no-repeat,
linear-gradient(var(--face),var(--face)) center/16px 6px no-repeat}
.ill-handheld .ab{position:absolute;top:58%;right:38%;width:22px;height:9px;border-radius:999px;background:var(--red);opacity:.85}
.empty{margin-top:1.5rem;color:rgba(216,205,182,.6);font-size:.85rem}
/* recap kit */
.kit-grid{display:grid;grid-template-columns:1.6fr 1fr;gap:1.4rem;align-items:start}
.kit{padding:1.4rem}
.kit-head{display:flex;gap:1rem;align-items:flex-start;justify-content:space-between;margin-bottom:1.1rem}
.kit-head h2{font-size:1.3rem}
.kit-head p{margin-top:.3rem;font-size:.74rem;color:var(--muted);letter-spacing:.06em}
.table-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-md)}
.kit-table{width:100%;border-collapse:collapse;font-size:.82rem;min-width:430px}
.kit-table th,.kit-table td{padding:.55rem .7rem;text-align:left;border-bottom:1px solid var(--line)}
.kit-table thead th{background:var(--bakelite);color:var(--beige-l);font-size:.68rem;letter-spacing:.1em;text-transform:uppercase}
.kit-table tbody tr:nth-child(odd){background:rgba(216,205,182,.16)}
.kit-table tbody tr:hover{background:rgba(255,171,61,.18)}
.kit-table .num{text-align:right}
.kit-table tfoot th,.kit-table tfoot td{background:rgba(36,30,25,.06);font-weight:700;border-bottom:none}
.note{margin-top:.9rem;font-size:.78rem;color:var(--ink-2);background:rgba(255,171,61,.14);border-left:3px solid var(--amber);padding:.7rem .85rem;border-radius:0 var(--r-sm) var(--r-sm) 0}
.kit-foot{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-top:1.2rem;flex-wrap:wrap}
.price{font-size:1.7rem;font-weight:700}
.price small{font-size:.9rem}
.bench-note{padding:1.4rem}
.bench-note h3{font-size:1.05rem;margin-bottom:.8rem}
.meter{display:flex;align-items:center;gap:.6rem;margin-top:1.2rem;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.bars{display:flex;gap:4px}
.bars i{width:16px;height:8px;border-radius:2px;background:rgba(36,30,25,.14)}
.bars i.on{background:var(--amber)}
.dim{color:var(--ink-2)}
/* timeline */
.timeline{list-style:none;margin:0;padding:0 0 0 2.2rem;position:relative;display:grid;gap:1.5rem;counter-reset:tl}
.timeline::before{content:"";position:absolute;left:14px;top:6px;bottom:6px;width:2px;background:linear-gradient(var(--phosphor-dim),rgba(89,242,122,.08))}
.timeline li{position:relative;display:flex;gap:1rem;align-items:flex-start}
.tl-ill{position:absolute;left:-2.2rem;top:2px;width:30px;height:30px;border-radius:50%;background:var(--bakelite-d);border:2px solid var(--phosphor-dim);display:grid;place-items:center}
.timeline li.done .tl-ill{border-color:var(--phosphor);box-shadow:0 0 14px rgba(89,242,122,.5)}
.dot-ill{display:block}
.dot-ill.box{width:12px;height:9px;border:2px solid var(--beige);border-radius:2px}
.dot-ill.wave{width:14px;height:8px;background:
linear-gradient(var(--amber),var(--amber)) 0 50%/14px 2px no-repeat;
border-left:2px solid var(--amber);border-right:2px solid var(--amber)}
.dot-ill.cap{width:8px;height:13px;border-radius:2px;background:linear-gradient(#3b6fa8,#1e3c60)}
.dot-ill.key{width:14px;height:9px;background:repeating-linear-gradient(90deg,var(--beige) 0 3px,transparent 3px 5px)}
.dot-ill.sun{width:12px;height:12px;border-radius:50%;background:var(--amber);box-shadow:0 0 10px var(--amber)}
.dot-ill.tick{width:12px;height:7px;border-left:2px solid var(--phosphor);border-bottom:2px solid var(--phosphor);transform:rotate(-45deg) translateY(-2px)}
.tl-body time{display:block;font-size:.7rem;letter-spacing:.16em;color:var(--amber)}
.tl-body h3{margin-top:.2rem;font-size:1.02rem;color:var(--beige-l)}
.tl-body p{margin-top:.3rem;font-size:.9rem;color:rgba(216,205,182,.7);max-width:62ch}
/* quote */
.quote-band{background:
repeating-linear-gradient(135deg, rgba(36,30,25,.035) 0 12px, transparent 12px 24px),
var(--bg)}
.quote-in{display:grid;grid-template-columns:1fr 1fr;gap:2.4rem;align-items:center}
.quote-copy h2{font-size:clamp(1.7rem,3vw,2.3rem);font-weight:800}
.quote-copy p{margin-top:.7rem;color:var(--ink-2);max-width:46ch}
.quote-form{padding:1.4rem;display:grid;gap:.85rem}
.field{display:grid;gap:.3rem}
.field label{font-size:.76rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.field input,.field select,.field textarea{
font:inherit;font-size:.92rem;padding:.6rem .7rem;border-radius:var(--r-sm);
border:1px solid var(--line-2);background:#fbf7ec;color:var(--ink);
box-shadow:inset 1px 1px 2px rgba(0,0,0,.08);
}
.field textarea{resize:vertical}
.field input::placeholder,.field textarea::placeholder{color:rgba(122,110,96,.75)}
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible{border-color:var(--amber)}
.err{color:var(--danger);font-size:.78rem;font-weight:600}
.fine{font-size:.7rem;color:var(--muted);text-align:center}
/* footer */
.footer{background:var(--bakelite-d);color:rgba(216,205,182,.72);padding:2.2rem 0}
.foot-in{display:flex;flex-wrap:wrap;gap:1.4rem;align-items:center;justify-content:space-between}
.foot-brand{font-weight:800;color:var(--beige-l);font-size:1.05rem}
.foot-note{font-size:.8rem;margin-top:.25rem}
.clock{display:grid;gap:.3rem;justify-items:center;padding:.7rem 1.1rem;border-radius:var(--r-md);background:var(--screen);border:2px solid var(--bakelite-l);box-shadow:inset 0 0 22px rgba(89,242,122,.14)}
.seg{font-size:1.5rem;font-weight:700;letter-spacing:.12em;color:var(--phosphor);text-shadow:0 0 12px rgba(89,242,122,.7)}
.clock-cap{font-size:.58rem;letter-spacing:.3em;color:rgba(89,242,122,.45)}
/* toast */
.toast-host{position:fixed;right:1rem;bottom:1rem;z-index:90;display:grid;gap:.5rem;justify-items:end}
.toast{
background:var(--bakelite);color:var(--beige-l);
border:1px solid rgba(89,242,122,.4);border-left:4px solid var(--phosphor);
padding:.7rem .95rem;border-radius:var(--r-sm);font-size:.86rem;max-width:min(360px,88vw);
box-shadow:var(--sh-2);animation:toast-in .28s ease both;
}
.toast.out{animation:toast-out .3s ease both}
@keyframes toast-in{from{opacity:0;transform:translateY(10px) scale(.97)}}
@keyframes toast-out{to{opacity:0;transform:translateY(8px)}}
/* ---------- responsive ---------- */
@media (max-width:960px){
.hero-in,.quote-in{grid-template-columns:1fr}
.grid-4{grid-template-columns:repeat(2,1fr)}
.grid-3{grid-template-columns:repeat(2,1fr)}
.kit-grid{grid-template-columns:1fr}
.nav{display:none}
}
@media (max-width:520px){
.wrap{width:min(1180px,100% - 1.6rem)}
.section{padding:3rem 0}
.hero{padding:2.6rem 0 3rem}
.grid-4,.grid-3{grid-template-columns:1fr}
.stats{gap:1.2rem}
.stats dd{font-size:1.2rem}
.btn{width:100%}
.hero-cta{flex-direction:column}
.topbar-in{min-height:58px}
.crt-bezel{padding:14px 14px 10px}
.boot{font-size:.68rem}
.foot-in{flex-direction:column;align-items:flex-start}
.clock{width:100%}
.timeline{padding-left:1.9rem}
.tl-ill{left:-1.9rem;width:26px;height:26px}
.kit-foot{flex-direction:column;align-items:stretch}
.price{text-align:center}
}
@media (prefers-reduced-motion:reduce){
*,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important}
.boot .cursor{opacity:1}
}(function () {
"use strict";
var reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------------- toast ---------------- */
var host = document.getElementById("toastHost");
function toast(msg) {
if (!host) return;
var el = document.createElement("div");
el.className = "toast";
el.textContent = msg;
host.appendChild(el);
window.setTimeout(function () {
el.classList.add("out");
window.setTimeout(function () {
if (el.parentNode) el.parentNode.removeChild(el);
}, 320);
}, 3600);
}
/* ---------------- CRT boot typing ---------------- */
var screenEl = document.getElementById("screen");
var bootEl = document.getElementById("boot");
var lamp = document.getElementById("lamp");
var powerBtn = document.getElementById("power");
var BOOT = [
"CATHODE REVIVAL BENCH OS v2.7",
"",
"> degauss coil ......... OK",
"> HV rail 24.1 kV ...... OK",
"> filament 6.3 V ....... OK",
"> convergence .......... ALIGNED",
"> 22 caps on tray 4 .... READY",
"",
"bench 4 idle. awaiting unit."
];
var typeTimer = null;
function typeBoot() {
if (!bootEl) return;
window.clearTimeout(typeTimer);
bootEl.textContent = "";
var full = BOOT.join("\n");
if (reduced) {
bootEl.textContent = full;
addCursor();
return;
}
var i = 0;
(function step() {
if (i > full.length) {
addCursor();
return;
}
bootEl.textContent = full.slice(0, i);
i += 1;
typeTimer = window.setTimeout(step, full.charAt(i) === "\n" ? 90 : 18);
})();
}
function addCursor() {
var c = document.createElement("span");
c.className = "cursor";
bootEl.appendChild(c);
}
function setPower(on) {
if (!screenEl || !powerBtn) return;
powerBtn.setAttribute("aria-checked", on ? "true" : "false");
screenEl.setAttribute("data-on", on ? "true" : "false");
if (lamp) lamp.classList.toggle("on", on);
screenEl.classList.remove("collapsing", "igniting");
/* force reflow so the animation restarts cleanly */
void screenEl.offsetWidth;
screenEl.classList.add(on ? "igniting" : "collapsing");
if (on) {
typeBoot();
toast("Tube warming up — filament at 6.3 V.");
} else {
window.clearTimeout(typeTimer);
toast("Set powered down. Let the HV bleed off before opening it.");
}
}
if (powerBtn) {
powerBtn.addEventListener("click", function () {
setPower(powerBtn.getAttribute("aria-checked") !== "true");
});
}
typeBoot();
if (lamp) lamp.classList.add("on");
/* ---------------- gallery filter ---------------- */
var pills = Array.prototype.slice.call(document.querySelectorAll(".pill[data-filter]"));
var cards = Array.prototype.slice.call(document.querySelectorAll(".ba"));
var emptyMsg = document.getElementById("galleryEmpty");
function applyFilter(kind) {
var shown = 0;
cards.forEach(function (card) {
var match = kind === "all" || card.getAttribute("data-kind") === kind;
card.classList.toggle("hide", !match);
if (match) shown += 1;
});
if (emptyMsg) emptyMsg.hidden = shown !== 0;
return shown;
}
pills.forEach(function (pill) {
pill.addEventListener("click", function () {
pills.forEach(function (p) {
var on = p === pill;
p.classList.toggle("is-on", on);
p.setAttribute("aria-pressed", on ? "true" : "false");
});
var kind = pill.getAttribute("data-filter");
var n = applyFilter(kind);
toast(n === 1 ? "1 unit on the bench." : n + " units on the bench.");
});
});
/* touch: tap a gallery card to hold the "after" state */
cards.forEach(function (card) {
card.addEventListener("click", function () {
card.focus();
});
});
/* ---------------- recap kit ---------------- */
var addKit = document.getElementById("addKit");
var kitAdded = false;
var deviceSel = document.getElementById("qDevice");
if (addKit) {
addKit.addEventListener("click", function () {
kitAdded = true;
addKit.textContent = "Kit added ✓";
if (deviceSel) deviceSel.value = "Vectra 64 console";
toast("CRK-0642 recap kit (22 pcs, $34.50) attached to your quote.");
var q = document.getElementById("quote");
if (q) q.scrollIntoView({ behavior: reduced ? "auto" : "smooth", block: "start" });
});
}
/* ---------------- quote form ---------------- */
var form = document.getElementById("quoteForm");
var err = document.getElementById("qErr");
if (form) {
form.addEventListener("submit", function (ev) {
ev.preventDefault();
var name = document.getElementById("qName");
var email = document.getElementById("qEmail");
var device = deviceSel ? deviceSel.value : "your unit";
var problem = null;
if (!name.value.trim()) problem = "We need a name for the bench card.";
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email.value.trim()))
problem = "That email doesn't look reachable — check it once more.";
if (problem) {
if (err) {
err.textContent = problem;
err.hidden = false;
}
(problem.indexOf("name") > -1 ? name : email).focus();
return;
}
if (err) err.hidden = true;
var ticket = "CR-" + String(4400 + Math.floor(Math.random() * 500));
toast(
"Ticket " + ticket + " opened for the " + device +
(kitAdded ? " (recap kit included)." : ".") +
" We'll reply within 2 business days."
);
form.reset();
addKit && (addKit.textContent = "Add kit to quote");
kitAdded = false;
});
}
/* ---------------- seven-segment bench clock ---------------- */
var clock = document.getElementById("clock");
function pad(n) { return n < 10 ? "0" + n : "" + n; }
function tick() {
if (!clock) return;
var d = new Date();
clock.textContent = pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds());
}
tick();
window.setInterval(tick, 1000);
/* ---------------- smooth in-page nav ---------------- */
document.querySelectorAll('a[href^="#"]').forEach(function (a) {
a.addEventListener("click", function (ev) {
var id = a.getAttribute("href");
if (!id || id === "#") return;
var target = document.querySelector(id);
if (!target) return;
ev.preventDefault();
target.scrollIntoView({ behavior: reduced ? "auto" : "smooth", block: "start" });
});
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Cathode Revival — Retro Electronics Restoration</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>
<a class="skip" href="#main">Skip to content</a>
<header class="topbar">
<div class="wrap topbar-in">
<a class="brand" href="#main">
<span class="brand-tube" aria-hidden="true"><i></i></span>
<span class="brand-txt">
<strong>Cathode Revival</strong>
<em>Est. 1987 · Bench 4</em>
</span>
</a>
<nav class="nav" aria-label="Primary">
<a href="#services">Services</a>
<a href="#gallery">Gallery</a>
<a href="#kit">Recap kits</a>
<a href="#log">Repair log</a>
</nav>
<a class="btn btn-amber" href="#quote">Request a quote</a>
</div>
</header>
<main id="main">
<!-- HERO -->
<section class="hero">
<div class="wrap hero-in">
<div class="hero-copy">
<span class="eyebrow">Bench-tested restorations since 1987</span>
<h1>We bring dead <span class="glow">phosphor</span> back to life.</h1>
<p class="lede">Full electrolytic recapping, flyback rebuilds, yellowed-plastic retrobrighting and case
refinishing for consoles, radios and 8-bit computers. Every unit leaves the bench with a signed
service card and a 24-month workmanship warranty.</p>
<div class="hero-cta">
<a class="btn btn-amber" href="#quote">Book a bench slot</a>
<a class="btn btn-ghost" href="#gallery">See restorations</a>
</div>
<dl class="stats">
<div><dt>Units revived</dt><dd class="mono">2,418</dd></div>
<div><dt>Avg. turnaround</dt><dd class="mono">11 days</dd></div>
<div><dt>Caps replaced</dt><dd class="mono">61,930</dd></div>
</dl>
</div>
<div class="crt-shell">
<div class="crt-bezel">
<div class="crt-screen" id="screen" data-on="true">
<div class="crt-content">
<pre class="boot mono" id="boot" aria-live="polite" aria-label="Terminal boot sequence"></pre>
</div>
<div class="scanlines" aria-hidden="true"></div>
<div class="vignette" aria-hidden="true"></div>
<div class="collapse" aria-hidden="true"></div>
</div>
<div class="crt-badge mono">CR‑19 TRINISCAN</div>
<div class="crt-panel">
<button class="knob" id="power" type="button" role="switch" aria-checked="true" aria-label="CRT power">
<span class="knob-face" aria-hidden="true"><i></i></span>
</button>
<div class="knob-label">
<span class="mono">POWER</span>
<span class="lamp" id="lamp" aria-hidden="true"></span>
</div>
<div class="sliders" aria-hidden="true">
<span></span><span></span><span></span>
</div>
<div class="vents" aria-hidden="true"></div>
</div>
</div>
<p class="crt-caption mono">Bench unit — flip the knob</p>
</div>
</div>
</section>
<!-- SERVICES -->
<section id="services" class="section">
<div class="wrap">
<header class="sec-head">
<h2>Bench services</h2>
<p>Flat-rate diagnostics of $28, credited to the job if you approve the estimate.</p>
</header>
<div class="grid-4">
<article class="card svc">
<div class="svc-ill" aria-hidden="true"><span class="cap c1"></span><span class="cap c2"></span><span class="cap c3"></span><span class="pcb"></span></div>
<h3>Full recapping</h3>
<p>Every electrolytic swapped for 105°C low-ESR parts, board cleaned and re-flowed.</p>
<ul class="ticks mono"><li>ESR sweep before/after</li><li>Photo log of each board</li></ul>
<span class="chip mono">from $89</span>
</article>
<article class="card svc">
<div class="svc-ill" aria-hidden="true"><span class="tube"></span><span class="beam"></span></div>
<h3>Screen & tube repair</h3>
<p>Flyback rebuilds, yoke re-solder, convergence and geometry alignment on the jig.</p>
<ul class="ticks mono"><li>HV discharge, safe handling</li><li>Purity + white balance</li></ul>
<span class="chip mono">from $145</span>
</article>
<article class="card svc">
<div class="svc-ill" aria-hidden="true"><span class="shell-a"></span><span class="shell-b"></span></div>
<h3>Case restoration</h3>
<p>Crack welding, screw-boss repair, texture matching and screen-printed label reproduction.</p>
<ul class="ticks mono"><li>ABS-safe adhesives</li><li>Satin clear top-coat</li></ul>
<span class="chip mono">from $64</span>
</article>
<article class="card svc">
<div class="svc-ill" aria-hidden="true"><span class="bath"></span><span class="bubble b1"></span><span class="bubble b2"></span><span class="bubble b3"></span></div>
<h3>Retrobrighting</h3>
<p>Peroxide-cream bath under controlled UV, colour-metered against the original chip.</p>
<ul class="ticks mono"><li>Batch-matched panels</li><li>No-yellowing 12mo check</li></ul>
<span class="chip mono">from $42</span>
</article>
</div>
</div>
</section>
<!-- GALLERY -->
<section id="gallery" class="section section-dark">
<div class="wrap">
<header class="sec-head sec-head-dark">
<h2>Restoration gallery</h2>
<p>Hover or focus a card to crossfade from the intake photo to the finished unit.</p>
</header>
<div class="filters" role="group" aria-label="Filter gallery by platform">
<button class="pill is-on mono" data-filter="all" aria-pressed="true">All</button>
<button class="pill mono" data-filter="console" aria-pressed="false">Consoles</button>
<button class="pill mono" data-filter="radio" aria-pressed="false">Radios</button>
<button class="pill mono" data-filter="computer" aria-pressed="false">Computers</button>
<button class="pill mono" data-filter="handheld" aria-pressed="false">Handhelds</button>
</div>
<div class="grid-3" id="galleryGrid">
<article class="ba" data-kind="console" tabindex="0" aria-label="Vectra 64 console before and after restoration">
<div class="ba-stage">
<div class="ill ill-console yellowed" aria-hidden="true"><span class="slot"></span><span class="led"></span><span class="ridge"></span></div>
<div class="ill ill-console restored" aria-hidden="true"><span class="slot"></span><span class="led"></span><span class="ridge"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Vectra 64</h3>
<p class="mono meta">1983 · recap + retrobright · 9 days</p>
</div>
</article>
<article class="ba" data-kind="radio" tabindex="0" aria-label="Marlow TR-8 radio before and after restoration">
<div class="ba-stage">
<div class="ill ill-radio yellowed" aria-hidden="true"><span class="dial"></span><span class="grille"></span><span class="needle"></span></div>
<div class="ill ill-radio restored" aria-hidden="true"><span class="dial"></span><span class="grille"></span><span class="needle"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Marlow TR‑8</h3>
<p class="mono meta">1968 · recap + dial cord · 6 days</p>
</div>
</article>
<article class="ba" data-kind="computer" tabindex="0" aria-label="Halcyon 128K computer before and after restoration">
<div class="ba-stage">
<div class="ill ill-computer yellowed" aria-hidden="true"><span class="keys"></span><span class="badge"></span></div>
<div class="ill ill-computer restored" aria-hidden="true"><span class="keys"></span><span class="badge"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Halcyon 128K</h3>
<p class="mono meta">1985 · PSU rebuild + keycaps · 14 days</p>
</div>
</article>
<article class="ba" data-kind="handheld" tabindex="0" aria-label="Pocket Nova handheld before and after restoration">
<div class="ba-stage">
<div class="ill ill-handheld yellowed" aria-hidden="true"><span class="lcd"></span><span class="dpad"></span><span class="ab"></span></div>
<div class="ill ill-handheld restored" aria-hidden="true"><span class="lcd"></span><span class="dpad"></span><span class="ab"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Pocket Nova</h3>
<p class="mono meta">1990 · screen swap + shell · 5 days</p>
</div>
</article>
<article class="ba" data-kind="console" tabindex="0" aria-label="Astro Duel 2600 console before and after restoration">
<div class="ba-stage">
<div class="ill ill-console alt yellowed" aria-hidden="true"><span class="slot"></span><span class="led"></span><span class="ridge"></span></div>
<div class="ill ill-console alt restored" aria-hidden="true"><span class="slot"></span><span class="led"></span><span class="ridge"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Astro Duel 2600</h3>
<p class="mono meta">1979 · RF mod + woodgrain · 8 days</p>
</div>
</article>
<article class="ba" data-kind="radio" tabindex="0" aria-label="Beacon Cathedral radio before and after restoration">
<div class="ba-stage">
<div class="ill ill-radio alt yellowed" aria-hidden="true"><span class="dial"></span><span class="grille"></span><span class="needle"></span></div>
<div class="ill ill-radio alt restored" aria-hidden="true"><span class="dial"></span><span class="grille"></span><span class="needle"></span></div>
<span class="ba-tag mono">before / after</span>
</div>
<div class="ba-body">
<h3>Beacon Cathedral</h3>
<p class="mono meta">1947 · re-veneer + rewire · 21 days</p>
</div>
</article>
</div>
<p class="empty mono" id="galleryEmpty" hidden>No units on the bench for that platform.</p>
</div>
</section>
<!-- RECAP KIT -->
<section id="kit" class="section">
<div class="wrap kit-grid">
<article class="card kit">
<header class="kit-head">
<div>
<h2>Recap kit — Vectra 64 mainboard</h2>
<p class="mono">SKU CRK‑0642 · rev C/D boards</p>
</div>
<span class="chip chip-green mono">in stock</span>
</header>
<div class="table-scroll">
<table class="mono kit-table">
<caption class="sr-only">Capacitor values included in the Vectra 64 recap kit</caption>
<thead>
<tr><th scope="col">Ref</th><th scope="col">Value</th><th scope="col">V</th><th scope="col">Type</th><th scope="col" class="num">Qty</th></tr>
</thead>
<tbody>
<tr><td>C1–C4</td><td>1000µF</td><td>16</td><td>low‑ESR radial</td><td class="num">4</td></tr>
<tr><td>C7</td><td>470µF</td><td>25</td><td>low‑ESR radial</td><td class="num">1</td></tr>
<tr><td>C11–C14</td><td>100µF</td><td>16</td><td>radial 105°C</td><td class="num">4</td></tr>
<tr><td>C19–C26</td><td>22µF</td><td>25</td><td>radial 105°C</td><td class="num">8</td></tr>
<tr><td>C31</td><td>10µF</td><td>50</td><td>bipolar</td><td class="num">1</td></tr>
<tr><td>C40–C43</td><td>4.7µF</td><td>50</td><td>radial 105°C</td><td class="num">4</td></tr>
</tbody>
<tfoot>
<tr><th scope="row" colspan="4">Total pieces</th><td class="num">22</td></tr>
</tfoot>
</table>
</div>
<p class="note mono">Total bulk ESR at 100 kHz measures 0.34 Ω — roughly a fifth of the tired
originals we pull (typ. 1.6–2.1 Ω). Discharge the PSU rail before you touch anything.</p>
<div class="kit-foot">
<span class="price mono">$34.<small>50</small></span>
<button class="btn btn-amber" id="addKit" type="button">Add kit to quote</button>
</div>
</article>
<aside class="card bench-note">
<h3>What ships in the envelope</h3>
<ul class="ticks ticks-lg">
<li>22 matched capacitors, bagged by value</li>
<li>Printed board map with polarity marks</li>
<li>Two lengths of 1 mm leaded solder</li>
<li>Desoldering braid, 2 mm × 1.5 m</li>
<li>Signed QC card from bench 4</li>
</ul>
<div class="meter" role="img" aria-label="Kit difficulty: 2 of 5, beginner friendly">
<span class="mono">difficulty</span>
<span class="bars"><i class="on"></i><i class="on"></i><i></i><i></i><i></i></span>
<span class="mono dim">2 / 5</span>
</div>
</aside>
</div>
</section>
<!-- REPAIR LOG -->
<section id="log" class="section section-dark">
<div class="wrap">
<header class="sec-head sec-head-dark">
<h2>Repair log — Halcyon 128K, job #4471</h2>
<p>Fourteen days on the bench, logged entry by entry.</p>
</header>
<ol class="timeline">
<li>
<span class="tl-ill" aria-hidden="true"><span class="dot-ill box"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-02">02 JUN</time>
<h3>Intake & triage</h3>
<p>Arrived dead. Shell heavily yellowed, one broken screw boss. No smoke smell — good sign.</p>
</div>
</li>
<li>
<span class="tl-ill" aria-hidden="true"><span class="dot-ill wave"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-04">04 JUN</time>
<h3>PSU on the scope</h3>
<p>5 V rail sagging to 4.1 V under load with 400 mV of ripple. Bulk cap reading 3.1 Ω ESR.</p>
</div>
</li>
<li>
<span class="tl-ill" aria-hidden="true"><span class="dot-ill cap"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-07">07 JUN</time>
<h3>Full recap</h3>
<p>31 electrolytics replaced, board washed and dried. Rail now 5.02 V, ripple under 25 mV.</p>
</div>
</li>
<li>
<span class="tl-ill" aria-hidden="true"><span class="dot-ill key"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-10">10 JUN</time>
<h3>Keyboard membrane</h3>
<p>Traces reprinted with conductive ink, three keycaps recast in matched beige resin.</p>
</div>
</li>
<li>
<span class="tl-ill" aria-hidden="true"><span class="dot-ill sun"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-13">13 JUN</time>
<h3>Retrobright bath</h3>
<p>Nine hours under UV, rotated hourly. Colour metered within two shades of the untouched battery door.</p>
</div>
</li>
<li class="done">
<span class="tl-ill" aria-hidden="true"><span class="dot-ill tick"></span></span>
<div class="tl-body">
<time class="mono" datetime="2026-06-16">16 JUN</time>
<h3>Burn-in passed — shipped</h3>
<p>48 hours continuous, no faults logged. Service card signed, unit boxed in cut foam.</p>
</div>
</li>
</ol>
</div>
</section>
<!-- QUOTE -->
<section id="quote" class="section quote-band">
<div class="wrap quote-in">
<div class="quote-copy">
<h2>Tell us what's gone quiet.</h2>
<p>We'll come back within two business days with a bench estimate, a parts list and a slot date.
Shipping crates available on request.</p>
</div>
<form class="quote-form card" id="quoteForm" novalidate>
<div class="field">
<label for="qName">Your name</label>
<input id="qName" name="name" type="text" autocomplete="name" placeholder="Dana Kowalczyk" required />
</div>
<div class="field">
<label for="qEmail">Email</label>
<input id="qEmail" name="email" type="email" autocomplete="email" placeholder="[email protected]" required />
</div>
<div class="field">
<label for="qDevice">Device</label>
<select id="qDevice" name="device">
<option value="Vectra 64 console">Vectra 64 console</option>
<option value="Astro Duel 2600">Astro Duel 2600</option>
<option value="Halcyon 128K computer">Halcyon 128K computer</option>
<option value="Marlow TR-8 radio">Marlow TR‑8 radio</option>
<option value="Beacon Cathedral radio">Beacon Cathedral radio</option>
<option value="Pocket Nova handheld">Pocket Nova handheld</option>
<option value="Something else entirely">Something else entirely</option>
</select>
</div>
<div class="field">
<label for="qFault">What it does now</label>
<textarea id="qFault" name="fault" rows="3" placeholder="Powers on, screen stays black, faint whine from the PSU."></textarea>
</div>
<p class="err mono" id="qErr" role="alert" hidden></p>
<button class="btn btn-amber btn-block" type="submit">Send to bench 4</button>
<p class="fine mono">No deposit until you approve the estimate.</p>
</form>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap foot-in">
<div>
<p class="foot-brand">Cathode Revival</p>
<p class="foot-note">Unit 12, Sparrow Works · Fictional demo shop · Bench hours 09:00–18:00</p>
</div>
<div class="clock" aria-label="Bench clock">
<span class="seg mono" id="clock">00:00:00</span>
<span class="clock-cap mono">BENCH TIME</span>
</div>
</div>
</footer>
<div class="toast-host" id="toastHost" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Retro Electronics Restoration Landing
A full marketing page for Cathode Revival, a fictional shop that recaps, rebuilds and retrobrights old consoles, radios and 8-bit computers. The whole thing is dressed as workshop hardware: aged beige plastic, bakelite brown, phosphor green readouts on near-black screens and a warm amber dial glow. Every illustration on the page — capacitors, tubes, cartridges, dial needles, handheld d-pads — is drawn with CSS boxes and gradients, so there is not one image request in the document.
The hero is a beveled CRT set. On load, a boot sequence types itself into the screen character by
character in phosphor green, finishing with a blinking block cursor. The chunky power knob beside
it is a real role="switch" button: click it and the picture collapses into a horizontal line,
then a point, exactly the way a tube discharges; click again and it ignites back and re-types the
boot text. Scanline and vignette layers sit above the content the whole time.
Further down, service cards carry beveled edges and price-from chips; the gallery crossfades each unit from a yellowed intake state to a restored one on hover or keyboard focus, and platform chips filter it live with a toast count. A recap-kit card lists real capacitor values, voltages and quantities in a monospaced table with a bulk-ESR note, the repair log walks a fourteen-day job entry by entry, and the quote band validates a name and email before opening a ticket number. The footer keeps a live seven-segment bench clock.
How this look is built
The CRT effect is layered entirely in CSS: repeating-linear-gradient gives the scanlines (blended
with mix-blend-mode: multiply so it darkens the phosphor instead of washing it out), a
radial-gradient overlay supplies the vignette, and the collapse is one absolutely positioned
sheet animating transform: scaleY() then scaleX() toward zero — compositor-only properties, so
it stays smooth without touching layout. The yellowed/restored gallery swap is just two stacked
illustrations whose shared --case / --face custom properties are redefined per state, so a
single opacity crossfade repaints both palettes at once instead of duplicating markup. Watch two
things: the collapse animation must be restarted by removing the class and forcing a reflow
(void el.offsetWidth) or a second toggle silently does nothing, and every continuous animation —
bubbles, cursor blink, collapse — is neutralised under prefers-reduced-motion, where the boot text
is printed instantly rather than typed.
Illustrative UI only — always follow real safety guidance when working with tools, electronics, or repairs.