Run details
- Model
- opencode-go/mimo-v2.6-pro
- Route
- opencode CLI
- Reasoning
- provider default
- Limits
- 60 min · 131,072 output tokens
- Date
- 2 Oct 2026
- Time
- 11 min 19 s
- Size
- 108 kB
- Tokens
- 47,664 in, 45,707 out
- List price
- $0.060 ($0.435 in / $0.87 out per M)
- Paid
- Not billed per run (CLI plan)
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). Save it as index.html in the current directory, then stop. Do not ask questions.
Source
108 kB 3,201 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 to order in Copenhagen</title>
<meta name="description" content="Lumen Cycles is a Copenhagen workshop building custom electric cargo bikes to order. Fitted to the rider, configured around real cargo, serviced for the long term.">
<style>
/* ============================================================
LUMEN CYCLES — The Rolling Blueprint
Self-contained. No network requests. No web fonts. No remote images.
============================================================ */
:root{
--canvas-warm:#F3F0E8;
--canvas-light:#FBFAF6;
--ink:#202322;
--ink-muted:#6B6D67;
--green:#315B52;
--green-light:#D7E0D8;
--orange:#E95B2B;
--orange-dark:#B94420;
--line:#C9C8BF;
--focus:#202322;
--s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
--s7:48px; --s8:72px; --s9:96px; --s10:128px; --s11:176px;
--serif:"Newsreader","Iowan Old Style","Palatino Linotype",Georgia,"Times New Roman",serif;
--sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
--mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
--ease-out:cubic-bezier(0.22,1,0.36,1);
--ease-snap:cubic-bezier(0.2,0.8,0.2,1);
--content:min(1320px, calc(100vw - 64px));
--gutter:24px;
--header-h:72px;
}
*,*::before,*::after{box-sizing:border-box}
html{
-webkit-text-size-adjust:100%;
scroll-behavior:smooth;
}
body{
margin:0;
background:var(--canvas-warm);
color:var(--ink);
font-family:var(--sans);
font-size:16px;
line-height:1.55;
font-weight:400;
-webkit-font-smoothing:antialiased;
text-rendering:optimizeLegibility;
overflow-x:hidden;
}
img,svg{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit}
h1,h2,h3,h4,p,figure,blockquote{margin:0}
ul{margin:0;padding:0;list-style:none}
::selection{background:var(--orange);color:var(--ink)}
:focus-visible{
outline:2px solid var(--focus);
outline-offset:3px;
}
.skip{
position:absolute;left:var(--s4);top:-64px;z-index:200;
background:var(--ink);color:var(--canvas-light);
padding:var(--s3) var(--s4);
font-family:var(--sans);font-size:13px;font-weight:600;
text-decoration:none;
}
.skip:focus{top:var(--s4)}
/* ---------- layout primitives ---------- */
.wrap{
width:var(--content);
margin-inline:auto;
}
.grid{
display:grid;
grid-template-columns:repeat(12,1fr);
gap:var(--gutter);
}
.mono{
font-family:var(--mono);
font-size:11px;
font-weight:500;
line-height:1.35;
letter-spacing:0.12em;
text-transform:uppercase;
font-variant-numeric:tabular-nums;
}
.caption{
font-family:var(--sans);
font-size:12px;
font-weight:500;
line-height:1.35;
color:var(--ink-muted);
}
.price{
font-family:var(--mono);
font-size:20px;
font-weight:500;
line-height:1.1;
letter-spacing:0;
font-variant-numeric:tabular-nums;
text-transform:none;
}
.display{
font-family:var(--serif);
font-size:72px;
font-weight:400;
line-height:0.96;
letter-spacing:0;
}
.display em{
font-style:italic;
font-weight:400;
}
.heading{
font-family:var(--sans);
font-size:32px;
font-weight:500;
line-height:1.08;
letter-spacing:0;
}
.body-lg{
font-size:16px;
line-height:1.55;
max-width:60ch;
}
.metadata-rail{
border-top:1px solid var(--line);
padding:var(--s2) 0;
display:flex;
justify-content:space-between;
align-items:center;
gap:var(--s4);
color:var(--ink-muted);
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
font-variant-numeric:tabular-nums;
}
.rule{
border:0;
border-top:1px solid var(--line);
margin:0;
}
/* ---------- buttons & links ---------- */
.btn{
display:inline-flex;
align-items:center;
gap:var(--s3);
height:48px;
padding:0 22px;
border-radius:999px;
background:var(--orange);
color:var(--ink);
font-family:var(--sans);
font-size:13px;
font-weight:600;
line-height:1;
letter-spacing:0.04em;
text-transform:uppercase;
text-decoration:none;
transition:background 160ms ease-out,color 160ms ease-out;
min-height:44px;
}
.btn svg{transition:transform 160ms ease-out}
.btn:hover{background:var(--orange-dark);color:var(--canvas-light)}
.btn:hover svg{transform:translateX(6px)}
.btn:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
.btn--ghost{
background:transparent;
color:var(--ink);
border:1px solid var(--ink);
}
.btn--ghost:hover{background:var(--ink);color:var(--canvas-light)}
.btn--on-dark{
background:var(--orange);
color:var(--ink);
}
.btn--on-dark:hover{background:var(--orange-dark);color:var(--canvas-light)}
.btn--on-dark:focus-visible{outline-color:var(--canvas-light)}
.link{
display:inline-flex;
align-items:center;
gap:var(--s2);
font-family:var(--sans);
font-size:13px;
font-weight:600;
line-height:1;
letter-spacing:0.04em;
text-transform:uppercase;
text-decoration:underline;
text-decoration-thickness:1px;
text-underline-offset:4px;
color:var(--ink);
background:none;
padding:0;
min-height:44px;
}
.link:hover{text-decoration-color:var(--orange)}
.link svg{transition:transform 160ms ease-out}
.link:hover svg{transform:translateX(6px)}
.link--on-dark{color:var(--green-light)}
.link--on-dark:hover{text-decoration-color:var(--orange)}
/* ---------- header ---------- */
.header{
position:sticky;
top:0;
z-index:100;
background:var(--canvas-warm);
border-bottom:1px solid var(--line);
}
.header.is-stuck{
background:var(--canvas-warm);
}
.header__inner{
width:var(--content);
margin-inline:auto;
height:var(--header-h);
display:flex;
align-items:center;
justify-content:space-between;
gap:var(--s5);
}
.wordmark{
display:flex;
align-items:baseline;
gap:var(--s3);
text-decoration:none;
}
.wordmark__name{
font-family:var(--sans);
font-size:15px;
font-weight:600;
letter-spacing:0.16em;
text-transform:uppercase;
line-height:1;
}
.wordmark__sub{
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--ink-muted);
line-height:1;
}
.nav{
display:flex;
align-items:center;
gap:var(--s6);
}
.nav a{
font-family:var(--sans);
font-size:13px;
font-weight:600;
line-height:1;
letter-spacing:0.04em;
text-transform:uppercase;
text-decoration:none;
padding:var(--s3) 0;
border-bottom:1px solid transparent;
}
.nav a:hover{border-bottom-color:var(--orange)}
.header__cta{
height:40px;
min-height:40px;
padding:0 16px;
font-size:12px;
}
.nav-toggle{
display:none;
width:44px;height:44px;
align-items:center;justify-content:center;
border:1px solid var(--line);
}
/* ---------- hero ---------- */
.hero{
position:relative;
background:var(--canvas-warm);
padding-top:var(--s8);
min-height:min(760px,92vh);
display:flex;
flex-direction:column;
justify-content:space-between;
}
.hero__body{
position:relative;
padding-bottom:var(--s7);
}
.hero__rail{
grid-column:1 / 3;
display:flex;
flex-direction:column;
gap:var(--s3);
color:var(--ink-muted);
padding-top:6px;
}
.hero__rail span{display:block}
.hero__copy{
grid-column:3 / 8;
position:relative;
z-index:2;
}
.hero__title{
font-family:var(--serif);
font-size:clamp(44px,5.6vw,72px);
font-weight:400;
line-height:0.96;
letter-spacing:0;
margin-bottom:var(--s6);
}
.hero__title .line{
display:block;
overflow:hidden;
}
.hero__title .line > span{
display:block;
transform:translateY(105%);
transition:transform 900ms var(--ease-out);
}
.is-ready .hero__title .line > span{transform:translateY(0)}
.hero__title .line:nth-child(1) > span{transition-delay:60ms}
.hero__title .line:nth-child(2) > span{transition-delay:120ms}
.hero__title .line:nth-child(3) > span{transition-delay:180ms}
.hero__title em{font-style:italic}
.hero__sub{
max-width:46ch;
color:var(--ink);
margin-bottom:var(--s6);
opacity:0;
transform:translateY(12px);
transition:opacity 900ms var(--ease-out) 240ms, transform 900ms var(--ease-out) 240ms;
}
.is-ready .hero__sub{opacity:1;transform:none}
.hero__actions{
display:flex;
flex-wrap:wrap;
align-items:center;
gap:var(--s5);
opacity:0;
transform:translateY(12px);
transition:opacity 900ms var(--ease-out) 320ms, transform 900ms var(--ease-out) 320ms;
}
.is-ready .hero__actions{opacity:1;transform:none}
.hero__figure{
grid-column:7 / 13;
grid-row:1;
position:relative;
z-index:1;
align-self:center;
}
.hero__stage{
position:relative;
border:1px solid var(--line);
background:var(--canvas-warm);
padding:var(--s5) var(--s4) var(--s4);
}
.hero__stage-label{
position:absolute;
top:var(--s3);
left:var(--s4);
color:var(--ink-muted);
z-index:3;
}
.hero__bike{
width:100%;
height:auto;
filter:none;
transform:translateX(-24px);
opacity:0;
transition:transform 900ms var(--ease-out) 120ms, opacity 700ms var(--ease-out) 120ms;
}
.is-ready .hero__bike{transform:none;opacity:1}
.hero__bike .shadow-plate{
fill:rgba(32,35,34,0.16);
}
/* measurement callouts */
.callout{
position:absolute;
z-index:4;
display:flex;
align-items:center;
gap:var(--s2);
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--ink);
opacity:0;
transform:scale(0.9);
transition:opacity 400ms var(--ease-out), transform 400ms var(--ease-out);
}
.is-ready .callout{opacity:1;transform:scale(1)}
.is-ready .callout:nth-of-type(1){transition-delay:540ms}
.is-ready .callout:nth-of-type(2){transition-delay:660ms}
.is-ready .callout:nth-of-type(3){transition-delay:780ms}
.is-ready .callout:nth-of-type(4){transition-delay:900ms}
.callout__dot{
width:9px;height:9px;
border-radius:999px;
background:var(--orange);
flex:none;
}
.callout__line{
width:44px;height:1px;
background:var(--ink);
flex:none;
}
.callout--flip{flex-direction:row-reverse}
.hero__rail-bottom{
padding-bottom:var(--s5);
}
/* ---------- trust strip ---------- */
.trust{
background:var(--canvas-warm);
padding-bottom:var(--s9);
}
.trust__row{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:var(--gutter);
border-top:1px solid var(--line);
padding-top:var(--s5);
}
.trust__item{
display:flex;
gap:var(--s4);
align-items:flex-start;
}
.trust__icon{
flex:none;
width:32px;height:32px;
color:var(--green);
}
.trust__label{
font-family:var(--sans);
font-size:12px;
font-weight:500;
letter-spacing:0.08em;
text-transform:uppercase;
line-height:1.35;
margin-bottom:var(--s2);
}
.trust__copy{
font-size:16px;
line-height:1.55;
color:var(--ink-muted);
max-width:34ch;
}
/* ---------- models ---------- */
.models{
background:var(--canvas-light);
padding:var(--s10) 0 var(--s10);
}
.models__head{
align-items:end;
margin-bottom:var(--s8);
}
.models__title{
grid-column:1 / 8;
}
.models__marker{
grid-column:8 / 13;
color:var(--green);
padding-bottom:6px;
}
.models__rail{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:0;
border-top:1px solid var(--line);
border-bottom:1px solid var(--line);
}
.model{
position:relative;
background:var(--canvas-light);
border-right:1px solid var(--line);
padding:var(--s5) var(--s5) var(--s5);
display:flex;
flex-direction:column;
gap:var(--s4);
text-align:left;
width:100%;
transition:background 320ms var(--ease-snap);
min-width:0;
}
.model:last-child{border-right:0}
.model:hover{background:var(--canvas-warm)}
.model[aria-pressed="true"]{
background:var(--canvas-warm);
}
.model__marker{
position:absolute;
top:var(--s5);
right:var(--s5);
background:var(--orange);
color:var(--ink);
border-radius:999px;
padding:4px 8px;
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
opacity:0;
transition:opacity 180ms var(--ease-snap);
}
.model[aria-pressed="true"] .model__marker{opacity:1}
.model__fig{
border:1px solid var(--line);
background:var(--canvas-warm);
aspect-ratio:3 / 4;
overflow:hidden;
display:flex;
align-items:center;
justify-content:center;
}
.model__fig svg{
width:100%;height:100%;
}
.model__name{
font-family:var(--sans);
font-size:32px;
font-weight:500;
line-height:1.08;
}
.model__use{
color:var(--ink-muted);
font-size:16px;
line-height:1.55;
min-height:3.1em;
}
.model__specs{
display:grid;
gap:0;
}
.model__specs div{
display:flex;
justify-content:space-between;
gap:var(--s4);
border-top:1px solid var(--line);
padding:var(--s2) 0;
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
font-variant-numeric:tabular-nums;
}
.model__specs dt{color:var(--ink-muted)}
.model__specs dd{margin:0;color:var(--ink);text-align:right}
.model__foot{
margin-top:auto;
display:flex;
align-items:center;
justify-content:space-between;
gap:var(--s4);
border-top:2px solid var(--ink);
padding-top:var(--s3);
}
.model__foot .link{min-height:44px}
.model__toggle{
position:absolute;
inset:0;
z-index:1;
}
.model__foot .link{position:relative;z-index:2}
.models__summary{
margin-top:var(--s7);
border-top:1px solid var(--line);
padding-top:var(--s5);
display:grid;
grid-template-columns:repeat(4,1fr);
gap:var(--gutter);
align-items:start;
}
.models__summary .sum-label{
color:var(--ink-muted);
margin-bottom:var(--s3);
}
.models__summary .sum-value{
font-family:var(--mono);
font-size:20px;
font-weight:500;
line-height:1.1;
font-variant-numeric:tabular-nums;
}
.models__summary .sum-note{
grid-column:1 / -1;
color:var(--ink-muted);
max-width:68ch;
font-size:16px;
}
.sum-fade{
transition:opacity 180ms var(--ease-snap);
}
.sum-fade.is-fading{opacity:0}
/* ---------- build sheet (signature) ---------- */
.sheet{
background:var(--green);
color:var(--green-light);
padding:var(--s10) 0 var(--s9);
position:relative;
}
.sheet .metadata-rail{
border-top-color:rgba(215,224,216,0.28);
color:rgba(215,224,216,0.72);
}
.sheet__intro{
margin-bottom:var(--s8);
}
.sheet__label{
grid-column:1 / 4;
color:var(--orange);
padding-top:8px;
}
.sheet__title{
grid-column:4 / 13;
font-family:var(--serif);
font-size:clamp(36px,4.6vw,60px);
font-weight:400;
line-height:1.02;
color:var(--canvas-light);
max-width:18ch;
}
.sheet__body{
display:grid;
grid-template-columns:minmax(180px,1.1fr) minmax(0,3.2fr) minmax(200px,1.2fr);
gap:var(--s7);
align-items:start;
}
.sheet__stack{
display:flex;
flex-direction:column;
gap:var(--s7);
}
.stage-block{
border-top:1px solid rgba(215,224,216,0.32);
padding-top:var(--s3);
}
.stage-block__num{
color:var(--orange);
margin-bottom:var(--s3);
display:flex;
align-items:center;
gap:var(--s2);
}
.stage-block__title{
font-family:var(--sans);
font-size:26px;
font-weight:500;
line-height:1.08;
color:var(--canvas-light);
margin-bottom:var(--s3);
}
.stage-block__list{
display:flex;
flex-direction:column;
gap:var(--s2);
}
.stage-block__list li{
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:rgba(215,224,216,0.78);
}
.stage-block__copy{
color:rgba(215,224,216,0.78);
font-size:16px;
line-height:1.55;
max-width:34ch;
}
.sheet__figure{
position:relative;
}
.sheet__diagram{
width:100%;
height:auto;
}
.sheet__diagram text{
font-family:var(--mono);
font-size:11px;
letter-spacing:0.12em;
text-transform:uppercase;
}
.sheet__ruler{
margin-top:var(--s4);
border-top:1px solid rgba(215,224,216,0.32);
padding-top:var(--s2);
display:flex;
justify-content:space-between;
color:rgba(215,224,216,0.6);
}
.usecases{
margin-top:var(--s5);
display:flex;
gap:var(--s3);
flex-wrap:wrap;
}
.usecase{
border:1px solid rgba(215,224,216,0.32);
border-radius:999px;
padding:6px 12px;
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--green-light);
opacity:0.35;
transform:translateY(6px);
transition:opacity 200ms var(--ease-out), transform 200ms var(--ease-out), border-color 200ms ease-out, color 200ms ease-out;
}
.usecase.is-on{
opacity:1;
transform:none;
border-color:var(--orange);
color:var(--canvas-light);
}
/* draw-in paths */
.draw{
stroke-dasharray:var(--len,1000);
stroke-dashoffset:var(--len,1000);
transition:stroke-dashoffset 200ms linear;
}
.draw.is-drawn{stroke-dashoffset:0}
.callout-svg{
opacity:0;
transition:opacity 300ms var(--ease-out);
}
.callout-svg.is-on{opacity:1}
/* ---------- process ---------- */
.process{
background:var(--canvas-warm);
padding:var(--s10) 0 var(--s9);
}
.process__head{
margin-bottom:var(--s8);
align-items:end;
}
.process__label{
grid-column:1 / 4;
color:var(--ink-muted);
padding-bottom:8px;
}
.process__title{
grid-column:4 / 13;
font-family:var(--serif);
font-size:clamp(34px,4.2vw,56px);
font-weight:400;
line-height:1.02;
max-width:16ch;
}
.process__stamp{
position:absolute;
right:0;
top:0;
width:96px;height:96px;
}
.process__stamp svg{
width:96px;height:96px;
transition:transform 240ms ease-out;
}
.process__stamp.is-active svg{transform:rotate(90deg)}
.process__grid{
display:grid;
grid-template-columns:repeat(4,1fr);
gap:var(--gutter);
}
.step{
border-top:2px solid var(--ink);
padding-top:var(--s4);
display:flex;
flex-direction:column;
gap:var(--s4);
position:relative;
}
.step__num{
color:var(--ink-muted);
}
.step__media{
aspect-ratio:4 / 3;
border:1px solid var(--line);
background:var(--canvas-light);
overflow:hidden;
}
.step__media svg{width:100%;height:100%}
.step__label{
font-family:var(--mono);
font-size:12px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
}
.step__copy{
font-size:16px;
line-height:1.55;
color:var(--ink-muted);
}
.step__index{
position:absolute;
right:0;top:calc(var(--s4) * -1 - 2px);
font-family:var(--mono);
font-size:11px;
letter-spacing:0.12em;
color:var(--ink-muted);
opacity:0;
transform:translateX(8px);
transition:opacity 240ms ease-out, transform 240ms ease-out;
}
.step.is-active .step__index{opacity:1;transform:none}
.proof{
margin-top:var(--s9);
display:grid;
grid-template-columns:repeat(3,1fr);
gap:var(--gutter);
}
.proof__item{
border-top:1px solid var(--line);
padding-top:var(--s3);
}
.proof__value{
font-family:var(--mono);
font-size:20px;
font-weight:500;
line-height:1.1;
letter-spacing:0.04em;
font-variant-numeric:tabular-nums;
margin-bottom:var(--s2);
}
.proof__label{
color:var(--ink-muted);
font-size:16px;
line-height:1.55;
max-width:32ch;
}
/* ---------- case study ---------- */
.case{
background:var(--canvas-light);
padding:var(--s10) 0 var(--s10);
}
.case__quote{
grid-column:3 / 10;
font-family:var(--serif);
font-size:clamp(30px,3.8vw,52px);
font-weight:400;
line-height:1.12;
margin-bottom:var(--s7);
}
.case__attr{
grid-column:3 / 10;
display:flex;
flex-wrap:wrap;
gap:var(--s5);
border-top:1px solid var(--line);
padding-top:var(--s3);
margin-bottom:var(--s8);
color:var(--ink-muted);
}
.case__diptych{
grid-column:1 / 13;
display:grid;
grid-template-columns:1fr 1fr;
gap:var(--s6);
position:relative;
padding-left:var(--s6);
}
.case__diptych::before{
content:"";
position:absolute;
left:0;top:0;bottom:0;
width:1px;
background:var(--line);
}
.shot{
position:relative;
}
.shot:nth-child(2){margin-top:32px}
.shot__panel{
position:absolute;
inset:0;
background:var(--canvas-warm);
transform-origin:top;
z-index:2;
}
.shot.is-in .shot__panel{
transform:scaleY(0);
transition:transform 650ms var(--ease-out);
}
.shot:nth-child(2).is-in .shot__panel{transition-delay:120ms}
.shot__frame{
border:1px solid var(--line);
background:var(--canvas-warm);
aspect-ratio:16 / 10;
overflow:hidden;
}
.shot__frame svg{width:100%;height:100%}
.shot figcaption{
margin-top:var(--s3);
color:var(--ink-muted);
}
/* ---------- final CTA ---------- */
.final{
background:var(--ink);
color:var(--canvas-light);
padding:var(--s10) 0 var(--s9);
}
.final .metadata-rail{
border-top-color:rgba(251,250,246,0.22);
color:rgba(251,250,246,0.6);
}
.final__label{
color:var(--orange);
margin-bottom:var(--s5);
}
.final__title{
grid-column:1 / 10;
font-family:var(--serif);
font-size:clamp(52px,7vw,108px);
font-weight:400;
line-height:0.96;
margin-bottom:var(--s6);
}
.final__copy{
grid-column:1 / 7;
color:rgba(251,250,246,0.78);
font-size:16px;
line-height:1.55;
max-width:52ch;
margin-bottom:var(--s7);
}
.final__actions{
grid-column:1 / 8;
display:flex;
flex-wrap:wrap;
align-items:center;
gap:var(--s5);
margin-bottom:var(--s6);
}
.final__promise{
grid-column:1 / 13;
color:rgba(251,250,246,0.55);
}
.final__utils{
grid-column:9 / 13;
display:flex;
flex-direction:column;
gap:var(--s3);
align-items:flex-start;
}
/* ---------- form ---------- */
.form{
grid-column:1 / 13;
margin-top:var(--s8);
border-top:1px solid rgba(251,250,246,0.22);
padding-top:var(--s7);
}
.form__grid{
display:grid;
grid-template-columns:repeat(12,1fr);
gap:var(--gutter);
}
.field{
grid-column:span 6;
display:flex;
flex-direction:column;
gap:var(--s2);
}
.field--full{grid-column:1 / 13}
.field--third{grid-column:span 4}
.field label{
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:rgba(251,250,246,0.72);
}
.field input,
.field select,
.field textarea{
background:var(--canvas-light);
color:var(--ink);
border:1px solid var(--line);
border-radius:0;
height:52px;
padding:0 var(--s4);
font-family:var(--sans);
font-size:16px;
line-height:1.55;
width:100%;
appearance:none;
}
.field textarea{
min-height:144px;
padding:var(--s3) var(--s4);
resize:vertical;
}
.field select{
background-image:linear-gradient(45deg,transparent 50%,var(--ink) 50%),linear-gradient(135deg,var(--ink) 50%,transparent 50%);
background-position:calc(100% - 20px) 24px, calc(100% - 14px) 24px;
background-size:6px 6px,6px 6px;
background-repeat:no-repeat;
padding-right:40px;
}
.field input:focus,
.field select:focus,
.field textarea:focus{
border-color:var(--ink);
outline:2px solid var(--canvas-light);
outline-offset:-3px;
}
.field .err{
font-family:var(--sans);
font-size:12px;
font-weight:500;
line-height:1.35;
color:var(--orange);
min-height:0;
}
.field.is-invalid input,
.field.is-invalid select,
.field.is-invalid textarea{
border-color:var(--orange);
}
.check{
grid-column:1 / 13;
display:flex;
gap:var(--s3);
align-items:flex-start;
border-top:1px solid rgba(251,250,246,0.22);
padding-top:var(--s5);
}
.check input{
width:22px;height:22px;
flex:none;
margin:0;
accent-color:var(--orange);
}
.check label{
font-family:var(--sans);
font-size:16px;
letter-spacing:0;
text-transform:none;
color:rgba(251,250,246,0.78);
line-height:1.55;
}
.form__submit{
grid-column:1 / 13;
display:flex;
flex-wrap:wrap;
align-items:center;
gap:var(--s5);
margin-top:var(--s5);
}
.error-summary{
grid-column:1 / 13;
border:1px solid var(--orange);
padding:var(--s4);
margin-bottom:var(--s5);
display:none;
}
.error-summary.is-on{display:block}
.error-summary h3{
font-family:var(--mono);
font-size:11px;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--orange);
margin-bottom:var(--s3);
font-weight:500;
}
.error-summary ul{display:flex;flex-direction:column;gap:var(--s2)}
.error-summary a{
color:var(--canvas-light);
font-size:16px;
text-decoration:underline;
text-underline-offset:4px;
}
.form__status{
font-family:var(--mono);
font-size:11px;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--green-light);
}
.form__status.is-error{color:var(--orange)}
/* ---------- footer ---------- */
.footer{
background:var(--canvas-warm);
padding:var(--s9) 0 var(--s7);
}
.footer__grid{
align-items:start;
margin-bottom:var(--s8);
}
.footer__brand{grid-column:1 / 4}
.footer__addr{grid-column:5 / 8}
.footer__hours{grid-column:8 / 11}
.footer__legal{grid-column:11 / 13;display:flex;flex-direction:column;gap:var(--s2);align-items:flex-start}
.footer__legal a{
font-family:var(--sans);
font-size:12px;
font-weight:500;
letter-spacing:0.08em;
text-transform:uppercase;
text-decoration:none;
color:var(--ink-muted);
min-height:44px;
display:inline-flex;
align-items:center;
}
.footer__legal a:hover{color:var(--ink);text-decoration:underline;text-underline-offset:4px}
.footer__block-label{
color:var(--ink-muted);
margin-bottom:var(--s3);
}
.footer__block-copy{
font-family:var(--mono);
font-size:11px;
font-weight:500;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--ink);
line-height:1.9;
font-variant-numeric:tabular-nums;
}
.footer__block-copy a{text-decoration:none}
.footer__block-copy a:hover{text-decoration:underline;text-underline-offset:4px}
.footer__stamp{
display:flex;
justify-content:flex-end;
}
.footer__stamp span{
border:1px solid var(--line);
border-radius:999px;
padding:var(--s3) var(--s4);
color:var(--ink-muted);
}
/* ---------- responsive ---------- */
@media (max-width:1199px){
:root{
--content:min(1200px, calc(100vw - 48px));
--gutter:20px;
--s10:88px;
--s9:72px;
--s11:112px;
}
.display{font-size:56px}
.hero__title{font-size:clamp(40px,5.2vw,56px)}
.hero__copy{grid-column:1 / 7}
.hero__rail{grid-column:1 / 3;grid-row:2;padding-top:var(--s6)}
.hero__figure{grid-column:7 / 13;grid-row:1}
.sheet__body{grid-template-columns:minmax(150px,1fr) minmax(0,2.6fr) minmax(170px,1fr);gap:var(--s5)}
.models__title{grid-column:1 / 8}
.models__marker{grid-column:8 / 13}
.process__grid{grid-template-columns:repeat(2,1fr);gap:var(--s6) var(--gutter)}
.case__quote,.case__attr{grid-column:1 / 11}
.final__title{grid-column:1 / 12}
.final__copy{grid-column:1 / 8}
.final__actions{grid-column:1 / 10}
.final__utils{grid-column:1 / 13;flex-direction:row;gap:var(--s5);margin-top:var(--s6);flex-wrap:wrap}
.nav a[data-opt]{display:none}
}
@media (max-width:767px){
:root{
--content:calc(100vw - 32px);
--gutter:16px;
--header-h:64px;
--s10:64px;
--s9:56px;
--s8:48px;
--s7:32px;
}
.display{font-size:48px}
.heading{font-size:26px}
.nav{display:none}
.nav.is-open{
display:flex;
position:absolute;
top:var(--header-h);left:0;right:0;
flex-direction:column;
align-items:flex-start;
gap:0;
background:var(--canvas-warm);
border-bottom:1px solid var(--line);
padding:var(--s3) var(--s4) var(--s5);
}
.nav.is-open a{
padding:var(--s4) 0;
width:100%;
border-bottom:1px solid var(--line);
min-height:44px;
display:flex;
align-items:center;
}
.nav.is-open a[data-opt]{display:flex}
.nav-toggle{display:inline-flex}
.header__inner{position:relative}
.header__cta{display:none}
.hero{
min-height:0;
padding-top:var(--s6);
display:block;
}
.hero__body{display:flex;flex-direction:column;gap:var(--s5);padding-bottom:var(--s6)}
.hero__rail{
display:flex;
flex-direction:row;
gap:var(--s5);
padding-top:0;
order:-1;
}
.hero__copy{order:1}
.hero__figure{order:2}
.hero__title{
font-size:48px;
max-width:12ch;
}
.hero__stage{padding:var(--s6) var(--s3) var(--s3)}
.callout{font-size:10px}
.callout__line{width:22px}
.trust__row{
grid-template-columns:1fr;
gap:var(--s5);
overflow-x:auto;
}
.models__head{display:flex;flex-direction:column;gap:var(--s4);align-items:flex-start}
.models__title,.models__marker{grid-column:auto}
.models__rail{
display:flex;
overflow-x:auto;
scroll-snap-type:x mandatory;
gap:var(--s4);
border-bottom:0;
padding-bottom:var(--s4);
margin-right:calc(var(--s4) * -1);
padding-right:12%;
scrollbar-width:thin;
}
.model{
flex:0 0 78%;
scroll-snap-align:start;
border:1px solid var(--line);
}
.model:last-child{border-right:1px solid var(--line)}
.models__summary{grid-template-columns:1fr 1fr;gap:var(--s5) var(--gutter)}
.sheet__intro{display:flex;flex-direction:column;gap:var(--s4)}
.sheet__label,.sheet__title{grid-column:auto}
.sheet__body{
display:flex;
flex-direction:column;
gap:var(--s6);
}
.sheet__stack{gap:var(--s6)}
.sheet__figure{margin:0 calc(var(--s4) * -1);}
.process__head{display:flex;flex-direction:column;gap:var(--s4);align-items:flex-start}
.process__label,.process__title{grid-column:auto}
.process__grid{grid-template-columns:1fr;gap:var(--s7)}
.proof{grid-template-columns:1fr;gap:var(--s5)}
.case__quote,.case__attr,.case__diptych{grid-column:1 / 13}
.case__diptych{
grid-template-columns:1fr;
padding-left:var(--s4);
gap:var(--s5);
}
.shot:nth-child(2){margin-top:0}
.final__title,.final__copy,.final__actions,.final__utils,.final__promise{grid-column:1 / 13}
.field,.field--third{grid-column:1 / 13}
.footer__grid{display:flex;flex-direction:column;gap:var(--s6)}
.footer__brand,.footer__addr,.footer__hours,.footer__legal{grid-column:auto}
.footer__stamp{justify-content:flex-start}
.metadata-rail{
flex-direction:column;
align-items:flex-start;
gap:var(--s1);
}
}
@media (prefers-reduced-motion: reduce){
html{scroll-behavior:auto}
*,*::before,*::after{
animation-duration:0.001ms !important;
animation-iteration-count:1 !important;
transition-duration:0.001ms !important;
}
.hero__title .line > span{transform:none}
.hero__sub,.hero__actions,.hero__bike,.callout{opacity:1;transform:none}
.draw{stroke-dashoffset:0 !important}
.callout-svg{opacity:1 !important}
.usecase{opacity:1;transform:none}
.shot .shot__panel{display:none}
}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<!-- ============ HEADER ============ -->
<header class="header" id="header">
<div class="header__inner">
<a class="wordmark" href="#top" aria-label="Lumen Cycles, home">
<span class="wordmark__name">Lumen</span>
<span class="wordmark__sub">Cycles / Copenhagen</span>
</a>
<nav class="nav" id="nav" aria-label="Primary">
<a href="#bikes">Bikes</a>
<a href="#fit">The fit</a>
<a href="#workshop">Workshop</a>
<a href="#service">Service</a>
<a href="#service" data-opt>Service & care</a>
<a href="#fit" data-opt>Journal</a>
<a href="#start" data-opt>Contact</a>
</nav>
<a class="btn header__cta" href="#start">
Book a fit
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</a>
<button class="nav-toggle" id="navToggle" aria-expanded="false" aria-controls="nav" aria-label="Menu">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true">
<path d="M2 5h14M2 9h14M2 13h14" stroke="currentColor" stroke-width="1.5"/>
</svg>
</button>
</div>
</header>
<main id="main">
<!-- ============ HERO ============ -->
<section class="hero" id="top" aria-labelledby="heroTitle">
<div class="wrap hero__body grid">
<div class="hero__rail mono" aria-hidden="true">
<span>LC / 001</span>
<span>Custom cargo</span>
<span>Made to fit</span>
</div>
<div class="hero__copy">
<h1 class="hero__title" id="heroTitle">
<span class="line"><span>A bike built</span></span>
<span class="line"><span><em>around</em> your</span></span>
<span class="line"><span>life.</span></span>
</h1>
<p class="hero__sub body-lg">
Custom electric cargo bikes, designed and assembled in Copenhagen for the way
you actually carry people, work, and everyday things.
</p>
<div class="hero__actions">
<a class="btn" href="#start">
Book a fitting
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</a>
<a class="link" href="#bikes">
Explore the bikes
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</a>
</div>
</div>
<figure class="hero__figure">
<div class="hero__stage">
<div class="hero__stage-label mono">Diagram / LC-001 / side elevation</div>
<svg class="hero__bike" viewBox="0 0 1200 620" role="img"
aria-label="Technical side elevation of a Lumen Cycles custom electric cargo bike: long-tail steel frame, front cargo bay, steering linkage, mid-drive motor and integrated battery.">
<title>Lumen Cycles custom cargo bike — side elevation</title>
<!-- contact shadow -->
<ellipse class="shadow-plate" cx="620" cy="562" rx="430" ry="16"/>
<!-- ground rail -->
<line x1="40" y1="545" x2="1160" y2="545" stroke="#C9C8BF" stroke-width="1"/>
<!-- ===== wheels ===== -->
<!-- rear wheel (long-tail side) -->
<g>
<circle cx="300" cy="430" r="118" fill="none" stroke="#202322" stroke-width="3"/>
<circle cx="300" cy="430" r="106" fill="none" stroke="#202322" stroke-width="1"/>
<circle cx="300" cy="430" r="14" fill="none" stroke="#202322" stroke-width="2"/>
<circle cx="300" cy="430" r="4" fill="#202322"/>
<g stroke="#202322" stroke-width="1">
<line x1="300" y1="312" x2="300" y2="548"/>
<line x1="182" y1="430" x2="418" y2="430"/>
<line x1="217" y1="347" x2="383" y2="513"/>
<line x1="383" y1="347" x2="217" y2="513"/>
<line x1="253" y1="320" x2="347" y2="540"/>
<line x1="347" y1="320" x2="253" y2="540"/>
<line x1="192" y1="383" x2="408" y2="477"/>
<line x1="192" y1="477" x2="408" y2="383"/>
</g>
</g>
<!-- front wheel -->
<g>
<circle cx="985" cy="430" r="112" fill="none" stroke="#202322" stroke-width="3"/>
<circle cx="985" cy="430" r="100" fill="none" stroke="#202322" stroke-width="1"/>
<circle cx="985" cy="430" r="13" fill="none" stroke="#202322" stroke-width="2"/>
<circle cx="985" cy="430" r="4" fill="#202322"/>
<g stroke="#202322" stroke-width="1">
<line x1="985" y1="318" x2="985" y2="542"/>
<line x1="873" y1="430" x2="1097" y2="430"/>
<line x1="906" y1="351" x2="1064" y2="509"/>
<line x1="1064" y1="351" x2="906" y2="509"/>
<line x1="941" y1="325" x2="1029" y2="535"/>
<line x1="1029" y1="325" x2="941" y2="535"/>
</g>
</g>
<!-- ===== frame ===== -->
<g stroke="#202322" stroke-width="4" fill="none" stroke-linecap="square">
<!-- seat tube -->
<line x1="505" y1="222" x2="528" y2="452"/>
<!-- top tube -->
<line x1="518" y1="252" x2="838" y2="262"/>
<!-- down tube -->
<line x1="532" y1="412" x2="852" y2="330"/>
<!-- head tube -->
<line x1="838" y1="248" x2="868" y2="322"/>
<!-- chainstay -->
<line x1="528" y1="452" x2="300" y2="430"/>
<!-- seatstay -->
<line x1="512" y1="268" x2="312" y2="412"/>
<!-- bottom bracket shell -->
<circle cx="528" cy="452" r="17" stroke-width="3"/>
</g>
<!-- long-tail cargo deck -->
<g stroke="#202322" stroke-width="3" fill="none">
<!-- deck rails -->
<line x1="238" y1="292" x2="556" y2="292"/>
<line x1="238" y1="316" x2="556" y2="316"/>
<!-- stanchions -->
<line x1="262" y1="316" x2="300" y2="418"/>
<line x1="332" y1="316" x2="352" y2="418"/>
<line x1="452" y1="316" x2="472" y2="392"/>
<line x1="540" y1="316" x2="522" y2="288"/>
<!-- deck end caps -->
<line x1="238" y1="292" x2="238" y2="316"/>
<line x1="556" y1="292" x2="556" y2="316"/>
<!-- side rail of passenger deck -->
<line x1="250" y1="272" x2="548" y2="272" stroke-width="2"/>
<line x1="250" y1="272" x2="238" y2="292" stroke-width="2"/>
<line x1="548" y1="272" x2="556" y2="292" stroke-width="2"/>
</g>
<!-- child seat mounts on deck -->
<g stroke="#202322" stroke-width="2" fill="none">
<rect x="278" y="236" width="76" height="36"/>
<line x1="278" y1="254" x2="354" y2="254"/>
<rect x="382" y="236" width="76" height="36"/>
<line x1="382" y1="254" x2="458" y2="254"/>
</g>
<!-- front cargo bay -->
<g>
<!-- platform -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="838" y1="352" x2="1112" y2="352"/>
<line x1="838" y1="352" x2="838" y2="384"/>
<line x1="1112" y1="352" x2="1112" y2="384"/>
<line x1="838" y1="384" x2="1112" y2="384"/>
</g>
<!-- box -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M856 352 V246 H1096 V352"/>
<line x1="856" y1="246" x2="1096" y2="246"/>
<line x1="856" y1="272" x2="1096" y2="272"/>
<!-- lid seam -->
<line x1="872" y1="272" x2="872" y2="246" stroke-width="1.5"/>
<line x1="1080" y1="272" x2="1080" y2="246" stroke-width="1.5"/>
</g>
<!-- box floor texture -->
<g stroke="#C9C8BF" stroke-width="1">
<line x1="868" y1="336" x2="1084" y2="336"/>
<line x1="868" y1="320" x2="1084" y2="320"/>
<line x1="868" y1="304" x2="1084" y2="304"/>
<line x1="868" y1="288" x2="1084" y2="288"/>
</g>
</g>
<!-- steering linkage -->
<g stroke="#202322" fill="none">
<!-- head tube extension / stem -->
<line x1="848" y1="252" x2="800" y2="196" stroke-width="4"/>
<!-- handlebar -->
<line x1="762" y1="188" x2="838" y2="204" stroke-width="5" stroke-linecap="round"/>
<circle cx="762" cy="188" r="7" stroke-width="2" fill="#F3F0E8"/>
<!-- linkage rod down to fork -->
<line x1="862" y1="318" x2="952" y2="398" stroke-width="3.5"/>
<line x1="952" y1="398" x2="985" y2="422" stroke-width="3.5"/>
<!-- fork -->
<line x1="968" y1="392" x2="985" y2="418" stroke-width="4"/>
<line x1="968" y1="392" x2="1002" y2="418" stroke-width="4"/>
<!-- linkage pivot -->
<circle cx="862" cy="318" r="7" stroke-width="2" fill="#F3F0E8"/>
<circle cx="952" cy="398" r="6" stroke-width="2" fill="#F3F0E8"/>
</g>
<!-- saddle + seatpost -->
<g stroke="#202322" fill="none">
<line x1="505" y1="222" x2="492" y2="172" stroke-width="4"/>
<path d="M446 168 C462 156, 528 154, 546 166 C534 180, 470 182, 446 168 Z" stroke-width="2.5" fill="#F3F0E8"/>
</g>
<!-- motor at bottom bracket -->
<g>
<circle cx="528" cy="452" r="30" fill="#202322"/>
<circle cx="528" cy="452" r="18" fill="none" stroke="#F3F0E8" stroke-width="2"/>
<circle cx="528" cy="452" r="5" fill="#E95B2B"/>
<!-- crank -->
<line x1="528" y1="452" x2="566" y2="512" stroke="#202322" stroke-width="5"/>
<rect x="556" y="512" width="42" height="10" fill="#202322"/>
<!-- chainring -->
<circle cx="528" cy="452" r="42" fill="none" stroke="#202322" stroke-width="2"/>
</g>
<!-- chain -->
<path d="M528 410 L300 418 M528 494 L300 442" stroke="#202322" stroke-width="1.5" stroke-dasharray="5 4"/>
<!-- battery on seat tube (voltage accent) -->
<g transform="rotate(-6 592 344)">
<rect x="552" y="286" width="62" height="118" rx="0" fill="#202322"/>
<rect x="560" y="294" width="46" height="86" fill="none" stroke="#E95B2B" stroke-width="2"/>
<rect x="560" y="294" width="46" height="16" fill="#E95B2B"/>
<line x1="568" y1="322" x2="598" y2="322" stroke="#E95B2B" stroke-width="2"/>
<line x1="568" y1="338" x2="598" y2="338" stroke="#E95B2B" stroke-width="2"/>
<line x1="568" y1="354" x2="590" y2="354" stroke="#E95B2B" stroke-width="2"/>
</g>
<!-- mudguards -->
<g stroke="#202322" stroke-width="2" fill="none">
<path d="M188 424 A118 118 0 0 1 268 318"/>
<path d="M884 418 A112 112 0 0 1 962 322"/>
</g>
<!-- lights -->
<g>
<rect x="1108" y="326" width="26" height="18" fill="#202322"/>
<rect x="1134" y="330" width="8" height="10" fill="#E95B2B"/>
<rect x="212" y="300" width="20" height="14" fill="#202322"/>
</g>
<!-- dimension rails -->
<g stroke="#C9C8BF" stroke-width="1">
<line x1="300" y1="588" x2="985" y2="588"/>
<line x1="300" y1="578" x2="300" y2="598"/>
<line x1="985" y1="578" x2="985" y2="598"/>
</g>
<text x="642" y="610" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="13" letter-spacing="2" fill="#6B6D67">WHEELBASE 1180 MM</text>
<!-- registration marks -->
<g stroke="#E95B2B" stroke-width="2">
<line x1="300" y1="430" x2="300" y2="430"/>
<circle cx="300" cy="430" r="4" fill="#E95B2B" stroke="none"/>
<circle cx="985" cy="430" r="4" fill="#E95B2B" stroke="none"/>
<circle cx="528" cy="452" r="4" fill="#E95B2B" stroke="none"/>
</g>
</svg>
<!-- callouts -->
<div class="callout" style="left:4%;top:38%">
<span class="callout__dot"></span>
<span class="callout__line"></span>
<span>01 / Steel frame</span>
</div>
<div class="callout" style="left:4%;top:56%">
<span class="callout__dot"></span>
<span class="callout__line"></span>
<span>02 / Configurable cargo</span>
</div>
<div class="callout callout--flip" style="right:4%;top:22%">
<span class="callout__dot"></span>
<span class="callout__line"></span>
<span>03 / Steering linkage</span>
</div>
<div class="callout callout--flip" style="right:4%;top:70%">
<span class="callout__dot"></span>
<span class="callout__line"></span>
<span>04 / Electric assist</span>
</div>
</div>
</figure>
</div>
<div class="wrap hero__rail-bottom">
<div class="metadata-rail">
<span>01 / The object</span>
<span>LC-001 / long-tail configuration</span>
</div>
</div>
</section>
<!-- ============ TRUST ============ -->
<section class="trust" aria-label="How Lumen works">
<div class="wrap">
<div class="trust__row">
<div class="trust__item">
<svg class="trust__icon" viewBox="0 0 32 32" fill="none" aria-hidden="true">
<path d="M4 24h24M8 24V12l8-5 8 5v12" stroke="currentColor" stroke-width="1.5"/>
<path d="M13 24v-6h6v6" stroke="currentColor" stroke-width="1.5"/>
</svg>
<div>
<h2 class="trust__label">Built in Copenhagen</h2>
<p class="trust__copy">Designed, welded, assembled, and tested by the same small workshop team.</p>
</div>
</div>
<div class="trust__item">
<svg class="trust__icon" viewBox="0 0 32 32" fill="none" aria-hidden="true">
<circle cx="16" cy="16" r="11" stroke="currentColor" stroke-width="1.5"/>
<path d="M16 8v8l6 4" stroke="currentColor" stroke-width="1.5"/>
<path d="M5 16h3M24 16h3M16 5v3M16 24v3" stroke="currentColor" stroke-width="1.5"/>
</svg>
<div>
<h2 class="trust__label">Fitted to the rider</h2>
<p class="trust__copy">Every build starts with your height, reach, cargo, passengers, and daily route.</p>
</div>
</div>
<div class="trust__item">
<svg class="trust__icon" viewBox="0 0 32 32" fill="none" aria-hidden="true">
<path d="M16 5 27 10v7c0 6-4.6 10.4-11 12-6.4-1.6-11-6-11-12v-7L16 5Z" stroke="currentColor" stroke-width="1.5"/>
<path d="M11 16l3.5 3.5L21 13" stroke="currentColor" stroke-width="1.5"/>
</svg>
<div>
<h2 class="trust__label">Serviced for the long term</h2>
<p class="trust__copy">A local workshop, spare parts, and a service relationship that continues after handover.</p>
</div>
</div>
</div>
</div>
</section>
<!-- ============ MODELS ============ -->
<section class="models" id="bikes" aria-labelledby="modelsTitle">
<div class="wrap">
<div class="grid models__head">
<h2 class="display models__title" id="modelsTitle">Three ways to carry a life.</h2>
<p class="mono models__marker">Choose your frame</p>
</div>
<div class="models__rail" id="modelRail" role="group" aria-label="Cargo bike models">
<!-- CORE -->
<div class="model" data-model="core">
<button class="model__toggle" type="button" aria-pressed="false"
aria-label="Select Core model, urban utility cargo bike from 4,950 euros">
</button>
<span class="model__marker">Best value</span>
<div class="model__fig">
<svg viewBox="0 0 300 400" role="img" aria-label="Frame geometry of the Lumen Core: compact urban utility cargo bike with a flat front platform.">
<rect width="300" height="400" fill="#F3F0E8"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="24" y1="330" x2="276" y2="330"/>
<line x1="24" y1="60" x2="24" y2="340"/>
</g>
<!-- wheels -->
<circle cx="82" cy="286" r="46" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="82" cy="286" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<circle cx="228" cy="286" r="46" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="228" cy="286" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<!-- frame -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="112" y1="160" x2="118" y2="288"/>
<line x1="118" y1="178" x2="196" y2="186"/>
<line x1="118" y1="262" x2="204" y2="212"/>
<line x1="196" y1="182" x2="206" y2="218"/>
<line x1="118" y1="288" x2="82" y2="286"/>
<line x1="114" y1="192" x2="88" y2="272"/>
<circle cx="118" cy="288" r="9" stroke-width="2"/>
</g>
<!-- cargo platform -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<line x1="196" y1="232" x2="266" y2="232"/>
<line x1="196" y1="232" x2="196" y2="248"/>
<line x1="266" y1="232" x2="266" y2="248"/>
<line x1="196" y1="248" x2="266" y2="248"/>
</g>
<!-- battery -->
<rect x="140" y="200" width="22" height="54" fill="#202322"/>
<rect x="145" y="206" width="12" height="30" fill="none" stroke="#E95B2B" stroke-width="1.5"/>
<!-- saddle -->
<path d="M92 152 C102 145 128 145 138 152 C128 160 102 160 92 152Z" fill="none" stroke="#202322" stroke-width="2"/>
<!-- bar -->
<line x1="188" y1="152" x2="216" y2="160" stroke="#202322" stroke-width="3"/>
<text x="24" y="42" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">LC-CORE / 700C / FLAT BAY</text>
</svg>
</div>
<h3 class="model__name">Core</h3>
<p class="model__use">Urban utility for school runs, groceries, and compact daily cargo.</p>
<dl class="model__specs">
<div><dt>Capacity</dt><dd>80 kg</dd></div>
<div><dt>Assist</dt><dd>250 W mid-drive</dd></div>
<div><dt>Range</dt><dd>60–90 km</dd></div>
<div><dt>Turnaround</dt><dd>5–7 weeks</dd></div>
</dl>
<div class="model__foot">
<span class="price">From €4,950</span>
<span class="link">View details
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</span>
</div>
</div>
<!-- LOAD -->
<div class="model" data-model="load">
<button class="model__toggle" type="button" aria-pressed="true"
aria-label="Select Load model, front-bay family and work cargo bike from 6,450 euros">
</button>
<span class="model__marker">Most requested</span>
<div class="model__fig">
<svg viewBox="0 0 300 400" role="img" aria-label="Frame geometry of the Lumen Load: long front-bay cargo bike for family and work use.">
<rect width="300" height="400" fill="#F3F0E8"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="24" y1="330" x2="276" y2="330"/>
<line x1="24" y1="60" x2="24" y2="340"/>
</g>
<circle cx="72" cy="288" r="42" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="72" cy="288" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<circle cx="236" cy="292" r="38" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="236" cy="292" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<!-- frame, front loader -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="108" y1="158" x2="114" y2="292"/>
<line x1="114" y1="176" x2="176" y2="184"/>
<line x1="114" y1="266" x2="180" y2="222"/>
<line x1="176" y1="180" x2="184" y2="228"/>
<line x1="114" y1="292" x2="72" y2="288"/>
<line x1="110" y1="190" x2="80" y2="274"/>
<circle cx="114" cy="292" r="9" stroke-width="2"/>
</g>
<!-- front bay box -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M186 232 V152 H268 V232"/>
<line x1="186" y1="168" x2="268" y2="168"/>
<line x1="186" y1="232" x2="268" y2="232"/>
<line x1="186" y1="232" x2="186" y2="248"/>
<line x1="268" y1="232" x2="268" y2="248"/>
</g>
<!-- steering linkage -->
<g stroke="#202322" stroke-width="2" fill="none">
<line x1="182" y1="228" x2="224" y2="266"/>
<line x1="224" y1="266" x2="236" y2="286"/>
<line x1="168" y1="156" x2="188" y2="152"/>
</g>
<rect x="136" y="200" width="22" height="52" fill="#202322"/>
<rect x="141" y="206" width="12" height="28" fill="none" stroke="#E95B2B" stroke-width="1.5"/>
<path d="M88 150 C98 143 124 143 134 150 C124 158 98 158 88 150Z" fill="none" stroke="#202322" stroke-width="2"/>
<text x="24" y="42" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">LC-LOAD / 20" FWD / FRONT BAY</text>
</svg>
</div>
<h3 class="model__name">Load</h3>
<p class="model__use">Maximum everyday usefulness for families, tools, deliveries, and shared cargo.</p>
<dl class="model__specs">
<div><dt>Capacity</dt><dd>120 kg</dd></div>
<div><dt>Assist</dt><dd>250 W mid-drive</dd></div>
<div><dt>Range</dt><dd>70–110 km</dd></div>
<div><dt>Turnaround</dt><dd>6–8 weeks</dd></div>
</dl>
<div class="model__foot">
<span class="price">From €6,450</span>
<span class="link">View details
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</span>
</div>
</div>
<!-- LONGTAIL -->
<div class="model" data-model="longtail">
<button class="model__toggle" type="button" aria-pressed="false"
aria-label="Select Longtail model, extended cargo deck bike from 6,950 euros">
</button>
<span class="model__marker">Longest deck</span>
<div class="model__fig">
<svg viewBox="0 0 300 400" role="img" aria-label="Frame geometry of the Lumen Longtail: extended rear cargo deck for two passengers or bulky loads.">
<rect width="300" height="400" fill="#F3F0E8"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="24" y1="330" x2="276" y2="330"/>
<line x1="24" y1="60" x2="24" y2="340"/>
</g>
<circle cx="88" cy="288" r="42" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="88" cy="288" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<circle cx="222" cy="288" r="42" fill="none" stroke="#202322" stroke-width="2.5"/>
<circle cx="222" cy="288" r="6" fill="none" stroke="#202322" stroke-width="1.5"/>
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="132" y1="156" x2="138" y2="290"/>
<line x1="138" y1="176" x2="200" y2="182"/>
<line x1="138" y1="262" x2="210" y2="214"/>
<line x1="200" y1="178" x2="210" y2="220"/>
<line x1="138" y1="290" x2="88" y2="288"/>
<line x1="134" y1="190" x2="94" y2="272"/>
<circle cx="138" cy="290" r="9" stroke-width="2"/>
</g>
<!-- long deck -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<line x1="36" y1="216" x2="140" y2="216"/>
<line x1="36" y1="232" x2="140" y2="232"/>
<line x1="36" y1="216" x2="36" y2="232"/>
<line x1="52" y1="232" x2="66" y2="276"/>
<line x1="112" y1="232" x2="122" y2="272"/>
</g>
<!-- passenger rails + seats -->
<g stroke="#202322" stroke-width="2" fill="none">
<line x1="40" y1="198" x2="136" y2="198"/>
<line x1="40" y1="198" x2="36" y2="216"/>
<line x1="136" y1="198" x2="140" y2="216"/>
<rect x="52" y="172" width="34" height="26"/>
<rect x="98" y="172" width="34" height="26"/>
</g>
<rect x="158" y="200" width="22" height="52" fill="#202322"/>
<rect x="163" y="206" width="12" height="28" fill="none" stroke="#E95B2B" stroke-width="1.5"/>
<path d="M112 148 C122 141 148 141 158 148 C148 156 122 156 112 148Z" fill="none" stroke="#202322" stroke-width="2"/>
<line x1="192" y1="152" x2="214" y2="160" stroke="#202322" stroke-width="3"/>
<text x="24" y="42" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">LC-LONG / 20"/26" / EXT. DECK</text>
</svg>
</div>
<h3 class="model__name">Longtail</h3>
<p class="model__use">Extended capacity with an agile footprint for two passengers and larger loads.</p>
<dl class="model__specs">
<div><dt>Capacity</dt><dd>150 kg</dd></div>
<div><dt>Assist</dt><dd>250 W mid-drive</dd></div>
<div><dt>Range</dt><dd>80–120 km</dd></div>
<div><dt>Turnaround</dt><dd>7–8 weeks</dd></div>
</dl>
<div class="model__foot">
<span class="price">From €6,950</span>
<span class="link">View details
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</span>
</div>
</div>
</div>
<!-- live specification summary -->
<div class="models__summary" id="modelSummary" aria-live="polite">
<div>
<p class="mono sum-label">Selected</p>
<p class="sum-value sum-fade" id="sumName">Load</p>
</div>
<div>
<p class="mono sum-label">From</p>
<p class="sum-value sum-fade" id="sumPrice">€6,450</p>
</div>
<div>
<p class="mono sum-label">Payload</p>
<p class="sum-value sum-fade" id="sumCap">120 kg</p>
</div>
<div>
<p class="mono sum-label">Assist range</p>
<p class="sum-value sum-fade" id="sumRange">70–110 km</p>
</div>
<p class="sum-note" id="sumNote">
Load is the configuration most Copenhagen families choose: a full front bay, two child-seat
positions, and 120 kg of everyday payload. Prices include the fitting session, custom frame
build, assembly, and handover.
</p>
</div>
<div class="metadata-rail" style="margin-top:var(--s8)">
<span>02 / Choose the frame</span>
<span>Prices incl. VAT / fitting & handover included</span>
</div>
</div>
</section>
<!-- ============ BUILD SHEET (signature) ============ -->
<section class="sheet" id="fit" aria-labelledby="sheetTitle">
<div class="wrap">
<div class="grid sheet__intro">
<p class="mono sheet__label">From first measurement</p>
<h2 class="sheet__title" id="sheetTitle">One frame. Your cargo. Your everyday.</h2>
</div>
<div class="sheet__body" id="sheetBody">
<div class="sheet__stack">
<div class="stage-block">
<p class="mono stage-block__num">01 / Use</p>
<h3 class="stage-block__title">What it carries</h3>
<ul class="stage-block__list">
<li>Family</li>
<li>Work</li>
<li>Weekend</li>
</ul>
<p class="stage-block__copy" style="margin-top:var(--s4)">
The build starts with what moves with you — passengers, tools, deliveries, or the weekly shop.
</p>
</div>
</div>
<figure class="sheet__figure">
<svg class="sheet__diagram" id="sheetDiagram" viewBox="0 0 1100 560" role="img"
aria-label="Construction diagram: cargo bike frame geometry drawn from the front cargo bay through the steering column to the rear wheel, with the long-tail deck extending rearward.">
<title>Frame construction diagram</title>
<!-- horizontal guide rails -->
<g stroke="#D7E0D8" stroke-width="1" opacity="0.34">
<line class="draw rail" x1="40" y1="120" x2="1060" y2="120"/>
<line class="draw rail" x1="40" y1="240" x2="1060" y2="240"/>
<line class="draw rail" x1="40" y1="380" x2="1060" y2="380"/>
<line class="draw rail" x1="40" y1="470" x2="1060" y2="470"/>
</g>
<!-- vertical measurement guides -->
<g stroke="#D7E0D8" stroke-width="1" opacity="0.24">
<line class="draw rail" x1="150" y1="60" x2="150" y2="520"/>
<line class="draw rail" x1="520" y1="60" x2="520" y2="520"/>
<line class="draw rail" x1="900" y1="60" x2="900" y2="520"/>
</g>
<!-- axles -->
<g>
<circle class="callout-svg" cx="180" cy="380" r="5" fill="#E95B2B"/>
<circle class="callout-svg" cx="900" cy="380" r="5" fill="#E95B2B"/>
</g>
<!-- wheels -->
<g fill="none" stroke="#D7E0D8" stroke-width="2.5">
<circle cx="180" cy="380" r="92"/>
<circle cx="180" cy="380" r="10" stroke-width="1.5"/>
<circle cx="900" cy="380" r="92"/>
<circle cx="900" cy="380" r="10" stroke-width="1.5"/>
</g>
<!-- main frame triangle -->
<g fill="none" stroke="#FBFAF6" stroke-width="3.5" stroke-linecap="square">
<line class="draw rail" x1="430" y1="182" x2="446" y2="392"/>
<line class="draw rail" x1="440" y1="208" x2="762" y2="218"/>
<line class="draw rail" x1="446" y1="362" x2="752" y2="288"/>
<line class="draw rail" x1="762" y1="212" x2="788" y2="292"/>
<line class="draw rail" x1="446" y1="392" x2="180" y2="380"/>
<line class="draw rail" x1="436" y1="224" x2="196" y2="358"/>
<circle cx="446" cy="392" r="14" stroke-width="2.5"/>
</g>
<!-- long-tail deck extension (grows) -->
<g fill="none" stroke="#E95B2B" stroke-width="3">
<line class="draw tail" x1="430" y1="252" x2="128" y2="252"/>
<line class="draw tail" x1="430" y1="278" x2="128" y2="278"/>
<line class="draw tail" x1="128" y1="252" x2="128" y2="278"/>
<line class="draw tail" x1="152" y1="278" x2="176" y2="352" stroke-width="2"/>
<line class="draw tail" x1="268" y1="278" x2="290" y2="358" stroke-width="2"/>
<line class="draw tail" x1="410" y1="278" x2="424" y2="336" stroke-width="2"/>
</g>
<!-- front cargo bay -->
<g fill="none" stroke="#D7E0D8" stroke-width="2.5">
<path class="draw rail" d="M766 292 V196 H984 V292"/>
<line class="draw rail" x1="766" y1="216" x2="984" y2="216"/>
<line class="draw rail" x1="766" y1="292" x2="984" y2="292"/>
<line class="draw rail" x1="780" y1="196" x2="780" y2="216"/>
<line class="draw rail" x1="970" y1="196" x2="970" y2="216"/>
</g>
<!-- steering column + linkage -->
<g fill="none" stroke="#FBFAF6" stroke-width="3">
<line class="draw rail" x1="772" y1="214" x2="720" y2="146"/>
<line class="draw rail" x1="688" y1="138" x2="752" y2="154" stroke-width="4"/>
<line class="draw rail" x1="782" y1="292" x2="862" y2="348" stroke="#E95B2B"/>
<line class="draw rail" x1="862" y1="348" x2="898" y2="372" stroke="#E95B2B"/>
<circle class="callout-svg" cx="782" cy="292" r="7" stroke="#E95B2B" stroke-width="2"/>
<circle class="callout-svg" cx="862" cy="348" r="6" stroke="#E95B2B" stroke-width="2"/>
</g>
<!-- battery / motor markers -->
<g class="callout-svg">
<rect x="470" y="272" width="36" height="86" fill="#FBFAF6"/>
<rect x="477" y="279" width="22" height="52" fill="none" stroke="#E95B2B" stroke-width="2"/>
<rect x="477" y="279" width="22" height="12" fill="#E95B2B"/>
<circle cx="446" cy="392" r="34" fill="none" stroke="#FBFAF6" stroke-width="2"/>
<circle cx="446" cy="392" r="8" fill="#E95B2B"/>
</g>
<!-- saddle -->
<g fill="none" stroke="#D7E0D8" stroke-width="2">
<line class="draw rail" x1="430" y1="182" x2="416" y2="132"/>
<path class="draw rail" d="M370 128 C384 118 442 116 460 128 C444 140 388 142 370 128 Z"/>
</g>
<!-- callout labels -->
<g class="callout-svg" fill="#D7E0D8">
<text x="150" y="72">Axle A / rear</text>
<text x="520" y="72">BB / motor</text>
<text x="900" y="72">Axle B / front</text>
</g>
<!-- measurement callouts -->
<g class="callout-svg" stroke="#E95B2B" stroke-width="1.5" fill="none">
<line x1="180" y1="500" x2="900" y2="500"/>
<line x1="180" y1="490" x2="180" y2="510"/>
<line x1="900" y1="490" x2="900" y2="510"/>
</g>
<g class="callout-svg">
<text x="540" y="532" text-anchor="middle" fill="#E95B2B"
font-family="ui-monospace,Menlo,monospace" font-size="13" letter-spacing="2">WHEELBASE 1180 MM</text>
<text x="40" y="176" fill="#D7E0D8" opacity="0.8"
font-family="ui-monospace,Menlo,monospace" font-size="12" letter-spacing="2">REACH</text>
<text x="40" y="332" fill="#D7E0D8" opacity="0.8"
font-family="ui-monospace,Menlo,monospace" font-size="12" letter-spacing="2">LOAD FLOOR</text>
</g>
</svg>
<div class="usecases" id="useCases" aria-label="Use case positions">
<span class="usecase">Family</span>
<span class="usecase">Work</span>
<span class="usecase">Weekend</span>
</div>
<div class="sheet__ruler mono">
<span>0</span><span>250</span><span>500</span><span>750</span><span>1000 MM</span>
</div>
</figure>
<div class="sheet__stack">
<div class="stage-block">
<p class="mono stage-block__num">02 / Fit</p>
<h3 class="stage-block__title">Rider + load</h3>
<ul class="stage-block__list">
<li>Saddle height</li>
<li>Reach</li>
<li>Step-over</li>
<li>Stand-over</li>
</ul>
<p class="stage-block__copy" style="margin-top:var(--s4)">
Your measurements set the geometry. The frame is built to those numbers, not to a size chart.
</p>
</div>
<div class="stage-block">
<p class="mono stage-block__num">03 / Finish</p>
<h3 class="stage-block__title">Paint + parts</h3>
<ul class="stage-block__list">
<li>6 frame colours</li>
<li>3 cargo configurations</li>
<li>2 wheel builds</li>
</ul>
<p class="stage-block__copy" style="margin-top:var(--s4)">
Colour, rack, seating, lighting, and drivetrain are specified with you before we cut a tube.
</p>
</div>
</div>
</div>
<div class="metadata-rail" style="margin-top:var(--s9)">
<span>Scroll / frame-to-cargo transformation</span>
<span>LC / construction sheet / rev. 04</span>
</div>
</div>
</section>
<!-- ============ PROCESS ============ -->
<section class="process" id="workshop" aria-labelledby="processTitle">
<div class="wrap">
<div class="grid process__head">
<p class="mono process__label">We build in the open</p>
<h2 class="process__title" id="processTitle">The work is part of the warranty.</h2>
<div class="process__stamp" id="processStamp" aria-hidden="true">
<svg viewBox="0 0 96 96" fill="none">
<circle cx="48" cy="48" r="45" stroke="#202322" stroke-width="1"/>
<circle cx="48" cy="48" r="36" stroke="#C9C8BF" stroke-width="1"/>
<path d="M48 12v10M48 74v10M12 48h10M74 48h10" stroke="#E95B2B" stroke-width="2"/>
<path d="M32 48h32M48 32v32" stroke="#202322" stroke-width="1"/>
<text x="48" y="45" text-anchor="middle" fill="#202322"
font-family="ui-monospace,Menlo,monospace" font-size="9" letter-spacing="1.4">BUILT</text>
<text x="48" y="58" text-anchor="middle" fill="#202322"
font-family="ui-monospace,Menlo,monospace" font-size="9" letter-spacing="1.4">TO ORDER</text>
</svg>
</div>
</div>
<div class="process__grid">
<article class="step" data-step>
<span class="mono step__num">01</span>
<div class="step__media">
<svg viewBox="0 0 400 300" role="img" aria-label="A rider stands beside a workstand while a builder measures saddle height and reach with a tape and fitting jig.">
<rect width="400" height="300" fill="#FBFAF6"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="240" x2="400" y2="240"/>
<line x1="0" y1="40" x2="400" y2="40"/>
</g>
<!-- workstand -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="236" y1="240" x2="236" y2="96"/>
<line x1="206" y1="240" x2="266" y2="240"/>
<line x1="236" y1="120" x2="290" y2="140"/>
<line x1="212" y1="150" x2="260" y2="150"/>
</g>
<!-- frame on stand -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="140" y1="150" x2="196" y2="200"/>
<line x1="140" y1="150" x2="196" y2="122"/>
<line x1="196" y1="200" x2="196" y2="122"/>
<circle cx="140" cy="150" r="7"/>
</g>
<!-- measuring tape -->
<path d="M96 96 L196 122" stroke="#E95B2B" stroke-width="2" stroke-dasharray="6 5"/>
<rect x="72" y="82" width="28" height="20" fill="#E95B2B"/>
<!-- builder -->
<g stroke="#202322" stroke-width="3" fill="none">
<circle cx="84" cy="132" r="15"/>
<line x1="84" y1="147" x2="84" y2="198"/>
<line x1="84" y1="164" x2="112" y2="112"/>
<line x1="84" y1="164" x2="60" y2="186"/>
<line x1="84" y1="198" x2="66" y2="240"/>
<line x1="84" y1="198" x2="102" y2="240"/>
</g>
<!-- rider -->
<g stroke="#202322" stroke-width="3" fill="none">
<circle cx="330" cy="122" r="15"/>
<line x1="330" y1="137" x2="330" y2="196"/>
<line x1="330" y1="156" x2="304" y2="182"/>
<line x1="330" y1="156" x2="356" y2="180"/>
<line x1="330" y1="196" x2="312" y2="240"/>
<line x1="330" y1="196" x2="348" y2="240"/>
</g>
<!-- dimension marks -->
<g stroke="#E95B2B" stroke-width="1.5">
<line x1="140" y1="262" x2="196" y2="262"/>
<line x1="140" y1="256" x2="140" y2="268"/>
<line x1="196" y1="256" x2="196" y2="268"/>
</g>
<text x="24" y="284" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">FITTING JIG / SADDLE + REACH</text>
</svg>
</div>
<p class="mono step__label">Measure & specify</p>
<p class="step__copy">
We record rider height, inseam, reach, and the cargo you carry most often. Seat height,
step-over, handlebar position, and cargo volume are fixed from those numbers. You leave
the session with a written specification.
</p>
<span class="mono step__index">Stage 01</span>
</article>
<article class="step" data-step>
<span class="mono step__num">02</span>
<div class="step__media">
<svg viewBox="0 0 400 300" role="img" aria-label="Close view of a welder joining a steel frame tube at a jig, with clean weld beads and a masked dropout area.">
<rect width="400" height="300" fill="#FBFAF6"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="238" x2="400" y2="238"/>
</g>
<!-- frame in jig -->
<g stroke="#202322" stroke-width="5" fill="none">
<line x1="70" y1="200" x2="230" y2="120"/>
<line x1="230" y1="120" x2="320" y2="188"/>
<line x1="70" y1="200" x2="320" y2="188"/>
</g>
<!-- jig plates -->
<g stroke="#202322" stroke-width="2" fill="none">
<rect x="40" y="176" width="60" height="48"/>
<rect x="292" y="164" width="58" height="48"/>
<line x1="40" y1="224" x2="40" y2="240"/>
<line x1="100" y1="224" x2="100" y2="240"/>
<line x1="292" y1="212" x2="292" y2="240"/>
<line x1="350" y1="212" x2="350" y2="240"/>
</g>
<!-- weld beads -->
<g stroke="#E95B2B" stroke-width="2.5" fill="none">
<path d="M224 118 c4 -6 8 -6 12 0 c4 -6 8 -6 12 0 c4 -6 8 -6 12 0"/>
<path d="M224 128 c4 -6 8 -6 12 0 c4 -6 8 -6 12 0"/>
</g>
<!-- torch -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="182" y1="60" x2="238" y2="112"/>
<rect x="150" y="34" width="44" height="26" transform="rotate(38 172 47)"/>
</g>
<g stroke="#E95B2B" stroke-width="1.5" fill="none">
<path d="M244 116 l14 -6M246 124 l16 2M240 110 l8 -14"/>
</g>
<!-- hand -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M126 22 c14 -10 34 -4 40 12 c4 12 -4 22 -16 24 l-22 -6 z"/>
</g>
<text x="24" y="278" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">TIG / 4130 CHROMOLY / JIG TRUE</text>
</svg>
</div>
<p class="mono step__label">Weld & align</p>
<p class="step__copy">
Tubes are cut, mitred, and TIG-welded in a frame jig in Nørrebro. Alignment is checked
cold, then checked again after welding. Every frame is measured before paint and the
numbers are recorded against your specification.
</p>
<span class="mono step__index">Stage 02</span>
</article>
<article class="step" data-step>
<span class="mono step__num">03</span>
<div class="step__media">
<svg viewBox="0 0 400 300" role="img" aria-label="Mechanic installing a front cargo module onto a painted frame on a workshop bench, with parts bins and a torque wrench.">
<rect width="400" height="300" fill="#FBFAF6"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="236" x2="400" y2="236"/>
<line x1="0" y1="52" x2="400" y2="52"/>
</g>
<!-- bench -->
<rect x="40" y="200" width="320" height="36" fill="none" stroke="#202322" stroke-width="2.5"/>
<!-- frame half on bench -->
<g stroke="#202322" stroke-width="4" fill="none">
<line x1="80" y1="188" x2="196" y2="128"/>
<line x1="196" y1="128" x2="268" y2="188"/>
<line x1="80" y1="188" x2="268" y2="188"/>
</g>
<!-- cargo module being fitted -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<rect x="268" y="128" width="86" height="60"/>
<line x1="268" y1="148" x2="354" y2="148"/>
<line x1="268" y1="188" x2="354" y2="188"/>
</g>
<!-- dashed mount lines -->
<g stroke="#E95B2B" stroke-width="1.5" stroke-dasharray="5 5">
<line x1="268" y1="158" x2="236" y2="158"/>
<line x1="268" y1="176" x2="236" y2="176"/>
</g>
<!-- mechanic -->
<g stroke="#202322" stroke-width="3" fill="none">
<circle cx="300" cy="82" r="15"/>
<line x1="300" y1="97" x2="300" y2="150"/>
<line x1="300" y1="114" x2="268" y2="132"/>
<line x1="300" y1="114" x2="336" y2="136"/>
<line x1="300" y1="150" x2="284" y2="200"/>
<line x1="300" y1="150" x2="318" y2="200"/>
</g>
<!-- torque wrench -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="222" y1="96" x2="268" y2="128"/>
<rect x="196" y="82" width="34" height="16" transform="rotate(36 213 90)"/>
</g>
<!-- parts bins -->
<g stroke="#202322" stroke-width="2" fill="none">
<rect x="48" y="150" width="52" height="36"/>
<rect x="48" y="106" width="52" height="36"/>
<line x1="48" y1="168" x2="100" y2="168"/>
<line x1="48" y1="124" x2="100" y2="124"/>
</g>
<text x="24" y="276" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">MODULE FIT / 12 Nm / FRONT BAY</text>
</svg>
</div>
<p class="mono step__label">Assemble & tune</p>
<p class="step__copy">
Wheels are built and tensioned, the motor and battery are paired and tested, and the cargo
modules you specified are fitted. Brakes, shifting, and lighting are set to workshop
tolerances before the bike leaves the stand.
</p>
<span class="mono step__index">Stage 03</span>
</article>
<article class="step" data-step>
<span class="mono step__num">04</span>
<div class="step__media">
<svg viewBox="0 0 400 300" role="img" aria-label="Handover scene outside the workshop: rider and builder facing a finished cargo bike at the doorway, with the service booklet on a bench.">
<rect width="400" height="300" fill="#FBFAF6"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="238" x2="400" y2="238"/>
</g>
<!-- workshop doorway -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M236 238 V96 H372 V238"/>
<line x1="236" y1="112" x2="372" y2="112"/>
<rect x="252" y="132" width="42" height="106"/>
<rect x="310" y="132" width="42" height="106"/>
</g>
<!-- finished cargo bike -->
<g stroke="#202322" stroke-width="3" fill="none">
<circle cx="92" cy="212" r="28"/>
<circle cx="212" cy="212" r="28"/>
<line x1="92" y1="212" x2="140" y2="160"/>
<line x1="140" y1="160" x2="196" y2="172"/>
<line x1="140" y1="160" x2="152" y2="212"/>
<line x1="152" y1="212" x2="212" y2="212"/>
<rect x="176" y="140" width="62" height="34"/>
<line x1="196" y1="172" x2="212" y2="196"/>
</g>
<rect x="150" y="164" width="14" height="34" fill="#E95B2B"/>
<!-- two figures -->
<g stroke="#202322" stroke-width="3" fill="none">
<circle cx="268" cy="150" r="13"/>
<line x1="268" y1="163" x2="268" y2="208"/>
<line x1="268" y1="178" x2="246" y2="196"/>
<line x1="268" y1="178" x2="292" y2="196"/>
<line x1="268" y1="208" x2="254" y2="238"/>
<line x1="268" y1="208" x2="282" y2="238"/>
<circle cx="332" cy="150" r="13"/>
<line x1="332" y1="163" x2="332" y2="208"/>
<line x1="332" y1="178" x2="310" y2="196"/>
<line x1="332" y1="178" x2="352" y2="194"/>
<line x1="332" y1="208" x2="318" y2="238"/>
<line x1="332" y1="208" x2="346" y2="238"/>
</g>
<!-- service booklet -->
<rect x="40" y="182" width="52" height="36" fill="none" stroke="#202322" stroke-width="2"/>
<line x1="40" y1="192" x2="92" y2="192" stroke="#E95B2B" stroke-width="2"/>
<line x1="40" y1="202" x2="92" y2="202" stroke="#C9C8BF" stroke-width="1.5"/>
<line x1="40" y1="210" x2="80" y2="210" stroke="#C9C8BF" stroke-width="1.5"/>
<text x="24" y="276" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="1.6" fill="#6B6D67">HANDOVER / SERVICE BOOKLET</text>
</svg>
</div>
<p class="mono step__label">Hand over & service</p>
<p class="step__copy">
At handover we set the bike up on your body, load your actual cargo, and walk through
charging and care. Service bookings, spare parts, and adjustments continue with the same
workshop after you ride away.
</p>
<span class="mono step__index">Stage 04</span>
</article>
</div>
<div class="proof" id="service">
<div class="proof__item">
<p class="proof__value">05–08 WEEKS</p>
<p class="proof__label">Typical build time from approved specification to handover.</p>
</div>
<div class="proof__item">
<p class="proof__value">2-YEAR WORKSHOP WARRANTY</p>
<p class="proof__label">Frame and build covered by the people who built it.</p>
</div>
<div class="proof__item">
<p class="proof__value">COPENHAGEN SERVICE & REMOTE SUPPORT</p>
<p class="proof__label">A direct line to the workshop before and after delivery.</p>
</div>
</div>
<div class="metadata-rail" style="margin-top:var(--s8)">
<span>03 / The build</span>
<span>Measure / weld / assemble / hand over</span>
</div>
</div>
</section>
<!-- ============ CASE STUDY ============ -->
<section class="case" aria-labelledby="caseTitle">
<div class="wrap grid">
<blockquote class="case__quote" id="caseTitle">
“I stopped planning around the bike.<br>
The bike started planning around us.”
</blockquote>
<div class="case__attr">
<span class="mono">Sofie & Kasper / Nørrebro</span>
<span class="mono">Family configuration</span>
<span class="mono">Load / front bay + two child seats</span>
<span class="mono">25 km daily / 18 months owned</span>
</div>
<div class="case__diptych">
<figure class="shot">
<div class="shot__panel" aria-hidden="true"></div>
<div class="shot__frame">
<svg viewBox="0 0 640 400" role="img" aria-label="A loaded Lumen cargo bike parked at a Copenhagen apartment doorway in winter: front bay full of groceries, a blanket over the child seats.">
<rect width="640" height="400" fill="#F3F0E8"/>
<!-- facade -->
<rect x="0" y="0" width="640" height="400" fill="#EDE9DF"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="330" x2="640" y2="330"/>
</g>
<!-- doorway -->
<g stroke="#202322" stroke-width="3" fill="none">
<rect x="300" y="60" width="200" height="270"/>
<line x1="300" y1="86" x2="500" y2="86"/>
<rect x="318" y="106" width="76" height="224"/>
<rect x="406" y="106" width="76" height="224"/>
<circle cx="386" cy="222" r="5" fill="#202322"/>
<circle cx="414" cy="222" r="5" fill="#202322"/>
</g>
<!-- steps -->
<g stroke="#202322" stroke-width="2" fill="none">
<line x1="286" y1="330" x2="514" y2="330"/>
<line x1="272" y1="348" x2="528" y2="348"/>
</g>
<!-- window left -->
<g stroke="#202322" stroke-width="2" fill="none">
<rect x="60" y="88" width="132" height="168"/>
<line x1="126" y1="88" x2="126" y2="256"/>
<line x1="60" y1="172" x2="192" y2="172"/>
</g>
<!-- bike -->
<g stroke="#202322" fill="none">
<circle cx="148" cy="300" r="44" stroke-width="3"/>
<circle cx="148" cy="300" r="7" stroke-width="2"/>
<circle cx="372" cy="300" r="40" stroke-width="3"/>
<circle cx="372" cy="300" r="7" stroke-width="2"/>
<line x1="148" y1="300" x2="212" y2="238" stroke-width="3.5"/>
<line x1="212" y1="238" x2="304" y2="252" stroke-width="3.5"/>
<line x1="212" y1="238" x2="228" y2="300" stroke-width="3.5"/>
<line x1="228" y1="300" x2="372" y2="300" stroke-width="3.5"/>
<line x1="304" y1="252" x2="348" y2="288" stroke-width="3"/>
<!-- bay -->
<rect x="304" y="212" width="112" height="52" stroke-width="2.5"/>
<!-- groceries -->
<g stroke-width="2">
<rect x="316" y="182" width="30" height="30"/>
<rect x="352" y="176" width="24" height="36"/>
<rect x="382" y="186" width="26" height="26"/>
</g>
<!-- deck + blanket -->
<line x1="86" y1="234" x2="212" y2="234" stroke-width="2.5"/>
<path d="M92 234 c18 -30 96 -30 114 0 z" stroke-width="2.5"/>
<path d="M110 222 c14 -16 62 -16 76 0" stroke-width="1.5"/>
<!-- saddle + bar -->
<path d="M188 216 c12 -8 34 -8 46 0 c-12 8 -34 8 -46 0z" stroke-width="2"/>
<line x1="288" y1="208" x2="316" y2="216" stroke-width="3"/>
</g>
<!-- battery mark -->
<rect x="238" y="252" width="16" height="38" fill="#202322"/>
<rect x="241" y="256" width="10" height="18" fill="none" stroke="#E95B2B" stroke-width="1.5"/>
<!-- winter marks -->
<g stroke="#6B6D67" stroke-width="1" opacity="0.5">
<line x1="40" y1="360" x2="600" y2="360"/>
<line x1="70" y1="372" x2="560" y2="372"/>
</g>
<text x="24" y="40" font-family="ui-monospace,Menlo,monospace" font-size="12" letter-spacing="1.8" fill="#6B6D67">NERREBRO / 07:40 / -2 C</text>
</svg>
</div>
<figcaption class="mono">Loaded for the school run / Nørrebro</figcaption>
</figure>
<figure class="shot">
<div class="shot__panel" aria-hidden="true"></div>
<div class="shot__frame">
<svg viewBox="0 0 640 400" role="img" aria-label="A rider installs a child seat onto the rear deck of a Lumen Longtail in a workshop, hands tightening the mount rail.">
<rect width="640" height="400" fill="#F3F0E8"/>
<rect x="0" y="0" width="640" height="400" fill="#EDE9DF"/>
<g stroke="#C9C8BF" stroke-width="1">
<line x1="0" y1="322" x2="640" y2="322"/>
<line x1="0" y1="56" x2="640" y2="56"/>
</g>
<!-- bench back wall -->
<g stroke="#202322" stroke-width="2" fill="none">
<rect x="420" y="88" width="160" height="96"/>
<line x1="420" y1="136" x2="580" y2="136"/>
<line x1="500" y1="88" x2="500" y2="184"/>
</g>
<!-- longtail bike -->
<g stroke="#202322" fill="none">
<circle cx="176" cy="286" r="48" stroke-width="3"/>
<circle cx="176" cy="286" r="7" stroke-width="2"/>
<circle cx="424" cy="286" r="48" stroke-width="3"/>
<circle cx="424" cy="286" r="7" stroke-width="2"/>
<line x1="176" y1="286" x2="252" y2="222" stroke-width="3.5"/>
<line x1="252" y1="222" x2="386" y2="232" stroke-width="3.5"/>
<line x1="252" y1="222" x2="268" y2="286" stroke-width="3.5"/>
<line x1="268" y1="286" x2="424" y2="286" stroke-width="3.5"/>
<!-- long deck -->
<line x1="112" y1="212" x2="252" y2="212" stroke-width="2.5"/>
<line x1="112" y1="232" x2="252" y2="232" stroke-width="2.5"/>
<line x1="112" y1="212" x2="112" y2="232" stroke-width="2.5"/>
<line x1="132" y1="232" x2="152" y2="276" stroke-width="2"/>
<!-- rear rail -->
<line x1="116" y1="192" x2="248" y2="192" stroke-width="2"/>
</g>
<!-- child seat being installed -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M146 190 v-38 c0 -14 12 -22 28 -22 h34 c16 0 28 8 28 22 v38 z"/>
<line x1="152" y1="152" x2="230" y2="152"/>
<line x1="158" y1="132" x2="222" y2="132"/>
</g>
<!-- mount bolts -->
<g fill="#E95B2B">
<circle cx="166" cy="192" r="5"/>
<circle cx="216" cy="192" r="5"/>
</g>
<!-- hands -->
<g stroke="#202322" stroke-width="2.5" fill="none">
<path d="M244 126 c16 -14 44 -10 52 10 c6 16 -4 30 -22 32 l-28 -8 z"/>
<path d="M116 148 c14 -16 42 -16 52 4 c6 14 -2 28 -18 32 l-28 -10 z"/>
</g>
<!-- tool -->
<g stroke="#202322" stroke-width="3" fill="none">
<line x1="286" y1="150" x2="330" y2="112"/>
<rect x="322" y="98" width="34" height="16" transform="rotate(-42 339 106)"/>
</g>
<!-- battery -->
<rect x="300" y="238" width="18" height="42" fill="#202322"/>
<rect x="303" y="242" width="12" height="20" fill="none" stroke="#E95B2B" stroke-width="1.5"/>
<text x="24" y="40" font-family="ui-monospace,Menlo,monospace" font-size="12" letter-spacing="1.8" fill="#6B6D67">WORKSHOP / SEAT RAIL / 12 Nm</text>
</svg>
</div>
<figcaption class="mono">Child seat mount / rear deck</figcaption>
</figure>
</div>
</div>
</section>
<!-- ============ FINAL CTA ============ -->
<section class="final" id="start" aria-labelledby="finalTitle">
<div class="wrap">
<div class="grid">
<p class="mono final__label" style="grid-column:1 / 13">Start with a conversation</p>
<h2 class="final__title" id="finalTitle">Your cargo life begins with a fit.</h2>
<p class="final__copy">
Tell us what you carry, where you ride, and what your current setup gets wrong. We will
recommend the right frame, cargo configuration, and next step.
</p>
<div class="final__actions">
<a class="btn btn--on-dark" href="#fitForm">
Book a fitting
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</a>
<a class="link link--on-dark" href="mailto:hello@lumencycles.dk">
Email the workshop
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</a>
</div>
<p class="mono final__promise">We reply within 2 working days / Copenhagen & remote fittings</p>
<div class="final__utils">
<a class="link link--on-dark" href="#bikes">Compare models</a>
<a class="link link--on-dark" href="#service">Read the service promise</a>
<a class="link link--on-dark" href="#workshop">Meet the workshop</a>
</div>
<!-- ===== fitting form ===== -->
<form class="form" id="fitForm" novalidate>
<div class="form__grid">
<div class="error-summary" id="errorSummary" tabindex="-1" role="alert" aria-live="assertive">
<h3>Check these fields</h3>
<ul id="errorList"></ul>
</div>
<div class="field">
<label for="f-name">Name</label>
<input id="f-name" name="name" type="text" autocomplete="name" required>
<span class="err" id="e-name"></span>
</div>
<div class="field">
<label for="f-email">Email</label>
<input id="f-email" name="email" type="email" autocomplete="email" required>
<span class="err" id="e-email"></span>
</div>
<div class="field">
<label for="f-city">City</label>
<input id="f-city" name="city" type="text" autocomplete="address-level2" required>
<span class="err" id="e-city"></span>
</div>
<div class="field">
<label for="f-riding">What will you use the bike for?</label>
<select id="f-riding" name="riding" required>
<option value="">Select one</option>
<option>Family</option>
<option>Work</option>
<option>Weekend</option>
</select>
<span class="err" id="e-riding"></span>
</div>
<div class="field">
<label for="f-cargo">What do you carry most often?</label>
<select id="f-cargo" name="cargo" required>
<option value="">Select one</option>
<option>1 child</option>
<option>2 children</option>
<option>Tools / equipment</option>
<option>Deliveries</option>
<option>Groceries / household</option>
<option>Other</option>
</select>
<span class="err" id="e-cargo"></span>
</div>
<div class="field">
<label for="f-start">Preferred start date</label>
<input id="f-start" name="start" type="text" placeholder="e.g. March, or flexible">
<span class="err" id="e-start"></span>
</div>
<div class="field">
<label for="f-model">Model of interest</label>
<select id="f-model" name="model">
<option>Not sure yet</option>
<option>Core</option>
<option selected>Load</option>
<option>Longtail</option>
</select>
<span class="err" id="e-model"></span>
</div>
<div class="field field--full">
<label for="f-notes">Anything we should know?</label>
<textarea id="f-notes" name="notes" rows="5"
placeholder="Route, storage, rider height, current bike, or what it gets wrong today."></textarea>
<span class="err" id="e-notes"></span>
</div>
<div class="check">
<input id="f-consent" name="consent" type="checkbox" required>
<label for="f-consent">Please contact me about a fitting.</label>
</div>
<div class="field field--full" style="margin-top:calc(var(--s3) * -1)">
<span class="err" id="e-consent"></span>
</div>
<div class="form__submit">
<button class="btn btn--on-dark" type="submit">
Book a fitting
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
<path d="M2 7h9M8 3.5 11.5 7 8 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
</svg>
</button>
<p class="form__status" id="formStatus" role="status"></p>
</div>
</div>
</form>
</div>
<div class="metadata-rail" style="margin-top:var(--s8)">
<span>04 / The conversation</span>
<span>hello@lumencycles.dk / +45 00 00 00 00</span>
</div>
</div>
</section>
</main>
<!-- ============ FOOTER ============ -->
<footer class="footer">
<div class="wrap">
<div class="grid footer__grid">
<div class="footer__brand">
<a class="wordmark" href="#top" aria-label="Lumen Cycles, back to top">
<span class="wordmark__name">Lumen</span>
<span class="wordmark__sub">Cycles</span>
</a>
<p class="caption" style="margin-top:var(--s4);max-width:28ch">
Custom electric cargo bikes, designed and assembled in Copenhagen.
</p>
</div>
<div class="footer__addr">
<p class="mono footer__block-label">Workshop</p>
<p class="footer__block-copy">
Nørrebrogade 000<br>
2200 Copenhagen N<br>
Denmark
</p>
</div>
<div class="footer__hours">
<p class="mono footer__block-label">Hours</p>
<p class="footer__block-copy">
Tue–Fri / 08:00–17:00<br>
<a href="mailto:hello@lumencycles.dk">hello@lumencycles.dk</a><br>
<a href="tel:+4500000000">+45 00 00 00 00</a>
</p>
</div>
<div class="footer__legal">
<a href="#start">Privacy</a>
<a href="#start">Terms</a>
<a href="#service">Service promise</a>
</div>
</div>
<div class="footer__stamp">
<span class="mono">Copenhagen / Built to order</span>
</div>
<div class="metadata-rail" style="margin-top:var(--s6)">
<span>© 2026 Lumen Cycles</span>
<span>LC / 001–003</span>
</div>
</div>
</footer>
<script>
(function(){
"use strict";
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- hero entrance ---------- */
function ready(){
document.body.classList.add("is-ready");
}
if (document.fonts && document.fonts.ready && !reduce) {
document.fonts.ready.then(function(){ requestAnimationFrame(ready); });
setTimeout(ready, 400);
} else {
requestAnimationFrame(ready);
}
/* ---------- sticky header state ---------- */
var header = document.getElementById("header");
var lastY = 0;
function onScrollHeader(){
var y = window.scrollY || window.pageYOffset;
if (y > 72) header.classList.add("is-stuck");
else header.classList.remove("is-stuck");
lastY = y;
}
window.addEventListener("scroll", onScrollHeader, {passive:true});
onScrollHeader();
/* ---------- mobile nav ---------- */
var navToggle = document.getElementById("navToggle");
var nav = document.getElementById("nav");
if (navToggle && nav){
navToggle.addEventListener("click", function(){
var open = nav.classList.toggle("is-open");
navToggle.setAttribute("aria-expanded", open ? "true" : "false");
navToggle.setAttribute("aria-label", open ? "Close menu" : "Menu");
});
nav.addEventListener("click", function(e){
if (e.target.tagName === "A"){
nav.classList.remove("is-open");
navToggle.setAttribute("aria-expanded","false");
navToggle.setAttribute("aria-label","Menu");
}
});
}
/* ---------- model selector ---------- */
var models = Array.prototype.slice.call(document.querySelectorAll(".model"));
var summary = {
name: document.getElementById("sumName"),
price: document.getElementById("sumPrice"),
cap: document.getElementById("sumCap"),
range: document.getElementById("sumRange"),
note: document.getElementById("sumNote")
};
var modelData = {
core: {
name:"Core", price:"€4,950", cap:"80 kg", range:"60–90 km",
note:"Core is the compact everyday build: a flat front platform, 80 kg of payload, and a short wheelbase that fits narrow apartment courtyards. Prices include the fitting session, custom frame build, assembly, and handover."
},
load: {
name:"Load", price:"€6,450", cap:"120 kg", range:"70–110 km",
note:"Load is the configuration most Copenhagen families choose: a full front bay, two child-seat positions, and 120 kg of everyday payload. Prices include the fitting session, custom frame build, assembly, and handover."
},
longtail: {
name:"Longtail", price:"€6,950", cap:"150 kg", range:"80–120 km",
note:"Longtail keeps an agile footprint but extends the rear deck for two passengers or bulky loads. Prices include the fitting session, custom frame build, assembly, and handover."
}
};
function selectModel(key, focusEl){
models.forEach(function(m){
var on = m.getAttribute("data-model") === key;
m.setAttribute("aria-pressed", on ? "true" : "false");
});
var d = modelData[key];
if (!d || !summary.name) return;
var fades = [summary.name, summary.price, summary.cap, summary.range];
fades.forEach(function(el){ el.classList.add("is-fading"); });
var apply = function(){
summary.name.textContent = d.name;
summary.price.textContent = d.price;
summary.cap.textContent = d.cap;
summary.range.textContent = d.range;
summary.note.textContent = d.note;
fades.forEach(function(el){ el.classList.remove("is-fading"); });
};
if (reduce) apply();
else setTimeout(apply, 180);
if (focusEl){
var toggle = focusEl.querySelector(".model__toggle");
if (toggle) toggle.focus();
}
}
models.forEach(function(m){
var key = m.getAttribute("data-model");
var toggle = m.querySelector(".model__toggle");
if (toggle){
toggle.addEventListener("click", function(e){
e.preventDefault();
selectModel(key);
});
}
m.addEventListener("keydown", function(e){
if (e.key === "Enter" || e.key === " " || e.key === "Spacebar"){
e.preventDefault();
selectModel(key);
}
});
/* keyboard arrows move between models */
m.addEventListener("keydown", function(e){
var i = models.indexOf(m), n = null;
if (e.key === "ArrowRight" || e.key === "ArrowDown") n = models[(i+1) % models.length];
if (e.key === "ArrowLeft" || e.key === "ArrowUp") n = models[(i-1+models.length) % models.length];
if (n){
e.preventDefault();
selectModel(n.getAttribute("data-model"), n);
}
});
});
/* ---------- signature: frame-to-cargo scroll transformation ---------- */
var sheet = document.getElementById("fit");
var diagram = document.getElementById("sheetDiagram");
var useCases = document.getElementById("useCases");
if (sheet && diagram){
var rails = Array.prototype.slice.call(diagram.querySelectorAll(".draw.rail"));
var tails = Array.prototype.slice.call(diagram.querySelectorAll(".draw.tail"));
var dots = Array.prototype.slice.call(diagram.querySelectorAll(".callout-svg"));
var labels = useCases ? Array.prototype.slice.call(useCases.querySelectorAll(".usecase")) : [];
function prep(el){
var len = 1000;
try {
if (el.getTotalLength) len = Math.ceil(el.getTotalLength());
} catch(err){ len = 1000; }
if (!len || !isFinite(len)) len = 1000;
el.style.setProperty("--len", len);
el.style.strokeDasharray = len;
el.style.strokeDashoffset = reduce ? 0 : len;
}
rails.concat(tails).forEach(prep);
function setProgress(p){
if (reduce){
rails.concat(tails).forEach(function(el){ el.style.strokeDashoffset = 0; });
dots.forEach(function(d){ d.classList.add("is-on"); });
labels.forEach(function(l){ l.classList.add("is-on"); });
return;
}
/* rails draw across the first 55% of progress */
rails.forEach(function(el, i){
var len = parseFloat(el.style.getPropertyValue("--len")) || 1000;
var local = Math.min(1, Math.max(0, (p - i * 0.02) / 0.55));
el.style.strokeDashoffset = len * (1 - local);
});
/* long-tail extension grows 35% -> 85% */
tails.forEach(function(el, i){
var len = parseFloat(el.style.getPropertyValue("--len")) || 1000;
var local = Math.min(1, Math.max(0, (p - 0.35 - i * 0.03) / 0.5));
el.style.strokeDashoffset = len * (1 - local);
});
/* callout marks */
dots.forEach(function(d, i){
if (p > 0.42 + i * 0.05) d.classList.add("is-on");
else d.classList.remove("is-on");
});
/* use-case labels lock in one at a time */
labels.forEach(function(l, i){
if (p > 0.58 + i * 0.12) l.classList.add("is-on");
else l.classList.remove("is-on");
});
}
var ticking = false;
function updateSheet(){
ticking = false;
var rect = sheet.getBoundingClientRect();
var vh = window.innerHeight || document.documentElement.clientHeight;
var total = rect.height + vh * 0.4;
var seen = vh * 0.85 - rect.top;
var p = Math.min(1, Math.max(0, seen / total));
setProgress(p);
}
function onScrollSheet(){
if (!ticking){
ticking = true;
requestAnimationFrame(updateSheet);
}
}
if (reduce){
setProgress(1);
} else {
window.addEventListener("scroll", onScrollSheet, {passive:true});
window.addEventListener("resize", onScrollSheet);
updateSheet();
}
}
/* ---------- process stamp + step registration ---------- */
var steps = Array.prototype.slice.call(document.querySelectorAll("[data-step]"));
var stamp = document.getElementById("processStamp");
if ("IntersectionObserver" in window && steps.length){
var stepObs = new IntersectionObserver(function(entries){
entries.forEach(function(entry){
if (entry.isIntersecting){
entry.target.classList.add("is-active");
if (stamp) stamp.classList.add("is-active");
}
});
}, {threshold:0.35});
steps.forEach(function(s){ stepObs.observe(s); });
} else {
steps.forEach(function(s){ s.classList.add("is-active"); });
if (stamp) stamp.classList.add("is-active");
}
/* ---------- case study image registration ---------- */
var shots = Array.prototype.slice.call(document.querySelectorAll(".shot"));
if ("IntersectionObserver" in window && shots.length){
var shotObs = new IntersectionObserver(function(entries){
entries.forEach(function(entry){
if (entry.isIntersecting){
entry.target.classList.add("is-in");
shotObs.unobserve(entry.target);
}
});
}, {threshold:0.28});
shots.forEach(function(s){ shotObs.observe(s); });
} else {
shots.forEach(function(s){ s.classList.add("is-in"); });
}
/* ---------- fitting form ---------- */
var form = document.getElementById("fitForm");
if (form){
var summaryBox = document.getElementById("errorSummary");
var errorList = document.getElementById("errorList");
var status = document.getElementById("formStatus");
var fields = [
{id:"f-name", err:"e-name", label:"Name", test:function(v){ return v.trim().length > 1; }, msg:"Please enter your name."},
{id:"f-email", err:"e-email", label:"Email", test:function(v){ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()); }, msg:"Please enter a valid email address."},
{id:"f-city", err:"e-city", label:"City", test:function(v){ return v.trim().length > 1; }, msg:"Please tell us which city you ride in."},
{id:"f-riding", err:"e-riding", label:"What will you use the bike for?", test:function(v){ return v !== ""; }, msg:"Please choose what you will use the bike for."},
{id:"f-cargo", err:"e-cargo", label:"What do you carry most often?", test:function(v){ return v !== ""; }, msg:"Please choose what you carry most often."},
{id:"f-consent",err:"e-consent",label:"Please contact me about a fitting.", test:null, msg:"Please confirm we may contact you about a fitting."}
];
function fieldWrap(el){ return el.closest ? el.closest(".field") || el.closest(".check") : null; }
function clearField(f){
var el = document.getElementById(f.id);
var err = document.getElementById(f.err);
if (err) err.textContent = "";
var wrap = fieldWrap(el);
if (wrap) wrap.classList.remove("is-invalid");
}
function markField(f){
var el = document.getElementById(f.id);
var err = document.getElementById(f.err);
if (err) err.textContent = f.msg;
var wrap = fieldWrap(el);
if (wrap && wrap.classList) wrap.classList.add("is-invalid");
}
function validate(){
var bad = [];
fields.forEach(function(f){
clearField(f);
var el = document.getElementById(f.id);
if (!el) return;
var ok;
if (f.test) ok = f.test(el.value);
else ok = el.checked;
if (!ok){ markField(f); bad.push(f); }
});
return bad;
}
fields.forEach(function(f){
var el = document.getElementById(f.id);
if (!el) return;
el.addEventListener("blur", function(){
var ok = f.test ? f.test(el.value) : el.checked;
if (ok) clearField(f);
});
el.addEventListener("change", function(){
var ok = f.test ? f.test(el.value) : el.checked;
if (ok) clearField(f);
});
});
form.addEventListener("submit", function(e){
e.preventDefault();
var bad = validate();
if (bad.length){
errorList.innerHTML = "";
bad.forEach(function(f){
var li = document.createElement("li");
var a = document.createElement("a");
a.href = "#" + f.id;
a.textContent = f.label + " — " + f.msg;
a.addEventListener("click", function(ev){
ev.preventDefault();
var el = document.getElementById(f.id);
if (el) el.focus();
});
li.appendChild(a);
errorList.appendChild(li);
});
summaryBox.classList.add("is-on");
summaryBox.focus();
status.textContent = "Please check the fields below.";
status.classList.add("is-error");
return;
}
summaryBox.classList.remove("is-on");
status.classList.remove("is-error");
status.textContent = "Your fitting request is ready to send.";
});
}
/* ---------- smooth in-page focus for skip link / anchors ---------- */
document.addEventListener("click", function(e){
var a = e.target.closest ? e.target.closest('a[href^="#"]') : null;
if (!a) return;
var id = a.getAttribute("href");
if (!id || id === "#" || id.length < 2) return;
var target = document.querySelector(id);
if (!target) return;
/* let native smooth scroll run; move focus for keyboard users */
window.setTimeout(function(){
if (!target.hasAttribute("tabindex")) target.setAttribute("tabindex","-1");
target.focus({preventScroll:true});
}, reduce ? 0 : 420);
});
})();
</script>
</body>
</html>

