Run details
- Model
- fireworks/ember-1
- Route
- OpenRouter API, one user message
- Served by
- Fireworks
- Effort
- max, OpenRouter's default for this model
- Limits
- 60 min · 40,000 output tokens (our $0.60 limit per run at $15/M)
- Date
- 23 Oct 2026
- Time
- 7 min 29 s
- Size
- 72 kB
- Tokens
- 175 in, 34,086 out (10,610 of them thinking)
- List price
- $0.51 at today's price ($3 in / $15 out per M)
- Paid
- $0.51
Exact prompt
Build the landing page for Lumen Cycles, a Copenhagen workshop that builds custom cargo bikes to order. Make it look like a real brand you would trust with 4,000 euros. It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Reply with the file in a single ```html code block.
Source
72 kB 1,247 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lumen Cycles — Custom Cargo Bikes, Built to Order in Copenhagen</title>
<meta name="description" content="Lumen Cycles is a small Copenhagen workshop building made-to-order cargo bikes. Fillet-brazed steel frames, marine-ply boxes, 5-year warranty.">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%23B4551F' stroke-width='3'/%3E%3Ccircle cx='16' cy='16' r='4' fill='%231C1B17'/%3E%3C/svg%3E">
<style>
/* ============ TOKENS ============ */
:root{
--paper:#F5F1E7;
--paper-2:#EEE8DA;
--ink:#1C1B17;
--ink-70:rgba(28,27,23,.72);
--ink-50:rgba(28,27,23,.5);
--ink-14:rgba(28,27,23,.14);
--line:#DCD3C0;
--accent:#B4551F;
--accent-deep:#8E3F14;
--green:#22392D;
--green-2:#1B2F25;
--serif:"Didot","Bodoni MT","Cochin",Georgia,"Times New Roman",serif;
--sans:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
--mono:ui-monospace,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
--max:1240px;
--ease:cubic-bezier(.22,.61,.21,1);
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
background:var(--paper);
color:var(--ink);
font-family:var(--sans);
font-size:16px;
line-height:1.6;
-webkit-font-smoothing:antialiased;
overflow-x:hidden;
}
::selection{background:var(--accent);color:var(--paper)}
img,svg{display:block;max-width:100%}
a{color:inherit}
button{font-family:inherit;cursor:pointer}
section{scroll-margin-top:84px}
.wrap{max-width:var(--max);margin:0 auto;padding:0 clamp(20px,4vw,48px)}
.mono{font-family:var(--mono);text-transform:uppercase;letter-spacing:.18em;font-size:11px}
/* grain overlay (generated at runtime, no network) */
#grain{position:fixed;inset:0;z-index:2000;pointer-events:none;opacity:.05;mix-blend-mode:multiply}
/* progress bar */
#progress{position:fixed;top:0;left:0;height:3px;width:0;background:var(--accent);z-index:1500}
.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);padding:10px 16px;z-index:3000}
.skip:focus{left:12px;top:12px}
/* ============ HEADER ============ */
header{position:fixed;top:0;left:0;right:0;z-index:1000;transition:background .35s,border-color .35s,backdrop-filter .35s;border-bottom:1px solid transparent}
header.scrolled{background:rgba(245,241,231,.9);backdrop-filter:blur(10px);border-bottom-color:var(--line)}
.nav{display:flex;align-items:center;justify-content:space-between;height:72px;max-width:var(--max);margin:0 auto;padding:0 clamp(20px,4vw,48px)}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none}
.brand-name{font-family:var(--serif);font-size:20px;letter-spacing:.04em;line-height:1}
.brand-name em{font-style:italic;color:var(--accent)}
.brand-sub{font-family:var(--mono);font-size:9px;letter-spacing:.28em;text-transform:uppercase;color:var(--ink-50);margin-top:3px}
.nav-links{display:flex;gap:32px;list-style:none}
.nav-links a{text-decoration:none;font-size:13px;letter-spacing:.04em;color:var(--ink-70);position:relative;padding:4px 0}
.nav-links a::after{content:"";position:absolute;left:0;bottom:0;width:0;height:1px;background:var(--accent);transition:width .3s var(--ease)}
.nav-links a:hover{color:var(--ink)}
.nav-links a:hover::after{width:100%}
.btn{display:inline-flex;align-items:center;gap:10px;background:var(--ink);color:var(--paper);border:1px solid var(--ink);padding:13px 24px;font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-family:var(--mono);text-decoration:none;transition:background .3s,color .3s,transform .3s;border-radius:2px}
.btn svg{transition:transform .3s var(--ease)}
.btn:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.btn:hover svg{transform:translateX(4px)}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--ink)}
.btn.ghost:hover{background:var(--ink);color:var(--paper)}
.btn.small{padding:9px 18px;font-size:11px}
.btn.accent{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.accent:hover{background:var(--accent-deep);border-color:var(--accent-deep)}
@media(max-width:900px){.nav-links{display:none}}
/* ============ HERO ============ */
.hero{position:relative;padding:160px 0 0;overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(24px,4vw,64px);align-items:center}
.eyebrow{display:inline-flex;align-items:center;gap:10px;color:var(--ink-70);margin-bottom:26px}
.eyebrow .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)}
h1{font-family:var(--serif);font-weight:400;font-size:clamp(46px,6.4vw,88px);line-height:1.02;letter-spacing:-.01em}
h1 em{font-style:italic;color:var(--accent)}
.hero-sub{max-width:480px;margin:28px 0 36px;color:var(--ink-70);font-size:17px}
.hero-ctas{display:flex;gap:14px;flex-wrap:wrap}
.hero-trust{display:flex;gap:28px;flex-wrap:wrap;margin-top:44px;padding-top:24px;border-top:1px solid var(--line)}
.hero-trust span{display:flex;align-items:center;gap:9px;font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-70)}
.hero-trust i{width:5px;height:5px;border-radius:50%;background:var(--accent);flex:none}
.hero-art{position:relative}
.hero-art svg{width:100%;height:auto}
.hero-fig{animation:rise 1.2s var(--ease) both .3s}
@keyframes rise{from{opacity:0;transform:translateY(34px)}to{opacity:1;transform:none}}
/* entrance */
.fade-l{opacity:0;transform:translateY(26px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
body.loaded .fade-l{opacity:1;transform:none}
.fade-l.d1{transition-delay:.1s}.fade-l.d2{transition-delay:.22s}.fade-l.d3{transition-delay:.34s}.fade-l.d4{transition-delay:.46s}
@media(max-width:900px){.hero-grid{grid-template-columns:1fr}.hero{padding-top:130px}}
/* ============ MARQUEE ============ */
.marquee{border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-top:72px;padding:16px 0;overflow:hidden;background:var(--paper-2)}
.marquee-track{display:flex;width:max-content;animation:mq 30s linear infinite}
.marquee:hover .marquee-track{animation-play-state:paused}
.mq-set{display:flex;align-items:center;gap:44px;padding-right:44px}
.mq-set span{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--ink-70);white-space:nowrap}
.mq-set i{width:7px;height:7px;background:var(--accent);transform:rotate(45deg);flex:none}
@keyframes mq{to{transform:translateX(-50%)}}
/* ============ SECTIONS ============ */
.section{padding:clamp(80px,10vw,140px) 0}
.kicker{display:flex;align-items:center;gap:14px;color:var(--accent);margin-bottom:22px}
.kicker::after{content:"";height:1px;width:56px;background:var(--accent)}
h2{font-family:var(--serif);font-weight:400;font-size:clamp(34px,4.4vw,58px);line-height:1.08;letter-spacing:-.01em}
h2 em{font-style:italic;color:var(--accent)}
.lead{color:var(--ink-70);max-width:560px;font-size:17px;margin-top:18px}
/* reveal */
[data-reveal]{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease),transform .9s var(--ease);transition-delay:var(--d,0s)}
[data-reveal].in{opacity:1;transform:none}
/* ============ MANIFESTO ============ */
.manifesto{border-bottom:1px solid var(--line)}
.manifesto-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:clamp(32px,6vw,96px);align-items:start}
.big-quote{font-family:var(--serif);font-size:clamp(26px,3.2vw,40px);line-height:1.3;font-weight:400}
.big-quote em{font-style:italic;color:var(--accent)}
.sig{margin-top:28px;display:flex;align-items:center;gap:16px}
.sig-line{width:48px;height:1px;background:var(--ink)}
.sig span{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-70)}
.stats{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border:1px solid var(--line)}
.stat{background:var(--paper);padding:32px 28px}
.stat b{font-family:var(--serif);font-weight:400;font-size:clamp(38px,4vw,54px);display:block;line-height:1}
.stat b sup{font-size:.45em;color:var(--accent)}
.stat span{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-50);display:block;margin-top:10px}
@media(max-width:900px){.manifesto-grid{grid-template-columns:1fr}}
/* ============ MODELS ============ */
.models-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:56px}
.model-card{border:1px solid var(--line);background:var(--paper);padding:34px 30px 30px;display:flex;flex-direction:column;transition:transform .4s var(--ease),box-shadow .4s var(--ease),border-color .4s}
.model-card:hover{transform:translateY(-6px);box-shadow:0 24px 48px -24px rgba(28,27,23,.25);border-color:var(--ink)}
.model-card .tag{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent)}
.model-icon{margin:22px 0 26px}
.model-card h3{font-family:var(--serif);font-weight:400;font-size:28px;margin-bottom:8px}
.model-card p{color:var(--ink-70);font-size:14px;flex:1}
.specs{list-style:none;margin:22px 0;padding:16px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.specs li{display:flex;justify-content:space-between;font-size:12.5px;padding:5px 0;color:var(--ink-70)}
.specs li b{color:var(--ink);font-weight:600}
.price-row{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:20px}
.price-row .from{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-50)}
.price-row .price{font-family:var(--serif);font-size:26px}
.text-link{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink);text-decoration:none;display:inline-flex;align-items:center;gap:8px}
.text-link i{width:18px;height:1px;background:var(--accent);transition:width .3s var(--ease)}
.text-link:hover i{width:32px}
@media(max-width:900px){.models-grid{grid-template-columns:1fr}}
/* ============ CONFIGURATOR ============ */
.configurator{background:var(--paper-2);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.cfg-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,72px);margin-top:56px;align-items:start}
.cfg-preview{position:sticky;top:100px}
.cfg-stage{background:var(--paper);border:1px solid var(--line);padding:clamp(16px,3vw,36px);position:relative}
.cfg-stage .badge{position:absolute;top:16px;left:16px;font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-50)}
.cfg-svg{--frame:#2E4B3A;width:100%;height:auto}
.cfg-svg .part{stroke:var(--ink);fill:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round}
.cfg-svg .thin{stroke-width:2}
.cfg-svg .spoke{stroke-width:1.4;opacity:.45}
.cfg-svg .f{stroke:var(--frame)}
.cfg-svg .boxfill{fill:#DCC49B;stroke:var(--frame);stroke-width:3.5}
.cfg-svg .boxline{stroke:rgba(28,27,23,.4);stroke-width:2;fill:none}
.cfg-svg .g{display:none}
.cfg-svg .g.on{display:block}
.cfg-total{background:var(--ink);color:var(--paper);padding:26px 28px;margin-top:16px;display:flex;justify-content:space-between;align-items:flex-end;flex-wrap:wrap;gap:12px}
.cfg-total .lbl{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;opacity:.6}
.cfg-total .amt{font-family:var(--serif);font-size:clamp(34px,3.6vw,48px);line-height:1}
.cfg-total .meta{text-align:right;font-family:var(--mono);font-size:11px;letter-spacing:.08em;line-height:1.9;opacity:.75}
.cfg-group{margin-bottom:34px}
.cfg-label{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}
.cfg-label .t{font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-70)}
.cfg-label .v{font-size:13px;color:var(--accent);font-weight:600}
.seg{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.seg button{border:1px solid var(--line);background:var(--paper);padding:14px 10px;text-align:left;transition:border-color .25s,background .25s;border-radius:2px}
.seg button b{display:block;font-size:13.5px;font-weight:600}
.seg button span{font-family:var(--mono);font-size:10.5px;color:var(--ink-50);letter-spacing:.06em}
.seg button[aria-pressed="true"]{border-color:var(--ink);background:#fff;box-shadow:inset 0 0 0 1px var(--ink)}
.seg button[aria-pressed="true"] span{color:var(--accent)}
.swatches{display:flex;gap:12px;flex-wrap:wrap}
.swatch{width:44px;height:44px;border-radius:50%;border:2px solid transparent;padding:3px;background:none;transition:transform .25s,border-color .25s}
.swatch i{display:block;width:100%;height:100%;border-radius:50%;border:1px solid var(--ink-14)}
.swatch:hover{transform:scale(1.08)}
.swatch[aria-pressed="true"]{border-color:var(--accent)}
.addons{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.addon{display:flex;justify-content:space-between;align-items:center;gap:10px;border:1px solid var(--line);background:var(--paper);padding:13px 14px;text-align:left;transition:border-color .25s,background .25s;border-radius:2px}
.addon .n{font-size:13px;font-weight:600}
.addon .p{font-family:var(--mono);font-size:11px;color:var(--ink-50)}
.addon .tick{width:18px;height:18px;border:1px solid var(--ink-50);border-radius:50%;flex:none;display:grid;place-items:center;transition:background .25s,border-color .25s}
.addon .tick svg{opacity:0;transform:scale(.5);transition:.25s}
.addon[aria-pressed="true"]{border-color:var(--ink);background:#fff}
.addon[aria-pressed="true"] .tick{background:var(--accent);border-color:var(--accent)}
.addon[aria-pressed="true"] .tick svg{opacity:1;transform:none}
.addon:disabled{opacity:.4;cursor:not-allowed}
.cfg-summary{font-size:13.5px;color:var(--ink-70);border-left:2px solid var(--accent);padding:4px 0 4px 16px;margin:6px 0 24px;font-style:italic}
@media(max-width:900px){.cfg-grid{grid-template-columns:1fr}.cfg-preview{position:static}}
/* ============ PROCESS ============ */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:24px;margin-top:64px;counter-reset:step}
.step{border-top:2px solid var(--ink);padding-top:22px;position:relative}
.step::before{counter-increment:step;content:"0" counter(step);font-family:var(--mono);font-size:11px;letter-spacing:.2em;color:var(--accent)}
.step h3{font-family:var(--serif);font-weight:400;font-size:24px;margin:14px 0 10px}
.step p{font-size:13.5px;color:var(--ink-70)}
.step .dur{display:inline-block;margin-top:14px;font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;border:1px solid var(--line);padding:5px 10px;color:var(--ink-70)}
@media(max-width:900px){.steps{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.steps{grid-template-columns:1fr}}
/* ============ CRAFT (dark) ============ */
.craft{background:var(--green);color:var(--paper)}
.craft .kicker{color:#E0A37E}
.craft .kicker::after{background:#E0A37E}
.craft h2 em{color:#E0A37E}
.craft .lead{color:rgba(245,241,231,.72)}
.craft-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:rgba(245,241,231,.16);border:1px solid rgba(245,241,231,.16);margin-top:56px}
.craft-card{background:var(--green);padding:34px 30px;transition:background .35s}
.craft-card:hover{background:var(--green-2)}
.craft-card svg{margin-bottom:20px}
.craft-card h3{font-family:var(--serif);font-weight:400;font-size:22px;margin-bottom:8px}
.craft-card p{font-size:13.5px;color:rgba(245,241,231,.68)}
.warranty{display:flex;justify-content:space-between;align-items:center;gap:24px;flex-wrap:wrap;margin-top:56px;border:1px solid rgba(245,241,231,.25);padding:28px 32px}
.warranty b{font-family:var(--serif);font-weight:400;font-size:clamp(22px,2.6vw,30px)}
.warranty b em{font-style:italic;color:#E0A37E}
.warranty span{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:rgba(245,241,231,.6)}
@media(max-width:900px){.craft-grid{grid-template-columns:1fr}}
/* ============ TESTIMONIALS ============ */
.t-head{display:flex;justify-content:space-between;align-items:flex-end;gap:24px;flex-wrap:wrap}
.t-nav{display:flex;gap:10px}
.t-btn{width:46px;height:46px;border:1px solid var(--ink);background:transparent;display:grid;place-items:center;transition:background .3s,color .3s;border-radius:50%}
.t-btn:hover{background:var(--ink);color:var(--paper)}
.t-viewport{overflow:hidden;margin-top:48px}
.t-track{display:flex;transition:transform .65s var(--ease)}
.t-slide{flex:0 0 100%;padding-right:8px}
.t-quote{font-family:var(--serif);font-size:clamp(24px,3vw,38px);line-height:1.35;font-weight:400;max-width:900px}
.t-quote em{font-style:italic;color:var(--accent)}
.t-meta{display:flex;align-items:center;gap:18px;margin-top:32px}
.t-ava{width:52px;height:52px;border-radius:50%;background:var(--accent);color:#fff;display:grid;place-items:center;font-family:var(--serif);font-size:20px;flex:none}
.t-meta b{display:block;font-size:14px}
.t-meta span{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-50)}
.t-stars{display:flex;gap:3px;margin-left:auto}
.t-dots{display:flex;gap:8px;margin-top:36px}
.t-dots button{width:28px;height:3px;border:none;background:var(--line);transition:background .3s}
.t-dots button[aria-current="true"]{background:var(--accent)}
/* ============ FAQ ============ */
.faq-wrap{max-width:820px;margin:56px auto 0}
.faq-item{border-bottom:1px solid var(--line)}
.faq-item:first-child{border-top:1px solid var(--line)}
.faq-q{width:100%;background:none;border:none;display:flex;justify-content:space-between;align-items:center;gap:20px;padding:24px 4px;text-align:left;font-family:var(--serif);font-size:clamp(18px,2vw,23px);color:var(--ink);transition:color .25s}
.faq-q:hover{color:var(--accent)}
.faq-q .ic{width:30px;height:30px;flex:none;border:1px solid var(--ink-14);border-radius:50%;display:grid;place-items:center;transition:transform .4s var(--ease),background .3s,border-color .3s}
.faq-q .ic svg{transition:transform .4s var(--ease)}
.faq-item.open .ic{background:var(--accent);border-color:var(--accent);color:#fff}
.faq-item.open .ic svg{transform:rotate(45deg)}
.faq-a{max-height:0;overflow:hidden;transition:max-height .45s var(--ease)}
.faq-a p{padding:0 44px 26px 4px;color:var(--ink-70);font-size:15px;max-width:640px}
/* ============ VISIT ============ */
.visit{background:var(--paper-2);border-top:1px solid var(--line)}
.visit-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(32px,5vw,72px);margin-top:56px;align-items:start}
.map-card{border:1px solid var(--line);background:var(--paper)}
.map-card svg{width:100%;height:auto}
.pin-pulse{animation:pulse 2.4s ease-out infinite;transform-origin:center;transform-box:fill-box}
@keyframes pulse{0%{transform:scale(.4);opacity:.8}100%{transform:scale(2.2);opacity:0}}
.visit-info{padding:26px 30px;border-top:1px solid var(--line);display:grid;grid-template-columns:1fr 1fr;gap:18px}
.visit-info h4{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.visit-info p{font-size:13.5px;color:var(--ink-70)}
.form-card{background:var(--ink);color:var(--paper);padding:clamp(28px,3.4vw,44px)}
.form-card h3{font-family:var(--serif);font-weight:400;font-size:clamp(24px,2.6vw,32px);margin-bottom:8px}
.form-card>p{color:rgba(245,241,231,.65);font-size:14px;margin-bottom:28px}
.f-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.f-field{margin-bottom:14px}
.f-field label{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:rgba(245,241,231,.55);margin-bottom:7px}
.f-field input,.f-field select,.f-field textarea{width:100%;background:rgba(245,241,231,.06);border:1px solid rgba(245,241,231,.22);color:var(--paper);padding:13px 14px;font-size:14px;font-family:var(--sans);border-radius:2px;transition:border-color .25s,background .25s}
.f-field input:focus,.f-field select:focus,.f-field textarea:focus{outline:none;border-color:var(--accent);background:rgba(245,241,231,.1)}
.f-field textarea{resize:vertical;min-height:88px}
.f-field select option{color:var(--ink)}
.form-card .btn{width:100%;justify-content:center;margin-top:6px}
.form-done{display:none;text-align:center;padding:40px 0}
.form-done svg{margin:0 auto 22px}
.form-done h4{font-family:var(--serif);font-weight:400;font-size:28px;margin-bottom:8px}
.form-done p{color:rgba(245,241,231,.65);font-size:14px}
form.sent .form-body{display:none}
form.sent .form-done{display:block}
@media(max-width:900px){.visit-grid{grid-template-columns:1fr}.f-row{grid-template-columns:1fr}}
/* ============ FOOTER ============ */
footer{background:var(--ink);color:var(--paper);padding:72px 0 0}
.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:40px;padding-bottom:56px}
.foot-brand p{color:rgba(245,241,231,.55);font-size:13.5px;max-width:280px;margin-top:16px}
footer h5{font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:rgba(245,241,231,.45);margin-bottom:16px}
footer ul{list-style:none}
footer li{margin-bottom:9px}
footer a{color:rgba(245,241,231,.75);text-decoration:none;font-size:13.5px;transition:color .25s}
footer a:hover{color:var(--accent)}
.foot-bar{border-top:1px solid rgba(245,241,231,.14);padding:22px 0;display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap}
.foot-bar span{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:rgba(245,241,231,.4)}
@media(max-width:900px){.foot-grid{grid-template-columns:1fr 1fr}}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
@media (prefers-reduced-motion: reduce){
html{scroll-behavior:auto}
*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
[data-reveal],.fade-l{opacity:1;transform:none}
.marquee-track{animation:none}
}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<div id="progress"></div>
<div id="grain"></div>
<!-- ============ HEADER ============ -->
<header id="header">
<nav class="nav" aria-label="Main">
<a class="brand" href="#top" aria-label="Lumen Cycles home">
<svg width="40" height="26" viewBox="0 0 40 26" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<circle cx="8" cy="18" r="6.5"/><circle cx="33" cy="18" r="5"/>
<path d="M8 18 L17 6 H27 M17 6 L21 18 H33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M27 6 L30 12" stroke-linecap="round"/>
</svg>
<span>
<span class="brand-name">Lumen <em>Cycles</em></span>
<span class="brand-sub">København</span>
</span>
</a>
<ul class="nav-links">
<li><a href="#models">Models</a></li>
<li><a href="#configure">Configure</a></li>
<li><a href="#process">Process</a></li>
<li><a href="#craft">Craft</a></li>
<li><a href="#stories">Stories</a></li>
<li><a href="#faq">FAQ</a></li>
</ul>
<a class="btn small" href="#visit">Book a test ride
<svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M1 5h11M8 1l4 4-4 4"/></svg>
</a>
</nav>
</header>
<main id="main">
<!-- ============ HERO ============ -->
<section class="hero" id="top">
<div class="wrap">
<div class="hero-grid">
<div>
<p class="eyebrow mono fade-l"><span class="dot"></span> Værksted for ladcykler · Est. 2016</p>
<h1 class="fade-l d1">Cargo bikes,<br>built <em>one at a time.</em></h1>
<p class="hero-sub fade-l d2">Lumen Cycles is a two-person workshop on Refshaleøen, Copenhagen. We design, braze and finish made-to-order cargo bikes — steel frames, marine-ply boxes, and a five-year promise.</p>
<div class="hero-ctas fade-l d3">
<a class="btn accent" href="#configure">Configure yours
<svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M1 5h11M8 1l4 4-4 4"/></svg>
</a>
<a class="btn ghost" href="#visit">Book a test ride</a>
</div>
<div class="hero-trust fade-l d4">
<span><i></i>312 bikes on the road</span>
<span><i></i>5-year frame warranty</span>
<span><i></i>Free 500 km service</span>
</div>
</div>
<div class="hero-art">
<svg class="hero-fig" id="heroSvg" viewBox="0 0 860 440" role="img" aria-label="Line drawing of a Lumen Longjohn cargo bike">
<circle cx="600" cy="185" r="178" fill="#E7DEC9" opacity=".55"/>
<circle cx="600" cy="185" r="178" fill="none" stroke="#DCD3C0" stroke-width="1"/>
<ellipse cx="420" cy="398" rx="330" ry="9" fill="rgba(28,27,23,.06)"/>
<g stroke="#1C1B17" fill="none" stroke-linecap="round" stroke-linejoin="round">
<!-- ground -->
<path d="M30 392 H800" stroke-width="2" opacity=".35"/>
<!-- rear wheel -->
<circle cx="160" cy="312" r="80" stroke-width="5"/>
<circle cx="160" cy="312" r="66" stroke-width="1.4" opacity=".4"/>
<g stroke-width="1.4" opacity=".45">
<path d="M160 312 L240 312 M160 312 L224.7 265 M160 312 L184.7 235.9 M160 312 L135.3 235.9 M160 312 L95.3 265 M160 312 L80 312 M160 312 L95.3 359 M160 312 L135.3 388.1 M160 312 L184.7 388.1 M160 312 L224.7 359"/>
</g>
<circle cx="160" cy="312" r="7" fill="#1C1B17"/>
<!-- front wheel -->
<circle cx="668" cy="330" r="62" stroke-width="5"/>
<circle cx="668" cy="330" r="50" stroke-width="1.4" opacity=".4"/>
<g stroke-width="1.4" opacity=".45">
<path d="M668 330 L730 330 M668 330 L711.8 286.2 M668 330 L668 268 M668 330 L624.2 286.2 M668 330 L606 330 M668 330 L624.2 373.8 M668 330 L668 392 M668 330 L711.8 373.8"/>
</g>
<circle cx="668" cy="330" r="6" fill="#1C1B17"/>
<!-- fenders -->
<path d="M80 312 A80 80 0 0 1 240 312" stroke-width="3"/>
<path d="M606 330 A62 62 0 0 1 730 330" stroke-width="3"/>
<!-- frame -->
<g stroke="#B4551F" stroke-width="4.5">
<path d="M160 312 L318 292 M160 312 L268 190 M268 190 L318 292 M318 292 L606 280 M268 190 L596 236 M596 236 L606 280 M668 330 L662 272"/>
</g>
<!-- steering -->
<path d="M596 236 L584 178" stroke-width="4.5" stroke="#B4551F"/>
<path d="M584 178 Q562 169 540 174" stroke-width="4.5"/>
<path d="M540 174 L525 180" stroke-width="6"/>
<path d="M607 278 L663 274" stroke-width="2"/>
<!-- seat -->
<path d="M268 190 L262 168" stroke-width="4"/>
<path d="M240 166 Q262 157 286 163" stroke-width="5"/>
<!-- chain + crank -->
<circle cx="318" cy="292" r="17" stroke-width="3"/>
<path d="M318 275 L162 306 M318 309 L162 318" stroke-width="1.6" opacity=".7"/>
<path d="M318 292 L342 318" stroke-width="4"/>
<path d="M332 320 h20" stroke-width="5"/>
<!-- stand -->
<path d="M305 330 L291 392" stroke-width="3"/>
<!-- lights -->
<circle cx="655" cy="298" r="5" fill="#B4551F" stroke="none"/>
<circle cx="205" cy="250" r="4" fill="#B4551F" stroke="none"/>
<!-- box -->
<path d="M352 226 H592 L606 322 H364 Z" fill="#DCC49B" stroke="#B4551F" stroke-width="3.5"/>
<path d="M356 256 H597 M360 289 H601" stroke="rgba(28,27,23,.4)" stroke-width="2"/>
<path d="M430 226 V322 M500 226 V322 M565 226 V322" stroke="rgba(28,27,23,.4)" stroke-width="2"/>
</g>
</svg>
</div>
</div>
</div>
<!-- marquee -->
<div class="marquee" aria-hidden="true">
<div class="marquee-track">
<div class="mq-set">
<span>Hand-brazed steel frames</span><i></i>
<span>Built to order in København</span><i></i>
<span>Marine-ply cargo boxes</span><i></i>
<span>5-year frame warranty</span><i></i>
<span>Test rides every Saturday</span><i></i>
<span>Standard parts, serviceable anywhere</span><i></i>
</div>
<div class="mq-set">
<span>Hand-brazed steel frames</span><i></i>
<span>Built to order in København</span><i></i>
<span>Marine-ply cargo boxes</span><i></i>
<span>5-year frame warranty</span><i></i>
<span>Test rides every Saturday</span><i></i>
<span>Standard parts, serviceable anywhere</span><i></i>
</div>
</div>
</div>
</section>
<!-- ============ MANIFESTO ============ -->
<section class="section manifesto">
<div class="wrap manifesto-grid">
<div data-reveal>
<p class="kicker mono">01 — The workshop</p>
<p class="big-quote">We build around <em>thirty bicycles a year.</em> Not because we can't build more — because each one is measured, brazed and finished for the person who will ride it.</p>
<div class="sig"><span class="sig-line"></span><span>Marie & Jonas · Founders</span></div>
</div>
<div class="stats" data-reveal style="--d:.15s">
<div class="stat"><b><span data-count="312">0</span></b><span>Bikes built since 2016</span></div>
<div class="stat"><b><span data-count="41">0</span><sup>h</sup></b><span>Hours in every frame</span></div>
<div class="stat"><b><span data-count="5">0</span><sup>yr</sup></b><span>Frame warranty</span></div>
<div class="stat"><b><span data-count="9">0</span></b><span>Years on Refshaleøen</span></div>
</div>
</div>
</section>
<!-- ============ MODELS ============ -->
<section class="section" id="models">
<div class="wrap">
<p class="kicker mono" data-reveal>02 — The models</p>
<h2 data-reveal>Three starting points.<br><em>Infinite variations.</em></h2>
<p class="lead" data-reveal style="--d:.1s">Every Lumen begins as one of three platforms, then becomes entirely yours — geometry, colour, box layout and components are all chosen with you, for you.</p>
<div class="models-grid">
<article class="model-card" data-reveal>
<span class="tag">The city one</span>
<svg class="model-icon" viewBox="0 0 160 96" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="36" cy="66" r="20"/><circle cx="122" cy="68" r="16"/>
<path d="M36 66 L66 34 M36 66 L72 64 M66 34 L72 64 M72 64 L112 62 M66 34 L108 40 M108 40 L112 62 M122 68 L118 50" stroke="#B4551F"/>
<path d="M66 34 L63 24 M56 24 Q63 21 72 23"/>
<path d="M108 40 L104 28 M104 28 Q96 25 90 27"/>
<path d="M74 44 H108 L112 62 H78 Z" stroke="#B4551F"/>
</svg>
<h3>Kompakt</h3>
<p>A short-wheelbase hauler for tight bike lanes and basement storage. One child, the weekly shop, or a very relaxed dog.</p>
<ul class="specs">
<li>Platform <b>60 cm</b></li>
<li>Payload <b>100 kg</b></li>
<li>Weight <b>24 kg</b></li>
</ul>
<div class="price-row"><span class="from">From</span><span class="price">€2,950</span></div>
<a class="text-link" href="#configure" data-model="kompakt">Configure <i></i></a>
</article>
<article class="model-card" data-reveal style="--d:.12s">
<span class="tag">The classic</span>
<svg class="model-icon" viewBox="0 0 160 96" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="30" cy="66" r="20"/><circle cx="134" cy="70" r="14"/>
<path d="M30 66 L60 34 M30 66 L66 64 M60 34 L66 64 M66 64 L126 60 M60 34 L122 40 M122 40 L126 60 M134 70 L131 54" stroke="#B4551F"/>
<path d="M60 34 L57 24 M50 24 Q57 21 66 23"/>
<path d="M122 40 L118 28 M118 28 Q110 25 104 27"/>
<path d="M66 40 H120 L126 62 H70 Z" stroke="#B4551F"/>
<path d="M80 40 V62 M98 40 V62" opacity=".5"/>
</svg>
<h3>Longjohn Standard</h3>
<p>The Copenhagen workhorse. Two wheels, an 85 cm box, and room for two children plus everything they insist on bringing.</p>
<ul class="specs">
<li>Box <b>85 cm</b></li>
<li>Payload <b>120 kg</b></li>
<li>Weight <b>27 kg</b></li>
</ul>
<div class="price-row"><span class="from">From</span><span class="price">€3,450</span></div>
<a class="text-link" href="#configure" data-model="longjohn">Configure <i></i></a>
</article>
<article class="model-card" data-reveal style="--d:.24s">
<span class="tag">The family bus</span>
<svg class="model-icon" viewBox="0 0 160 96" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="28" cy="66" r="20"/><circle cx="116" cy="72" r="12"/><circle cx="142" cy="72" r="12"/>
<path d="M28 66 L58 34 M28 66 L64 64 M58 34 L64 64 M64 64 L118 58 M58 34 L114 40 M114 40 L118 58 M116 72 L116 58 M142 72 L142 58 M116 72 H142" stroke="#B4551F"/>
<path d="M58 34 L55 24 M48 24 Q55 21 64 23"/>
<path d="M114 40 L110 28 M110 28 Q102 25 96 27"/>
<path d="M64 38 H118 L124 62 H68 Z" stroke="#B4551F"/>
<path d="M82 38 V62 M102 38 V62" opacity=".5"/>
</svg>
<h3>Trike Classic</h3>
<p>Three wheels, a full metre of box, and rock-solid stability at standstill. Carries up to four children — or one piano, once.</p>
<ul class="specs">
<li>Box <b>100 cm</b></li>
<li>Payload <b>150 kg</b></li>
<li>Weight <b>34 kg</b></li>
</ul>
<div class="price-row"><span class="from">From</span><span class="price">€3,980</span></div>
<a class="text-link" href="#configure" data-model="trike">Configure <i></i></a>
</article>
</div>
</div>
</section>
<!-- ============ CONFIGURATOR ============ -->
<section class="section configurator" id="configure">
<div class="wrap">
<p class="kicker mono" data-reveal>03 — Configure</p>
<h2 data-reveal>Build yours, <em>roughly.</em></h2>
<p class="lead" data-reveal style="--d:.1s">This is a sketch, not a checkout. The real decisions happen over coffee at the workshop — but this gives you an honest starting price.</p>
<div class="cfg-grid">
<div class="cfg-preview" data-reveal>
<div class="cfg-stage">
<span class="badge" id="cfgBadge">Longjohn Standard · Forest green</span>
<svg class="cfg-svg" id="cfgSvg" viewBox="0 0 820 430" role="img" aria-label="Preview of your configured cargo bike">
<path d="M30 392 H790" stroke="#1C1B17" stroke-width="2" opacity=".3" fill="none"/>
<!-- rear wheel -->
<g class="part">
<circle cx="160" cy="312" r="80" stroke-width="5"/>
<g class="spoke"><path d="M160 312 L240 312 M160 312 L224.7 265 M160 312 L184.7 235.9 M160 312 L135.3 235.9 M160 312 L95.3 265 M160 312 L80 312 M160 312 L95.3 359 M160 312 L135.3 388.1 M160 312 L184.7 388.1 M160 312 L224.7 359"/></g>
<circle cx="160" cy="312" r="7" fill="#1C1B17" stroke="none"/>
<path d="M80 312 A80 80 0 0 1 240 312" stroke-width="3"/>
</g>
<!-- two-wheel front -->
<g class="g on" id="g-two">
<g class="part">
<circle cx="668" cy="330" r="62" stroke-width="5"/>
<g class="spoke"><path d="M668 330 L730 330 M668 330 L711.8 286.2 M668 330 L668 268 M668 330 L624.2 286.2 M668 330 L606 330 M668 330 L624.2 373.8 M668 330 L668 392 M668 330 L711.8 373.8"/></g>
<circle cx="668" cy="330" r="6" fill="#1C1B17" stroke="none"/>
<path d="M606 330 A62 62 0 0 1 730 330" stroke-width="3"/>
<path class="f" d="M668 330 L662 272"/>
<path class="thin" d="M607 278 L663 274"/>
</g>
</g>
<!-- trike front -->
<g class="g" id="g-trike">
<g class="part">
<circle cx="612" cy="342" r="50" stroke-width="5"/>
<circle cx="724" cy="342" r="50" stroke-width="5"/>
<g class="spoke">
<path d="M612 342 L662 342 M612 342 L637 298.7 M612 342 L587 298.7 M612 342 L562 342 M612 342 L587 385.3 M612 342 L637 385.3"/>
<path d="M724 342 L774 342 M724 342 L749 298.7 M724 342 L699 298.7 M724 342 L674 342 M724 342 L699 385.3 M724 342 L749 385.3"/>
</g>
<circle cx="612" cy="342" r="6" fill="#1C1B17" stroke="none"/>
<circle cx="724" cy="342" r="6" fill="#1C1B17" stroke="none"/>
<path class="f" d="M612 342 H724 M668 342 L662 272"/>
<path class="thin" d="M607 278 L663 274"/>
</g>
</g>
<!-- frame -->
<g class="part f">
<path d="M160 312 L318 292 M160 312 L268 190 M268 190 L318 292 M318 292 L606 280 M268 190 L596 236 M596 236 L606 280 M596 236 L584 178"/>
</g>
<g class="part">
<path d="M584 178 Q562 169 540 174"/>
<path d="M540 174 L525 180" stroke-width="6"/>
<path d="M268 190 L262 168"/>
<path d="M240 166 Q262 157 286 163" stroke-width="5"/>
<circle cx="318" cy="292" r="17" stroke-width="3"/>
<path class="thin" d="M318 275 L162 306 M318 309 L162 318" opacity=".7"/>
<path d="M318 292 L342 318"/>
<path d="M332 320 h20" stroke-width="5"/>
<path class="thin" d="M305 330 L291 392"/>
<circle cx="655" cy="298" r="5" fill="#B4551F" stroke="none"/>
</g>
<!-- big box -->
<g class="g on" id="g-boxbig">
<path class="boxfill" d="M352 226 H592 L606 322 H364 Z"/>
<path class="boxline" d="M356 256 H597 M360 289 H601 M430 226 V322 M500 226 V322 M565 226 V322"/>
</g>
<!-- small box -->
<g class="g" id="g-boxsmall">
<path class="boxfill" d="M432 248 H592 L604 322 H444 Z"/>
<path class="boxline" d="M436 273 H596 M440 298 H600 M492 248 V322 M548 248 V322"/>
</g>
<!-- bench -->
<g class="g" id="g-bench">
<path d="M392 268 H560 M402 268 V300 M550 268 V300" stroke="#1C1B17" stroke-width="3.5" fill="none" stroke-linecap="round"/>
</g>
<!-- canopy -->
<g class="g" id="g-canopy">
<path d="M356 226 Q474 112 592 226 Z" fill="rgba(28,27,23,.07)" stroke="#1C1B17" stroke-width="3" stroke-linejoin="round"/>
<path d="M474 128 V226" stroke="#1C1B17" stroke-width="1.6" opacity=".4" fill="none"/>
</g>
<!-- motor -->
<g class="g" id="g-motor">
<rect x="430" y="252" width="92" height="26" rx="13" transform="rotate(-2 476 265)" fill="#1C1B17"/>
<path d="M478 258 l-8 9 h7 l-4 9 11 -11 h-7 z" fill="#F5F1E7"/>
</g>
</svg>
</div>
<div class="cfg-total">
<div>
<span class="lbl">Estimated total</span>
<div class="amt" id="cfgTotal">€3,450</div>
</div>
<div class="meta">
<div>Deposit <b id="cfgDeposit">€690</b></div>
<div>or <b id="cfgMonthly">€96</b>/mo × 36</div>
<div>Lead time <b id="cfgLead">8–10 weeks</b></div>
</div>
</div>
</div>
<div data-reveal style="--d:.15s">
<div class="cfg-group">
<div class="cfg-label"><span class="t">Platform</span><span class="v" id="modelName">Longjohn Standard</span></div>
<div class="seg" role="group" aria-label="Choose platform">
<button type="button" data-model-btn="kompakt" aria-pressed="false"><b>Kompakt</b><span>€2,950</span></button>
<button type="button" data-model-btn="longjohn" aria-pressed="true"><b>Longjohn</b><span>€3,450</span></button>
<button type="button" data-model-btn="trike" aria-pressed="false"><b>Trike</b><span>€3,980</span></button>
</div>
</div>
<div class="cfg-group">
<div class="cfg-label"><span class="t">Frame colour</span><span class="v" id="colorName">Forest green</span></div>
<div class="swatches" role="group" aria-label="Choose frame colour">
<button type="button" class="swatch" data-color="ink" aria-pressed="false" aria-label="Ink black"><i style="background:#232220"></i></button>
<button type="button" class="swatch" data-color="forest" aria-pressed="true" aria-label="Forest green"><i style="background:#2E4B3A"></i></button>
<button type="button" class="swatch" data-color="clay" aria-pressed="false" aria-label="Burnt clay"><i style="background:#B4551F"></i></button>
<button type="button" class="swatch" data-color="cream" aria-pressed="false" aria-label="Cream"><i style="background:#E7DEC9"></i></button>
<button type="button" class="swatch" data-color="navy" aria-pressed="false" aria-label="Midnight blue"><i style="background:#2C3A56"></i></button>
</div>
</div>
<div class="cfg-group">
<div class="cfg-label"><span class="t">Options</span></div>
<div class="addons">
<button type="button" class="addon" data-addon="electric" aria-pressed="false">
<span><span class="n">Electric assist</span><br><span class="p">250W mid-drive · 90 km</span></span>
<span class="p">+€1,250</span>
<span class="tick"><svg width="10" height="8" viewBox="0 0 10 8" fill="none" stroke="#fff" stroke-width="2"><path d="M1 4l3 3 5-6"/></svg></span>
</button>
<button type="button" class="addon" data-addon="canopy" aria-pressed="false" id="addonCanopy">
<span><span class="n">Rain canopy</span><br><span class="p">Waterproof canvas</span></span>
<span class="p">+€240</span>
<span class="tick"><svg width="10" height="8" viewBox="0 0 10 8" fill="none" stroke="#fff" stroke-width="2"><path d="M1 4l3 3 5-6"/></svg></span>
</button>
<button type="button" class="addon" data-addon="bench" aria-pressed="false" id="addonBench">
<span><span class="n">Child bench + belts</span><br><span class="p">Two 3-point harnesses</span></span>
<span class="p">+€190</span>
<span class="tick"><svg width="10" height="8" viewBox="0 0 10 8" fill="none" stroke="#fff" stroke-width="2"><path d="M1 4l3 3 5-6"/></svg></span>
</button>
<button type="button" class="addon" data-addon="saddle" aria-pressed="false">
<span><span class="n">Leather saddle</span><br><span class="p">Hand-stitched, cognac</span></span>
<span class="p">+€130</span>
<span class="tick"><svg width="10" height="8" viewBox="0 0 10 8" fill="none" stroke="#fff" stroke-width="2"><path d="M1 4l3 3 5-6"/></svg></span>
</button>
<button type="button" class="addon" data-addon="lock" aria-pressed="false">
<span><span class="n">Frame lock + chain</span><br><span class="p">ART-2 certified</span></span>
<span class="p">+€85</span>
<span class="tick"><svg width="10" height="8" viewBox="0 0 10 8" fill="none" stroke="#fff" stroke-width="2"><path d="M1 4l3 3 5-6"/></svg></span>
</button>
</div>
</div>
<p class="cfg-summary" id="cfgSummary">Longjohn Standard · Forest green · No extras</p>
<button class="btn accent" id="reserveBtn" style="width:100%;justify-content:center">Reserve a build slot
<svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M1 5h11M8 1l4 4-4 4"/></svg>
</button>
<p style="font-size:12px;color:var(--ink-50);margin-top:14px">20% deposit, fully refundable for 14 days. Final specification and price are confirmed together at the workshop before any tube is cut.</p>
</div>
</div>
</div>
</section>
<!-- ============ PROCESS ============ -->
<section class="section" id="process">
<div class="wrap">
<p class="kicker mono" data-reveal>04 — The process</p>
<h2 data-reveal>From first coffee<br><em>to first ride.</em></h2>
<div class="steps">
<div class="step" data-reveal>
<h3>Conversation</h3>
<p>Thirty minutes, in person or by phone. Kids, hills, parking, budget — we listen more than we talk, and we'll tell you honestly if a Lumen isn't right for you.</p>
<span class="dur">Free · 30 min</span>
</div>
<div class="step" data-reveal style="--d:.1s">
<h3>Fitting & drawing</h3>
<p>We measure you, draw your frame in CAD, and agree every component and colour. You sign the drawing; we take a 20% deposit.</p>
<span class="dur">1–2 weeks</span>
</div>
<div class="step" data-reveal style="--d:.2s">
<h3>The build</h3>
<p>Tubes are cut, mitred and fillet-brazed. Your box is glued, screwed and oiled. You get photos every Friday — most customers frame them.</p>
<span class="dur">6–10 weeks</span>
</div>
<div class="step" data-reveal style="--d:.3s">
<h3>Handover</h3>
<p>A final fitting, a handling lesson in the courtyard, and your service book. The first 500 km service is on us, forever part of the deal.</p>
<span class="dur">One good morning</span>
</div>
</div>
</div>
</section>
<!-- ============ CRAFT ============ -->
<section class="section craft" id="craft">
<div class="wrap">
<p class="kicker mono" data-reveal>05 — The craft</p>
<h2 data-reveal>Built like we have to<br><em>answer for it. Because we do.</em></h2>
<p class="lead" data-reveal style="--d:.1s">Copenhagen is flat, salty and wet. We build for exactly that — and for the second owner, and the third.</p>
<div class="craft-grid">
<div class="craft-card" data-reveal>
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round"><path d="M15 3 C18 8 22 10 22 17 a7 7 0 1 1 -14 0 C8 10 12 8 15 3 Z"/><path d="M15 14 c1.5 2.5 3 3.5 3 6 a3 3 0 1 1 -6 0 c0 -2.5 1.5 -3.5 3 -6z"/></svg>
<h3>Fillet-brazed chromoly</h3>
<p>Double-butted steel tubes, brazed by hand at low heat. Lighter than lugged, kinder to the metal than TIG, and repairable for decades.</p>
</div>
<div class="craft-card" data-reveal style="--d:.08s">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round"><rect x="4" y="7" width="22" height="16" rx="1"/><path d="M4 12.5 H26 M4 18 H26 M11 7 V23 M19 7 V23"/></svg>
<h3>Marine-ply boxes</h3>
<p>Nine-ply FSC birch, the same grade used in boat hulls. Glued, screwed, edge-sealed and oiled — it shrugs off a Danish winter.</p>
</div>
<div class="craft-card" data-reveal style="--d:.16s">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3 L25 7 V14 c0 7 -4.5 11 -10 13 C9.5 25 5 21 5 14 V7 Z"/><path d="M10.5 14.5 l3 3 6 -6.5"/></svg>
<h3>A five-year promise</h3>
<p>Five years on the frame, two on everything we bolt to it. If a braze ever fails, we re-braze it free — it hasn't happened yet.</p>
</div>
<div class="craft-card" data-reveal>
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round"><path d="M20 4 a7 7 0 1 0 6 10 L17 23 H10 V16 Z"/><circle cx="21" cy="9" r="2"/></svg>
<h3>Standard parts only</h3>
<p>No proprietary anything. Shimano drivetrains, standard bearings, common spokes — any good shop on Earth can keep a Lumen rolling.</p>
</div>
<div class="craft-card" data-reveal style="--d:.08s">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 3 L7 17 h6 l-1 10 L23 12 h-6 Z"/></svg>
<h3>Electric, if you want it</h3>
<p>A 250W mid-drive with a 500Wh battery, good for roughly 90 km. Integrated into the frame at build time — never strapped on after.</p>
</div>
<div class="craft-card" data-reveal style="--d:.16s">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" stroke="#E0A37E" stroke-width="1.8" stroke-linecap="round"><path d="M15 4 c4 6 8 9 8 14 a8 8 0 1 1 -16 0 c0 -5 4 -8 8 -14z"/><path d="M11 19 a4 4 0 0 0 4 4"/></svg>
<h3>70-micron powder coat</h3>
<p>Blasted, primed and powder-coated matte, twice the thickness of wet paint. Chips touch up invisibly with the bottle we include.</p>
</div>
</div>
<div class="warranty" data-reveal>
<b>“If you maintain it, your grandchildren <em>will fight over it.”</em></b>
<span>— Jonas, head builder, after his third coffee</span>
</div>
</div>
</section>
<!-- ============ TESTIMONIALS ============ -->
<section class="section" id="stories">
<div class="wrap">
<div class="t-head">
<div>
<p class="kicker mono" data-reveal>06 — Stories</p>
<h2 data-reveal>312 bikes.<br><em>312 households, changed.</em></h2>
</div>
<div class="t-nav" data-reveal>
<button class="t-btn" id="tPrev" aria-label="Previous story"><svg width="16" height="12" viewBox="0 0 16 12" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M15 6H1M6 1L1 6l5 5"/></svg></button>
<button class="t-btn" id="tNext" aria-label="Next story"><svg width="16" height="12" viewBox="0 0 16 12" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M1 6h14M10 1l5 5-5 5"/></svg></button>
</div>
</div>
<div class="t-viewport" data-reveal>
<div class="t-track" id="tTrack">
<div class="t-slide">
<p class="t-quote">“Our Longjohn replaced a second car. Two years, 6,000 kilometres, one set of brake pads. Marie still calls to ask <em>how the kids like the box.”</em></p>
<div class="t-meta">
<span class="t-ava">F</span>
<div><b>Freja Lindqvist</b><span>Østerbro · Longjohn Standard, 2023</span></div>
<span class="t-stars" aria-label="5 out of 5 stars">
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
</span>
</div>
</div>
<div class="t-slide">
<p class="t-quote">“I test-rode three cargo bikes before Lumen. The others felt like appliances. This one felt like <em>it had been waiting for me.”</em></p>
<div class="t-meta">
<span class="t-ava">M</span>
<div><b>Mikkel Andersen</b><span>Vesterbro · Kompakt, 2024</span></div>
<span class="t-stars" aria-label="5 out of 5 stars">
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
</span>
</div>
</div>
<div class="t-slide">
<p class="t-quote">“Two kids, one dog, the Saturday market run. The Trike carries all of it, and Jonas re-brazed a fender mount for free <em>when I crashed it into a bollard.”</em></p>
<div class="t-meta">
<span class="t-ava">S</span>
<div><b>Sara & Thomas Holm</b><span>Nørrebro · Trike Classic, 2022</span></div>
<span class="t-stars" aria-label="5 out of 5 stars">
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="#B4551F"><path d="M7.5 0l1.8 4.9H15l-4 3.2 1.5 5L7.5 9.9 2.5 13l1.5-5-4-3.1h5.7z"/></svg>
</span>
</div>
</div>
</div>
</div>
<div class="t-dots" id="tDots" role="tablist" aria-label="Choose story"></div>
</div>
</section>
<!-- ============ FAQ ============ -->
<section class="section" id="faq" style="padding-top:0">
<div class="wrap">
<p class="kicker mono" data-reveal>07 — Questions</p>
<h2 data-reveal>Asked often,<br><em>answered honestly.</em></h2>
<div class="faq-wrap">
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">How long does a build actually take?
<span class="ic"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 1v10M1 6h10"/></svg></span>
</button>
<div class="faq-a"><p>Six to twelve weeks depending on platform and season. Spring is our busiest time — order in January and you'll be riding by Easter. We give you a firm date at deposit, and we've missed exactly two in nine years.</p></div>
</div>
<div class="faq-item" data-reveal style="--d:.05s">
<button class="faq-q" aria-expanded="false">Is the deposit refundable?
<span class="ic"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 1v10M1 6h10"/></svg></span>
</button>
<div class="faq-a"><p>Fully, for 14 days after you pay it. After that we begin ordering your components, and the deposit becomes non-refundable — but transferable, if life changes and a friend wants your slot.</p></div>
</div>
<div class="faq-item" data-reveal style="--d:.1s">
<button class="faq-q" aria-expanded="false">Do you deliver outside Denmark?
<span class="ic"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 1v10M1 6h10"/></svg></span>
</button>
<div class="faq-a"><p>Yes. We crate and freight anywhere in the EU, typically €180–350 depending on distance. Roughly one in five Lumens lives abroad — there are three in Amsterdam that we know of, which feels like a compliment.</p></div>
</div>
<div class="faq-item" data-reveal style="--d:.15s">
<button class="faq-q" aria-expanded="false">What does the warranty really cover?
<span class="ic"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 1v10M1 6h10"/></svg></span>
</button>
<div class="faq-a"><p>Five years on frame and fork, two years on parts and box, against anything that is our fault. Crashes, bollards and creative children are not covered — but bring it in anyway. We repair at cost, and the coffee is free.</p></div>
</div>
<div class="faq-item" data-reveal style="--d:.2s">
<button class="faq-q" aria-expanded="false">Can I test ride before deciding?
<span class="ic"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 1v10M1 6h10"/></svg></span>
</button>
<div class="faq-a"><p>Every Saturday, 10:00–14:00, all three platforms, no appointment needed. Bring the kids — the box is the thing they're supposed to test. We keep helmets, and the harbour loop behind the workshop is flat and car-free.</p></div>
</div>
</div>
</div>
</section>
<!-- ============ VISIT ============ -->
<section class="section visit" id="visit">
<div class="wrap">
<p class="kicker mono" data-reveal>08 — Visit</p>
<h2 data-reveal>Come see the sparks.<br><em>Literally, most Tuesdays.</em></h2>
<div class="visit-grid">
<div class="map-card" data-reveal>
<svg viewBox="0 0 400 300" role="img" aria-label="Stylised map showing the workshop location by the harbour">
<rect width="400" height="300" fill="#EDE6D6"/>
<path d="M0 190 C60 170 90 210 150 195 C210 180 240 220 300 205 C340 195 370 210 400 200 L400 300 L0 300 Z" fill="#C6D6CC"/>
<path d="M0 190 C60 170 90 210 150 195 C210 180 240 220 300 205 C340 195 370 210 400 200" fill="none" stroke="#9DB5A6" stroke-width="1.5"/>
<g stroke="#D8CDB8" stroke-width="2" fill="none">
<path d="M40 0 V190 M110 0 V185 M180 0 V180 M250 0 V185 M320 0 V190"/>
<path d="M0 50 H400 M0 110 H400 M0 150 H400"/>
</g>
<g stroke="#B4551F" stroke-width="2.5" fill="none">
<path d="M40 110 H180 V50 M180 110 H320"/>
</g>
<circle cx="180" cy="110" r="26" fill="none" stroke="#B4551F" stroke-width="1.5" class="pin-pulse"/>
<circle cx="180" cy="110" r="8" fill="#B4551F"/>
<circle cx="180" cy="110" r="3" fill="#F5F1E7"/>
<text x="200" y="100" font-family="ui-monospace,Menlo,monospace" font-size="10" letter-spacing="2" fill="#1C1B17">LUMEN CYCLES</text>
<text x="200" y="116" font-family="ui-monospace,Menlo,monospace" font-size="9" letter-spacing="1.5" fill="rgba(28,27,23,.55)">REFSHALEVEJ 163A</text>
<text x="20" y="262" font-family="ui-monospace,Menlo,monospace" font-size="9" letter-spacing="2" fill="rgba(28,27,23,.45)">KØBENHAVNS HAVN</text>
</svg>
<div class="visit-info">
<div>
<h4>Workshop</h4>
<p>Refshalevej 163A<br>1432 København K</p>
</div>
<div>
<h4>Hours</h4>
<p>Tue–Fri 9–17<br>Sat 10–14 · Sun & Mon closed</p>
</div>
<div>
<h4>Contact</h4>
<p>+45 33 55 16 40<br>hej@lumencycles.dk</p>
</div>
<div>
<h4>Test rides</h4>
<p>Every Saturday<br>No booking needed</p>
</div>
</div>
</div>
<form class="form-card" id="rideForm" data-reveal style="--d:.12s" novalidate>
<div class="form-body">
<h3>Book a test ride</h3>
<p>Tell us who you are and what you're curious about. We reply within one working day — usually faster.</p>
<div class="f-row">
<div class="f-field">
<label for="f-name">Name</label>
<input id="f-name" name="name" type="text" autocomplete="name" required placeholder="Your name">
</div>
<div class="f-field">
<label for="f-email">Email</label>
<input id="f-email" name="email" type="email" autocomplete="email" required placeholder="you@example.dk">
</div>
</div>
<div class="f-field">
<label for="f-model">Interested in</label>
<select id="f-model" name="model">
<option>Not sure yet</option>
<option>Kompakt</option>
<option selected>Longjohn Standard</option>
<option>Trike Classic</option>
</select>
</div>
<div class="f-field">
<label for="f-msg">Anything we should know?</label>
<textarea id="f-msg" name="message" placeholder="Two kids, a steep bridge, a narrow shed…"></textarea>
</div>
<button class="btn accent" type="submit">Request my test ride
<svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M1 5h11M8 1l4 4-4 4"/></svg>
</button>
<p style="font-size:11.5px;color:rgba(245,241,231,.45);margin-top:14px">No newsletter, no spam. We write back like humans, because we are two.</p>
</div>
<div class="form-done" role="status">
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" stroke="#E0A37E" stroke-width="2"><circle cx="28" cy="28" r="26"/><path d="M17 29l8 8 14-16" stroke-linecap="round" stroke-linejoin="round"/></svg>
<h4>Tak — we've got it.</h4>
<p>Marie or Jonas will write back within one working day to find a time. Looking forward to meeting you.</p>
</div>
</form>
</div>
</div>
</section>
</main>
<!-- ============ FOOTER ============ -->
<footer>
<div class="wrap">
<div class="foot-grid">
<div class="foot-brand">
<a class="brand" href="#top" style="text-decoration:none">
<svg width="40" height="26" viewBox="0 0 40 26" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<circle cx="8" cy="18" r="6.5"/><circle cx="33" cy="18" r="5"/>
<path d="M8 18 L17 6 H27 M17 6 L21 18 H33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M27 6 L30 12" stroke-linecap="round"/>
</svg>
<span><span class="brand-name">Lumen <em>Cycles</em></span><span class="brand-sub" style="color:rgba(245,241,231,.4)">København</span></span>
</a>
<p>A two-person workshop building made-to-order cargo bikes on Refshaleøen since 2016. Steel, wood, and patience.</p>
</div>
<div>
<h5>Explore</h5>
<ul>
<li><a href="#models">Models</a></li>
<li><a href="#configure">Configure</a></li>
<li><a href="#process">Process</a></li>
<li><a href="#craft">Craft</a></li>
</ul>
</div>
<div>
<h5>Practical</h5>
<ul>
<li><a href="#faq">FAQ</a></li>
<li><a href="#visit">Test rides</a></li>
<li><a href="#visit">Delivery & warranty</a></li>
<li><a href="#stories">Stories</a></li>
</ul>
</div>
<div>
<h5>Workshop</h5>
<ul>
<li><a href="#visit">Refshalevej 163A</a></li>
<li><a href="#visit">+45 33 55 16 40</a></li>
<li><a href="#visit">hej@lumencycles.dk</a></li>
<li><a href="#top">Back to top</a></li>
</ul>
</div>
</div>
<div class="foot-bar">
<span>© 2025 Lumen Cycles ApS · CVR 38 47 21 95</span>
<span>Hand-built in København — this page included</span>
</div>
</div>
</footer>
<script>
(function(){
"use strict";
var RM = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- grain (runtime canvas, no network) ---------- */
try{
var c = document.createElement("canvas"); c.width = c.height = 128;
var g = c.getContext("2d"), d = g.createImageData(128,128);
for(var i=0;i<d.data.length;i+=4){ var v = Math.random()*255|0; d.data[i]=d.data[i+1]=d.data[i+2]=v; d.data[i+3]=255; }
g.putImageData(d,0,0);
document.getElementById("grain").style.backgroundImage = "url("+c.toDataURL()+")";
}catch(e){}
/* ---------- load-in ---------- */
window.addEventListener("DOMContentLoaded", function(){ document.body.classList.add("loaded"); });
/* ---------- header + progress + parallax ---------- */
var header = document.getElementById("header"),
progress = document.getElementById("progress"),
heroSvg = document.getElementById("heroSvg"),
ticking = false;
function onScroll(){
var y = window.scrollY;
header.classList.toggle("scrolled", y > 40);
var h = document.documentElement.scrollHeight - window.innerHeight;
progress.style.width = (h > 0 ? (y/h)*100 : 0) + "%";
if(!RM && heroSvg && y < window.innerHeight){
heroSvg.style.transform = "translateY(" + (y*0.07) + "px)";
}
ticking = false;
}
window.addEventListener("scroll", function(){
if(!ticking){ requestAnimationFrame(onScroll); ticking = true; }
}, {passive:true});
onScroll();
/* ---------- reveal on scroll ---------- */
var io = new IntersectionObserver(function(entries){
entries.forEach(function(en){
if(en.isIntersecting){ en.target.classList.add("in"); io.unobserve(en.target); }
});
},{threshold:.12, rootMargin:"0px 0px -40px 0px"});
document.querySelectorAll("[data-reveal]").forEach(function(el){ io.observe(el); });
/* ---------- counters ---------- */
function animateCount(el){
var target = parseInt(el.getAttribute("data-count"),10);
if(RM){ el.textContent = target; return; }
var start = null, dur = 1400;
function step(ts){
if(!start) start = ts;
var p = Math.min((ts-start)/dur, 1);
var e = 1 - Math.pow(1-p, 3);
el.textContent = Math.round(target*e);
if(p<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
var cio = new IntersectionObserver(function(entries){
entries.forEach(function(en){
if(en.isIntersecting){ animateCount(en.target); cio.unobserve(en.target); }
});
},{threshold:.5});
document.querySelectorAll("[data-count]").forEach(function(el){ cio.observe(el); });
/* ---------- configurator ---------- */
var MODELS = {
kompakt: {name:"Kompakt", price:2950, lead:"6–8 weeks"},
longjohn: {name:"Longjohn Standard", price:3450, lead:"8–10 weeks"},
trike: {name:"Trike Classic", price:3980, lead:"10–12 weeks"}
};
var COLORS = {
ink: {name:"Ink black", hex:"#232220"},
forest:{name:"Forest green", hex:"#2E4B3A"},
clay: {name:"Burnt clay", hex:"#B4551F"},
cream: {name:"Cream", hex:"#D8CBAF"},
navy: {name:"Midnight blue", hex:"#2C3A56"}
};
var ADDONS = {
electric:{name:"Electric assist", price:1250},
canopy: {name:"Rain canopy", price:240},
bench: {name:"Child bench", price:190},
saddle: {name:"Leather saddle", price:130},
lock: {name:"Frame lock", price:85}
};
var state = { model:"longjohn", color:"forest", electric:false, canopy:false, bench:false, saddle:false, lock:false };
var svg = document.getElementById("cfgSvg");
function fmt(n){ return "€" + n.toLocaleString("en-US"); }
function setGroup(id, on){ document.getElementById(id).classList.toggle("on", !!on); }
function updateCfg(){
var m = MODELS[state.model], total = m.price, extras = [];
Object.keys(ADDONS).forEach(function(k){
if(state[k]){ total += ADDONS[k].price; extras.push(ADDONS[k].name); }
});
document.getElementById("cfgTotal").textContent = fmt(total);
document.getElementById("cfgDeposit").textContent = fmt(Math.round(total*0.2));
document.getElementById("cfgMonthly").textContent = fmt(Math.round(total/36));
document.getElementById("cfgLead").textContent = m.lead;
document.getElementById("modelName").textContent = m.name;
document.getElementById("colorName").textContent = COLORS[state.color].name;
document.getElementById("cfgBadge").textContent = m.name + " · " + COLORS[state.color].name;
document.getElementById("cfgSummary").textContent =
m.name + " · " + COLORS[state.color].name + " · " + (extras.length ? extras.join(" · ") : "No extras") + " — " + fmt(total);
svg.style.setProperty("--frame", COLORS[state.color].hex);
setGroup("g-two", state.model !== "trike");
setGroup("g-trike", state.model === "trike");
setGroup("g-boxbig", state.model !== "kompakt");
setGroup("g-boxsmall", state.model === "kompakt");
setGroup("g-canopy", state.canopy);
setGroup("g-bench", state.bench);
setGroup("g-motor", state.electric);
var bigBox = state.model !== "kompakt";
document.getElementById("addonCanopy").disabled = !bigBox;
document.getElementById("addonBench").disabled = !bigBox;
}
document.querySelectorAll("[data-model-btn]").forEach(function(btn){
btn.addEventListener("click", function(){
state.model = btn.getAttribute("data-model-btn");
if(state.model === "kompakt"){ state.canopy = false; state.bench = false;
document.querySelector('[data-addon="canopy"]').setAttribute("aria-pressed","false");
document.querySelector('[data-addon="bench"]').setAttribute("aria-pressed","false");
}
document.querySelectorAll("[data-model-btn]").forEach(function(b){
b.setAttribute("aria-pressed", b===btn ? "true" : "false");
});
updateCfg();
});
});
document.querySelectorAll(".swatch").forEach(function(sw){
sw.addEventListener("click", function(){
state.color = sw.getAttribute("data-color");
document.querySelectorAll(".swatch").forEach(function(s){
s.setAttribute("aria-pressed", s===sw ? "true" : "false");
});
updateCfg();
});
});
document.querySelectorAll(".addon").forEach(function(ad){
ad.addEventListener("click", function(){
if(ad.disabled) return;
var k = ad.getAttribute("data-addon");
state[k] = !state[k];
ad.setAttribute("aria-pressed", state[k] ? "true" : "false");
updateCfg();
});
});
/* model card shortcuts */
document.querySelectorAll("[data-model]").forEach(function(link){
link.addEventListener("click", function(){
var btn = document.querySelector('[data-model-btn="'+link.getAttribute("data-model")+'"]');
if(btn) btn.click();
});
});
/* reserve → prefill form */
document.getElementById("reserveBtn").addEventListener("click", function(){
var sel = document.getElementById("f-model");
var map = {kompakt:"Kompakt", longjohn:"Longjohn Standard", trike:"Trike Classic"};
sel.value = map[state.model];
document.getElementById("f-msg").value =
"Hej Lumen — I'd like to reserve a build slot.\n" + document.getElementById("cfgSummary").textContent;
document.getElementById("visit").scrollIntoView({behavior: RM ? "auto" : "smooth"});
setTimeout(function(){ document.getElementById("f-name").focus({preventScroll:true}); }, RM ? 0 : 700);
});
updateCfg();
/* ---------- testimonial slider ---------- */
var track = document.getElementById("tTrack"),
slides = track.children.length,
dotsWrap = document.getElementById("tDots"),
idx = 0, timer = null;
for(var s=0;s<slides;s++){
var b = document.createElement("button");
b.setAttribute("aria-label","Go to story "+(s+1));
b.setAttribute("aria-current", s===0 ? "true" : "false");
(function(n){ b.addEventListener("click", function(){ go(n); restart(); }); })(s);
dotsWrap.appendChild(b);
}
function go(n){
idx = (n+slides)%slides;
track.style.transform = "translateX(-"+(idx*100)+"%)";
Array.prototype.forEach.call(dotsWrap.children, function(d,i){
d.setAttribute("aria-current", i===idx ? "true" : "false");
});
}
function restart(){
if(RM) return;
clearInterval(timer);
timer = setInterval(function(){ go(idx+1); }, 6500);
}
document.getElementById("tPrev").addEventListener("click", function(){ go(idx-1); restart(); });
document.getElementById("tNext").addEventListener("click", function(){ go(idx+1); restart(); });
var vp = document.querySelector(".t-viewport");
vp.addEventListener("pointerenter", function(){ clearInterval(timer); });
vp.addEventListener("pointerleave", restart);
restart();
/* ---------- FAQ accordion ---------- */
document.querySelectorAll(".faq-item").forEach(function(item){
var q = item.querySelector(".faq-q"), a = item.querySelector(".faq-a");
q.addEventListener("click", function(){
var open = item.classList.toggle("open");
q.setAttribute("aria-expanded", open ? "true" : "false");
a.style.maxHeight = open ? a.scrollHeight + "px" : "0px";
});
});
/* ---------- form ---------- */
document.getElementById("rideForm").addEventListener("submit", function(e){
e.preventDefault();
var name = document.getElementById("f-name"),
email = document.getElementById("f-email"),
ok = true;
[name, email].forEach(function(f){
var bad = !f.value.trim() || (f.type==="email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(f.value));
f.style.borderColor = bad ? "#E06B4C" : "";
if(bad) ok = false;
});
if(!ok) return;
this.classList.add("sent");
});
})();
</script>
</body>
</html>

