DIY — Electronics Shop & Learn Landing
A dark, playful landing page for SOLDERBOX, a fictional electronics shop and learning hub. It pairs a rotating announcement bar, sticky header with live cart counter, and a horizontal new-arrivals scroller of white product plates holding hand-drawn SVG component art with a weekly live-show promo, a running countdown, newsletter capture, a filterable Learn library of guide cards with difficulty badges and author chips, and a best-sellers grid whose quick-view modal lists specifications in monospace.
MCP
Code
/* ── SOLDERBOX — electronics shop & learn landing ─────────────────── */
:root{
--bg:#101418;
--surface:#1a2028;
--surface-2:#222a34;
--line:rgba(238,242,246,0.12);
--line-2:rgba(238,242,246,0.22);
--blue:#2b8cff;
--blue-d:#1a6fd6;
--magenta:#ff3d81;
--lime:#b8ff3d;
--amber:#ffd66b;
--text:#eef2f6;
--muted:#9aa7b4;
--muted-2:#c2ccd6;
--white:#ffffff;
--ok:#7ee0c6;
--warn:#ffd66b;
--r-sm:6px; --r-md:12px; --r-lg:18px;
--sh-1:0 2px 10px rgba(0,0,0,.35);
--sh-2:0 14px 40px rgba(0,0,0,.5);
--grid:rgba(43,140,255,0.09);
--grid-major:rgba(43,140,255,0.16);
}
*,*::before,*::after{box-sizing:border-box}
/* Keeps [hidden] winning over class rules that set a display value. */
[hidden]{display:none!important}
html{scroll-behavior:smooth}
body{
margin:0;
font-family:Inter,system-ui,sans-serif;
line-height:1.5;
color:var(--text);
background:var(--bg);
-webkit-font-smoothing:antialiased;
text-rendering:optimizeLegibility;
}
h1,h2,h3{margin:0;line-height:1.15;letter-spacing:-0.02em}
p{margin:0}
ul{margin:0;padding:0;list-style:none}
a{color:inherit;text-decoration:none}
.sprite{position:absolute;width:0;height:0;overflow:hidden}
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.mono{font-family:"JetBrains Mono",ui-monospace,monospace}
.wrap{width:min(1200px,100% - 40px);margin-inline:auto}
:focus-visible{outline:3px solid var(--lime);outline-offset:2px;border-radius:4px}
/* ── announcement ─────────────────────────────────────────────────── */
.announce{
display:flex;align-items:center;justify-content:center;gap:6px;
background:linear-gradient(90deg,var(--magenta),#c8258f 55%,var(--blue));
color:#fff;padding:7px 12px;font-size:.82rem;font-weight:600;
}
.announce__msg{text-align:center;max-width:70ch;transition:opacity .25s ease}
.announce__msg.is-fade{opacity:0}
.announce__nav{
background:rgba(255,255,255,.16);border:0;color:#fff;cursor:pointer;
width:22px;height:22px;border-radius:50%;font-size:1rem;line-height:1;
display:grid;place-items:center;flex:none;
}
.announce__nav:hover{background:rgba(255,255,255,.32)}
/* ── header ───────────────────────────────────────────────────────── */
.hdr{
position:sticky;top:0;z-index:40;
background:rgba(16,20,24,.86);
backdrop-filter:blur(12px);
border-bottom:1px solid var(--line);
transition:box-shadow .2s ease,background .2s ease;
}
.hdr.is-stuck{box-shadow:0 8px 28px rgba(0,0,0,.5);background:rgba(16,20,24,.96)}
.hdr__in{display:flex;align-items:center;gap:18px;padding:12px 0}
.brand{display:flex;align-items:center;gap:10px;flex:none}
.brand__mark{display:grid;place-items:center;filter:drop-shadow(0 0 12px rgba(43,140,255,.45))}
.brand__txt{font-weight:800;font-size:1.18rem;letter-spacing:-0.04em}
.brand__txt em{font-style:normal;color:var(--magenta)}
.search{flex:1;display:flex;min-width:0}
.search input{
flex:1;min-width:0;font:inherit;font-size:.9rem;color:var(--text);
background:var(--surface);border:1px solid var(--line);border-right:0;
padding:10px 14px;border-radius:var(--r-md) 0 0 var(--r-md);
}
.search input::placeholder{color:var(--muted)}
.search input:focus{outline:none;border-color:var(--blue);box-shadow:inset 0 0 0 1px var(--blue)}
.search__go{
font:inherit;font-weight:700;font-size:.86rem;cursor:pointer;color:#04121f;
background:var(--lime);border:0;padding:10px 18px;border-radius:0 var(--r-md) var(--r-md) 0;
}
.search__go:hover{background:#a4ef22}
.hdr__acts{display:flex;gap:8px;flex:none}
.icobtn{
display:flex;align-items:center;gap:7px;font:inherit;font-size:.84rem;font-weight:600;
color:var(--text);background:var(--surface);border:1px solid var(--line);
padding:9px 13px;border-radius:var(--r-md);cursor:pointer;transition:.16s ease;
}
.icobtn:hover{border-color:var(--blue);background:var(--surface-2);transform:translateY(-1px)}
.icobtn--cart{position:relative;padding-right:34px}
.cartCount{
position:absolute;right:7px;top:50%;transform:translateY(-50%);
min-width:20px;height:20px;padding:0 5px;border-radius:10px;
background:var(--magenta);color:#fff;font-size:.72rem;font-weight:700;
display:grid;place-items:center;font-family:"JetBrains Mono",monospace;
}
.cartCount.is-bump{animation:bump .45s cubic-bezier(.3,1.6,.5,1)}
@keyframes bump{0%{transform:translateY(-50%) scale(1)}40%{transform:translateY(-50%) scale(1.45)}100%{transform:translateY(-50%) scale(1)}}
/* ── buttons ──────────────────────────────────────────────────────── */
.btn{
font:inherit;font-weight:700;font-size:.88rem;cursor:pointer;border:1px solid transparent;
padding:11px 20px;border-radius:var(--r-md);transition:.16s ease;display:inline-block;
}
.btn--pri{background:var(--blue);color:#fff;box-shadow:0 6px 18px rgba(43,140,255,.3)}
.btn--pri:hover{background:var(--blue-d);transform:translateY(-1px)}
.btn--acc{background:var(--magenta);color:#fff;box-shadow:0 6px 18px rgba(255,61,129,.3)}
.btn--acc:hover{background:#e42a6c;transform:translateY(-1px)}
.btn--acc.is-on{background:var(--lime);color:#04121f;box-shadow:none}
.btn--ghost{background:transparent;color:var(--text);border-color:var(--line-2)}
.btn--ghost:hover{border-color:var(--lime);color:var(--lime)}
.btn--sm{padding:8px 12px;font-size:.8rem}
.btn:active{transform:translateY(1px)}
.btn--add{
width:100%;background:var(--surface-2);color:var(--text);border-color:var(--line-2);
padding:9px 14px;font-size:.82rem;
}
.btn--add:hover{background:var(--lime);color:#04121f;border-color:var(--lime)}
.pact .btn--add{width:auto;flex:1}
/* ── hero ─────────────────────────────────────────────────────────── */
.hero{
position:relative;padding:56px 0 60px;
background:
linear-gradient(180deg,#141a21 0%,var(--bg) 78%),
repeating-linear-gradient(0deg,var(--grid) 0 1px,transparent 1px 8px),
repeating-linear-gradient(90deg,var(--grid) 0 1px,transparent 1px 8px),
repeating-linear-gradient(0deg,var(--grid-major) 0 1px,transparent 1px 80px),
repeating-linear-gradient(90deg,var(--grid-major) 0 1px,transparent 1px 80px);
background-blend-mode:normal;
}
.hero::after{
content:"";position:absolute;inset:0;pointer-events:none;
background:radial-gradient(700px 320px at 12% 0%,rgba(43,140,255,.22),transparent 70%),
radial-gradient(500px 280px at 92% 18%,rgba(255,61,129,.16),transparent 72%);
}
.hero>*{position:relative;z-index:1}
.hero__head{display:grid;grid-template-columns:1.5fr .8fr;gap:44px;align-items:end;margin-bottom:52px}
.kicker{
font-family:"JetBrains Mono",monospace;font-size:.74rem;font-weight:700;
letter-spacing:.14em;text-transform:uppercase;color:var(--lime);
display:inline-block;margin-bottom:14px;
}
h1{font-size:clamp(2.1rem,5vw,3.5rem);font-weight:800}
.hl{
background:linear-gradient(90deg,var(--blue),var(--magenta));
-webkit-background-clip:text;background-clip:text;color:transparent;
}
.lede{color:var(--muted-2);max-width:56ch;margin-top:18px;font-size:1.02rem}
.hero__cta{display:flex;gap:12px;margin-top:26px;flex-wrap:wrap}
.hero__stats{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.hero__stats li{
background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
padding:14px 16px;
}
.hero__stats b{display:block;font-family:"JetBrains Mono",monospace;font-size:1.4rem;color:var(--blue)}
.hero__stats li:nth-child(2) b{color:var(--magenta)}
.hero__stats li:nth-child(3) b{color:var(--lime)}
.hero__stats li:nth-child(4) b{color:var(--amber)}
.hero__stats span{font-size:.78rem;color:var(--muted)}
/* ── product rail ─────────────────────────────────────────────────── */
.strip__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px;gap:16px}
.strip__head h2{font-size:1.5rem}
.strip__nav{display:flex;gap:8px}
.rnd{
width:38px;height:38px;border-radius:50%;cursor:pointer;font-size:1.2rem;line-height:1;
background:var(--surface);border:1px solid var(--line-2);color:var(--text);
display:grid;place-items:center;transition:.16s ease;
}
.rnd:hover{background:var(--blue);border-color:var(--blue);color:#fff}
.rail{
display:grid;grid-auto-flow:column;grid-auto-columns:minmax(232px,1fr);gap:16px;
overflow-x:auto;scroll-snap-type:x mandatory;padding:4px 4px 16px;
scrollbar-width:thin;scrollbar-color:var(--surface-2) transparent;
}
.rail::-webkit-scrollbar{height:8px}
.rail::-webkit-scrollbar-thumb{background:var(--surface-2);border-radius:8px}
.rail>.pcard{scroll-snap-align:start}
.pcard{
background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
padding:14px;display:flex;flex-direction:column;gap:8px;
transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease;
}
.pcard:hover{transform:translateY(-4px);border-color:var(--blue);box-shadow:var(--sh-2)}
.plate{
position:relative;background:var(--white);border-radius:var(--r-md);
display:grid;place-items:center;padding:14px;aspect-ratio:4/3;overflow:hidden;
}
.plate::after{
content:"";position:absolute;inset:0;
background:radial-gradient(120px 70px at 50% 115%,rgba(16,20,24,.1),transparent 70%);
}
.art{width:100%;height:100%;max-height:120px;display:block}
.art--sm{max-height:64px}
.badge{
position:absolute;top:8px;left:8px;z-index:2;
font-family:"JetBrains Mono",monospace;font-size:.66rem;font-weight:700;
letter-spacing:.06em;text-transform:uppercase;
background:#101418;color:#fff;padding:3px 8px;border-radius:var(--r-sm);
}
.badge--new{background:var(--blue)}
.badge--hot{background:var(--magenta)}
.rank{
position:absolute;top:8px;right:8px;z-index:2;
font-family:"JetBrains Mono",monospace;font-size:.72rem;font-weight:700;
background:#101418;color:var(--lime);padding:3px 8px;border-radius:var(--r-sm);
}
.pcard h3{font-size:.96rem;font-weight:700}
.pmeta{font-family:"JetBrains Mono",monospace;font-size:.72rem;color:var(--muted)}
.prow{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto}
.price{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:1.02rem;color:var(--lime)}
.price--lg{font-size:1.6rem;display:block;margin:6px 0 14px}
.stock{font-size:.72rem;font-weight:600;padding:2px 8px;border-radius:20px}
.stock.ok{color:var(--ok);background:rgba(126,224,198,.12)}
.stock.low{color:var(--warn);background:rgba(255,214,107,.14)}
.pact{display:flex;gap:8px}
/* ── categories ───────────────────────────────────────────────────── */
.cats{padding:44px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:#131920}
.sec__t{font-size:1.5rem;margin-bottom:6px}
.sec__s{color:var(--muted);font-size:.92rem;max-width:62ch}
.pills{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px}
.pill{
display:flex;align-items:center;gap:9px;font:inherit;font-size:.86rem;font-weight:600;
color:var(--text);background:var(--surface);border:1px solid var(--line);
padding:9px 16px 9px 9px;border-radius:40px;cursor:pointer;transition:.16s ease;
}
.pill:hover{transform:translateY(-2px);border-color:var(--c,var(--blue))}
.pill__i{
width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
background:color-mix(in srgb,var(--c) 22%,transparent);color:var(--c);font-size:.9rem;
}
/* ── band: show + newsletter ──────────────────────────────────────── */
.band{padding:56px 0}
.band__grid{display:grid;grid-template-columns:1.25fr 1fr;gap:20px}
.show,.news{border-radius:var(--r-lg);padding:28px;border:1px solid var(--line)}
.show{
position:relative;overflow:hidden;
background:
linear-gradient(135deg,rgba(255,61,129,.2),rgba(43,140,255,.16)),
var(--surface);
}
.show::before{
content:"";position:absolute;inset:0;pointer-events:none;
background:repeating-linear-gradient(90deg,rgba(238,242,246,.05) 0 1px,transparent 1px 14px);
}
.show>*{position:relative}
.show__tag{
display:inline-flex;align-items:center;gap:8px;font-family:"JetBrains Mono",monospace;
font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
color:var(--magenta);margin-bottom:12px;
}
.dot{width:8px;height:8px;border-radius:50%;background:var(--magenta);animation:pulse 1.6s infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(255,61,129,.6)}70%{box-shadow:0 0 0 8px rgba(255,61,129,0)}}
.show h2{font-size:1.9rem;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.ep{
font-family:"JetBrains Mono",monospace;font-size:.74rem;font-weight:700;
background:var(--lime);color:#04121f;padding:4px 9px;border-radius:var(--r-sm);letter-spacing:.04em;
}
.show p{color:var(--muted-2);margin-top:12px;max-width:52ch}
.count{display:grid;grid-template-columns:repeat(4,minmax(0,84px));gap:10px;margin:22px 0 12px}
.count div{background:rgba(16,20,24,.55);border:1px solid var(--line);border-radius:var(--r-md);padding:10px 6px;text-align:center}
.count b{display:block;font-family:"JetBrains Mono",monospace;font-size:1.5rem;color:var(--lime)}
.count span{font-size:.66rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted)}
.show__when{font-size:.82rem;color:var(--muted);margin-bottom:18px}
.news{background:var(--surface)}
.news h2{font-size:1.5rem}
.news p{color:var(--muted-2);margin-top:10px;font-size:.94rem}
.news__form{display:flex;gap:8px;margin-top:18px;flex-wrap:wrap}
.news__form input{
flex:1;min-width:160px;font:inherit;font-size:.9rem;color:var(--text);
background:var(--bg);border:1px solid var(--line-2);padding:11px 14px;border-radius:var(--r-md);
}
.news__form input::placeholder{color:var(--muted)}
.news__form input:focus{outline:none;border-color:var(--blue)}
.news__form input.is-bad{border-color:var(--magenta)}
.news__err{flex-basis:100%;color:var(--magenta);font-size:.8rem;font-weight:600}
.news__pts{margin-top:18px;display:grid;gap:8px}
.news__pts li{position:relative;padding-left:22px;font-size:.85rem;color:var(--muted)}
.news__pts li::before{content:"▸";position:absolute;left:0;color:var(--lime);font-weight:700}
/* ── learn ────────────────────────────────────────────────────────── */
.learn{padding:56px 0;background:#131920;border-top:1px solid var(--line)}
.sec__head{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;flex-wrap:wrap;margin-bottom:24px}
.filters{display:flex;gap:8px;flex-wrap:wrap}
.fbtn{
font:inherit;font-size:.82rem;font-weight:600;cursor:pointer;color:var(--muted-2);
background:var(--surface);border:1px solid var(--line);padding:8px 15px;border-radius:30px;transition:.16s ease;
}
.fbtn:hover{color:var(--text);border-color:var(--line-2)}
.fbtn.is-on{background:var(--blue);border-color:var(--blue);color:#fff}
.guides{display:grid;grid-template-columns:repeat(auto-fill,minmax(258px,1fr));gap:16px}
.guide{
background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
padding:16px;display:flex;flex-direction:column;gap:9px;
transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease,opacity .2s ease;
}
.guide:hover{transform:translateY(-4px);border-color:var(--lime);box-shadow:var(--sh-2)}
.guide.is-hidden{display:none}
.guide__top{background:var(--white);border-radius:var(--r-md);padding:12px;display:grid;place-items:center}
.diff{
align-self:flex-start;font-family:"JetBrains Mono",monospace;font-size:.66rem;font-weight:700;
letter-spacing:.06em;text-transform:uppercase;padding:3px 9px;border-radius:20px;
}
.diff--1{background:rgba(184,255,61,.16);color:var(--lime)}
.diff--2{background:rgba(43,140,255,.18);color:#7db4ff}
.diff--3{background:rgba(255,61,129,.18);color:#ff85ae}
.guide h3{font-size:1.02rem}
.guide p{font-size:.86rem;color:var(--muted);flex:1}
.guide__foot{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:10px;border-top:1px solid var(--line)}
.chip{display:flex;align-items:center;gap:7px;font-size:.78rem;font-weight:600;color:var(--muted-2)}
.chip i{
width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-style:normal;
font-family:"JetBrains Mono",monospace;font-size:.62rem;font-weight:700;
background:linear-gradient(135deg,var(--blue),var(--magenta));color:#fff;
}
.guide__foot .mono{font-size:.74rem;color:var(--muted)}
.guides__empty{margin-top:22px;color:var(--muted);text-align:center}
/* ── best sellers ─────────────────────────────────────────────────── */
.best{padding:56px 0}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:16px;margin-top:24px}
/* ── footer ───────────────────────────────────────────────────────── */
.ftr{background:#0b0e12;border-top:1px solid var(--line);padding:46px 0 26px;margin-top:12px}
.ftr__grid{display:grid;grid-template-columns:1.6fr repeat(3,1fr);gap:28px}
.ftr__brand p{color:var(--muted);font-size:.88rem;margin-top:10px;max-width:38ch}
.ftr__addr{font-size:.74rem;color:var(--muted);margin-top:12px}
.ftr h3{font-size:.78rem;text-transform:uppercase;letter-spacing:.12em;color:var(--lime);margin-bottom:12px}
.ftr li{margin-bottom:8px}
.ftr li a{font-size:.88rem;color:var(--muted);transition:color .14s ease}
.ftr li a:hover{color:var(--text)}
.ftr__end{
display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
margin-top:34px;padding-top:18px;border-top:1px solid var(--line);
font-size:.78rem;color:var(--muted);
}
.ftr__sign{color:var(--magenta);font-weight:600}
/* ── modal ────────────────────────────────────────────────────────── */
.modal{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:20px}
.modal__scrim{position:absolute;inset:0;background:rgba(5,8,11,.76);backdrop-filter:blur(3px);animation:fade .18s ease}
@keyframes fade{from{opacity:0}to{opacity:1}}
.modal__box{
position:relative;width:min(760px,100%);max-height:88vh;overflow:auto;
background:var(--surface);border:1px solid var(--line-2);border-radius:var(--r-lg);
box-shadow:var(--sh-2);display:grid;grid-template-columns:.85fr 1fr;
animation:pop .2s cubic-bezier(.2,1.3,.5,1);
}
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
.modal__x{
position:absolute;top:10px;right:12px;z-index:3;width:32px;height:32px;border-radius:50%;
background:rgba(16,20,24,.7);border:1px solid var(--line);color:var(--text);
font-size:1.3rem;line-height:1;cursor:pointer;
}
.modal__x:hover{background:var(--magenta);border-color:var(--magenta);color:#fff}
.modal__art{background:var(--white);display:grid;place-items:center;padding:26px;border-radius:var(--r-lg) 0 0 var(--r-lg)}
.modal__art .art{max-height:210px}
.modal__body{padding:26px}
.mSku{font-size:.74rem;color:var(--muted);letter-spacing:.06em}
.modal__body h3{font-size:1.35rem;margin-top:4px}
.specs{margin:0 0 18px;display:grid;grid-template-columns:auto 1fr;gap:8px 16px;font-family:"JetBrains Mono",monospace;font-size:.78rem}
.specs dt{color:var(--muted);white-space:nowrap}
.specs dd{margin:0;color:var(--text)}
/* ── toasts ───────────────────────────────────────────────────────── */
.toasts{position:fixed;right:16px;bottom:16px;z-index:90;display:grid;gap:8px;justify-items:end}
.toast{
background:var(--surface-2);border:1px solid var(--line-2);border-left:3px solid var(--lime);
color:var(--text);padding:11px 16px;border-radius:var(--r-md);font-size:.85rem;font-weight:600;
box-shadow:var(--sh-2);max-width:320px;animation:slide .22s ease;
}
@keyframes slide{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:none}}
.toast.is-out{opacity:0;transform:translateX(20px);transition:.25s ease}
/* ── reveal ───────────────────────────────────────────────────────── */
.reveal{opacity:0;transform:translateY(16px)}
.reveal.is-in{opacity:1;transform:none;transition:opacity .5s ease,transform .5s ease}
/* ── responsive ───────────────────────────────────────────────────── */
@media (max-width:980px){
.hero__head{grid-template-columns:1fr;align-items:start;gap:28px}
.hero__stats{grid-template-columns:repeat(4,1fr)}
.band__grid{grid-template-columns:1fr}
.ftr__grid{grid-template-columns:1fr 1fr}
.modal__box{grid-template-columns:1fr}
.modal__art{border-radius:var(--r-lg) var(--r-lg) 0 0}
}
@media (max-width:760px){
.hdr__in{flex-wrap:wrap}
.search{order:3;flex-basis:100%}
.icobtn__t{display:none}
.icobtn--cart{padding-right:30px}
}
@media (max-width:520px){
.wrap{width:min(1200px,100% - 24px)}
.announce{font-size:.74rem;padding:6px 8px}
.hero{padding:34px 0 40px}
h1{font-size:1.9rem}
.lede{font-size:.94rem}
.hero__stats{grid-template-columns:1fr 1fr}
.hero__cta .btn{flex:1;text-align:center}
.rail{grid-auto-columns:minmax(198px,1fr)}
.show,.news{padding:20px}
.show h2{font-size:1.45rem}
.count{grid-template-columns:repeat(4,1fr)}
.count b{font-size:1.15rem}
.guides,.grid{grid-template-columns:1fr}
.ftr__grid{grid-template-columns:1fr}
.sec__head{align-items:flex-start}
.toasts{left:12px;right:12px;justify-items:stretch}
.toast{max-width:none}
}
@media (prefers-reduced-motion:reduce){
*,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
html{scroll-behavior:auto}
.reveal{opacity:1;transform:none}
}/* SOLDERBOX — electronics shop & learn landing. Vanilla JS only. */
(function () {
"use strict";
var $ = function (s, r) { return (r || document).querySelector(s); };
var $$ = function (s, r) { return Array.prototype.slice.call((r || document).querySelectorAll(s)); };
/* ── toast helper ─────────────────────────────────────────────── */
var toastHost = $("#toasts");
function toast(msg, accent) {
if (!toastHost) return;
var el = document.createElement("div");
el.className = "toast";
if (accent) el.style.borderLeftColor = accent;
el.textContent = msg;
toastHost.appendChild(el);
setTimeout(function () {
el.classList.add("is-out");
setTimeout(function () { el.remove(); }, 280);
}, 2600);
}
/* ── announcement rotator ─────────────────────────────────────── */
var ANN = [
"Free shipping on solder-shaped orders over $59 — continental orders only.",
"Tuesday restock lands 11:00 ET. Bins are full, coffee is not.",
"Every kit ships with a printed guide and a spare of the part you'll lose.",
"Bench Hours EP 214 streams Thursday 20:00 ET — bring bad wiring photos."
];
var annEl = $("#annMsg"), annIdx = 0, annTimer;
function showAnn(i) {
annIdx = (i + ANN.length) % ANN.length;
annEl.classList.add("is-fade");
setTimeout(function () {
annEl.textContent = ANN[annIdx];
annEl.classList.remove("is-fade");
}, 240);
}
function autoAnn() {
clearInterval(annTimer);
annTimer = setInterval(function () { showAnn(annIdx + 1); }, 5200);
}
$$("[data-ann]").forEach(function (b) {
b.addEventListener("click", function () {
showAnn(annIdx + parseInt(b.dataset.ann, 10));
autoAnn();
});
});
autoAnn();
/* ── sticky header shadow ─────────────────────────────────────── */
var hdr = $("#hdr");
window.addEventListener("scroll", function () {
hdr.classList.toggle("is-stuck", window.scrollY > 12);
}, { passive: true });
/* ── cart ─────────────────────────────────────────────────────── */
var count = 2;
var countEl = $("#cartCount");
function addToCart(name) {
count += 1;
countEl.textContent = String(count);
countEl.classList.remove("is-bump");
void countEl.offsetWidth;
countEl.classList.add("is-bump");
$("#cartBtn").setAttribute("aria-label", "Cart, " + count + " items");
toast("Added " + name + " to cart", "#2b8cff");
}
document.addEventListener("click", function (e) {
var add = e.target.closest("[data-add]");
if (add) { addToCart(add.dataset.add); return; }
var t = e.target.closest("[data-toast]");
if (t) toast(t.dataset.toast, "#ff3d81");
});
/* ── search ───────────────────────────────────────────────────── */
$("#searchForm").addEventListener("submit", function (e) {
e.preventDefault();
var q = $("#q").value.trim();
toast(q ? 'Searching parts & guides for "' + q + '"…' : "Type a part number or a topic to search.");
});
/* ── product rail scrolling ───────────────────────────────────── */
var rail = $("#rail");
$$("[data-scroll]").forEach(function (b) {
b.addEventListener("click", function () {
var card = rail.querySelector(".pcard");
var step = card ? card.getBoundingClientRect().width + 16 : 240;
rail.scrollBy({ left: step * 2 * parseInt(b.dataset.scroll, 10), behavior: "smooth" });
});
});
rail.addEventListener("keydown", function (e) {
if (e.key === "ArrowRight") { rail.scrollBy({ left: 240, behavior: "smooth" }); e.preventDefault(); }
if (e.key === "ArrowLeft") { rail.scrollBy({ left: -240, behavior: "smooth" }); e.preventDefault(); }
});
/* ── countdown to next Thursday 20:00 local ───────────────────── */
var pad = function (n) { return n < 10 ? "0" + n : String(n); };
function nextThursday() {
var d = new Date();
d.setHours(20, 0, 0, 0);
var delta = (4 - d.getDay() + 7) % 7; // 4 = Thursday
if (delta === 0 && Date.now() > d.getTime()) delta = 7;
d.setDate(d.getDate() + delta);
return d;
}
var target = nextThursday();
function tick() {
var ms = target - Date.now();
if (ms <= 0) { target = nextThursday(); ms = target - Date.now(); }
var s = Math.floor(ms / 1000);
$("#cd").textContent = pad(Math.floor(s / 86400));
$("#ch").textContent = pad(Math.floor(s / 3600) % 24);
$("#cm").textContent = pad(Math.floor(s / 60) % 60);
$("#cs").textContent = pad(s % 60);
}
tick();
setInterval(tick, 1000);
var notify = $("#notifyBtn");
notify.addEventListener("click", function () {
var on = notify.classList.toggle("is-on");
notify.textContent = on ? "Reminder set ✓" : "Notify me";
toast(on ? "We'll ping you 15 minutes before EP 214." : "Reminder removed.", on ? "#b8ff3d" : "#ff3d81");
});
/* ── newsletter ───────────────────────────────────────────────── */
var newsForm = $("#newsForm"), email = $("#email"), newsErr = $("#newsErr");
newsForm.addEventListener("submit", function (e) {
e.preventDefault();
var ok = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email.value.trim());
newsErr.hidden = ok;
email.classList.toggle("is-bad", !ok);
if (!ok) { email.focus(); return; }
toast("Subscribed — first Tuesday Bin lands next week.", "#b8ff3d");
newsForm.reset();
});
email.addEventListener("input", function () {
if (!newsErr.hidden) { newsErr.hidden = true; email.classList.remove("is-bad"); }
});
/* ── learn filters ────────────────────────────────────────────── */
var guides = $$(".guide"), empty = $("#guidesEmpty");
$$(".fbtn").forEach(function (btn) {
btn.addEventListener("click", function () {
$$(".fbtn").forEach(function (b) {
b.classList.toggle("is-on", b === btn);
b.setAttribute("aria-selected", b === btn ? "true" : "false");
});
var track = btn.dataset.track, shown = 0;
guides.forEach(function (g) {
var hit = track === "all" || g.dataset.track === track;
g.classList.toggle("is-hidden", !hit);
if (hit) shown++;
});
empty.hidden = shown > 0;
toast(shown + (shown === 1 ? " guide" : " guides") + " in " + btn.textContent.trim());
});
});
/* ── quick view modal ─────────────────────────────────────────── */
var modal = $("#modal"), mUse = $("#mUse"), lastFocus = null, current = "";
function openModal(card) {
lastFocus = document.activeElement;
current = card.dataset.name;
$("#mTitle").textContent = current;
$("#mSku").textContent = card.dataset.sku;
$("#mPrice").textContent = card.dataset.price;
var href = card.querySelector("use").getAttribute("href");
mUse.setAttribute("href", href);
var dl = $("#mSpecs");
dl.innerHTML = "";
card.dataset.specs.split(";").forEach(function (pair) {
var kv = pair.split("|");
var dt = document.createElement("dt"); dt.textContent = kv[0];
var dd = document.createElement("dd"); dd.textContent = kv[1];
dl.appendChild(dt); dl.appendChild(dd);
});
modal.hidden = false;
document.body.style.overflow = "hidden";
$(".modal__x").focus();
}
function closeModal() {
modal.hidden = true;
document.body.style.overflow = "";
if (lastFocus) lastFocus.focus();
}
document.addEventListener("click", function (e) {
var q = e.target.closest("[data-quick]");
if (q) { openModal(q.closest(".pcard")); return; }
if (e.target.closest("[data-close]")) closeModal();
});
$("#mAdd").addEventListener("click", function () { addToCart(current); closeModal(); });
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && !modal.hidden) closeModal();
if (e.key === "Tab" && !modal.hidden) {
var f = $$('button, [href], input', $(".modal__box"));
if (!f.length) return;
var first = f[0], last = f[f.length - 1];
if (e.shiftKey && document.activeElement === first) { last.focus(); e.preventDefault(); }
else if (!e.shiftKey && document.activeElement === last) { first.focus(); e.preventDefault(); }
}
});
/* ── scroll reveal ────────────────────────────────────────────── */
var targets = $$(".pcard, .guide, .show, .news, .hero__stats li");
if ("IntersectionObserver" in window) {
targets.forEach(function (el) { el.classList.add("reveal"); });
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (en, i) {
if (!en.isIntersecting) return;
var el = en.target;
setTimeout(function () { el.classList.add("is-in"); }, (i % 6) * 55);
io.unobserve(el);
});
}, { threshold: 0.12, rootMargin: "0px 0px -40px" });
targets.forEach(function (el) { io.observe(el); });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>SOLDERBOX — Parts & Guides for Makers</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>
<!-- ── SVG sprite: all "product photography" is drawn art ───────────── -->
<svg class="sprite" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">
<symbol id="art-board" viewBox="0 0 120 120">
<rect x="18" y="26" width="84" height="68" rx="6" fill="#1f7a52"/>
<rect x="18" y="26" width="84" height="68" rx="6" fill="none" stroke="#0f4a31" stroke-width="2"/>
<rect x="46" y="44" width="34" height="26" rx="3" fill="#12181f"/>
<text x="63" y="61" font-family="JetBrains Mono, monospace" font-size="9" fill="#b8ff3d" text-anchor="middle">SB32</text>
<g fill="#ffd66b">
<rect x="24" y="30" width="6" height="4" rx="1"/><rect x="34" y="30" width="6" height="4" rx="1"/>
<rect x="44" y="30" width="6" height="4" rx="1"/><rect x="54" y="30" width="6" height="4" rx="1"/>
<rect x="64" y="30" width="6" height="4" rx="1"/><rect x="74" y="30" width="6" height="4" rx="1"/>
<rect x="84" y="30" width="6" height="4" rx="1"/>
<rect x="24" y="86" width="6" height="4" rx="1"/><rect x="34" y="86" width="6" height="4" rx="1"/>
<rect x="44" y="86" width="6" height="4" rx="1"/><rect x="54" y="86" width="6" height="4" rx="1"/>
<rect x="64" y="86" width="6" height="4" rx="1"/><rect x="74" y="86" width="6" height="4" rx="1"/>
<rect x="84" y="86" width="6" height="4" rx="1"/>
</g>
<rect x="24" y="44" width="14" height="10" rx="2" fill="#0f4a31"/>
<rect x="24" y="60" width="14" height="10" rx="2" fill="#0f4a31"/>
<circle cx="92" cy="50" r="4" fill="#2b8cff"/>
<circle cx="92" cy="66" r="4" fill="#ff3d81"/>
</symbol>
<symbol id="art-display" viewBox="0 0 120 120">
<rect x="14" y="28" width="92" height="64" rx="5" fill="#12181f"/>
<rect x="20" y="34" width="80" height="52" rx="3" fill="#04121f"/>
<g fill="#2b8cff" opacity=".92">
<rect x="26" y="42" width="30" height="6" rx="2"/>
<rect x="26" y="54" width="52" height="4" rx="2"/>
<rect x="26" y="63" width="44" height="4" rx="2"/>
<rect x="26" y="72" width="24" height="4" rx="2"/>
</g>
<rect x="82" y="42" width="12" height="34" rx="3" fill="#ff3d81" opacity=".85"/>
<g fill="#ffd66b"><rect x="18" y="92" width="5" height="6" rx="1"/><rect x="28" y="92" width="5" height="6" rx="1"/><rect x="38" y="92" width="5" height="6" rx="1"/><rect x="48" y="92" width="5" height="6" rx="1"/></g>
</symbol>
<symbol id="art-neopix" viewBox="0 0 120 120">
<rect x="10" y="46" width="100" height="28" rx="8" fill="#12181f"/>
<circle cx="28" cy="60" r="9" fill="#ff3d81"/><circle cx="28" cy="60" r="4" fill="#fff" opacity=".7"/>
<circle cx="52" cy="60" r="9" fill="#b8ff3d"/><circle cx="52" cy="60" r="4" fill="#fff" opacity=".7"/>
<circle cx="76" cy="60" r="9" fill="#2b8cff"/><circle cx="76" cy="60" r="4" fill="#fff" opacity=".7"/>
<circle cx="98" cy="60" r="7" fill="#ffd66b"/>
<rect x="4" y="56" width="8" height="8" rx="2" fill="#6b7885"/>
</symbol>
<symbol id="art-sensor" viewBox="0 0 120 120">
<rect x="26" y="30" width="68" height="52" rx="6" fill="#2b3440"/>
<circle cx="60" cy="54" r="17" fill="#101418"/>
<circle cx="60" cy="54" r="11" fill="#2b8cff"/>
<circle cx="55" cy="49" r="4" fill="#eef2f6" opacity=".85"/>
<rect x="34" y="70" width="52" height="5" rx="2" fill="#b8ff3d" opacity=".8"/>
<g fill="#c9d3de"><rect x="32" y="84" width="5" height="12" rx="1"/><rect x="46" y="84" width="5" height="12" rx="1"/><rect x="60" y="84" width="5" height="12" rx="1"/><rect x="74" y="84" width="5" height="12" rx="1"/></g>
</symbol>
<symbol id="art-motor" viewBox="0 0 120 120">
<rect x="24" y="38" width="56" height="44" rx="8" fill="#4a5563"/>
<rect x="24" y="38" width="56" height="44" rx="8" fill="none" stroke="#2b3440" stroke-width="2"/>
<rect x="80" y="53" width="20" height="14" rx="3" fill="#c9d3de"/>
<circle cx="100" cy="60" r="10" fill="#ff3d81"/>
<circle cx="100" cy="60" r="4" fill="#101418"/>
<g stroke="#b8ff3d" stroke-width="3" stroke-linecap="round"><path d="M18 50h-12"/><path d="M18 70h-12"/></g>
<rect x="34" y="48" width="36" height="4" rx="2" fill="#2b3440"/>
<rect x="34" y="58" width="36" height="4" rx="2" fill="#2b3440"/>
</symbol>
<symbol id="art-iron" viewBox="0 0 120 120">
<rect x="20" y="52" width="54" height="16" rx="8" fill="#2b8cff"/>
<rect x="74" y="55" width="16" height="10" rx="3" fill="#c9d3de"/>
<path d="M90 60 L110 55 L110 65 Z" fill="#ff3d81"/>
<rect x="26" y="56" width="26" height="8" rx="4" fill="#101418" opacity=".35"/>
<path d="M20 60 q-12 0 -14 14" stroke="#101418" stroke-width="4" fill="none" stroke-linecap="round"/>
<circle cx="66" cy="60" r="3" fill="#b8ff3d"/>
</symbol>
<symbol id="art-kit" viewBox="0 0 120 120">
<rect x="16" y="34" width="88" height="58" rx="7" fill="#d9c7a7"/>
<rect x="16" y="34" width="88" height="14" rx="7" fill="#c2ad8a"/>
<rect x="16" y="34" width="88" height="58" rx="7" fill="none" stroke="#a8946f" stroke-width="2"/>
<rect x="52" y="28" width="16" height="14" rx="3" fill="#ff3d81"/>
<g fill="#2b8cff"><circle cx="38" cy="66" r="7"/><circle cx="60" cy="66" r="7"/><circle cx="82" cy="66" r="7"/></g>
<rect x="30" y="80" width="60" height="5" rx="2" fill="#101418" opacity=".25"/>
</symbol>
<symbol id="art-battery" viewBox="0 0 120 120">
<rect x="22" y="42" width="72" height="38" rx="6" fill="#101418"/>
<rect x="94" y="54" width="8" height="14" rx="2" fill="#c9d3de"/>
<rect x="30" y="50" width="42" height="22" rx="3" fill="#b8ff3d"/>
<text x="51" y="66" font-family="JetBrains Mono, monospace" font-size="11" font-weight="700" fill="#101418" text-anchor="middle">3.7V</text>
<circle cx="82" cy="61" r="5" fill="#ff3d81"/>
</symbol>
</svg>
<!-- ── announcement bar ─────────────────────────────────────────────── -->
<div class="announce" role="region" aria-label="Store announcements">
<button class="announce__nav" type="button" data-ann="-1" aria-label="Previous announcement">‹</button>
<p class="announce__msg" id="annMsg" aria-live="polite">Free shipping on solder-shaped orders over $59 — continental orders only.</p>
<button class="announce__nav" type="button" data-ann="1" aria-label="Next announcement">›</button>
</div>
<!-- ── header ──────────────────────────────────────────────────────── -->
<header class="hdr" id="hdr">
<div class="wrap hdr__in">
<a class="brand" href="#top" aria-label="SOLDERBOX home">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 40 40" width="34" height="34">
<rect x="3" y="8" width="34" height="24" rx="6" fill="#2b8cff"/>
<rect x="9" y="14" width="22" height="12" rx="3" fill="#101418"/>
<circle cx="15" cy="20" r="2.6" fill="#ff3d81"/>
<circle cx="25" cy="20" r="2.6" fill="#b8ff3d"/>
<path d="M3 20 H-1 M41 20 H37" stroke="#b8ff3d" stroke-width="3"/>
</svg>
</span>
<span class="brand__txt">SOLDER<em>BOX</em></span>
</a>
<form class="search" role="search" id="searchForm">
<label class="sr-only" for="q">Search parts and guides</label>
<input id="q" name="q" type="search" placeholder="Search 4,120 parts & 380 guides…" autocomplete="off" />
<button class="search__go" type="submit">Search</button>
</form>
<div class="hdr__acts">
<button class="icobtn" type="button" data-toast="Account panel is illustrative in this demo.">
<span aria-hidden="true">◍</span> <span class="icobtn__t">Account</span>
</button>
<button class="icobtn icobtn--cart" type="button" id="cartBtn" aria-label="Cart, 2 items">
<span aria-hidden="true">▣</span> <span class="icobtn__t">Cart</span>
<span class="cartCount" id="cartCount">2</span>
</button>
</div>
</div>
</header>
<main id="top">
<!-- ── hero / new this week ──────────────────────────────────────── -->
<section class="hero">
<div class="wrap">
<div class="hero__head">
<div>
<span class="kicker">Restocked every Tuesday, 11:00 ET</span>
<h1>Parts that arrive fast.<br /><span class="hl">Guides that actually finish.</span></h1>
<p class="lede">SOLDERBOX ships breakout boards, sensors and kits from a small warehouse full of very organized bins — and every part comes with a written guide, wiring diagram and code you can paste.</p>
<div class="hero__cta">
<a class="btn btn--pri" href="#best">Shop best sellers</a>
<a class="btn btn--ghost" href="#learn">Browse the Learn library</a>
</div>
</div>
<ul class="hero__stats">
<li><b>4,120</b><span>parts in stock</span></li>
<li><b>380</b><span>free guides</span></li>
<li><b>24h</b><span>median dispatch</span></li>
<li><b>1.2M</b><span>boards shipped</span></li>
</ul>
</div>
<div class="strip">
<div class="strip__head">
<h2>New this week</h2>
<div class="strip__nav">
<button class="rnd" type="button" data-scroll="-1" aria-label="Scroll products left">‹</button>
<button class="rnd" type="button" data-scroll="1" aria-label="Scroll products right">›</button>
</div>
</div>
<ul class="rail" id="rail" tabindex="0" aria-label="New products, horizontally scrollable">
<li class="pcard" data-sku="SB-4410">
<div class="plate"><svg class="art"><use href="#art-board"/></svg><span class="badge badge--new">New</span></div>
<h3>Pocket32 Wi-Fi Dev Board</h3>
<p class="pmeta">SB-4410 · dual-core · USB-C</p>
<div class="prow"><span class="price">$18.50</span><span class="stock ok">In stock</span></div>
<button class="btn btn--add" type="button" data-add="Pocket32 Wi-Fi Dev Board">Add to cart</button>
</li>
<li class="pcard" data-sku="SB-2207">
<div class="plate"><svg class="art"><use href="#art-display"/></svg><span class="badge badge--new">New</span></div>
<h3>CrispView 2.4" IPS Module</h3>
<p class="pmeta">SB-2207 · 320×240 · SPI</p>
<div class="prow"><span class="price">$24.95</span><span class="stock ok">In stock</span></div>
<button class="btn btn--add" type="button" data-add="CrispView 2.4 IPS Module">Add to cart</button>
</li>
<li class="pcard" data-sku="SB-0891">
<div class="plate"><svg class="art"><use href="#art-neopix"/></svg><span class="badge badge--hot">Hot</span></div>
<h3>GlowStrip RGB Sticks (4-pack)</h3>
<p class="pmeta">SB-0891 · 8 px each · 5V</p>
<div class="prow"><span class="price">$12.00</span><span class="stock low">Only 9 left</span></div>
<button class="btn btn--add" type="button" data-add="GlowStrip RGB Sticks">Add to cart</button>
</li>
<li class="pcard" data-sku="SB-3155">
<div class="plate"><svg class="art"><use href="#art-sensor"/></svg><span class="badge badge--new">New</span></div>
<h3>SeeMe Time-of-Flight Sensor</h3>
<p class="pmeta">SB-3155 · 4 m range · I²C</p>
<div class="prow"><span class="price">$15.75</span><span class="stock ok">In stock</span></div>
<button class="btn btn--add" type="button" data-add="SeeMe Time-of-Flight Sensor">Add to cart</button>
</li>
<li class="pcard" data-sku="SB-7720">
<div class="plate"><svg class="art"><use href="#art-motor"/></svg><span class="badge">Restock</span></div>
<h3>TinyTorque Geared Motor</h3>
<p class="pmeta">SB-7720 · 120 RPM · 6V</p>
<div class="prow"><span class="price">$9.40</span><span class="stock ok">In stock</span></div>
<button class="btn btn--add" type="button" data-add="TinyTorque Geared Motor">Add to cart</button>
</li>
<li class="pcard" data-sku="SB-1002">
<div class="plate"><svg class="art"><use href="#art-iron"/></svg><span class="badge badge--hot">Hot</span></div>
<h3>FirstJoint Soldering Station</h3>
<p class="pmeta">SB-1002 · 60 W · ESD-safe</p>
<div class="prow"><span class="price">$62.00</span><span class="stock low">Only 4 left</span></div>
<button class="btn btn--add" type="button" data-add="FirstJoint Soldering Station">Add to cart</button>
</li>
</ul>
</div>
</div>
</section>
<!-- ── category rail ─────────────────────────────────────────────── -->
<section class="cats">
<div class="wrap">
<h2 class="sec__t">Shop by aisle</h2>
<ul class="pills">
<li><button type="button" class="pill" data-toast="Aisle: Dev boards — 214 parts."><span class="pill__i" style="--c:#2b8cff">▤</span>Dev boards</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Sensors — 431 parts."><span class="pill__i" style="--c:#ff3d81">◎</span>Sensors</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Displays — 96 parts."><span class="pill__i" style="--c:#b8ff3d">▭</span>Displays</button></li>
<li><button type="button" class="pill" data-toast="Aisle: LEDs & light — 288 parts."><span class="pill__i" style="--c:#ffd66b">✷</span>LEDs</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Motors & motion — 152 parts."><span class="pill__i" style="--c:#7ee0c6">⟳</span>Motion</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Power & batteries — 178 parts."><span class="pill__i" style="--c:#2b8cff">⚡</span>Power</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Tools & benches — 121 parts."><span class="pill__i" style="--c:#ff3d81">✜</span>Tools</button></li>
<li><button type="button" class="pill" data-toast="Aisle: Wearables — 87 parts."><span class="pill__i" style="--c:#b8ff3d">◈</span>Wearables</button></li>
</ul>
</div>
</section>
<!-- ── split band: show promo + newsletter ───────────────────────── -->
<section class="band">
<div class="wrap band__grid">
<article class="show">
<div class="show__tag"><span class="dot"></span> Live every Thursday</div>
<h2>Bench Hours <span class="ep">EP 214</span></h2>
<p>Forty minutes of soldering, questions from chat, and one component we probably shouldn't have bought. This week: driving 300 LEDs from a coin-cell budget without letting the magic smoke out.</p>
<div class="count" id="count" aria-live="polite">
<div><b id="cd">00</b><span>days</span></div>
<div><b id="ch">00</b><span>hrs</span></div>
<div><b id="cm">00</b><span>min</span></div>
<div><b id="cs">00</b><span>sec</span></div>
</div>
<p class="show__when">Next stream: Thursday 20:00 ET · replay posted the next morning</p>
<button class="btn btn--acc" type="button" id="notifyBtn">Notify me</button>
</article>
<article class="news">
<h2>The Tuesday Bin</h2>
<p>One email a week: what restocked, what we broke on stream, and a guide worth your weekend. No coupons pretending to be friendship.</p>
<form class="news__form" id="newsForm" novalidate>
<label class="sr-only" for="email">Email address</label>
<input id="email" type="email" placeholder="[email protected]" required />
<button class="btn btn--pri" type="submit">Subscribe</button>
<p class="news__err" id="newsErr" role="alert" hidden>Enter a valid email address.</p>
</form>
<ul class="news__pts">
<li>Restock alerts before the strip updates</li>
<li>Early access to kit drops (usually 24h)</li>
<li>Unsubscribe in one click, no survey</li>
</ul>
</article>
</div>
</section>
<!-- ── learn ────────────────────────────────────────────────────── -->
<section class="learn" id="learn">
<div class="wrap">
<div class="sec__head">
<div>
<h2 class="sec__t">Learn</h2>
<p class="sec__s">Every guide is tested on the exact parts we sell. If a step is wrong, the fix ships with the errata note.</p>
</div>
<div class="filters" role="tablist" aria-label="Filter guides by track">
<button class="fbtn is-on" type="button" role="tab" aria-selected="true" data-track="all">All</button>
<button class="fbtn" type="button" role="tab" aria-selected="false" data-track="beginner">Beginner</button>
<button class="fbtn" type="button" role="tab" aria-selected="false" data-track="wearables">Wearables</button>
<button class="fbtn" type="button" role="tab" aria-selected="false" data-track="iot">IoT</button>
<button class="fbtn" type="button" role="tab" aria-selected="false" data-track="robotics">Robotics</button>
</div>
</div>
<ul class="guides" id="guides">
<li class="guide" data-track="beginner">
<div class="guide__top"><svg class="art art--sm"><use href="#art-iron"/></svg></div>
<span class="diff diff--1">Beginner</span>
<h3>Your first ten solder joints</h3>
<p>Tip temperature, wetting, and how to tell a cold joint from a good one — with close-up diagrams of both.</p>
<div class="guide__foot"><span class="chip"><i>MR</i>Mira Route</span><span class="mono">35 min</span></div>
</li>
<li class="guide" data-track="wearables">
<div class="guide__top"><svg class="art art--sm"><use href="#art-neopix"/></svg></div>
<span class="diff diff--2">Intermediate</span>
<h3>Sewable LEDs that survive the wash</h3>
<p>Conductive thread routing, strain relief at the battery, and a coating trick that adds about forty cycles.</p>
<div class="guide__foot"><span class="chip"><i>KD</i>Kit Delacroix</span><span class="mono">1 h 10 min</span></div>
</li>
<li class="guide" data-track="iot">
<div class="guide__top"><svg class="art art--sm"><use href="#art-board"/></svg></div>
<span class="diff diff--2">Intermediate</span>
<h3>A sensor that emails you once, not 400 times</h3>
<p>Debounce, deep sleep, and a tiny state machine so your door sensor stops flooding your inbox at 3 a.m.</p>
<div class="guide__foot"><span class="chip"><i>AO</i>Ade Okonjo</span><span class="mono">55 min</span></div>
</li>
<li class="guide" data-track="robotics">
<div class="guide__top"><svg class="art art--sm"><use href="#art-motor"/></svg></div>
<span class="diff diff--3">Advanced</span>
<h3>Line follower with a proper PID loop</h3>
<p>Tuning by hand instead of by vibes: how to read the wobble and turn it into three numbers that work.</p>
<div class="guide__foot"><span class="chip"><i>TS</i>Theo Sandoval</span><span class="mono">2 h 05 min</span></div>
</li>
<li class="guide" data-track="beginner">
<div class="guide__top"><svg class="art art--sm"><use href="#art-battery"/></svg></div>
<span class="diff diff--1">Beginner</span>
<h3>Powering a project without guessing</h3>
<p>Milliamp-hours in plain language, why your regulator gets hot, and a five-line budget worksheet.</p>
<div class="guide__foot"><span class="chip"><i>MR</i>Mira Route</span><span class="mono">40 min</span></div>
</li>
<li class="guide" data-track="iot">
<div class="guide__top"><svg class="art art--sm"><use href="#art-display"/></svg></div>
<span class="diff diff--2">Intermediate</span>
<h3>A tiny dashboard on a 2.4" screen</h3>
<p>Fetch, parse and draw without running out of RAM — plus a font-size table that stays readable at arm's length.</p>
<div class="guide__foot"><span class="chip"><i>JP</i>Juno Park</span><span class="mono">1 h 25 min</span></div>
</li>
<li class="guide" data-track="wearables">
<div class="guide__top"><svg class="art art--sm"><use href="#art-kit"/></svg></div>
<span class="diff diff--1">Beginner</span>
<h3>Badge kit: from bag to blinking</h3>
<p>A full evening build with photos of every joint, plus the three mistakes we see most often in workshops.</p>
<div class="guide__foot"><span class="chip"><i>KD</i>Kit Delacroix</span><span class="mono">1 h 45 min</span></div>
</li>
<li class="guide" data-track="robotics">
<div class="guide__top"><svg class="art art--sm"><use href="#art-sensor"/></svg></div>
<span class="diff diff--3">Advanced</span>
<h3>Obstacle mapping with one cheap sensor</h3>
<p>Sweep, sample, filter. Building a usable 180° picture from a single time-of-flight module and a servo.</p>
<div class="guide__foot"><span class="chip"><i>TS</i>Theo Sandoval</span><span class="mono">2 h 30 min</span></div>
</li>
</ul>
<p class="guides__empty" id="guidesEmpty" hidden>No guides in that track yet — try another.</p>
</div>
</section>
<!-- ── best sellers ─────────────────────────────────────────────── -->
<section class="best" id="best">
<div class="wrap">
<h2 class="sec__t">Best sellers this month</h2>
<p class="sec__s">Ranked by units shipped from the Tuesday restock. Quick view shows the specs sheet.</p>
<ul class="grid">
<li class="pcard pcard--g" data-name="Pocket32 Wi-Fi Dev Board" data-sku="SB-4410" data-price="$18.50"
data-specs="MCU|Dual-core 240 MHz;Flash|8 MB;Radio|Wi-Fi b/g/n + BLE 5;IO|22 GPIO, 2× I²C, 3× UART;Power|USB-C or 3.7 V LiPo;Size|51 × 23 mm">
<div class="plate"><svg class="art"><use href="#art-board"/></svg><span class="rank">01</span></div>
<h3>Pocket32 Wi-Fi Dev Board</h3>
<div class="prow"><span class="price">$18.50</span><span class="stock ok">In stock</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="Pocket32 Wi-Fi Dev Board">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
<li class="pcard pcard--g" data-name="GlowStrip RGB Sticks (4-pack)" data-sku="SB-0891" data-price="$12.00"
data-specs="LEDs|32 addressable (8 per stick);Protocol|Single-wire, 800 kHz;Voltage|5 V, 60 mA per pixel max;Pitch|10 mm;Connector|3-pin JST-SH;Chainable|Yes, up to 12 sticks">
<div class="plate"><svg class="art"><use href="#art-neopix"/></svg><span class="rank">02</span></div>
<h3>GlowStrip RGB Sticks (4-pack)</h3>
<div class="prow"><span class="price">$12.00</span><span class="stock low">Only 9 left</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="GlowStrip RGB Sticks">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
<li class="pcard pcard--g" data-name="Badge Kit — Blink Edition" data-sku="SB-6600" data-price="$34.00"
data-specs="Contents|PCB, 12 parts, coin cell, lanyard;Solder joints|38;Build time|~1 h 45 min;Skill|First-timer friendly;Includes|Printed guide + errata card;Spares|2 extra LEDs">
<div class="plate"><svg class="art"><use href="#art-kit"/></svg><span class="rank">03</span></div>
<h3>Badge Kit — Blink Edition</h3>
<div class="prow"><span class="price">$34.00</span><span class="stock ok">In stock</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="Badge Kit Blink Edition">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
<li class="pcard pcard--g" data-name="SeeMe Time-of-Flight Sensor" data-sku="SB-3155" data-price="$15.75"
data-specs="Range|30 mm – 4 m;Accuracy|±3 % typical indoors;Rate|Up to 50 Hz;Bus|I²C, address 0x29;Voltage|3.3 V (5 V tolerant);Field of view|27°">
<div class="plate"><svg class="art"><use href="#art-sensor"/></svg><span class="rank">04</span></div>
<h3>SeeMe Time-of-Flight Sensor</h3>
<div class="prow"><span class="price">$15.75</span><span class="stock ok">In stock</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="SeeMe Time-of-Flight Sensor">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
<li class="pcard pcard--g" data-name="CellPack 1200 mAh LiPo" data-sku="SB-5040" data-price="$8.95"
data-specs="Capacity|1200 mAh;Nominal|3.7 V;Protection|Over-charge / over-discharge PCB;Connector|2-pin JST-PH;Cycles|~500 to 80 %;Size|34 × 62 × 5 mm">
<div class="plate"><svg class="art"><use href="#art-battery"/></svg><span class="rank">05</span></div>
<h3>CellPack 1200 mAh LiPo</h3>
<div class="prow"><span class="price">$8.95</span><span class="stock ok">In stock</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="CellPack 1200 mAh LiPo">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
<li class="pcard pcard--g" data-name="FirstJoint Soldering Station" data-sku="SB-1002" data-price="$62.00"
data-specs="Power|60 W ceramic element;Range|200 – 450 °C;Warm-up|~25 s to 350 °C;Tips|4 included (chisel, conical);Safety|ESD-safe, sleep after 12 min;Warranty|2 years">
<div class="plate"><svg class="art"><use href="#art-iron"/></svg><span class="rank">06</span></div>
<h3>FirstJoint Soldering Station</h3>
<div class="prow"><span class="price">$62.00</span><span class="stock low">Only 4 left</span></div>
<div class="pact"><button class="btn btn--add" type="button" data-add="FirstJoint Soldering Station">Add</button><button class="btn btn--ghost btn--sm" type="button" data-quick>Quick view</button></div>
</li>
</ul>
</div>
</section>
</main>
<!-- ── footer ──────────────────────────────────────────────────────── -->
<footer class="ftr">
<div class="wrap ftr__grid">
<div class="ftr__brand">
<span class="brand__txt">SOLDER<em>BOX</em></span>
<p>A small shop, a big bin wall, and a stubborn belief that documentation is part of the product.</p>
<p class="mono ftr__addr">Bay 4, 118 Ferrite Row · Open Tue–Sat</p>
</div>
<div><h3>Shop</h3><ul><li><a href="#best">Best sellers</a></li><li><a href="#top">New this week</a></li><li><a href="#top">Kits</a></li><li><a href="#top">Tools</a></li><li><a href="#top">Gift cards</a></li></ul></div>
<div><h3>Learn</h3><ul><li><a href="#learn">All guides</a></li><li><a href="#learn">Beginner track</a></li><li><a href="#learn">Wearables</a></li><li><a href="#learn">IoT</a></li><li><a href="#learn">Robotics</a></li></ul></div>
<div><h3>Help</h3><ul><li><a href="#top">Shipping</a></li><li><a href="#top">Returns</a></li><li><a href="#top">Datasheets</a></li><li><a href="#top">Errata</a></li><li><a href="#top">Contact the bench</a></li></ul></div>
</div>
<div class="wrap ftr__end">
<p class="mono">© 2026 SOLDERBOX — fictional shop, real enthusiasm.</p>
<p class="ftr__sign">Keep the tip clean and the smoke inside. <span aria-hidden="true">⚡</span></p>
</div>
</footer>
<!-- ── quick view modal ────────────────────────────────────────────── -->
<div class="modal" id="modal" hidden>
<div class="modal__scrim" data-close></div>
<div class="modal__box" role="dialog" aria-modal="true" aria-labelledby="mTitle">
<button class="modal__x" type="button" data-close aria-label="Close quick view">×</button>
<div class="modal__art"><svg class="art" id="mArt"><use href="#art-board" id="mUse"/></svg></div>
<div class="modal__body">
<p class="mono mSku" id="mSku">SB-0000</p>
<h3 id="mTitle">Product</h3>
<p class="price price--lg" id="mPrice">$0.00</p>
<dl class="specs" id="mSpecs"></dl>
<button class="btn btn--pri" type="button" id="mAdd">Add to cart</button>
</div>
</div>
</div>
<div class="toasts" id="toasts" aria-live="polite" aria-atomic="false"></div>
<script src="script.js"></script>
</body>
</html>Electronics Shop & Learn Landing
SOLDERBOX is a fictional parts shop that treats documentation as part of the product, and the page is laid out to say so. A gradient announcement bar rotates four shipping and restock messages on a timer (with manual arrows that reset it), the sticky header carries the wordmark, a full-width search field, an account button and a cart whose counter bumps and animates on every add. Beneath it, the hero states the pitch over a blueprint-style grid glow and hands you four monospace stat tiles.
“New this week” is a snap-scrolling rail of product cards. Every product “photo” is an inline SVG symbol — dev board, IPS display, RGB sticks, time-of-flight sensor, geared motor, soldering iron, kit box, LiPo cell — rendered on a bright white rounded plate so the artwork pops against the near-black page. Cards carry New/Hot/Restock badges, price chips in JetBrains Mono, and stock states that switch between a mint “In stock” and an amber “Only 4 left”.
Below the category pills, a split band pairs the Bench Hours live-show card — episode number, pulsing live dot, a real countdown to the next Thursday at 20:00, and a toggling notify button — with a newsletter form that validates inline. The Learn section filters eight guide cards by track (Beginner / Wearables / IoT / Robotics) with an empty state, and the best-sellers grid opens a focus-trapped quick-view modal listing a specs sheet as a monospace definition list.
How this look is built
The information architecture nods to Adafruit-style maker shops — dark playful storefront fused with a learning library — but everything here is original: fictional brand, invented SKUs, hand-drawn art. The heavy lifting is modern CSS: layered repeating-linear-gradient layers paint the 8px/80px blueprint grid with zero image requests, grid-auto-flow: column plus scroll-snap-type: x mandatory gives the new-arrivals rail native momentum scrolling instead of a JS carousel, auto-fill + minmax() lets the guide and best-seller grids reflow without breakpoint bookkeeping, and position: sticky handles the header. An IntersectionObserver staggers the card reveals so nothing animates off-screen, filtering is a class toggle rather than DOM rebuilding, and a single delegated click listener on document powers add-to-cart, toasts and quick view for every card at once.
Illustrative UI only — always follow real safety guidance when working with tools, electronics, or repairs.