Run details
- Model
- x-ai/grok-4.7
- Route
- OpenRouter API, one user message
- Served by
- xAI
- Effort
- high, OpenRouter's default for this model
- Limits
- 60 min · 250,000 output tokens (the model's limit)
- Date
- 23 Oct 2026
- Time
- 3 min 12 s
- Size
- 42 kB
- Tokens
- 1,329 in, 19,317 out (5,574 of them thinking)
- List price
- $0.12 at today's price ($2 in / $6 out per M)
- Paid
- $0.12
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
42 kB 821 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Lumen Cycles — Custom cargo bikes, built in Copenhagen</title>
<meta name="description" content="Lumen Cycles is a Copenhagen workshop building custom cargo bikes to order. Fillet-brazed frames, a measured fitting, and a clear price from €3.900.">
<style>
:root {
--ink: #161411;
--ink-soft: #3a342c;
--paper: #f3eee6;
--paper-2: #e7e0d4;
--cream: #faf7f2;
--pine: #1b322e;
--pine-2: #274640;
--brass: #a68456;
--brass-deep: #7c623c;
--rule: rgba(22, 20, 17, 0.12);
--rule-strong: rgba(22, 20, 17, 0.28);
--cream-dim: rgba(250, 247, 242, 0.72);
--shadow: 0 24px 60px rgba(22, 20, 17, 0.12);
--serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
--sans: "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
--mono: "SFMono-Regular", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
--max: 1120px;
--nav: 72px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after {
animation: none !important;
transition: none !important;
}
}
body {
margin: 0;
color: var(--ink);
background: var(--paper);
font-family: var(--sans);
font-size: 17px;
line-height: 1.55;
text-rendering: optimizeLegibility;
}
img { max-width: 100%; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
.skip {
position: absolute;
left: 12px;
top: -40px;
background: var(--brass);
color: var(--ink);
padding: 8px 12px;
z-index: 20;
}
.skip:focus { top: 12px; }
.wrap { width: min(var(--max), calc(100% - 40px)); margin: 0 auto; }
.eyebrow {
font-family: var(--mono);
font-size: 12px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--brass-deep);
margin: 0 0 12px;
}
h1, h2, h3, .serif { font-family: var(--serif); font-weight: 500; letter-spacing: -0.02em; }
h1 { font-size: clamp(42px, 6.4vw, 78px); line-height: 0.96; margin: 0 0 18px; }
h2 { font-size: clamp(32px, 4vw, 48px); line-height: 1.05; margin: 0 0 14px; }
h3 { font-size: 26px; line-height: 1.15; margin: 0 0 8px; }
p { margin: 0 0 14px; }
.lede { font-size: 18.5px; line-height: 1.5; color: var(--ink-soft); max-width: 42rem; }
.nav {
position: sticky;
top: 0;
z-index: 10;
height: var(--nav);
display: flex;
align-items: center;
background: rgba(243, 238, 230, 0.92);
border-bottom: 1px solid var(--rule);
backdrop-filter: blur(10px);
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 20px; width: min(var(--max), calc(100% - 40px)); margin: 0 auto; }
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
.mark {
width: 34px; height: 34px; border-radius: 50%;
border: 1.5px solid var(--ink);
display: grid; place-items: center;
font-family: var(--serif); font-size: 18px;
}
.word { font-family: var(--serif); font-size: 18px; letter-spacing: 0.14em; }
.word span { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em; color: var(--ink-soft); margin-top: 1px; }
.nav-links { display: flex; align-items: center; gap: 22px; }
.nav-links a { text-decoration: none; font-size: 14.5px; }
.nav-links a:hover { text-decoration: underline; text-underline-offset: 4px; }
.nav-cta, .btn {
display: inline-flex; align-items: center; justify-content: center;
text-decoration: none; border: 1px solid transparent;
padding: 12px 16px; cursor: pointer; background: var(--pine); color: var(--cream);
font-size: 14.5px; letter-spacing: 0.01em;
}
.btn.light { background: var(--brass); color: var(--ink); }
.btn.ghost { background: transparent; color: var(--cream); border-color: rgba(250,247,242,0.4); }
.btn.ghost-ink { background: transparent; color: var(--ink); border-color: var(--rule-strong); }
.btn:hover { transform: translateY(-1px); }
.btn:focus-visible, a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
outline: 2px solid var(--brass-deep); outline-offset: 3px;
}
.menu-btn {
display: none; background: transparent; border: 1px solid var(--rule-strong);
padding: 8px 10px; cursor: pointer;
}
.hero { background: var(--pine); color: var(--cream); position: relative; overflow: hidden; }
.hero::after {
content: "LUMEN";
position: absolute; right: -2vw; bottom: -4vw;
font-family: var(--serif); font-size: 22vw; line-height: 0.8;
color: rgba(250, 247, 242, 0.04); pointer-events: none;
}
.hero-grid {
display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 40px;
padding: 64px 0 56px; align-items: end; position: relative; z-index: 1;
}
.hero .eyebrow { color: var(--brass); }
.hero .lede { color: var(--cream-dim); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 28px; }
.ticket {
display: grid; grid-template-columns: 1fr 1fr; gap: 0;
border: 1px solid rgba(250,247,242,0.22); max-width: 440px;
font-family: var(--mono); font-size: 12px; letter-spacing: 0.04em;
}
.ticket div { padding: 10px 12px; border-right: 1px solid rgba(250,247,242,0.14); border-bottom: 1px solid rgba(250,247,242,0.14); }
.ticket strong { display: block; color: var(--cream); font-weight: 560; margin-top: 3px; letter-spacing: 0; font-family: var(--sans); font-size: 13.5px; }
.ticket span { color: rgba(250,247,242,0.55); }
.bike-stage { min-height: 320px; display: grid; align-items: end; }
.bike-stage svg { width: 100%; height: auto; display: block; }
.trust {
display: grid; grid-template-columns: repeat(4, 1fr);
border-bottom: 1px solid var(--rule); background: var(--cream);
}
.trust div { padding: 18px 20px; border-right: 1px solid var(--rule); }
.trust div:last-child { border-right: 0; }
.trust b { display: block; font-family: var(--serif); font-size: 22px; font-weight: 500; }
.trust span { color: var(--ink-soft); font-size: 13.5px; }
section { padding: 84px 0; }
.split { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 56px; align-items: center; }
.workshop {
background: var(--paper-2);
border: 1px solid var(--rule);
min-height: 420px;
position: relative;
overflow: hidden;
box-shadow: var(--shadow);
}
.bricks {
position: absolute; inset: 0;
background:
linear-gradient(180deg, rgba(22,20,17,0.04), transparent 30%),
repeating-linear-gradient(90deg, #c9b39a 0 46px, #b7a088 46px 48px),
repeating-linear-gradient(#d8c6b0 0 22px, #cbb59c 22px 24px);
opacity: 0.55;
}
.bay {
position: absolute; left: 8%; right: 8%; top: 12%; bottom: 18%;
background: linear-gradient(180deg, #243f3b, #1b322e 70%);
border: 8px solid #8d7352;
}
.bay-light {
position: absolute; left: 10%; right: 10%; top: 10%; height: 46%;
background: linear-gradient(180deg, rgba(250,247,242,0.18), transparent);
}
.caption {
position: absolute; left: 16px; bottom: 14px;
font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
background: var(--cream); padding: 6px 8px;
}
.facts { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 24px; margin-top: 22px; }
.facts b { display: block; font-size: 15px; }
.facts span { color: var(--ink-soft); font-size: 14.5px; }
.range-head, .sec-head { display: flex; justify-content: space-between; gap: 24px; align-items: end; margin-bottom: 28px; }
.bikes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.card {
background: var(--cream);
border: 1px solid var(--rule);
padding: 18px 18px 20px;
display: flex; flex-direction: column; min-height: 100%;
}
.card .code { font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; color: var(--brass-deep); }
.card svg { width: 100%; height: 120px; margin: 8px 0 12px; }
.price { font-family: var(--serif); font-size: 28px; margin: 8px 0; }
.price small { font-family: var(--sans); font-size: 13px; color: var(--ink-soft); letter-spacing: 0; }
.card ul, .plain { margin: 0; padding: 0; list-style: none; color: var(--ink-soft); font-size: 14.5px; }
.card li { padding: 5px 0; border-top: 1px solid var(--rule); }
.card .btn { margin-top: auto; align-self: flex-start; }
.config {
background: var(--ink);
color: var(--cream);
}
.config .eyebrow { color: var(--brass); }
.config-grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 40px; align-items: center; }
.swatches, .choices { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 16px; }
.swatch, .choice {
border: 1px solid rgba(250,247,242,0.3);
background: transparent; color: var(--cream);
padding: 8px 10px; cursor: pointer; font-size: 13.5px;
}
.swatch { width: 42px; height: 42px; padding: 0; border-radius: 50%; }
.swatch[aria-pressed="true"], .choice[aria-pressed="true"] { outline: 2px solid var(--brass); outline-offset: 2px; }
.config label { display: block; font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(250,247,242,0.6); margin-top: 8px; }
.sum {
border-top: 1px solid rgba(250,247,242,0.16);
margin-top: 8px; padding-top: 14px;
display: flex; justify-content: space-between; align-items: end; gap: 12px;
}
.sum b { font-family: var(--serif); font-size: 40px; font-weight: 500; font-variant-numeric: tabular-nums; }
.check { display: flex; gap: 8px; align-items: flex-start; font-size: 14.5px; margin: 6px 0; color: var(--cream-dim); }
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; counter-reset: step; }
.step { border-top: 1px solid var(--ink); padding-top: 14px; }
.step em { font-family: var(--mono); font-style: normal; font-size: 12px; letter-spacing: 0.14em; color: var(--brass-deep); }
.spec {
width: 100%; border-collapse: collapse; background: var(--cream); border: 1px solid var(--rule);
}
.spec th, .spec td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--rule); vertical-align: top; }
.spec th { width: 28%; font-family: var(--mono); font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 560; color: var(--brass-deep); }
.two { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 36px; }
.include { background: var(--pine); color: var(--cream); padding: 28px; }
.include h3 { color: var(--cream); }
.include li { padding: 8px 0; border-bottom: 1px solid rgba(250,247,242,0.12); list-style: none; }
.include ul { margin: 0; padding: 0; }
.quotes { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
blockquote {
margin: 0; background: var(--cream); border: 1px solid var(--rule); padding: 20px;
font-family: var(--serif); font-size: 22px; line-height: 1.3;
}
blockquote footer { margin-top: 16px; font-family: var(--sans); font-size: 14px; color: var(--ink-soft); }
.visit { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; }
.mapfake {
min-height: 280px; background: var(--pine-2); color: var(--cream); position: relative; overflow: hidden;
border: 1px solid var(--pine);
}
.mapfake svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.pin {
position: absolute; left: 58%; top: 46%; transform: translate(-50%, -100%);
text-align: center; font-size: 13px;
}
.pin i {
display: block; width: 14px; height: 14px; border-radius: 50%; background: var(--brass);
margin: 0 auto 6px; box-shadow: 0 0 0 8px rgba(166, 132, 86, 0.25);
}
details { border-bottom: 1px solid var(--rule); padding: 14px 0; }
summary { cursor: pointer; font-size: 18px; font-family: var(--serif); }
summary:focus-visible { outline: 2px solid var(--brass-deep); }
details p { color: var(--ink-soft); margin: 10px 0 4px; max-width: 46rem; }
form { display: grid; gap: 12px; }
.fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
label.field { display: grid; gap: 6px; font-size: 13.5px; }
input, select, textarea {
background: var(--cream); border: 1px solid var(--rule-strong); padding: 11px 12px; width: 100%;
}
textarea { min-height: 120px; resize: vertical; }
.error { color: #8c3a2f; font-size: 14px; min-height: 1.2em; }
.note { font-size: 13.5px; color: var(--ink-soft); }
footer {
background: var(--ink); color: rgba(250,247,242,0.78); padding: 36px 0 28px; font-size: 14px;
}
.foot { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
footer a { color: var(--cream); }
.fine { margin-top: 18px; color: rgba(250,247,242,0.45); font-size: 12.5px; }
@media (max-width: 900px) {
.hero-grid, .split, .config-grid, .two, .visit, .quotes, .bikes, .steps, .trust, .fields { grid-template-columns: 1fr; }
.trust div { border-right: 0; border-bottom: 1px solid var(--rule); }
.menu-btn { display: block; }
.nav-links {
display: none; position: absolute; top: var(--nav); left: 0; right: 0;
background: var(--paper); border-bottom: 1px solid var(--rule);
flex-direction: column; align-items: flex-start; padding: 16px 20px 20px; gap: 14px;
}
.nav-links.open { display: flex; }
section { padding: 60px 0; }
.range-head, .sec-head { flex-direction: column; align-items: start; }
}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<header class="nav">
<div class="nav-inner">
<a class="brand" href="#top" aria-label="Lumen Cycles, home">
<span class="mark" aria-hidden="true">L</span>
<span class="word">LUMEN<span>CYCLES · CPH</span></span>
</a>
<button class="menu-btn" type="button" aria-expanded="false" aria-controls="navlinks">Menu</button>
<nav class="nav-links" id="navlinks" aria-label="Primary">
<a href="#workshop">Workshop</a>
<a href="#bikes">Bikes</a>
<a href="#build">Configure</a>
<a href="#price">Pricing</a>
<a href="#visit">Visit</a>
<a class="nav-cta" href="#order">Book a fitting</a>
</nav>
</div>
</header>
<main id="main">
<section class="hero" id="top">
<div class="wrap hero-grid">
<div>
<p class="eyebrow">Refshaleøen workshop · Est. 2016</p>
<h1>Cargo bikes, built for the street you actually ride.</h1>
<p class="lede">A six-person Copenhagen workshop. We fillet-braze the frame, measure you on the jig, and hand over a bike that is specified — not picked from a catalogue. From €3.900, ready in 6–10 weeks.</p>
<div class="hero-actions">
<a class="btn light" href="#order">Book a fitting</a>
<a class="btn ghost" href="#bikes">See the three models</a>
</div>
<div class="ticket" aria-label="Current workshop ticket">
<div><span>Next open slot</span><strong>Early October</strong></div>
<div><span>Build window</span><strong>6–10 weeks</strong></div>
<div><span>Frame warranty</span><strong>5 years</strong></div>
<div><span>Deposit</span><strong>30% to start</strong></div>
</div>
</div>
<div class="bike-stage" aria-hidden="true">
<svg viewBox="0 0 680 320" fill="none">
<path d="M40 268h600" stroke="#c4a574" stroke-width="1" opacity="0.5"/>
<circle cx="132" cy="228" r="40" stroke="#faf7f2" stroke-width="2.5"/>
<circle cx="132" cy="228" r="6" fill="#c4a574"/>
<circle cx="508" cy="214" r="56" stroke="#faf7f2" stroke-width="2.5"/>
<circle cx="508" cy="214" r="7" fill="#c4a574"/>
<path d="M96 168c8 18 22 28 36 32" stroke="#faf7f2" stroke-width="1.5" opacity="0.7"/>
<rect x="62" y="112" width="168" height="78" fill="#c4a574"/>
<path d="M74 126h144M74 140h96M74 154h120" stroke="#1b322e" stroke-width="1.4" opacity="0.35"/>
<path d="M132 228 L248 150 L400 206 L508 214 L400 206 L418 108" stroke="#faf7f2" stroke-width="2.6" stroke-linejoin="round" stroke-linecap="round"/>
<path d="M248 132 L430 96" stroke="#faf7f2" stroke-width="2.6" stroke-linecap="round"/>
<path d="M248 150 L168 188" stroke="#faf7f2" stroke-width="2.2" stroke-linecap="round"/>
<path d="M418 108 L430 78" stroke="#faf7f2" stroke-width="2.4"/>
<path d="M412 78h36" stroke="#faf7f2" stroke-width="3" stroke-linecap="round"/>
<path d="M236 118c-8-28 6-46 22-50" stroke="#faf7f2" stroke-width="2.2" stroke-linecap="round"/>
<path d="M214 70h48" stroke="#faf7f2" stroke-width="3" stroke-linecap="round"/>
<circle cx="196" cy="154" r="5" fill="#faf7f2"/>
<path d="M470 168c22 8 34 22 38 40" stroke="#c4a574" stroke-width="1.6"/>
</svg>
</div>
</div>
</section>
<div class="trust" aria-label="At a glance">
<div><b>Handmade</b><span>Frames brazed in-house, not imported and badged.</span></div>
<div><b>€3.900</b><span>Haul, complete and road-ready. VAT included.</span></div>
<div><b>Measured</b><span>A fitting before we cut tube, not after delivery.</span></div>
<div><b>Looked after</b><span>First service included. We still know your bike in year five.</span></div>
</div>
<section id="workshop">
<div class="wrap split">
<div class="workshop" role="img" aria-label="Stylised view of the Refshaleøen workshop bay">
<div class="bricks"></div>
<div class="bay"><div class="bay-light"></div></div>
<div class="caption">Bay 4 · Refshalevej 173B</div>
</div>
<div>
<p class="eyebrow">01 — The workshop</p>
<h2>A small floor, a long jig, and no showroom theatre.</h2>
<p class="lede">Lumen started because the cargo bikes on sale in Copenhagen were either too tall, too vague, or impossible to repair without a special key. We build three models, slowly, for people who will ride them every day.</p>
<div class="facts">
<div><b>Six people</b><span>Two frame builders, one painter, two mechanics, one who answers the phone.</span></div>
<div><b>Signed frames</b><span>The builder who brazed it stamps the bottom bracket shell.</span></div>
<div><b>Danish & English</b><span>Fittings in either. Paperwork in the language you prefer.</span></div>
<div><b>No same-week builds</b><span>If someone promises that, the frame was already on a shelf.</span></div>
</div>
</div>
</div>
</section>
<section id="bikes" style="padding-top: 10px;">
<div class="wrap">
<div class="range-head">
<div>
<p class="eyebrow">02 — The range</p>
<h2>Three bikes. Everything else is a decision, not a model.</h2>
</div>
<p class="lede" style="margin:0;">Child seats, a motor, and rain covers are options. Geometry, lights, guards, and a lock mount are not — they are part of a finished bike.</p>
</div>
<div class="bikes">
<article class="card">
<span class="code">LC-01 · LONTAIL</span>
<h3>Haul</h3>
<svg viewBox="0 0 280 100" aria-hidden="true">
<circle cx="58" cy="68" r="22" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<circle cx="210" cy="64" r="26" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<path d="M58 68 L120 40 L168 62 L210 64 L168 62 L176 28" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<rect x="118" y="36" width="70" height="16" fill="#a68456"/>
<path d="M168 28h16" stroke="#1b322e" stroke-width="2"/>
</svg>
<p>The family and market bike. Kids or crates sit behind you, low and between the wheels. Calm at 25 km/h on the harbour loop.</p>
<p class="price">€3.900 <small>from, incl. VAT</small></p>
<ul>
<li>180 kg system load · 60 kg on the tail</li>
<li>26″ wheels, Enviolo trekking hub</li>
<li>From 23 kg without a motor</li>
</ul>
</article>
<article class="card">
<span class="code">LC-02 · LONG JOHN</span>
<h3>Box</h3>
<svg viewBox="0 0 280 100" aria-hidden="true">
<circle cx="48" cy="70" r="16" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<circle cx="214" cy="64" r="26" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<rect x="22" y="28" width="78" height="34" fill="#a68456"/>
<path d="M48 70 L100 42 L160 60 L214 64 L160 60 L172 26" fill="none" stroke="#1b322e" stroke-width="1.6"/>
</svg>
<p>The front-loader. A 70-litre birch box you can see over, with a bench for two small children or a week of shopping.</p>
<p class="price">€4.600 <small>from, incl. VAT</small></p>
<ul>
<li>80 kg in the box · steering you can feel</li>
<li>20″ front / 26″ rear</li>
<li>Marine-varnished birch, replaceable panels</li>
</ul>
</article>
<article class="card">
<span class="code">LC-03 · COURIER</span>
<h3>Trade</h3>
<svg viewBox="0 0 280 100" aria-hidden="true">
<circle cx="62" cy="68" r="22" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<circle cx="208" cy="64" r="26" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<path d="M62 68 L118 38 L166 60 L208 64 L166 60 L174 26" fill="none" stroke="#1b322e" stroke-width="1.6"/>
<rect x="112" y="30" width="34" height="28" fill="#1b322e"/>
<rect x="148" y="34" width="28" height="24" fill="#a68456"/>
</svg>
<p>Reinforced tail, lockable pannier rails, and a stand that does not wander on cobbles. For shops and riders who load it hard.</p>
<p class="price">€4.200 <small>from, incl. VAT</small></p>
<ul>
<li>100 kg on the rack, tied down properly</li>
<li>Internal cable routing, serviceable hubs</li>
<li>Fleet bookings of three or more</li>
</ul>
</article>
</div>
</div>
</section>
<section class="config" id="build">
<div class="wrap config-grid">
<div>
<p class="eyebrow">03 — A first specification</p>
<h2>Price the bike before you visit. The fitting still decides the geometry.</h2>
<p class="lede" style="color: var(--cream-dim);">This is a working estimate, not a checkout. Powder coat, contact points, and exact tube lengths are set when we measure you. Nothing here is charged until you sign a build sheet.</p>
<div class="bike-stage" style="min-height: 0; margin-top: 12px;">
<svg viewBox="0 0 680 280" fill="none" aria-hidden="true">
<circle cx="132" cy="200" r="38" stroke="#faf7f2" stroke-width="2.2"/>
<circle cx="500" cy="188" r="52" stroke="#faf7f2" stroke-width="2.2"/>
<rect id="cfg-box" x="64" y="92" width="160" height="70" fill="#c4a574"/>
<path id="cfg-frame" d="M132 200 L246 128 L392 176 L500 188 L392 176 L408 96" stroke="#e4d3b5" stroke-width="3" stroke-linejoin="round"/>
<path d="M246 114 L422 86" stroke="#faf7f2" stroke-width="2.4"/>
<path d="M408 96 V70 M392 70h32" stroke="#faf7f2" stroke-width="2.4" stroke-linecap="round"/>
</svg>
</div>
</div>
<form id="configurator" aria-describedby="estimate-note">
<label>Model</label>
<div class="choices" role="group" aria-label="Model">
<button type="button" class="choice" data-model="haul" aria-pressed="true">Haul</button>
<button type="button" class="choice" data-model="box" aria-pressed="false">Box</button>
<button type="button" class="choice" data-model="trade" aria-pressed="false">Trade</button>
</div>
<label>Powder coat</label>
<div class="swatches" role="group" aria-label="Powder coat">
<button type="button" class="swatch" data-color="#e4d3b5" data-name="Sand" style="background:#e4d3b5" aria-pressed="true" aria-label="Sand"></button>
<button type="button" class="swatch" data-color="#1b322e" data-name="Pine" style="background:#1b322e" aria-pressed="false" aria-label="Pine"></button>
<button type="button" class="swatch" data-color="#161411" data-name="Ink" style="background:#161411" aria-pressed="false" aria-label="Ink"></button>
<button type="button" class="swatch" data-color="#8f3d32" data-name="Oxide" style="background:#8f3d32" aria-pressed="false" aria-label="Oxide"></button>
<button type="button" class="swatch" data-color="#d5d8d6" data-name="Fog" style="background:#d5d8d6" aria-pressed="false" aria-label="Fog"></button>
</div>
<label>Drivetrain</label>
<div class="choices" role="group" aria-label="Drivetrain">
<button type="button" class="choice" data-drive="enviolo" data-add="0" aria-pressed="true">Enviolo</button>
<button type="button" class="choice" data-drive="alfine" data-add="0" aria-pressed="false">Alfine 8</button>
<button type="button" class="choice" data-drive="motor" data-add="1180" aria-pressed="false">Mid-drive +€1.180</button>
</div>
<label class="check"><input type="checkbox" data-add="240" id="ex-seat"> Child seat or bench insert, fitted and tested · €240</label>
<label class="check"><input type="checkbox" data-add="180" id="ex-rain"> Rain hood and cover · €180</label>
<label class="check"><input type="checkbox" data-add="90" id="ex-lock"> Frame lock, mounted · €90</label>
<div class="sum">
<div>
<div class="eyebrow" style="margin:0;">Estimate · VAT included</div>
<b id="estimate" aria-live="polite">€3.900</b>
</div>
<a class="btn light" href="#order">Bring this to a fitting</a>
</div>
<p id="estimate-note" class="note" style="color: rgba(250,247,242,0.62);">Haul in Sand, Enviolo, no extras. A colour outside this palette is €220. We confirm the figure in writing before you pay the deposit.</p>
</form>
</div>
</section>
<section id="process">
<div class="wrap">
<p class="eyebrow">04 — How an order moves</p>
<h2>Four visits, or two if you live outside the city.</h2>
<div class="steps" style="margin-top: 28px;">
<article class="step">
<em>01 · Fitting</em>
<h3>Measure</h3>
<p>Forty minutes on the jig. We set bar height, crank length, and how you stand over the bike with a child or a crate already in mind. Remote riders send a short video and inseam; we still call.</p>
</article>
<article class="step">
<em>02 · Build sheet</em>
<h3>Confirm</h3>
<p>You receive a one-page specification and a fixed price. The 30% deposit starts the metal. You can change colour until the frame goes to paint — usually week three.</p>
</article>
<article class="step">
<em>03 · The floor</em>
<h3>Make</h3>
<p>Tubes are mitred, fillet-brazed, and aligned on the same table we fitted you on. Paint is done downstairs. Assembly is by the mechanic who will service it later.</p>
</article>
<article class="step">
<em>04 · Handover</em>
<h3>Ride home</h3>
<p>We adjust it with you on it, photograph the build sheet into your file, and book the first service — included, at about six weeks or 400 km.</p>
</article>
</div>
</div>
</section>
<section id="spec" style="padding-top: 0;">
<div class="wrap two">
<div>
<p class="eyebrow">05 — What is actually on the bike</p>
<h2>Parts we can still buy in ten years.</h2>
<table class="spec">
<tbody>
<tr><th>Frame</th><td>Reynolds 853 cromoly, fillet-brazed, oversized head tube. Alignment checked on a surface plate before paint.</td></tr>
<tr><th>Finish</th><td>Zinc-rich primer, powder coat in a Lumen colour. Touch-up kit in the tool roll.</td></tr>
<tr><th>Gears</th><td>Enviolo trekking or Shimano Alfine 8. Gates belt on request if the load case suits it.</td></tr>
<tr><th>Brakes</th><td>Magura hydraulic, 180 mm rotors. We bed them in before you leave.</td></tr>
<tr><th>Tyres</th><td>Schwalbe Pick-Up, puncture-protected. Tubes you can buy anywhere, not a proprietary insert.</td></tr>
<tr><th>Light & lock</th><td>Dynamo lighting, standlight, and a mount for an ABUS frame lock. The lock itself is optional.</td></tr>
<tr><th>Motor</th><td>Optional mid-drive, EU legal 25 km/h. We do not derestrict, and we will not hide a faster tune.</td></tr>
<tr><th>Paper</th><td>CE documentation, a serial number on the frame, and a service card. Useful if you insure it.</td></tr>
</tbody>
</table>
</div>
<aside class="include">
<p class="eyebrow" style="color: var(--brass);">Included, always</p>
<h3>The price is the bike, not a starting pistol.</h3>
<ul>
<li>Fitting in the workshop, or a video fitting</li>
<li>Lights, mudguards, stand, bell, reflectors</li>
<li>Stem, bars, grips, and saddle in your size</li>
<li>First service</li>
<li>5-year frame warranty, 2 years on parts</li>
<li>Crash inspection for as long as we are here</li>
</ul>
<p style="margin-top: 18px; color: var(--cream-dim);">Not included: the motor, child seats, rain covers, and delivery outside Copenhagen. We can crate a bike to the EU. Ask; it is priced as freight, not as a surprise.</p>
</aside>
</div>
</section>
<section id="price" style="background: var(--cream); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);">
<div class="wrap">
<p class="eyebrow">06 — Money, said plainly</p>
<h2>Around four thousand euros, and you should know where it goes.</h2>
<div class="steps">
<article class="step">
<em>Frame & paint</em>
<h3>About half</h3>
<p>Steel, brazing, alignment, and a proper coat. This is the part you cannot cheaply replace, so it is where the money sits.</p>
</article>
<article class="step">
<em>Running gear</em>
<h3>Named parts</h3>
<p>Brakes, hub, wheels, and tyres from makers a Copenhagen shop can service. We will not substitute a no-name caliper to protect a margin.</p>
</article>
<article class="step">
<em>Labour</em>
<h3>Hours, not a logo</h3>
<p>A Haul is roughly 30 hours of hands. You are paying for that, and for the person who picks up when something creaks in February.</p>
</article>
<article class="step">
<em>Deposit</em>
<h3>30%, then the rest</h3>
<p>Balance due at handover. Bank transfer. If we cannot build what we promised, the deposit returns. If you cancel after tubes are cut, we keep the metal cost and return the rest.</p>
</article>
</div>
</div>
</section>
<section id="riders">
<div class="wrap">
<p class="eyebrow">07 — From the road</p>
<h2>People who put a bike through a Copenhagen winter.</h2>
<div class="quotes" style="margin-top: 22px;">
<blockquote>
“The box sits lower than the Dutch bike we tested. I can see the cycle lane, and the steering does not wander when both children lean left.”
<footer>Sofie N. · Box, Østerbro · 2023</footer>
</blockquote>
<blockquote>
“We run three Trades for the bakery. One hub failed in year two. They had the wheel back the same week, and they already knew the serial.”
<footer>Anders, Lillebrød · Trade ×3 · 2021</footer>
</blockquote>
<blockquote>
“I am 188 cm and every catalogue cargo bike put the bars in my knees. They lengthened the front and stopped talking about ‘standard’.”
<footer>Marta K. · Haul · 2024</footer>
</blockquote>
</div>
</div>
</section>
<section id="visit" style="padding-top: 10px;">
<div class="wrap visit">
<div>
<p class="eyebrow">08 — Visit</p>
<h2>Come and throw a leg over one before you decide.</h2>
<p class="lede">Test rides are by appointment so a bike in your size is built up, not buried under a tarp. Tuesdays and Thursdays are quietest.</p>
<div class="facts">
<div><b>Address</b><span>Refshalevej 173B<br>1432 København K</span></div>
<div><b>Hours</b><span>Tue–Fri 10–18<br>Sat 11–15 · Mon closed</span></div>
<div><b>Phone</b><span><a href="tel:+4532140860">+45 32 14 08 60</a></span></div>
<div><b>Email</b><span><a href="mailto:atelier@lumencycles.dk">atelier@lumencycles.dk</a></span></div>
</div>
<p class="note">Cycle the harbour loop and you are here. Bus 9A stops at Refshaleøen. There is a rail by the door; do not leave a bike against the paint booth.</p>
</div>
<div class="mapfake" role="img" aria-label="Schematic of Refshaleøen with the workshop marked. Not a live map.">
<svg viewBox="0 0 400 280" aria-hidden="true">
<rect width="400" height="280" fill="#274640"/>
<path d="M0 40h180l30 50H70l-20 70H0z" fill="#1b322e"/>
<path d="M210 20h190v120l-40 30H250z" fill="#1b322e"/>
<path d="M40 180h120l40 60H20z" fill="#326058"/>
<path d="M30 90c80 10 140 40 200 30" stroke="#c4a574" stroke-width="2" fill="none" opacity="0.7"/>
<path d="M80 200c60-20 90-10 150 20" stroke="#faf7f2" stroke-width="1" fill="none" opacity="0.35"/>
</svg>
<div class="pin"><i></i>Lumen · bay 4</div>
</div>
</div>
</section>
<section id="faq" style="padding-top: 20px;">
<div class="wrap" style="max-width: 800px;">
<p class="eyebrow">09 — Questions we hear</p>
<h2>Before you write.</h2>
<details>
<summary>Can I ride it in the rain, every day?</summary>
<p>Yes. That is the design case. Guards, a sealed headset, and a powder coat over primer. Rinse salt off in winter; we will say this again at handover, because it matters more than any coating claim.</p>
</details>
<details>
<summary>Do you ship outside Copenhagen?</summary>
<p>In the city we can ride it to you. Elsewhere in Denmark and the EU we crate it. Collection from the workshop is free, and it is the option we prefer — the last adjustments are better with you standing there.</p>
</details>
<details>
<summary>What if the fit is wrong after a month?</summary>
<p>Contact points — stem, bars, saddle, position — are adjusted at no charge in the first two months. If we cut the frame wrong, that is on us, and we put it right. Taste is not a warranty claim; a knee in the bars is.</p>
</details>
<details>
<summary>Why not a big-brand cargo bike for the same money?</summary>
<p>Many of those bikes are excellent. Buy one if the geometry already fits and a dealer nearby will service the electronics. Come here if you are between sizes, you want a frame someone local can braze a dent out of, or you are tired of a display that bricks the bike.</p>
</details>
<details>
<summary>Is there a waiting list trick?</summary>
<p>No. The October slot is real because the jig holds one frame at a time and paint is batched. If we slip by more than two weeks, you can cancel for a full refund of the deposit.</p>
</details>
</div>
</section>
<section id="order" style="background: var(--paper-2);">
<div class="wrap two">
<div>
<p class="eyebrow">10 — Book a fitting</p>
<h2>Tell us who is riding, and what has to fit in the bike.</h2>
<p class="lede">We reply within two working days. If this page cannot open your email app, write directly to <a href="mailto:atelier@lumencycles.dk">atelier@lumencycles.dk</a> or call <a href="tel:+4532140860">+45 32 14 08 60</a>.</p>
<p class="note">A fitting is free. It is not a deposit, and it does not hold a build slot — the slot is held when the build sheet is signed.</p>
</div>
<form id="enquiry" novalidate>
<div class="fields">
<label class="field">Name
<input name="name" autocomplete="name" required>
</label>
<label class="field">Email
<input name="email" type="email" autocomplete="email" required>
</label>
<label class="field">Phone
<input name="phone" type="tel" autocomplete="tel">
</label>
<label class="field">Interested in
<select name="model">
<option>Haul</option>
<option>Box</option>
<option>Trade</option>
<option>Not sure yet</option>
</select>
</label>
</div>
<label class="field">What should the bike carry, and how tall is the main rider?
<textarea name="message" required placeholder="Two children under five, rider 172 cm, mostly Nørrebro to the office."></textarea>
</label>
<p class="error" id="form-error" role="alert"></p>
<button class="btn" type="submit">Open this enquiry in your email</button>
<p class="note" id="form-note">Submitting prepares a message to the workshop. It is sent only if you send it from your mail app. We do not run a hidden inbox on this page.</p>
</form>
</div>
</section>
</main>
<footer>
<div class="wrap">
<div class="foot">
<div>
<strong style="color: var(--cream); font-family: var(--serif); letter-spacing: 0.12em;">LUMEN CYCLES</strong>
<div>Refshalevej 173B, 1432 København K</div>
</div>
<div>
<a href="#workshop">Workshop</a> ·
<a href="#bikes">Bikes</a> ·
<a href="#price">Pricing</a> ·
<a href="#order">Fitting</a>
</div>
<div>Tue–Fri 10–18 · Sat 11–15</div>
</div>
<p class="fine">Lumen Cycles builds cargo bikes to order in Copenhagen. Prices on this page include Danish VAT and describe workshop builds, not stock. Frame warranty is five years to the original owner, excluding crash damage, which we will still inspect.</p>
</div>
</footer>
<script>
(function () {
var menu = document.querySelector(".menu-btn");
var links = document.getElementById("navlinks");
menu.addEventListener("click", function () {
var open = links.classList.toggle("open");
menu.setAttribute("aria-expanded", open ? "true" : "false");
});
links.addEventListener("click", function (e) {
if (e.target.tagName === "A") {
links.classList.remove("open");
menu.setAttribute("aria-expanded", "false");
}
});
var models = { haul: 3900, box: 4600, trade: 4200 };
var state = { model: "haul", add: 0, colorName: "Sand" };
var estimate = document.getElementById("estimate");
var note = document.getElementById("estimate-note");
var frame = document.getElementById("cfg-frame");
var box = document.getElementById("cfg-box");
function euro(n) {
return "€" + String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
function render() {
var extras = 0;
document.querySelectorAll("#configurator input[type=checkbox]").forEach(function (el) {
if (el.checked) extras += Number(el.getAttribute("data-add"));
});
var total = models[state.model] + state.add + extras;
estimate.textContent = euro(total);
var modelName = state.model.charAt(0).toUpperCase() + state.model.slice(1);
note.textContent = modelName + " in " + state.colorName + ". A colour outside this palette is €220. We confirm the figure in writing before you pay the deposit.";
}
document.querySelectorAll("[data-model]").forEach(function (btn) {
btn.addEventListener("click", function () {
document.querySelectorAll("[data-model]").forEach(function (b) { b.setAttribute("aria-pressed", "false"); });
btn.setAttribute("aria-pressed", "true");
state.model = btn.getAttribute("data-model");
render();
});
});
document.querySelectorAll(".swatch").forEach(function (btn) {
btn.addEventListener("click", function () {
document.querySelectorAll(".swatch").forEach(function (b) { b.setAttribute("aria-pressed", "false"); });
btn.setAttribute("aria-pressed", "true");
var c = btn.getAttribute("data-color");
state.colorName = btn.getAttribute("data-name");
frame.setAttribute("stroke", c);
box.setAttribute("fill", c === "#161411" || c === "#1b322e" ? "#c4a574" : c);
render();
});
});
document.querySelectorAll("[data-drive]").forEach(function (btn) {
btn.addEventListener("click", function () {
document.querySelectorAll("[data-drive]").forEach(function (b) { b.setAttribute("aria-pressed", "false"); });
btn.setAttribute("aria-pressed", "true");
state.add = Number(btn.getAttribute("data-add"));
render();
});
});
document.querySelectorAll("#configurator input").forEach(function (el) {
el.addEventListener("change", render);
});
var form = document.getElementById("enquiry");
var err = document.getElementById("form-error");
form.addEventListener("submit", function (e) {
e.preventDefault();
err.textContent = "";
var data = new FormData(form);
var name = String(data.get("name") || "").trim();
var email = String(data.get("email") || "").trim();
var message = String(data.get("message") || "").trim();
if (!name || !email || !message || email.indexOf("@") < 1) {
err.textContent = "Add your name, a real email, and a line about the rider and the load.";
return;
}
var body = [
"Name: " + name,
"Email: " + email,
"Phone: " + (data.get("phone") || "—"),
"Model: " + data.get("model"),
"",
message,
"",
"Estimate on the page when I wrote: " + estimate.textContent + " (" + note.textContent + ")"
].join("\n");
var href = "mailto:atelier@lumencycles.dk?subject=" + encodeURIComponent("Fitting request — " + name) + "&body=" + encodeURIComponent(body);
var noteEl = document.getElementById("form-note");
noteEl.innerHTML = "If a mail app did not open, copy this and send it to atelier@lumencycles.dk.<br><br>" + body.replace(/\n/g, "<br>");
window.location.href = href;
});
})();
</script>
</body>
</html>

