cyclecad 3.10.4 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1746 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>cycleCAD Suite — Animated Mockup</title>
7
+ <meta name="description" content="Animated wireframe mockup of the cycleCAD Suite website — idea to finished part in one browser tab." />
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700;9..144,900&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet" />
11
+
12
+ <style>
13
+ /* ─────────────────────────────────────────────
14
+ DESIGN TOKENS
15
+ ───────────────────────────────────────────── */
16
+ :root {
17
+ --bg: #0A1628;
18
+ --bg-alt: #122240;
19
+ --bg-card: #1A2D50;
20
+ --border: #1E3A5F;
21
+ --border-hi: #2A4F80;
22
+ --text: #F0F0E8;
23
+ --text-2: #8B9AB5;
24
+ --text-3: #5A6B85;
25
+ --gold: #D4A843;
26
+ --gold-2: #E8C065;
27
+ --blue: #2E86DE;
28
+ --teal: #3AAFA9;
29
+ --emerald: #10B981;
30
+ --purple: #8B6FC0;
31
+ --amber: #F59E0B;
32
+ --coral: #E05555;
33
+
34
+ /* Motion */
35
+ --ease: cubic-bezier(0.22, 1, 0.36, 1);
36
+ --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
37
+ --t-fast: 160ms;
38
+ --t-med: 420ms;
39
+ --t-slow: 900ms;
40
+ }
41
+
42
+ /* ─────────────────────────────────────────────
43
+ BASE
44
+ ───────────────────────────────────────────── */
45
+ * { margin: 0; padding: 0; box-sizing: border-box; }
46
+ html { scroll-behavior: smooth; }
47
+ body {
48
+ background: var(--bg); color: var(--text);
49
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
50
+ font-size: 16px; line-height: 1.6;
51
+ -webkit-font-smoothing: antialiased;
52
+ overflow-x: hidden;
53
+ }
54
+ a { color: inherit; text-decoration: none; }
55
+ code, .mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.9em; }
56
+
57
+ .wrap { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
58
+
59
+ /* ─────────────────────────────────────────────
60
+ MOCKUP WATERMARK
61
+ ───────────────────────────────────────────── */
62
+ .watermark {
63
+ position: fixed; top: 12px; right: 12px; z-index: 1000;
64
+ padding: 4px 12px; border-radius: 20px;
65
+ background: rgba(245,158,11,0.16); color: var(--amber);
66
+ font-size: 11px; letter-spacing: 2px; font-weight: 700;
67
+ border: 1px solid rgba(245,158,11,0.4); text-transform: uppercase;
68
+ backdrop-filter: blur(8px);
69
+ }
70
+
71
+ /* ─────────────────────────────────────────────
72
+ NAV
73
+ ───────────────────────────────────────────── */
74
+ nav {
75
+ position: sticky; top: 0; z-index: 50;
76
+ background: rgba(10, 22, 40, 0.72);
77
+ backdrop-filter: blur(20px) saturate(1.5);
78
+ border-bottom: 1px solid var(--border);
79
+ padding: 16px 0;
80
+ animation: navFadeIn 0.6s var(--ease) 0.1s both;
81
+ }
82
+ @keyframes navFadeIn { from { opacity: 0; transform: translateY(-100%); } to { opacity: 1; transform: translateY(0); } }
83
+
84
+ nav .wrap { display: flex; align-items: center; justify-content: space-between; }
85
+ nav .brand {
86
+ font-family: 'Fraunces', Georgia, serif; font-weight: 700; font-size: 21px;
87
+ letter-spacing: -0.02em; display: flex; align-items: center; gap: 10px;
88
+ }
89
+ nav .brand .logo {
90
+ width: 28px; height: 28px; border-radius: 6px;
91
+ background: linear-gradient(135deg, var(--gold), var(--blue));
92
+ display: grid; place-items: center; font-size: 15px;
93
+ animation: logoSpin 20s linear infinite;
94
+ }
95
+ @keyframes logoSpin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
96
+ nav .brand em { color: var(--gold); font-style: normal; }
97
+ nav .links { display: flex; gap: 32px; align-items: center; font-size: 14px; color: var(--text-2); }
98
+ nav .links a { position: relative; transition: color var(--t-fast) var(--ease); }
99
+ nav .links a:hover { color: var(--text); }
100
+ nav .links a::after {
101
+ content: ''; position: absolute; bottom: -4px; left: 0; width: 0; height: 2px;
102
+ background: var(--gold); transition: width var(--t-fast) var(--ease);
103
+ }
104
+ nav .links a:hover::after { width: 100%; }
105
+ nav .cta {
106
+ background: var(--gold); color: var(--bg);
107
+ padding: 9px 20px; border-radius: 6px; font-weight: 700; font-size: 14px;
108
+ transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
109
+ }
110
+ nav .cta:hover { transform: translateY(-2px); box-shadow: 0 12px 30px -8px rgba(212,168,67,0.4); }
111
+ nav .cta::after { display: none !important; }
112
+
113
+ /* ─────────────────────────────────────────────
114
+ HERO
115
+ ───────────────────────────────────────────── */
116
+ header.hero {
117
+ padding: 120px 0 80px; position: relative; overflow: hidden;
118
+ }
119
+ header.hero::before,
120
+ header.hero::after {
121
+ content: ''; position: absolute; border-radius: 50%; filter: blur(100px); pointer-events: none;
122
+ }
123
+ header.hero::before {
124
+ width: 600px; height: 600px; background: rgba(212,168,67,0.14);
125
+ top: -100px; right: -150px; animation: orb1 18s ease-in-out infinite;
126
+ }
127
+ header.hero::after {
128
+ width: 700px; height: 700px; background: rgba(46,134,222,0.12);
129
+ bottom: -200px; left: -200px; animation: orb2 22s ease-in-out infinite;
130
+ }
131
+ @keyframes orb1 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(-60px, 80px); } }
132
+ @keyframes orb2 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(80px, -40px); } }
133
+
134
+ .hero .wrap { position: relative; z-index: 1; }
135
+
136
+ .kicker {
137
+ display: inline-flex; align-items: center; gap: 8px;
138
+ font-size: 11px; letter-spacing: 4px; text-transform: uppercase; font-weight: 700;
139
+ color: var(--gold);
140
+ padding: 7px 14px;
141
+ background: rgba(212,168,67,0.08);
142
+ border: 1px solid rgba(212,168,67,0.3);
143
+ border-radius: 100px; margin-bottom: 28px;
144
+ animation: slideUp 0.8s var(--ease) 0.3s both;
145
+ }
146
+ .kicker .dot {
147
+ width: 6px; height: 6px; border-radius: 50%; background: var(--gold);
148
+ box-shadow: 0 0 8px var(--gold); animation: pulse 1.8s ease-in-out infinite;
149
+ }
150
+ @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.4); } }
151
+
152
+ h1.hero {
153
+ font-family: 'Fraunces', Georgia, serif; font-weight: 700;
154
+ font-size: clamp(44px, 8vw, 96px); line-height: 1.02; letter-spacing: -0.035em;
155
+ margin-bottom: 28px; max-width: 1100px;
156
+ animation: slideUp 0.9s var(--ease) 0.5s both;
157
+ }
158
+ h1.hero em { font-style: italic; color: var(--gold); font-weight: 400; }
159
+ h1.hero .cursor {
160
+ display: inline-block; width: 4px; height: 0.9em; background: var(--gold);
161
+ margin-left: 4px; vertical-align: baseline;
162
+ animation: blink 1s step-end infinite;
163
+ }
164
+ @keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
165
+
166
+ p.lead {
167
+ font-size: 20px; color: var(--text-2); max-width: 720px;
168
+ margin-bottom: 44px; line-height: 1.55;
169
+ animation: slideUp 0.9s var(--ease) 0.7s both;
170
+ }
171
+
172
+ .hero-ctas { display: flex; gap: 14px; flex-wrap: wrap; animation: slideUp 0.9s var(--ease) 0.9s both; }
173
+ .btn {
174
+ padding: 16px 28px; border-radius: 8px; font-weight: 700; font-size: 15px;
175
+ transition: all var(--t-fast) var(--ease);
176
+ border: 1.5px solid transparent; display: inline-flex; align-items: center; gap: 8px;
177
+ cursor: pointer; position: relative; overflow: hidden;
178
+ }
179
+ .btn-primary { background: var(--gold); color: var(--bg); border-color: var(--gold); }
180
+ .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 40px -10px rgba(212,168,67,0.5); background: var(--gold-2); }
181
+ .btn-primary::before {
182
+ content: ''; position: absolute; inset: 0;
183
+ background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(255,255,255,0.3) 0%, transparent 40%);
184
+ opacity: 0; transition: opacity var(--t-fast);
185
+ }
186
+ .btn-primary:hover::before { opacity: 1; }
187
+ .btn-secondary { background: transparent; color: var(--text); border-color: var(--border); }
188
+ .btn-secondary:hover { border-color: var(--text-2); background: rgba(255,255,255,0.03); transform: translateY(-2px); }
189
+ .btn .arrow { transition: transform var(--t-fast) var(--ease); }
190
+ .btn:hover .arrow { transform: translateX(4px); }
191
+
192
+ @keyframes slideUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
193
+
194
+ /* ─────────────────────────────────────────────
195
+ LIFECYCLE STRIP (animated on scroll)
196
+ ───────────────────────────────────────────── */
197
+ .stages {
198
+ margin: 80px 0 0; padding: 40px 0;
199
+ border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
200
+ background: linear-gradient(180deg, transparent, rgba(18,34,64,0.4), transparent);
201
+ }
202
+ .stages .row {
203
+ display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px;
204
+ align-items: stretch; position: relative;
205
+ }
206
+ .stages .row::before {
207
+ content: ''; position: absolute; top: 50%; left: 5%; right: 5%;
208
+ height: 2px; background: var(--border); z-index: 0;
209
+ }
210
+ .stages .row::after {
211
+ content: ''; position: absolute; top: 50%; left: 5%;
212
+ width: 0; height: 2px; background: linear-gradient(90deg, var(--gold), var(--blue), var(--teal), var(--emerald), var(--purple));
213
+ transition: width 2s var(--ease); z-index: 0;
214
+ }
215
+ .stages.anim .row::after { width: 90%; }
216
+
217
+ .stage-chip {
218
+ position: relative; z-index: 1; padding: 24px 12px;
219
+ border-radius: 12px; border: 1px solid var(--border);
220
+ background: var(--bg-alt); text-align: center;
221
+ transition: all var(--t-med) var(--ease);
222
+ opacity: 0; transform: translateY(24px);
223
+ }
224
+ .stages.anim .stage-chip { opacity: 1; transform: translateY(0); }
225
+ .stages.anim .stage-chip:nth-child(1) { transition-delay: 0.1s; }
226
+ .stages.anim .stage-chip:nth-child(2) { transition-delay: 0.25s; }
227
+ .stages.anim .stage-chip:nth-child(3) { transition-delay: 0.4s; }
228
+ .stages.anim .stage-chip:nth-child(4) { transition-delay: 0.55s; }
229
+ .stages.anim .stage-chip:nth-child(5) { transition-delay: 0.7s; }
230
+
231
+ .stage-chip:hover {
232
+ border-color: var(--gold); background: var(--bg-card);
233
+ transform: translateY(-6px); box-shadow: 0 20px 40px -10px rgba(212,168,67,0.2);
234
+ }
235
+ .stage-chip .num {
236
+ font-family: 'Fraunces', Georgia, serif; font-size: 40px; font-weight: 700;
237
+ background: linear-gradient(135deg, var(--gold), var(--gold-2));
238
+ -webkit-background-clip: text; background-clip: text; color: transparent;
239
+ line-height: 1; margin-bottom: 10px;
240
+ }
241
+ .stage-chip .n { font-weight: 700; letter-spacing: 2px; font-size: 11px; color: var(--text); text-transform: uppercase; margin-bottom: 6px; }
242
+ .stage-chip .sub { font-size: 11px; color: var(--text-3); }
243
+ @media (max-width: 900px) { .stages .row { grid-template-columns: repeat(2, 1fr); } .stages .row::before, .stages .row::after { display: none; } }
244
+
245
+ /* ─────────────────────────────────────────────
246
+ STAGE SECTIONS
247
+ ───────────────────────────────────────────── */
248
+ section.stage { padding: 120px 0; border-bottom: 1px solid var(--border); position: relative; }
249
+ section.stage:nth-child(odd) { background: linear-gradient(180deg, var(--bg) 0%, rgba(18,34,64,0.2) 100%); }
250
+
251
+ .stage-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center; }
252
+ @media (max-width: 900px) { .stage-layout { grid-template-columns: 1fr; gap: 40px; } }
253
+
254
+ .stage-body { opacity: 0; transform: translateX(-40px); transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease); }
255
+ .stage.rev .stage-body { transform: translateX(40px); }
256
+ .stage.in-view .stage-body { opacity: 1; transform: translateX(0); }
257
+
258
+ .stage-body .label {
259
+ display: inline-flex; align-items: center; gap: 8px;
260
+ color: var(--gold); font-weight: 700; letter-spacing: 3px; font-size: 11px;
261
+ text-transform: uppercase; margin-bottom: 18px;
262
+ padding: 5px 12px; border: 1px solid rgba(212,168,67,0.3);
263
+ border-radius: 100px; background: rgba(212,168,67,0.06);
264
+ }
265
+ .stage-body .label .n { font-family: 'Fraunces', serif; font-weight: 700; opacity: 0.6; }
266
+ .stage-body h2 {
267
+ font-family: 'Fraunces', Georgia, serif; font-size: clamp(32px, 4.2vw, 52px);
268
+ line-height: 1.08; letter-spacing: -0.025em; margin-bottom: 22px;
269
+ }
270
+ .stage-body h2 em { font-style: italic; color: var(--gold); font-weight: 400; }
271
+ .stage-body p { font-size: 17px; color: var(--text-2); margin-bottom: 16px; line-height: 1.65; }
272
+ .stage-body .products { margin-top: 28px; display: flex; gap: 10px; flex-wrap: wrap; }
273
+
274
+ .pill {
275
+ display: inline-flex; align-items: center; gap: 6px;
276
+ padding: 7px 14px; border-radius: 100px;
277
+ font-size: 13px; font-weight: 600; border: 1px solid;
278
+ transition: all var(--t-fast) var(--ease);
279
+ }
280
+ .pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
281
+ .pill:hover { transform: translateY(-2px); box-shadow: 0 8px 20px -6px currentColor; }
282
+ .pill.cyclecad { color: var(--gold); border-color: rgba(212,168,67,0.4); background: rgba(212,168,67,0.08); }
283
+ .pill.explode { color: var(--teal); border-color: rgba(58,175,169,0.4); background: rgba(58,175,169,0.08); }
284
+ .pill.pentacad { color: var(--emerald); border-color: rgba(16,185,129,0.4); background: rgba(16,185,129,0.08); }
285
+ .pill.ai { color: var(--purple); border-color: rgba(139,111,192,0.4); background: rgba(139,111,192,0.08); }
286
+
287
+ /* VISUAL PANE */
288
+ .visual {
289
+ background: var(--bg-alt);
290
+ border: 1px solid var(--border);
291
+ border-radius: 16px; aspect-ratio: 4 / 3;
292
+ position: relative; overflow: hidden;
293
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.5);
294
+ opacity: 0; transform: translateX(40px) scale(0.96);
295
+ transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
296
+ }
297
+ .stage.rev .visual { transform: translateX(-40px) scale(0.96); }
298
+ .stage.in-view .visual { opacity: 1; transform: translateX(0) scale(1); }
299
+ .visual::before {
300
+ content: ''; position: absolute; inset: 0;
301
+ background: linear-gradient(180deg, transparent, rgba(0,0,0,0.2));
302
+ pointer-events: none;
303
+ }
304
+
305
+ .visual .label-top {
306
+ position: absolute; top: 16px; left: 16px; z-index: 2;
307
+ font-size: 10px; letter-spacing: 2.5px; color: var(--text-3);
308
+ text-transform: uppercase; font-weight: 700;
309
+ padding: 5px 10px; background: rgba(10,22,40,0.6);
310
+ border-radius: 4px; backdrop-filter: blur(6px);
311
+ }
312
+ .visual svg { width: 100%; height: 100%; position: relative; z-index: 1; }
313
+
314
+ /* ─────────────────────────────────────────────
315
+ STAGE 1: IDEATE — glowing brain + text typing
316
+ ───────────────────────────────────────────── */
317
+ .vis-ideate { background: radial-gradient(circle at 30% 30%, rgba(139,111,192,0.2), transparent 60%), var(--bg-alt); }
318
+ .vis-ideate .term {
319
+ position: absolute; inset: 32px; border: 1px solid var(--border);
320
+ border-radius: 8px; background: rgba(10,22,40,0.8); padding: 20px;
321
+ font-family: 'JetBrains Mono', monospace; font-size: 12px;
322
+ display: flex; flex-direction: column; gap: 8px;
323
+ }
324
+ .vis-ideate .term .t-head { display: flex; gap: 6px; margin-bottom: 8px; }
325
+ .vis-ideate .term .t-head span { width: 9px; height: 9px; border-radius: 50%; }
326
+ .vis-ideate .term .t-head span:nth-child(1) { background: var(--coral); }
327
+ .vis-ideate .term .t-head span:nth-child(2) { background: var(--amber); }
328
+ .vis-ideate .term .t-head span:nth-child(3) { background: var(--emerald); }
329
+ .vis-ideate .line { color: var(--text-2); }
330
+ .vis-ideate .line .prompt { color: var(--purple); font-weight: 700; }
331
+ .vis-ideate .line .typed { color: var(--gold); border-right: 2px solid var(--gold); animation: typing 3s steps(40, end) 1s both, blink 0.7s step-end infinite; white-space: nowrap; overflow: hidden; display: inline-block; }
332
+ .vis-ideate .line.response { color: var(--emerald); opacity: 0; animation: fadeIn 0.4s var(--ease) 4.2s both; }
333
+ .vis-ideate .line.response::before { content: '→ '; color: var(--text-3); }
334
+ .stage.in-view .vis-ideate .typed { animation-play-state: running; }
335
+ @keyframes typing { from { width: 0; } to { width: 22ch; } }
336
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
337
+
338
+ /* ─────────────────────────────────────────────
339
+ STAGE 2: DESIGN — sketch drawing animation
340
+ ───────────────────────────────────────────── */
341
+ .vis-design { background: linear-gradient(135deg, var(--bg-alt), var(--bg-card)); }
342
+ .vis-design .grid-bg {
343
+ position: absolute; inset: 0;
344
+ background-image:
345
+ linear-gradient(to right, rgba(30,58,95,0.4) 1px, transparent 1px),
346
+ linear-gradient(to bottom, rgba(30,58,95,0.4) 1px, transparent 1px);
347
+ background-size: 28px 28px;
348
+ }
349
+ .vis-design svg { position: relative; z-index: 1; }
350
+ .vis-design .draw { stroke-dasharray: 1000; stroke-dashoffset: 1000; }
351
+ .stage.in-view .vis-design .draw { animation: draw 2s var(--ease) forwards; }
352
+ .stage.in-view .vis-design .draw-2 { animation: draw 2s var(--ease) 0.6s forwards; }
353
+ .stage.in-view .vis-design .draw-3 { animation: draw 1.4s var(--ease) 1.2s forwards; }
354
+ .vis-design .node { opacity: 0; }
355
+ .stage.in-view .vis-design .node { animation: nodePop 0.5s var(--ease) 2s forwards; }
356
+ .stage.in-view .vis-design .node:nth-of-type(2) { animation-delay: 2.15s; }
357
+ .stage.in-view .vis-design .node:nth-of-type(3) { animation-delay: 2.3s; }
358
+ .stage.in-view .vis-design .node:nth-of-type(4) { animation-delay: 2.45s; }
359
+ @keyframes draw { to { stroke-dashoffset: 0; } }
360
+ @keyframes nodePop { 0% { opacity: 0; transform: scale(0); } 70% { opacity: 1; transform: scale(1.4); } 100% { opacity: 1; transform: scale(1); } }
361
+
362
+ /* ─────────────────────────────────────────────
363
+ STAGE 3: PRESENT — exploded assembly
364
+ ───────────────────────────────────────────── */
365
+ .vis-present { background: radial-gradient(circle at 50% 50%, rgba(58,175,169,0.15), transparent 60%), var(--bg-alt); }
366
+ .vis-present .part { transition: transform 1.6s var(--ease); transform-origin: 100px 75px; }
367
+ .stage.in-view .vis-present .p1 { transform: translate(-30px, -20px); }
368
+ .stage.in-view .vis-present .p2 { transform: translate(0, -28px); }
369
+ .stage.in-view .vis-present .p3 { transform: translate(30px, -20px); }
370
+ .stage.in-view .vis-present .p4 { transform: translate(-30px, 8px); }
371
+ .stage.in-view .vis-present .p6 { transform: translate(30px, 8px); }
372
+ .vis-present .dash { stroke-dasharray: 2 2; stroke-dashoffset: 100; opacity: 0; }
373
+ .stage.in-view .vis-present .dash { animation: dashFlow 2s linear 1s infinite, fadeIn 0.3s 0.8s both; }
374
+ @keyframes dashFlow { to { stroke-dashoffset: 0; } }
375
+
376
+ /* ─────────────────────────────────────────────
377
+ STAGE 4: CAM — toolpath trace + moving spindle
378
+ ───────────────────────────────────────────── */
379
+ .vis-cam { background: linear-gradient(135deg, rgba(16,185,129,0.1), var(--bg-alt)); }
380
+ .vis-cam .toolpath { stroke-dasharray: 800; stroke-dashoffset: 800; }
381
+ .stage.in-view .vis-cam .toolpath { animation: draw 3s linear forwards, pulseLine 2s ease-in-out 3s infinite; }
382
+ @keyframes pulseLine { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
383
+ .vis-cam .spindle { transform: translate(50px, 35px); transition: transform 3s linear; }
384
+ .stage.in-view .vis-cam .spindle {
385
+ animation: spindleTravel 5s var(--ease-soft) forwards;
386
+ }
387
+ @keyframes spindleTravel {
388
+ 0% { transform: translate(50px, 35px); }
389
+ 25% { transform: translate(150px, 35px); }
390
+ 50% { transform: translate(150px, 50px); }
391
+ 75% { transform: translate(50px, 50px); }
392
+ 100% { transform: translate(100px, 35px); }
393
+ }
394
+ .vis-cam .chip {
395
+ opacity: 0;
396
+ animation: chipFly 1.2s ease-in-out infinite;
397
+ }
398
+ .stage.in-view .vis-cam .chip { opacity: 1; animation-delay: 3s; }
399
+ @keyframes chipFly {
400
+ 0% { transform: translate(0, 0) scale(0.5); opacity: 0; }
401
+ 30% { opacity: 1; }
402
+ 100% { transform: translate(15px, -30px) rotate(140deg) scale(1); opacity: 0; }
403
+ }
404
+ .vis-cam .ab-circle { transform-origin: 100px 75px; animation: abRotate 20s linear infinite; opacity: 0.4; }
405
+ @keyframes abRotate { to { transform: rotate(360deg); } }
406
+
407
+ /* ─────────────────────────────────────────────
408
+ STAGE 5: PRODUCE — browser → bridge → machine data flow
409
+ ───────────────────────────────────────────── */
410
+ .vis-produce { background: radial-gradient(circle at 50% 100%, rgba(16,185,129,0.18), transparent 60%), var(--bg-alt); }
411
+ .vis-produce .packet {
412
+ opacity: 0;
413
+ }
414
+ .stage.in-view .vis-produce .packet-down { animation: packetDown 2.4s linear 0.5s infinite; }
415
+ .stage.in-view .vis-produce .packet-up { animation: packetUp 2.4s linear 1.7s infinite; }
416
+ @keyframes packetDown { 0% { opacity: 0; transform: translate(60px, 60px); } 10% { opacity: 1; } 45% { transform: translate(100px, 60px); opacity: 1; } 55% { opacity: 0; } 60% { opacity: 1; transform: translate(140px, 60px); } 100% { transform: translate(155px, 60px); opacity: 0; } }
417
+ @keyframes packetUp { 0% { opacity: 0; transform: translate(155px, 70px); } 10% { opacity: 1; } 45% { transform: translate(100px, 70px); opacity: 1; } 55% { opacity: 0; } 60% { opacity: 1; transform: translate(60px, 70px); } 100% { transform: translate(50px, 70px); opacity: 0; } }
418
+ .vis-produce .dro-val { animation: droFlicker 0.8s steps(3, end) infinite; }
419
+ @keyframes droFlicker {
420
+ 0% { content: 'X 1.204'; }
421
+ 33% { content: 'X 1.208'; }
422
+ 66% { content: 'X 1.211'; }
423
+ 100% { content: 'X 1.215'; }
424
+ }
425
+
426
+ /* ─────────────────────────────────────────────
427
+ PRODUCTS GRID
428
+ ───────────────────────────────────────────── */
429
+ section.products-section { padding: 120px 0; background: var(--bg-alt); position: relative; }
430
+ section.products-section::before {
431
+ content: ''; position: absolute; inset: 0;
432
+ background-image:
433
+ radial-gradient(circle at 15% 30%, rgba(212,168,67,0.08), transparent 40%),
434
+ radial-gradient(circle at 85% 70%, rgba(16,185,129,0.08), transparent 40%);
435
+ pointer-events: none;
436
+ }
437
+ .products-section .wrap { position: relative; z-index: 1; }
438
+ .products-section .section-kicker {
439
+ display: block; text-align: center; font-size: 11px; letter-spacing: 4px;
440
+ color: var(--gold); text-transform: uppercase; font-weight: 700; margin-bottom: 14px;
441
+ }
442
+ .products-section h2 {
443
+ font-family: 'Fraunces', Georgia, serif; font-size: clamp(38px, 5vw, 56px);
444
+ text-align: center; margin-bottom: 14px; letter-spacing: -0.03em; line-height: 1.1;
445
+ }
446
+ .products-section h2 em { font-style: italic; color: var(--gold); font-weight: 400; }
447
+ .products-section .sub {
448
+ color: var(--text-2); text-align: center; font-size: 18px; margin-bottom: 60px;
449
+ max-width: 600px; margin-left: auto; margin-right: auto;
450
+ }
451
+ .products-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
452
+ @media (max-width: 900px) { .products-grid { grid-template-columns: 1fr; } }
453
+
454
+ .product-card {
455
+ background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px;
456
+ padding: 32px; transition: transform var(--t-med) var(--ease), border-color var(--t-fast) var(--ease), box-shadow var(--t-med) var(--ease);
457
+ position: relative; overflow: hidden;
458
+ opacity: 0; transform: translateY(32px);
459
+ }
460
+ .products-section.in-view .product-card { opacity: 1; transform: translateY(0); transition-duration: var(--t-slow), var(--t-fast), var(--t-med); }
461
+ .products-section.in-view .product-card:nth-child(1) { transition-delay: 0.15s; }
462
+ .products-section.in-view .product-card:nth-child(2) { transition-delay: 0.3s; }
463
+ .products-section.in-view .product-card:nth-child(3) { transition-delay: 0.45s; }
464
+
465
+ .product-card::before {
466
+ content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
467
+ transition: height var(--t-fast) var(--ease);
468
+ }
469
+ .product-card:hover { transform: translateY(-8px); border-color: var(--border-hi); box-shadow: 0 40px 80px -20px rgba(0,0,0,0.4); }
470
+ .product-card:hover::before { height: 6px; }
471
+ .p-cyclecad::before { background: linear-gradient(90deg, var(--gold), var(--gold-2)); }
472
+ .p-explodeview::before { background: linear-gradient(90deg, var(--teal), #56D1CC); }
473
+ .p-pentacad::before { background: linear-gradient(90deg, var(--emerald), #34D399); }
474
+
475
+ .product-card .status {
476
+ position: absolute; top: 20px; right: 20px; font-size: 10px; font-weight: 800;
477
+ letter-spacing: 1.5px; padding: 4px 10px; border-radius: 100px; text-transform: uppercase;
478
+ }
479
+ .status.live { background: rgba(16,185,129,0.18); color: var(--emerald); }
480
+ .status.live::before { content: '●'; margin-right: 4px; animation: pulse 1.5s ease-in-out infinite; }
481
+ .status.coming { background: rgba(245,158,11,0.18); color: var(--amber); }
482
+
483
+ .product-card .pname {
484
+ font-family: 'Fraunces', Georgia, serif; font-size: 32px; font-weight: 700;
485
+ margin-bottom: 6px; letter-spacing: -0.02em;
486
+ }
487
+ .p-cyclecad .pname { color: var(--gold); }
488
+ .p-explodeview .pname { color: var(--teal); }
489
+ .p-pentacad .pname { color: var(--emerald); }
490
+
491
+ .product-card .ptag { font-size: 11px; color: var(--text-3); margin-bottom: 22px; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; }
492
+ .product-card p.pdesc { color: var(--text-2); font-size: 15px; margin-bottom: 22px; line-height: 1.6; }
493
+ .product-card ul { list-style: none; margin-bottom: 28px; }
494
+ .product-card li {
495
+ padding: 7px 0; color: var(--text); font-size: 14px;
496
+ display: flex; align-items: flex-start; gap: 10px;
497
+ opacity: 0; transform: translateX(-8px);
498
+ }
499
+ .products-section.in-view .product-card li { opacity: 1; transform: translateX(0); transition: all var(--t-med) var(--ease); }
500
+ .product-card li::before { content: '→'; color: var(--gold); font-weight: 800; flex-shrink: 0; }
501
+ .product-card .p-cta { display: flex; gap: 10px; }
502
+ .product-card .p-cta a {
503
+ font-size: 13px; font-weight: 700; padding: 10px 16px; border-radius: 6px;
504
+ border: 1px solid var(--border); transition: all var(--t-fast) var(--ease);
505
+ }
506
+ .product-card .p-cta a.primary { background: var(--text); color: var(--bg); border-color: var(--text); }
507
+ .product-card .p-cta a:hover { transform: translateY(-2px); }
508
+ .product-card .p-cta a.primary:hover { box-shadow: 0 10px 25px -6px rgba(240,240,232,0.3); }
509
+
510
+ /* ─────────────────────────────────────────────
511
+ STATS
512
+ ───────────────────────────────────────────── */
513
+ section.stats { padding: 80px 0; }
514
+ .stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; text-align: center; }
515
+ @media (max-width: 700px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } }
516
+ .stat-card {
517
+ padding: 32px 20px; border: 1px solid var(--border); border-radius: 12px;
518
+ background: var(--bg-alt); transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
519
+ opacity: 0; transform: scale(0.92);
520
+ }
521
+ section.stats.in-view .stat-card { opacity: 1; transform: scale(1); transition: all var(--t-slow) var(--ease); }
522
+ section.stats.in-view .stat-card:nth-child(1) { transition-delay: 0.1s; }
523
+ section.stats.in-view .stat-card:nth-child(2) { transition-delay: 0.2s; }
524
+ section.stats.in-view .stat-card:nth-child(3) { transition-delay: 0.3s; }
525
+ section.stats.in-view .stat-card:nth-child(4) { transition-delay: 0.4s; }
526
+
527
+ .stat-card:hover { transform: translateY(-4px); border-color: var(--gold); }
528
+ .stat-card .n {
529
+ font-family: 'Fraunces', Georgia, serif; font-size: 48px; font-weight: 700;
530
+ background: linear-gradient(135deg, var(--gold), var(--gold-2));
531
+ -webkit-background-clip: text; background-clip: text; color: transparent;
532
+ line-height: 1; margin-bottom: 8px;
533
+ }
534
+ .stat-card .l { font-size: 12px; color: var(--text-2); letter-spacing: 1.5px; text-transform: uppercase; font-weight: 700; }
535
+
536
+ /* ─────────────────────────────────────────────
537
+ CTA BLOCK
538
+ ───────────────────────────────────────────── */
539
+ section.cta-block {
540
+ padding: 100px 0; text-align: center; background: var(--bg-alt);
541
+ border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
542
+ position: relative; overflow: hidden;
543
+ }
544
+ section.cta-block::before {
545
+ content: ''; position: absolute; inset: 0;
546
+ background: radial-gradient(ellipse at center top, rgba(212,168,67,0.15), transparent 50%);
547
+ pointer-events: none;
548
+ }
549
+ section.cta-block .wrap { position: relative; z-index: 1; }
550
+ section.cta-block h2 { font-family: 'Fraunces', Georgia, serif; font-size: clamp(36px, 5vw, 56px); margin-bottom: 18px; letter-spacing: -0.02em; line-height: 1.1; }
551
+ section.cta-block h2 em { font-style: italic; color: var(--gold); font-weight: 400; }
552
+ section.cta-block p { color: var(--text-2); font-size: 18px; max-width: 620px; margin: 0 auto 32px; }
553
+ section.cta-block .ctas { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
554
+
555
+ /* ─────────────────────────────────────────────
556
+ FOUNDER
557
+ ───────────────────────────────────────────── */
558
+ section.founder { padding: 100px 0; }
559
+ .note-box {
560
+ max-width: 760px; margin: 0 auto;
561
+ background: var(--bg-alt); border: 1px solid var(--border);
562
+ padding: 48px 48px 40px; border-radius: 16px;
563
+ position: relative;
564
+ }
565
+ .note-box::before {
566
+ content: '"'; position: absolute; top: 14px; left: 26px;
567
+ font-size: 100px; color: var(--gold); font-family: 'Fraunces', serif;
568
+ line-height: 1; opacity: 0.4;
569
+ }
570
+ .note-box p { color: var(--text); font-size: 18px; line-height: 1.7; font-style: italic; padding-left: 32px; margin-bottom: 20px; }
571
+ .note-box .sig {
572
+ padding-left: 32px; display: flex; align-items: center; gap: 14px;
573
+ }
574
+ .note-box .sig .avatar {
575
+ width: 44px; height: 44px; border-radius: 50%;
576
+ background: linear-gradient(135deg, var(--gold), var(--blue));
577
+ display: grid; place-items: center; font-weight: 700; color: var(--bg);
578
+ }
579
+ .note-box .sig .name { color: var(--text); font-weight: 700; font-size: 14px; }
580
+ .note-box .sig .role { color: var(--text-3); font-size: 12px; }
581
+
582
+ /* ─────────────────────────────────────────────
583
+ FOOTER
584
+ ───────────────────────────────────────────── */
585
+ footer { padding: 64px 0 40px; border-top: 1px solid var(--border); background: var(--bg); color: var(--text-3); font-size: 13px; }
586
+ footer .row { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr 1fr; gap: 40px; margin-bottom: 32px; }
587
+ @media (max-width: 700px) { footer .row { grid-template-columns: repeat(2, 1fr); } }
588
+ footer .brand-col { }
589
+ footer .brand-col .brand {
590
+ font-family: 'Fraunces', Georgia, serif; font-weight: 700; font-size: 20px;
591
+ color: var(--text); margin-bottom: 12px; display: block;
592
+ }
593
+ footer .brand-col .brand em { color: var(--gold); font-style: normal; }
594
+ footer .brand-col p { font-size: 13px; color: var(--text-3); max-width: 280px; line-height: 1.5; }
595
+ footer .col h4 { color: var(--text); font-size: 11px; letter-spacing: 2px; text-transform: uppercase; font-weight: 700; margin-bottom: 14px; }
596
+ footer .col a { display: block; padding: 5px 0; color: var(--text-2); transition: color var(--t-fast); }
597
+ footer .col a:hover { color: var(--text); }
598
+ footer .legal { padding-top: 24px; border-top: 1px solid var(--border); display: flex; justify-content: space-between; flex-wrap: wrap; color: var(--text-3); font-size: 12px; }
599
+
600
+ /* ─────────────────────────────────────────────
601
+ FLOATING SCROLL HINT
602
+ ───────────────────────────────────────────── */
603
+ .scroll-hint {
604
+ position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%);
605
+ color: var(--text-3); font-size: 11px; letter-spacing: 2px; font-weight: 600;
606
+ text-transform: uppercase; display: flex; flex-direction: column; align-items: center; gap: 6px;
607
+ pointer-events: none; opacity: 0; transition: opacity var(--t-med);
608
+ z-index: 40;
609
+ }
610
+ .scroll-hint.show { opacity: 1; animation: bob 2s ease-in-out infinite; }
611
+ .scroll-hint::after { content: '↓'; font-size: 16px; }
612
+ @keyframes bob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 6px); } }
613
+
614
+ /* ─────────────────────────────────────────────
615
+ END-TO-END JOURNEYS
616
+ ───────────────────────────────────────────── */
617
+ section.journeys { padding: 110px 0; position: relative; background: linear-gradient(180deg, var(--bg) 0%, rgba(18,34,64,0.35) 60%, var(--bg) 100%); border-bottom: 1px solid var(--border); overflow: hidden; }
618
+ section.journeys::before {
619
+ content: ''; position: absolute; inset: 0;
620
+ background-image:
621
+ radial-gradient(800px circle at 10% 20%, rgba(139,111,192,0.06), transparent 40%),
622
+ radial-gradient(700px circle at 90% 80%, rgba(58,175,169,0.05), transparent 40%);
623
+ pointer-events: none;
624
+ }
625
+ .journeys .wrap { position: relative; z-index: 1; }
626
+ .journeys .jhead { text-align: center; margin-bottom: 56px; }
627
+ .journeys .section-kicker { display: block; font-size: 11px; letter-spacing: 4px; color: var(--purple); text-transform: uppercase; font-weight: 700; margin-bottom: 14px; }
628
+ .journeys h2 { font-family: 'Fraunces', Georgia, serif; font-size: clamp(36px, 5vw, 54px); letter-spacing: -0.025em; line-height: 1.1; margin-bottom: 14px; }
629
+ .journeys h2 em { font-style: italic; color: var(--gold); font-weight: 400; }
630
+ .journeys .sub { color: var(--text-2); font-size: 17px; max-width: 620px; margin: 0 auto; }
631
+
632
+ .journey-stack { display: flex; flex-direction: column; gap: 24px; margin-top: 56px; }
633
+
634
+ .journey {
635
+ background: var(--bg-alt); border: 1px solid var(--border); border-radius: 14px;
636
+ padding: 20px 24px; position: relative; overflow: hidden;
637
+ opacity: 0; transform: translateY(24px);
638
+ transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), border-color var(--t-fast) var(--ease);
639
+ }
640
+ .journeys.in-view .journey { opacity: 1; transform: translateY(0); }
641
+ .journeys.in-view .journey:nth-child(1) { transition-delay: 0.1s; }
642
+ .journeys.in-view .journey:nth-child(2) { transition-delay: 0.25s; }
643
+ .journeys.in-view .journey:nth-child(3) { transition-delay: 0.4s; }
644
+ .journey:hover { border-color: var(--border-hi); }
645
+
646
+ .journey-head { display: grid; grid-template-columns: auto 1fr auto; gap: 16px; align-items: center; margin-bottom: 18px; }
647
+ .jicon { width: 48px; height: 48px; border-radius: 10px; display: grid; place-items: center; font-size: 26px; background: rgba(212,168,67,0.1); border: 1px solid rgba(212,168,67,0.3); }
648
+ .journey[data-journey="bell"] .jicon { background: rgba(139,111,192,0.1); border-color: rgba(139,111,192,0.35); }
649
+ .journey[data-journey="flange"] .jicon { background: rgba(58,175,169,0.1); border-color: rgba(58,175,169,0.35); }
650
+ .journey[data-journey="opener"] .jicon { background: rgba(16,185,129,0.1); border-color: rgba(16,185,129,0.35); }
651
+
652
+ .jname { font-family: 'Fraunces', Georgia, serif; font-size: 20px; font-weight: 700; color: var(--text); letter-spacing: -0.01em; line-height: 1.2; }
653
+ .jtag { font-size: 12px; color: var(--text-3); letter-spacing: 1px; font-weight: 500; margin-top: 2px; }
654
+ .jtimer { display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px; border-radius: 100px; background: rgba(10,22,40,0.6); border: 1px solid var(--border); font-size: 11px; letter-spacing: 2px; color: var(--text-2); font-family: 'JetBrains Mono', monospace; font-weight: 700; }
655
+ .jtimer-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--emerald); box-shadow: 0 0 6px var(--emerald); animation: pulse 1.5s ease-in-out infinite; }
656
+
657
+ /* Step track */
658
+ .journey-track {
659
+ display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px;
660
+ position: relative;
661
+ }
662
+ .journey-track::before {
663
+ content: ''; position: absolute;
664
+ top: 50%; left: 0; right: 0; height: 2px;
665
+ background: var(--border); z-index: 0;
666
+ }
667
+
668
+ .jstep {
669
+ position: relative; z-index: 1;
670
+ padding: 14px 10px; background: var(--bg-card);
671
+ border: 1px solid var(--border); border-radius: 10px;
672
+ transition: all var(--t-med) var(--ease);
673
+ min-height: 140px; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 6px;
674
+ }
675
+ .jstep .jstep-name { font-size: 10px; font-weight: 800; letter-spacing: 2px; color: var(--text-3); text-transform: uppercase; transition: color var(--t-fast); }
676
+ .jstep .jstep-vis { flex: 1; width: 100%; display: grid; place-items: center; min-height: 56px; position: relative; }
677
+ .jstep .jstep-vis svg { width: 100%; height: 56px; max-width: 100px; }
678
+ .jstep .jstep-meta { font-size: 10px; color: var(--text-3); text-align: center; font-family: 'JetBrains Mono', monospace; line-height: 1.3; min-height: 24px; word-break: break-word; }
679
+
680
+ .jstep.active { border-color: currentColor; background: rgba(212,168,67,0.05); transform: translateY(-4px); box-shadow: 0 18px 40px -12px currentColor; }
681
+ .journey[data-journey="bell"] .jstep.active { color: var(--purple); background: rgba(139,111,192,0.06); }
682
+ .journey[data-journey="flange"] .jstep.active { color: var(--teal); background: rgba(58,175,169,0.06); }
683
+ .journey[data-journey="opener"] .jstep.active { color: var(--emerald); background: rgba(16,185,129,0.06); }
684
+
685
+ .jstep.active .jstep-name { color: currentColor; }
686
+ .jstep.active .jstep-meta { color: var(--text); }
687
+ .jstep.done::after {
688
+ content: '✓'; position: absolute; top: 8px; right: 8px;
689
+ width: 16px; height: 16px; border-radius: 50%;
690
+ background: var(--emerald); color: var(--bg);
691
+ font-size: 10px; font-weight: 800; display: grid; place-items: center;
692
+ animation: popIn 0.3s var(--ease) forwards;
693
+ }
694
+ @keyframes popIn { 0% { transform: scale(0); } 80% { transform: scale(1.3); } 100% { transform: scale(1); } }
695
+
696
+ /* Step visual animations — each plays only when .active */
697
+ .jstep .vis-idea .bulb { transition: transform 0.4s var(--ease), filter 0.4s; filter: grayscale(0.7) opacity(0.5); }
698
+ .jstep.active .vis-idea .bulb { transform: scale(1.15); filter: grayscale(0) opacity(1) drop-shadow(0 0 8px currentColor); animation: flicker 1.6s ease-in-out infinite; }
699
+ @keyframes flicker { 0%, 100% { opacity: 1; } 50% { opacity: 0.65; } }
700
+
701
+ .jstep .vis-design .d-path { stroke-dasharray: 300; stroke-dashoffset: 300; }
702
+ .jstep.active .vis-design .d-path { animation: dDraw 1.6s ease-out forwards; }
703
+ @keyframes dDraw { to { stroke-dashoffset: 0; } }
704
+ .jstep.active .vis-design .d-fill { animation: dFill 1.6s ease-out 0.5s forwards; }
705
+ .jstep .vis-design .d-fill { opacity: 0; }
706
+ @keyframes dFill { to { opacity: 0.35; } }
707
+
708
+ .jstep .vis-market .m-card { transition: transform 0.6s var(--ease), opacity 0.6s; opacity: 0.5; transform: scale(0.9); }
709
+ .jstep.active .vis-market .m-card { opacity: 1; transform: scale(1); }
710
+ .jstep .vis-market .m-star { transition: opacity 0.3s var(--ease); opacity: 0.3; }
711
+ .jstep.active .vis-market .m-star { opacity: 1; animation: starPop 0.3s ease-out both; }
712
+ .jstep.active .vis-market .m-star-1 { animation-delay: 0.4s; }
713
+ .jstep.active .vis-market .m-star-2 { animation-delay: 0.55s; }
714
+ .jstep.active .vis-market .m-star-3 { animation-delay: 0.7s; }
715
+ .jstep.active .vis-market .m-star-4 { animation-delay: 0.85s; }
716
+ .jstep.active .vis-market .m-star-5 { animation-delay: 1.0s; }
717
+ @keyframes starPop { 0% { transform: scale(0.2); opacity: 0; } 80% { transform: scale(1.3); } 100% { transform: scale(1); opacity: 1; } }
718
+
719
+ .jstep .vis-sell .s-cart { transform: translateY(6px); opacity: 0.5; transition: all 0.5s var(--ease); }
720
+ .jstep.active .vis-sell .s-cart { transform: translateY(0); opacity: 1; }
721
+ .jstep .vis-sell .s-count { font-family: 'Fraunces', Georgia, serif; font-size: 22px; font-weight: 700; fill: currentColor; opacity: 0.5; }
722
+ .jstep.active .vis-sell .s-count { opacity: 1; animation: countUp 2s ease-out; }
723
+
724
+ .jstep .vis-mfg .m-spindle { transition: transform 0.5s var(--ease); }
725
+ .jstep.active .vis-mfg .m-spindle { animation: mfgTravel 2.2s ease-in-out infinite; }
726
+ @keyframes mfgTravel {
727
+ 0% { transform: translate(20px, 18px); }
728
+ 50% { transform: translate(70px, 18px); }
729
+ 100% { transform: translate(20px, 18px); }
730
+ }
731
+ .jstep .vis-mfg .m-chip { opacity: 0; }
732
+ .jstep.active .vis-mfg .m-chip { animation: mfgChip 0.8s ease-out infinite; }
733
+ @keyframes mfgChip {
734
+ 0% { opacity: 0; transform: translate(40px, 36px) scale(0.4); }
735
+ 30% { opacity: 1; }
736
+ 100% { opacity: 0; transform: translate(60px, 10px) rotate(140deg) scale(1); }
737
+ }
738
+ .jstep .vis-mfg .m-path { stroke-dasharray: 100; stroke-dashoffset: 100; }
739
+ .jstep.active .vis-mfg .m-path { animation: dDraw 2s ease-out forwards; }
740
+
741
+ .jstep .vis-feedback .fb-bubble { transform: translateX(-10px); opacity: 0.3; transition: all 0.5s var(--ease); }
742
+ .jstep.active .vis-feedback .fb-bubble { transform: translateX(0); opacity: 1; }
743
+ .jstep .vis-feedback .fb-loop { stroke-dasharray: 120; stroke-dashoffset: 120; }
744
+ .jstep.active .vis-feedback .fb-loop { animation: dDraw 1.6s ease-in-out 0.4s forwards; }
745
+
746
+ /* Step arrows between cells */
747
+ .jstep-arrow {
748
+ position: absolute; top: 50%; right: -10px; transform: translateY(-50%);
749
+ width: 20px; height: 14px; display: grid; place-items: center; z-index: 2;
750
+ color: var(--text-3); font-size: 14px; font-weight: 700;
751
+ background: var(--bg-alt); padding: 0 2px;
752
+ transition: color var(--t-fast);
753
+ }
754
+ .jstep.done + .jstep .jstep-arrow { color: var(--emerald); }
755
+ .jstep:last-child .jstep-arrow { display: none; }
756
+
757
+ @media (max-width: 900px) {
758
+ .journey-track { grid-template-columns: repeat(3, 1fr); }
759
+ .journey-track::before { display: none; }
760
+ .jstep-arrow { display: none !important; }
761
+ }
762
+ @media (max-width: 520px) {
763
+ .journey-track { grid-template-columns: repeat(2, 1fr); }
764
+ }
765
+
766
+ @keyframes countUp { 0% { opacity: 0.5; } 50% { opacity: 1; } 100% { opacity: 1; } }
767
+ </style>
768
+ </head>
769
+ <body>
770
+
771
+ <div class="watermark">Mockup · Wireframe</div>
772
+
773
+ <nav>
774
+ <div class="wrap">
775
+ <a href="/" class="brand">
776
+ <span class="logo">⚙</span>
777
+ cycle<em>CAD</em> suite
778
+ </a>
779
+ <div class="links">
780
+ <a href="#stages">Lifecycle</a>
781
+ <a href="#products">Products</a>
782
+ <a href="#">Docs</a>
783
+ <a href="#" class="cta">Launch →</a>
784
+ </div>
785
+ </div>
786
+ </nav>
787
+
788
+ <header class="hero">
789
+ <div class="wrap">
790
+ <div class="kicker">
791
+ <span class="dot"></span>
792
+ One tab · End to end
793
+ </div>
794
+ <h1 class="hero">
795
+ From <em>idea</em> to <em>finished&nbsp;part</em>.<br />
796
+ One browser tab.<span class="cursor"></span>
797
+ </h1>
798
+ <p class="lead">
799
+ Brainstorm with AI · Design in parametric CAD · Ship marketing renders ·
800
+ Generate 5-axis CAM · Stream G-code to your machine — all in one tab, all in the browser.
801
+ </p>
802
+ <div class="hero-ctas">
803
+ <a href="#" class="btn btn-primary">Launch the app <span class="arrow">→</span></a>
804
+ <a href="#stages" class="btn btn-secondary">See how it works</a>
805
+ </div>
806
+ </div>
807
+ </header>
808
+
809
+ <!-- LIFECYCLE STRIP -->
810
+ <div class="stages" id="stages" data-animate>
811
+ <div class="wrap">
812
+ <div class="row">
813
+ <a href="#ideate" class="stage-chip"><div class="num">01</div><div class="n">Ideate</div><div class="sub">AI Copilot</div></a>
814
+ <a href="#design" class="stage-chip"><div class="num">02</div><div class="n">Design</div><div class="sub">cycleCAD</div></a>
815
+ <a href="#present" class="stage-chip"><div class="num">03</div><div class="n">Present</div><div class="sub">ExplodeView</div></a>
816
+ <a href="#cam" class="stage-chip"><div class="num">04</div><div class="n">CAM</div><div class="sub">Pentacad</div></a>
817
+ <a href="#produce" class="stage-chip"><div class="num">05</div><div class="n">Produce</div><div class="sub">Bridge</div></a>
818
+ </div>
819
+ </div>
820
+ </div>
821
+
822
+ <!-- ─────────────────────────────────────────────
823
+ END-TO-END JOURNEYS — three real products, six steps each
824
+ ───────────────────────────────────────────── -->
825
+ <section class="journeys" data-animate>
826
+ <div class="wrap">
827
+ <div class="jhead">
828
+ <span class="section-kicker">End to End · In Action</span>
829
+ <h2>Three products. <em>Six steps</em>. One tab.</h2>
830
+ <p class="sub">Real parts flowing through the full lifecycle — from a prompt in the morning to a finished part and customer feedback on the same platform.</p>
831
+ </div>
832
+
833
+ <div class="journey-stack">
834
+
835
+ <!-- ═══════════════════════════════════════
836
+ JOURNEY 1 — Custom bike bell
837
+ ═══════════════════════════════════════ -->
838
+ <div class="journey" data-journey="bell">
839
+ <div class="journey-head">
840
+ <div class="jicon">🔔</div>
841
+ <div class="jmeta">
842
+ <div class="jname">Custom bike bell</div>
843
+ <div class="jtag">Consumer · 6 days total · €345 revenue from 23 pre-orders</div>
844
+ </div>
845
+ <div class="jtimer"><span class="jtimer-dot"></span><span>STEP <span class="jstep-n">1</span>/6</span></div>
846
+ </div>
847
+ <div class="journey-track">
848
+
849
+ <div class="jstep" data-step="0">
850
+ <div class="jstep-name">Ideate</div>
851
+ <div class="jstep-vis">
852
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
853
+ <g class="vis-idea">
854
+ <g class="bulb" style="color: #8B6FC0">
855
+ <path d="M40 8 C28 8 22 17 24 28 C25 33 28 36 30 40 L50 40 C52 36 55 33 56 28 C58 17 52 8 40 8 Z" fill="currentColor" fill-opacity="0.2" stroke="currentColor" stroke-width="1.4"/>
856
+ <rect x="32" y="40" width="16" height="4" fill="currentColor"/>
857
+ <rect x="34" y="45" width="12" height="2" fill="currentColor" opacity="0.7"/>
858
+ <path d="M38 18 L40 24 L42 18" stroke="#F0F0E8" stroke-width="1" fill="none" stroke-linecap="round"/>
859
+ </g>
860
+ </g>
861
+ </svg>
862
+ </div>
863
+ <div class="jstep-meta">"bike bell with my logo"</div>
864
+ <div class="jstep-arrow">›</div>
865
+ </div>
866
+
867
+ <div class="jstep" data-step="1">
868
+ <div class="jstep-name">Design</div>
869
+ <div class="jstep-vis">
870
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
871
+ <g class="vis-design">
872
+ <circle class="d-fill" cx="40" cy="28" r="16" fill="#8B6FC0"/>
873
+ <circle class="d-path" cx="40" cy="28" r="16" fill="none" stroke="#8B6FC0" stroke-width="1.4"/>
874
+ <circle class="d-path" cx="40" cy="28" r="10" fill="none" stroke="#8B6FC0" stroke-width="1" opacity="0.6"/>
875
+ <circle class="d-path" cx="40" cy="28" r="4" fill="none" stroke="#8B6FC0" stroke-width="0.8" opacity="0.5"/>
876
+ <path class="d-path" d="M40 12 L40 44 M24 28 L56 28" stroke="#8B6FC0" stroke-width="0.4" opacity="0.3" stroke-dasharray="2 2"/>
877
+ </g>
878
+ </svg>
879
+ </div>
880
+ <div class="jstep-meta">Ø 52 mm · 14 g · 1 part</div>
881
+ <div class="jstep-arrow">›</div>
882
+ </div>
883
+
884
+ <div class="jstep" data-step="2">
885
+ <div class="jstep-name">Market</div>
886
+ <div class="jstep-vis">
887
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
888
+ <g class="vis-market">
889
+ <g class="m-card">
890
+ <rect x="18" y="8" width="44" height="32" rx="4" fill="#1A2D50" stroke="#8B6FC0" stroke-width="1"/>
891
+ <circle cx="40" cy="22" r="7" fill="#8B6FC0" fill-opacity="0.4" stroke="#8B6FC0" stroke-width="0.8"/>
892
+ <rect x="22" y="32" width="36" height="2" fill="#8B6FC0" opacity="0.5"/>
893
+ </g>
894
+ <g class="m-stars" transform="translate(18 46)">
895
+ <path class="m-star m-star-1" d="M5 0 L6 3 L9 3 L7 5 L8 8 L5 7 L2 8 L3 5 L1 3 L4 3 Z" fill="#F59E0B"/>
896
+ <path class="m-star m-star-2" d="M15 0 L16 3 L19 3 L17 5 L18 8 L15 7 L12 8 L13 5 L11 3 L14 3 Z" fill="#F59E0B"/>
897
+ <path class="m-star m-star-3" d="M25 0 L26 3 L29 3 L27 5 L28 8 L25 7 L22 8 L23 5 L21 3 L24 3 Z" fill="#F59E0B"/>
898
+ <path class="m-star m-star-4" d="M35 0 L36 3 L39 3 L37 5 L38 8 L35 7 L32 8 L33 5 L31 3 L34 3 Z" fill="#F59E0B"/>
899
+ <path class="m-star m-star-5" d="M45 0 L46 3 L49 3 L47 5 L48 8 L45 7 L42 8 L43 5 L41 3 L44 3 Z" fill="#F59E0B"/>
900
+ </g>
901
+ </g>
902
+ </svg>
903
+ </div>
904
+ <div class="jstep-meta">Listed + AI render</div>
905
+ <div class="jstep-arrow">›</div>
906
+ </div>
907
+
908
+ <div class="jstep" data-step="3">
909
+ <div class="jstep-name">Sell</div>
910
+ <div class="jstep-vis">
911
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
912
+ <g class="vis-sell">
913
+ <g class="s-cart" transform="translate(20 14)">
914
+ <path d="M0 4 L8 4 L12 24 L34 24 L38 10 L10 10" fill="none" stroke="#8B6FC0" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round"/>
915
+ <circle cx="16" cy="32" r="3" fill="#8B6FC0"/>
916
+ <circle cx="32" cy="32" r="3" fill="#8B6FC0"/>
917
+ </g>
918
+ <text class="s-count" x="68" y="22" text-anchor="end">23</text>
919
+ <text x="68" y="34" text-anchor="end" fill="#8B9AB5" font-size="7" font-family="JetBrains Mono">pre-orders</text>
920
+ </g>
921
+ </svg>
922
+ </div>
923
+ <div class="jstep-meta">€345 revenue · 6 days</div>
924
+ <div class="jstep-arrow">›</div>
925
+ </div>
926
+
927
+ <div class="jstep" data-step="4">
928
+ <div class="jstep-name">Manufacture</div>
929
+ <div class="jstep-vis">
930
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
931
+ <g class="vis-mfg">
932
+ <rect x="18" y="28" width="48" height="14" rx="1" fill="#122240" stroke="#1E3A5F" stroke-width="0.8"/>
933
+ <path class="m-path" d="M22 32 L62 32 L62 36 L22 36 L22 40 L62 40" stroke="#8B6FC0" stroke-width="1.2" fill="none"/>
934
+ <g class="m-spindle">
935
+ <rect x="-4" y="-12" width="8" height="14" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.4" rx="1"/>
936
+ <polygon points="-2,2 2,2 0,6" fill="#F59E0B"/>
937
+ </g>
938
+ <circle class="m-chip" cx="0" cy="0" r="1.2" fill="#F59E0B"/>
939
+ </g>
940
+ </svg>
941
+ </div>
942
+ <div class="jstep-meta">3+2 CAM · V2-50</div>
943
+ <div class="jstep-arrow">›</div>
944
+ </div>
945
+
946
+ <div class="jstep" data-step="5">
947
+ <div class="jstep-name">Feedback</div>
948
+ <div class="jstep-vis">
949
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
950
+ <g class="vis-feedback">
951
+ <g class="fb-bubble" transform="translate(12 8)">
952
+ <rect x="0" y="0" width="44" height="22" rx="4" fill="#1A2D50" stroke="#8B6FC0" stroke-width="1"/>
953
+ <polygon points="8,22 12,22 10,28" fill="#1A2D50" stroke="#8B6FC0" stroke-width="1"/>
954
+ <rect x="4" y="5" width="30" height="2" fill="#8B6FC0" opacity="0.6" rx="1"/>
955
+ <rect x="4" y="10" width="36" height="2" fill="#8B6FC0" opacity="0.5" rx="1"/>
956
+ <rect x="4" y="15" width="24" height="2" fill="#8B6FC0" opacity="0.4" rx="1"/>
957
+ </g>
958
+ <path class="fb-loop" d="M60 8 Q72 20 60 40 Q44 52 30 40" stroke="#F59E0B" stroke-width="1.4" fill="none" marker-end="url(#arr-bell)"/>
959
+ <defs><marker id="arr-bell" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="4" markerHeight="4" orient="auto"><path d="M0 0 L10 5 L0 10 z" fill="#F59E0B"/></marker></defs>
960
+ </g>
961
+ </svg>
962
+ </div>
963
+ <div class="jstep-meta">"louder!" → iterate</div>
964
+ </div>
965
+
966
+ </div>
967
+ </div>
968
+
969
+ <!-- ═══════════════════════════════════════
970
+ JOURNEY 2 — Precision flange (B2B)
971
+ ═══════════════════════════════════════ -->
972
+ <div class="journey" data-journey="flange">
973
+ <div class="journey-head">
974
+ <div class="jicon">⚙️</div>
975
+ <div class="jmeta">
976
+ <div class="jname">Precision flange</div>
977
+ <div class="jtag">Industrial B2B · 3 days · 50-unit PO · €2 400 revenue</div>
978
+ </div>
979
+ <div class="jtimer"><span class="jtimer-dot"></span><span>STEP <span class="jstep-n">1</span>/6</span></div>
980
+ </div>
981
+ <div class="journey-track">
982
+
983
+ <div class="jstep" data-step="0">
984
+ <div class="jstep-name">Ideate</div>
985
+ <div class="jstep-vis">
986
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
987
+ <g class="vis-idea">
988
+ <g class="bulb" style="color: #3AAFA9">
989
+ <path d="M40 8 C28 8 22 17 24 28 C25 33 28 36 30 40 L50 40 C52 36 55 33 56 28 C58 17 52 8 40 8 Z" fill="currentColor" fill-opacity="0.2" stroke="currentColor" stroke-width="1.4"/>
990
+ <rect x="32" y="40" width="16" height="4" fill="currentColor"/>
991
+ <rect x="34" y="45" width="12" height="2" fill="currentColor" opacity="0.7"/>
992
+ </g>
993
+ </g>
994
+ </svg>
995
+ </div>
996
+ <div class="jstep-meta">"flange Ø80 6 bolts PCD 60"</div>
997
+ <div class="jstep-arrow">›</div>
998
+ </div>
999
+
1000
+ <div class="jstep" data-step="1">
1001
+ <div class="jstep-name">Design</div>
1002
+ <div class="jstep-vis">
1003
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1004
+ <g class="vis-design">
1005
+ <circle class="d-fill" cx="40" cy="28" r="18" fill="#3AAFA9"/>
1006
+ <circle class="d-path" cx="40" cy="28" r="18" fill="none" stroke="#3AAFA9" stroke-width="1.4"/>
1007
+ <circle class="d-path" cx="40" cy="28" r="5" fill="none" stroke="#3AAFA9" stroke-width="1"/>
1008
+ <circle class="d-path" cx="40" cy="16" r="2" fill="#3AAFA9"/>
1009
+ <circle class="d-path" cx="50" cy="22" r="2" fill="#3AAFA9"/>
1010
+ <circle class="d-path" cx="50" cy="34" r="2" fill="#3AAFA9"/>
1011
+ <circle class="d-path" cx="40" cy="40" r="2" fill="#3AAFA9"/>
1012
+ <circle class="d-path" cx="30" cy="34" r="2" fill="#3AAFA9"/>
1013
+ <circle class="d-path" cx="30" cy="22" r="2" fill="#3AAFA9"/>
1014
+ </g>
1015
+ </svg>
1016
+ </div>
1017
+ <div class="jstep-meta">Ø 80 · 6 × M6 · PCD 60</div>
1018
+ <div class="jstep-arrow">›</div>
1019
+ </div>
1020
+
1021
+ <div class="jstep" data-step="2">
1022
+ <div class="jstep-name">Market</div>
1023
+ <div class="jstep-vis">
1024
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1025
+ <g class="vis-market">
1026
+ <g class="m-card">
1027
+ <rect x="14" y="6" width="52" height="44" rx="4" fill="#1A2D50" stroke="#3AAFA9" stroke-width="1"/>
1028
+ <circle cx="40" cy="22" r="9" fill="#3AAFA9" fill-opacity="0.3" stroke="#3AAFA9" stroke-width="0.8"/>
1029
+ <rect x="18" y="36" width="28" height="2" fill="#3AAFA9" opacity="0.5"/>
1030
+ <rect x="18" y="40" width="20" height="2" fill="#3AAFA9" opacity="0.4"/>
1031
+ <rect x="48" y="36" width="14" height="8" rx="1" fill="#3AAFA9" opacity="0.3"/>
1032
+ <text x="55" y="42" font-size="5" fill="#3AAFA9" text-anchor="middle" font-weight="700">€48</text>
1033
+ </g>
1034
+ </g>
1035
+ </svg>
1036
+ </div>
1037
+ <div class="jstep-meta">Spec sheet · quote form</div>
1038
+ <div class="jstep-arrow">›</div>
1039
+ </div>
1040
+
1041
+ <div class="jstep" data-step="3">
1042
+ <div class="jstep-name">Sell</div>
1043
+ <div class="jstep-vis">
1044
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1045
+ <g class="vis-sell">
1046
+ <rect x="20" y="8" width="40" height="32" rx="2" fill="#122240" stroke="#3AAFA9" stroke-width="1"/>
1047
+ <rect x="24" y="12" width="32" height="4" fill="#3AAFA9" opacity="0.3"/>
1048
+ <text x="40" y="28" text-anchor="middle" class="s-count">50</text>
1049
+ <text x="40" y="38" text-anchor="middle" fill="#8B9AB5" font-size="5" font-family="JetBrains Mono">units PO</text>
1050
+ <g class="s-cart" transform="translate(6 14)">
1051
+ <rect x="0" y="0" width="12" height="2" fill="#3AAFA9"/>
1052
+ <rect x="0" y="5" width="10" height="2" fill="#3AAFA9"/>
1053
+ <rect x="0" y="10" width="14" height="2" fill="#3AAFA9"/>
1054
+ </g>
1055
+ </g>
1056
+ </svg>
1057
+ </div>
1058
+ <div class="jstep-meta">€2 400 · 50 units</div>
1059
+ <div class="jstep-arrow">›</div>
1060
+ </div>
1061
+
1062
+ <div class="jstep" data-step="4">
1063
+ <div class="jstep-name">Manufacture</div>
1064
+ <div class="jstep-vis">
1065
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1066
+ <g class="vis-mfg">
1067
+ <rect x="16" y="26" width="48" height="16" rx="1" fill="#122240" stroke="#1E3A5F" stroke-width="0.8"/>
1068
+ <path class="m-path" d="M22 32 L58 32 L58 36 L22 36 L22 40 L58 40" stroke="#3AAFA9" stroke-width="1.2" fill="none"/>
1069
+ <g class="m-spindle">
1070
+ <rect x="-4" y="-14" width="8" height="16" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.4" rx="1"/>
1071
+ <polygon points="-2,2 2,2 0,6" fill="#F59E0B"/>
1072
+ </g>
1073
+ <circle class="m-chip" cx="0" cy="0" r="1.2" fill="#F59E0B"/>
1074
+ </g>
1075
+ </svg>
1076
+ </div>
1077
+ <div class="jstep-meta">Batch run · 50 parts</div>
1078
+ <div class="jstep-arrow">›</div>
1079
+ </div>
1080
+
1081
+ <div class="jstep" data-step="5">
1082
+ <div class="jstep-name">Feedback</div>
1083
+ <div class="jstep-vis">
1084
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1085
+ <g class="vis-feedback">
1086
+ <g class="fb-bubble" transform="translate(12 6)">
1087
+ <rect x="0" y="0" width="44" height="20" rx="4" fill="#1A2D50" stroke="#3AAFA9" stroke-width="1"/>
1088
+ <rect x="4" y="5" width="32" height="2" fill="#3AAFA9" opacity="0.6" rx="1"/>
1089
+ <rect x="4" y="10" width="26" height="2" fill="#3AAFA9" opacity="0.5" rx="1"/>
1090
+ <polygon points="8,20 12,20 10,26" fill="#1A2D50" stroke="#3AAFA9" stroke-width="1"/>
1091
+ </g>
1092
+ <path class="fb-loop" d="M60 8 Q72 20 60 40 Q44 52 30 40" stroke="#F59E0B" stroke-width="1.4" fill="none" marker-end="url(#arr-flange)"/>
1093
+ <defs><marker id="arr-flange" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="4" markerHeight="4" orient="auto"><path d="M0 0 L10 5 L0 10 z" fill="#F59E0B"/></marker></defs>
1094
+ </g>
1095
+ </svg>
1096
+ </div>
1097
+ <div class="jstep-meta">"tolerance → ±0.05"</div>
1098
+ </div>
1099
+
1100
+ </div>
1101
+ </div>
1102
+
1103
+ <!-- ═══════════════════════════════════════
1104
+ JOURNEY 3 — Bottle opener ring (branded merch)
1105
+ ═══════════════════════════════════════ -->
1106
+ <div class="journey" data-journey="opener">
1107
+ <div class="journey-head">
1108
+ <div class="jicon">🍺</div>
1109
+ <div class="jmeta">
1110
+ <div class="jname">Branded bottle-opener ring</div>
1111
+ <div class="jtag">Promo · 2 days · 100-unit brewery order · €1 900 revenue</div>
1112
+ </div>
1113
+ <div class="jtimer"><span class="jtimer-dot"></span><span>STEP <span class="jstep-n">1</span>/6</span></div>
1114
+ </div>
1115
+ <div class="journey-track">
1116
+
1117
+ <div class="jstep" data-step="0">
1118
+ <div class="jstep-name">Ideate</div>
1119
+ <div class="jstep-vis">
1120
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1121
+ <g class="vis-idea">
1122
+ <g class="bulb" style="color: #10B981">
1123
+ <path d="M40 8 C28 8 22 17 24 28 C25 33 28 36 30 40 L50 40 C52 36 55 33 56 28 C58 17 52 8 40 8 Z" fill="currentColor" fill-opacity="0.2" stroke="currentColor" stroke-width="1.4"/>
1124
+ <rect x="32" y="40" width="16" height="4" fill="currentColor"/>
1125
+ <rect x="34" y="45" width="12" height="2" fill="currentColor" opacity="0.7"/>
1126
+ </g>
1127
+ </g>
1128
+ </svg>
1129
+ </div>
1130
+ <div class="jstep-meta">"brewery bottle opener"</div>
1131
+ <div class="jstep-arrow">›</div>
1132
+ </div>
1133
+
1134
+ <div class="jstep" data-step="1">
1135
+ <div class="jstep-name">Design</div>
1136
+ <div class="jstep-vis">
1137
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1138
+ <g class="vis-design">
1139
+ <circle class="d-fill" cx="40" cy="28" r="16" fill="#10B981"/>
1140
+ <circle class="d-path" cx="40" cy="28" r="16" fill="none" stroke="#10B981" stroke-width="1.4"/>
1141
+ <circle class="d-path" cx="40" cy="28" r="8" fill="none" stroke="#10B981" stroke-width="1.2"/>
1142
+ <path class="d-path" d="M30 28 C30 24 34 22 40 22 C46 22 50 24 50 28" stroke="#10B981" stroke-width="1" fill="none" opacity="0.6"/>
1143
+ </g>
1144
+ </svg>
1145
+ </div>
1146
+ <div class="jstep-meta">Al 6061 · Ø 50 · 6 mm</div>
1147
+ <div class="jstep-arrow">›</div>
1148
+ </div>
1149
+
1150
+ <div class="jstep" data-step="2">
1151
+ <div class="jstep-name">Market</div>
1152
+ <div class="jstep-vis">
1153
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1154
+ <g class="vis-market">
1155
+ <g class="m-card">
1156
+ <rect x="16" y="8" width="48" height="30" rx="3" fill="#1A2D50" stroke="#10B981" stroke-width="1"/>
1157
+ <circle cx="40" cy="22" r="7" fill="#10B981" fill-opacity="0.35" stroke="#10B981" stroke-width="0.8"/>
1158
+ <rect x="20" y="32" width="22" height="2" fill="#10B981" opacity="0.5"/>
1159
+ <rect x="48" y="30" width="14" height="6" rx="1" fill="#10B981"/>
1160
+ <text x="55" y="34.5" font-size="4.5" fill="#0A1628" text-anchor="middle" font-weight="700">BUY</text>
1161
+ </g>
1162
+ </g>
1163
+ </svg>
1164
+ </div>
1165
+ <div class="jstep-meta">Landing page · Instagram</div>
1166
+ <div class="jstep-arrow">›</div>
1167
+ </div>
1168
+
1169
+ <div class="jstep" data-step="3">
1170
+ <div class="jstep-name">Sell</div>
1171
+ <div class="jstep-vis">
1172
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1173
+ <g class="vis-sell">
1174
+ <g class="s-cart" transform="translate(14 16)">
1175
+ <path d="M0 0 L6 0 L10 18 L34 18 L38 6 L8 6" fill="none" stroke="#10B981" stroke-width="1.3" stroke-linejoin="round" stroke-linecap="round"/>
1176
+ <circle cx="14" cy="24" r="2.5" fill="#10B981"/>
1177
+ <circle cx="30" cy="24" r="2.5" fill="#10B981"/>
1178
+ </g>
1179
+ <text class="s-count" x="62" y="22" text-anchor="end">100</text>
1180
+ <text x="62" y="34" text-anchor="end" fill="#8B9AB5" font-size="6" font-family="JetBrains Mono">units sold</text>
1181
+ </g>
1182
+ </svg>
1183
+ </div>
1184
+ <div class="jstep-meta">Brewery wholesale order</div>
1185
+ <div class="jstep-arrow">›</div>
1186
+ </div>
1187
+
1188
+ <div class="jstep" data-step="4">
1189
+ <div class="jstep-name">Manufacture</div>
1190
+ <div class="jstep-vis">
1191
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1192
+ <g class="vis-mfg">
1193
+ <rect x="16" y="26" width="48" height="16" rx="1" fill="#122240" stroke="#1E3A5F" stroke-width="0.8"/>
1194
+ <path class="m-path" d="M22 32 L58 32 L58 36 L22 36 L22 40 L58 40" stroke="#10B981" stroke-width="1.2" fill="none"/>
1195
+ <g class="m-spindle">
1196
+ <rect x="-4" y="-14" width="8" height="16" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.4" rx="1"/>
1197
+ <polygon points="-2,2 2,2 0,6" fill="#F59E0B"/>
1198
+ </g>
1199
+ <circle class="m-chip" cx="0" cy="0" r="1.2" fill="#F59E0B"/>
1200
+ </g>
1201
+ </svg>
1202
+ </div>
1203
+ <div class="jstep-meta">V2-50 · bottle-opener.ngc</div>
1204
+ <div class="jstep-arrow">›</div>
1205
+ </div>
1206
+
1207
+ <div class="jstep" data-step="5">
1208
+ <div class="jstep-name">Feedback</div>
1209
+ <div class="jstep-vis">
1210
+ <svg viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
1211
+ <g class="vis-feedback">
1212
+ <g class="fb-bubble" transform="translate(10 10)">
1213
+ <rect x="0" y="0" width="44" height="18" rx="4" fill="#1A2D50" stroke="#10B981" stroke-width="1"/>
1214
+ <text x="22" y="12" text-anchor="middle" fill="#10B981" font-size="7" font-weight="700">★★★★★</text>
1215
+ </g>
1216
+ <path class="fb-loop" d="M60 10 Q72 22 60 40 Q44 52 30 40" stroke="#F59E0B" stroke-width="1.4" fill="none" marker-end="url(#arr-opener)"/>
1217
+ <defs><marker id="arr-opener" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="4" markerHeight="4" orient="auto"><path d="M0 0 L10 5 L0 10 z" fill="#F59E0B"/></marker></defs>
1218
+ </g>
1219
+ </svg>
1220
+ </div>
1221
+ <div class="jstep-meta">Reorder · 200 units Q3</div>
1222
+ </div>
1223
+
1224
+ </div>
1225
+ </div>
1226
+
1227
+ </div>
1228
+ </div>
1229
+ </section>
1230
+
1231
+ <!-- ─── 01 IDEATE ─── -->
1232
+ <section class="stage" id="ideate" data-animate>
1233
+ <div class="wrap stage-layout">
1234
+ <div class="stage-body">
1235
+ <div class="label"><span class="n">01</span>Ideate</div>
1236
+ <h2>Turn words into <em>geometry</em>.</h2>
1237
+ <p>Start with a prompt — "M4 flange with 6 bolt holes on a 40 mm PCD" — and watch it materialise in 3D. Upload a napkin sketch, a photo of a worn part, or a competitor's product, and the AI Copilot infers an editable parametric model.</p>
1238
+ <p>Eight template families ship ready to parametrise. Everything else is generated by Claude, Gemini, or Groq.</p>
1239
+ <div class="products">
1240
+ <span class="pill ai">AI Copilot</span>
1241
+ <span class="pill ai">Text-to-CAD</span>
1242
+ <span class="pill ai">Image-to-CAD</span>
1243
+ </div>
1244
+ </div>
1245
+ <div class="visual vis-ideate">
1246
+ <span class="label-top">Brainstorm → Geometry</span>
1247
+ <div class="term">
1248
+ <div class="t-head"><span></span><span></span><span></span></div>
1249
+ <div class="line"><span class="prompt">you ▸</span> <span class="typed">flange Ø80 6 bolts PCD60</span></div>
1250
+ <div class="line response">parsing intent · detecting PCD pattern · generating flange geometry</div>
1251
+ <div class="line response" style="animation-delay: 5s">✓ 1 solid · 6 through-holes · outer Ø80mm</div>
1252
+ <div class="line response" style="animation-delay: 5.6s">✓ parametric (ready to edit)</div>
1253
+ </div>
1254
+ </div>
1255
+ </div>
1256
+ </section>
1257
+
1258
+ <!-- ─── 02 DESIGN ─── -->
1259
+ <section class="stage rev" id="design" data-animate>
1260
+ <div class="wrap stage-layout">
1261
+ <div class="visual vis-design">
1262
+ <div class="grid-bg"></div>
1263
+ <span class="label-top">Parametric · Sketch · Solid · Assembly</span>
1264
+ <svg viewBox="0 0 200 150" xmlns="http://www.w3.org/2000/svg">
1265
+ <defs>
1266
+ <linearGradient id="design-grad" x1="0" y1="0" x2="1" y2="1">
1267
+ <stop offset="0" stop-color="#D4A843"/>
1268
+ <stop offset="1" stop-color="#2E86DE"/>
1269
+ </linearGradient>
1270
+ </defs>
1271
+ <rect class="draw" x="50" y="40" width="100" height="70" rx="6" stroke="url(#design-grad)" stroke-width="1.6" fill="none"/>
1272
+ <circle class="draw draw-2" cx="75" cy="75" r="14" stroke="url(#design-grad)" stroke-width="1.4" fill="none"/>
1273
+ <circle class="draw draw-2" cx="125" cy="75" r="14" stroke="url(#design-grad)" stroke-width="1.4" fill="none"/>
1274
+ <path class="draw draw-3" d="M50 40 L150 110 M50 110 L150 40" stroke="url(#design-grad)" stroke-width="0.6" opacity="0.3" fill="none"/>
1275
+ <g fill="#D4A843">
1276
+ <circle class="node" cx="50" cy="40" r="3"/>
1277
+ <circle class="node" cx="150" cy="40" r="3"/>
1278
+ <circle class="node" cx="50" cy="110" r="3"/>
1279
+ <circle class="node" cx="150" cy="110" r="3"/>
1280
+ </g>
1281
+ </svg>
1282
+ </div>
1283
+ <div class="stage-body">
1284
+ <div class="label"><span class="n">02</span>Design</div>
1285
+ <h2>Parametric CAD that actually runs <em>in a browser</em>.</h2>
1286
+ <p>Sketch, extrude, revolve, sweep, loft, fillet, chamfer, shell, boolean, pattern — the full Fusion 360 surface, minus the install, the annual licence, and the "quit everything to update" dance.</p>
1287
+ <p>A real B-rep kernel on OpenCascade.js. Thirteen sketch tools with twelve constraint types. Assemblies with seven joint types. Every feature is parametric and scriptable.</p>
1288
+ <div class="products">
1289
+ <span class="pill cyclecad">cycleCAD Modeller</span>
1290
+ <span class="pill cyclecad">Agent API</span>
1291
+ </div>
1292
+ </div>
1293
+ </div>
1294
+ </section>
1295
+
1296
+ <!-- ─── 03 PRESENT ─── -->
1297
+ <section class="stage" id="present" data-animate>
1298
+ <div class="wrap stage-layout">
1299
+ <div class="stage-body">
1300
+ <div class="label"><span class="n">03</span>Present · Market</div>
1301
+ <h2>Marketing-ready visuals the moment the design is <em>ready</em>.</h2>
1302
+ <p>One-click exploded views. Photoreal renders against any scene, driven by Gemini's image model with your CAD geometry preserved. Annotations, measurements, section cuts, AR walkthroughs — all in a shareable URL.</p>
1303
+ <p>No PDF roundtrips. No render farm licence. Your customer sees exactly how the product goes together.</p>
1304
+ <div class="products">
1305
+ <span class="pill explode">ExplodeView</span>
1306
+ <span class="pill explode">AI Render</span>
1307
+ <span class="pill explode">AR Mode</span>
1308
+ </div>
1309
+ </div>
1310
+ <div class="visual vis-present">
1311
+ <span class="label-top">Exploded · Rendered · AR</span>
1312
+ <svg viewBox="0 0 200 150" xmlns="http://www.w3.org/2000/svg">
1313
+ <g fill="rgba(58,175,169,0.16)" stroke="#3AAFA9" stroke-width="1.1">
1314
+ <rect class="part p1" x="70" y="55" width="20" height="20" rx="2"/>
1315
+ <rect class="part p2" x="90" y="55" width="20" height="20" rx="2"/>
1316
+ <rect class="part p3" x="110" y="55" width="20" height="20" rx="2"/>
1317
+ <rect class="part p4" x="70" y="75" width="20" height="20" rx="2"/>
1318
+ <circle class="part p5" cx="100" cy="85" r="7" fill="#3AAFA9"/>
1319
+ <rect class="part p6" x="110" y="75" width="20" height="20" rx="2"/>
1320
+ </g>
1321
+ <g stroke="#3AAFA9" stroke-width="0.6" class="dash" fill="none">
1322
+ <line x1="55" y1="45" x2="75" y2="60"/>
1323
+ <line x1="100" y1="35" x2="100" y2="55"/>
1324
+ <line x1="145" y1="45" x2="125" y2="60"/>
1325
+ <line x1="55" y1="110" x2="75" y2="90"/>
1326
+ <line x1="145" y1="110" x2="125" y2="90"/>
1327
+ </g>
1328
+ </svg>
1329
+ </div>
1330
+ </div>
1331
+ </section>
1332
+
1333
+ <!-- ─── 04 CAM ─── -->
1334
+ <section class="stage rev" id="cam" data-animate>
1335
+ <div class="wrap stage-layout">
1336
+ <div class="visual vis-cam">
1337
+ <span class="label-top">3+2 Strategies · Simulator · Post</span>
1338
+ <svg viewBox="0 0 200 150" xmlns="http://www.w3.org/2000/svg">
1339
+ <!-- A/B axis halo -->
1340
+ <g class="ab-circle">
1341
+ <circle cx="100" cy="75" r="60" stroke="#2E86DE" stroke-width="0.4" stroke-dasharray="3 3" fill="none" opacity="0.5"/>
1342
+ </g>
1343
+ <!-- Stock -->
1344
+ <rect x="40" y="58" width="120" height="36" fill="#122240" stroke="#1E3A5F" stroke-width="1" rx="2"/>
1345
+ <!-- Toolpath (animated drawing) -->
1346
+ <path class="toolpath" d="M50 65 L150 65 L150 72 L50 72 L50 79 L150 79 L150 86 L50 86"
1347
+ stroke="#10B981" stroke-width="1.2" fill="none"/>
1348
+ <!-- Spindle (animated traveling) -->
1349
+ <g class="spindle">
1350
+ <rect x="-6" y="-26" width="12" height="20" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.4" rx="1"/>
1351
+ <polygon points="-3,-6 3,-6 0,0" fill="#F59E0B"/>
1352
+ <circle cx="0" cy="0" r="8" fill="rgba(245,158,11,0.15)"/>
1353
+ </g>
1354
+ <!-- Chips flying -->
1355
+ <g class="chip" transform="translate(100 70)">
1356
+ <circle cx="0" cy="0" r="1.5" fill="#F59E0B"/>
1357
+ <circle cx="3" cy="2" r="1" fill="#F59E0B"/>
1358
+ </g>
1359
+ <!-- Axis labels -->
1360
+ <text x="170" y="78" font-size="8" fill="#2E86DE" font-family="JetBrains Mono" opacity="0.6">A</text>
1361
+ <text x="96" y="12" font-size="8" fill="#2E86DE" font-family="JetBrains Mono" opacity="0.6">B</text>
1362
+ </svg>
1363
+ </div>
1364
+ <div class="stage-body">
1365
+ <div class="label"><span class="n">04</span>CAM</div>
1366
+ <h2>5-axis CAM in the browser. Built for <em>Pentamachine</em>.</h2>
1367
+ <p>Pentacad turns your cycleCAD model into 3+2 strategies tuned to the Pentamachine V2 kinematics. Twelve strategies from 2D contour to radial scallop finishing. An integrated 5-axis simulator replays the toolpath with collision and material-removal check before a chip flies.</p>
1368
+ <p>The post-processor emits the exact Pentamachine <code>.ngc</code> dialect — G20 imperial, G93 inverse-time feed, A/B rotary, up to 40 000 RPM.</p>
1369
+ <div class="products">
1370
+ <span class="pill pentacad">Pentacad CAM</span>
1371
+ <span class="pill pentacad">5-axis Simulator</span>
1372
+ <span class="pill pentacad">Pentamachine Post</span>
1373
+ </div>
1374
+ </div>
1375
+ </div>
1376
+ </section>
1377
+
1378
+ <!-- ─── 05 PRODUCE ─── -->
1379
+ <section class="stage" id="produce" data-animate>
1380
+ <div class="wrap stage-layout">
1381
+ <div class="stage-body">
1382
+ <div class="label"><span class="n">05</span>Produce</div>
1383
+ <h2>Click <em>Run</em>. The browser becomes the shop floor.</h2>
1384
+ <p>A Docker bridge runs next to your machine on the shop LAN. The browser streams G-code over local WebSocket; live DRO, spindle load, probe data, and alarms stream back. Pause, resume, jog, feed override — from any device on the network.</p>
1385
+ <p>Safety is hardware-first. E-stop always wins. Every command is logged and replayable. Nothing leaves your LAN unless you opt in.</p>
1386
+ <div class="products">
1387
+ <span class="pill pentacad">Machine Bridge</span>
1388
+ <span class="pill pentacad">Live DRO</span>
1389
+ <span class="pill pentacad">Drip-feed</span>
1390
+ </div>
1391
+ </div>
1392
+ <div class="visual vis-produce">
1393
+ <span class="label-top">Browser → LAN Bridge → Kinetic Control</span>
1394
+ <svg viewBox="0 0 200 150" xmlns="http://www.w3.org/2000/svg">
1395
+ <!-- Browser -->
1396
+ <g transform="translate(20 45)">
1397
+ <rect width="50" height="40" rx="3" fill="#122240" stroke="#10B981" stroke-width="1.2"/>
1398
+ <rect width="50" height="8" rx="3" fill="#10B981"/>
1399
+ <circle cx="5" cy="4" r="1.2" fill="#E05555"/>
1400
+ <circle cx="9" cy="4" r="1.2" fill="#F59E0B"/>
1401
+ <circle cx="13" cy="4" r="1.2" fill="#10B981"/>
1402
+ <text x="25" y="22" font-size="5" fill="#F0F0E8" text-anchor="middle" font-family="JetBrains Mono">pentacad</text>
1403
+ <text x="25" y="32" font-size="3.8" fill="#8B9AB5" text-anchor="middle" font-family="JetBrains Mono">
1404
+ <tspan class="dro-val">X 1.204 Y 0.872</tspan>
1405
+ </text>
1406
+ </g>
1407
+ <!-- Bridge -->
1408
+ <g transform="translate(85 58)">
1409
+ <rect width="30" height="14" rx="2" fill="#1A2D50" stroke="#8B6FC0" stroke-width="1"/>
1410
+ <text x="15" y="9" font-size="4" fill="#8B6FC0" text-anchor="middle" font-family="JetBrains Mono">BRIDGE</text>
1411
+ </g>
1412
+ <!-- Machine -->
1413
+ <g transform="translate(130 40)">
1414
+ <rect width="50" height="50" rx="2" fill="#122240" stroke="#E05555" stroke-width="1.2"/>
1415
+ <rect x="4" y="8" width="42" height="5" fill="#5A6B85"/>
1416
+ <rect x="20" y="13" width="10" height="18" fill="#8B9AB5"/>
1417
+ <polygon points="25,31 22,36 28,36" fill="#F59E0B"/>
1418
+ <text x="25" y="46" font-size="3.5" fill="#8B9AB5" text-anchor="middle" font-family="JetBrains Mono">Pentamachine V2</text>
1419
+ </g>
1420
+ <!-- Connection lines -->
1421
+ <line x1="70" y1="65" x2="85" y2="65" stroke="#3AAFA9" stroke-width="1" stroke-dasharray="2 2"/>
1422
+ <line x1="115" y1="65" x2="130" y2="65" stroke="#3AAFA9" stroke-width="1" stroke-dasharray="2 2"/>
1423
+ <!-- Packets flowing -->
1424
+ <circle class="packet packet-down" cx="0" cy="0" r="2" fill="#3AAFA9"/>
1425
+ <circle class="packet packet-up" cx="0" cy="0" r="2" fill="#F59E0B"/>
1426
+ <!-- Labels -->
1427
+ <text x="100" y="100" font-size="5" fill="#3AAFA9" text-anchor="middle" font-family="JetBrains Mono">G-code →</text>
1428
+ <text x="100" y="112" font-size="5" fill="#F59E0B" text-anchor="middle" font-family="JetBrains Mono">← DRO · alarms · spindle</text>
1429
+ </svg>
1430
+ </div>
1431
+ </div>
1432
+ </section>
1433
+
1434
+ <!-- PRODUCTS GRID -->
1435
+ <section class="products-section" id="products" data-animate>
1436
+ <div class="wrap">
1437
+ <span class="section-kicker">The Suite</span>
1438
+ <h2>Three products. <em>One</em> suite.</h2>
1439
+ <p class="sub">Each product works standalone. Together they cover everything.</p>
1440
+
1441
+ <div class="products-grid">
1442
+
1443
+ <div class="product-card p-cyclecad">
1444
+ <span class="status live">Live</span>
1445
+ <div class="pname">cycleCAD</div>
1446
+ <div class="ptag">Parametric 3D CAD</div>
1447
+ <p class="pdesc">The modelling core. Sketch, solid, assembly, surfacing, constraints — all browser-native.</p>
1448
+ <ul>
1449
+ <li>13 sketch tools · 12 constraints</li>
1450
+ <li>16 solid ops · real B-rep CSG</li>
1451
+ <li>Assembly · 7 joint types</li>
1452
+ <li>AI Copilot · 8 template families</li>
1453
+ <li>55-command Agent API</li>
1454
+ </ul>
1455
+ <div class="p-cta">
1456
+ <a href="#" class="primary">Launch</a>
1457
+ <a href="#">GitHub</a>
1458
+ </div>
1459
+ </div>
1460
+
1461
+ <div class="product-card p-explodeview">
1462
+ <span class="status live">Live</span>
1463
+ <div class="pname">ExplodeView</div>
1464
+ <div class="ptag">Viewer · AR · AI Render</div>
1465
+ <p class="pdesc">Any STEP file into an interactive 3D presentation — exploded, annotated, AR-ready, AI-rendered.</p>
1466
+ <ul>
1467
+ <li>STEP · GLB import</li>
1468
+ <li>Assembly tree · section cut</li>
1469
+ <li>AI part identifier + McMaster</li>
1470
+ <li>AI Render · preserved geometry</li>
1471
+ <li>Multi-language · WebXR AR</li>
1472
+ </ul>
1473
+ <div class="p-cta">
1474
+ <a href="#" class="primary">Open</a>
1475
+ <a href="#">GitHub</a>
1476
+ </div>
1477
+ </div>
1478
+
1479
+ <div class="product-card p-pentacad">
1480
+ <span class="status coming">Phase 0</span>
1481
+ <div class="pname">Pentacad</div>
1482
+ <div class="ptag">CAM · Simulator · Bridge</div>
1483
+ <p class="pdesc">Browser-based 5-axis CAM, G-code simulator, and live machine control for desktop CNC.</p>
1484
+ <ul>
1485
+ <li>12 strategies including 3+2</li>
1486
+ <li>Pentamachine V2 post</li>
1487
+ <li>A/B kinematics simulator</li>
1488
+ <li>Kinetic Control bridge</li>
1489
+ <li>Live DRO · probe · feed over.</li>
1490
+ </ul>
1491
+ <div class="p-cta">
1492
+ <a href="#" class="primary">Learn more</a>
1493
+ <a href="#">Try app</a>
1494
+ </div>
1495
+ </div>
1496
+
1497
+ </div>
1498
+ </div>
1499
+ </section>
1500
+
1501
+ <!-- STATS -->
1502
+ <section class="stats" data-animate>
1503
+ <div class="wrap">
1504
+ <div class="stats-grid">
1505
+ <div class="stat-card"><div class="n">44K+</div><div class="l">Lines of code</div></div>
1506
+ <div class="stat-card"><div class="n">1.9K</div><div class="l">Weekly downloads</div></div>
1507
+ <div class="stat-card"><div class="n">63</div><div class="l">Features shipped</div></div>
1508
+ <div class="stat-card"><div class="n">3</div><div class="l">Products in suite</div></div>
1509
+ </div>
1510
+ </div>
1511
+ </section>
1512
+
1513
+ <!-- CTA BLOCK -->
1514
+ <section class="cta-block">
1515
+ <div class="wrap">
1516
+ <h2>Start anywhere. <em>Ship</em> everywhere.</h2>
1517
+ <p>Use cycleCAD to design. Use ExplodeView to present. Use Pentacad to machine. Or use all three in sequence — the suite is built to flow.</p>
1518
+ <div class="ctas">
1519
+ <a href="#" class="btn btn-primary">Launch the app <span class="arrow">→</span></a>
1520
+ <a href="#" class="btn btn-secondary">Explore Pentacad</a>
1521
+ </div>
1522
+ </div>
1523
+ </section>
1524
+
1525
+ <!-- FOUNDER -->
1526
+ <section class="founder">
1527
+ <div class="wrap">
1528
+ <div class="note-box">
1529
+ <p>Every CNC shop I know runs the same five tools every day — SolidWorks or Fusion, Mastercam or HSM, a simulator if they can afford one, a proprietary post, and some patchwork control software. Switching between them wastes hours. The cycleCAD Suite is what happens when you refuse to accept that.</p>
1530
+ <div class="sig">
1531
+ <div class="avatar">S</div>
1532
+ <div>
1533
+ <div class="name">Sachin Kumar</div>
1534
+ <div class="role">Founder · cycleCAD, ExplodeView, Pentacad</div>
1535
+ </div>
1536
+ </div>
1537
+ </div>
1538
+ </div>
1539
+ </section>
1540
+
1541
+ <!-- FOOTER -->
1542
+ <footer>
1543
+ <div class="wrap">
1544
+ <div class="row">
1545
+ <div class="col brand-col">
1546
+ <span class="brand">cycle<em>CAD</em> suite</span>
1547
+ <p>From idea to finished part, in one browser tab. Open-source CAD for designers, makers, and CNC shops.</p>
1548
+ </div>
1549
+ <div class="col">
1550
+ <h4>Products</h4>
1551
+ <a href="#">cycleCAD</a>
1552
+ <a href="#">ExplodeView</a>
1553
+ <a href="#">Pentacad</a>
1554
+ </div>
1555
+ <div class="col">
1556
+ <h4>Resources</h4>
1557
+ <a href="#">Documentation</a>
1558
+ <a href="#">Architecture</a>
1559
+ <a href="#">API reference</a>
1560
+ </div>
1561
+ <div class="col">
1562
+ <h4>Developers</h4>
1563
+ <a href="#">GitHub</a>
1564
+ <a href="#">npm</a>
1565
+ <a href="#">MCP</a>
1566
+ </div>
1567
+ <div class="col">
1568
+ <h4>Contact</h4>
1569
+ <a href="#">Email</a>
1570
+ <a href="#">LinkedIn</a>
1571
+ </div>
1572
+ </div>
1573
+ <div class="legal">
1574
+ <span>© 2026 cycleCAD Suite · Sachin Kumar</span>
1575
+ <span>cycleCAD MIT · ExplodeView MIT · Pentacad AGPL-3.0</span>
1576
+ </div>
1577
+ </div>
1578
+ </footer>
1579
+
1580
+ <div class="scroll-hint" id="scrollHint">Scroll to explore</div>
1581
+
1582
+ <script>
1583
+ /* ─────────────────────────────────────────────
1584
+ SCROLL-TRIGGERED ANIMATION
1585
+ ───────────────────────────────────────────── */
1586
+ (() => {
1587
+ const elements = document.querySelectorAll('[data-animate]');
1588
+ const observer = new IntersectionObserver((entries) => {
1589
+ entries.forEach(e => {
1590
+ if (e.isIntersecting) {
1591
+ e.target.classList.add('in-view');
1592
+ if (e.target.classList.contains('stages')) e.target.classList.add('anim');
1593
+ if (e.target.dataset.once !== 'false') observer.unobserve(e.target);
1594
+ }
1595
+ });
1596
+ }, { threshold: 0.2, rootMargin: '0px 0px -80px 0px' });
1597
+
1598
+ elements.forEach(el => observer.observe(el));
1599
+ })();
1600
+
1601
+ /* ─────────────────────────────────────────────
1602
+ SCROLL HINT
1603
+ ───────────────────────────────────────────── */
1604
+ (() => {
1605
+ const hint = document.getElementById('scrollHint');
1606
+ let shown = false;
1607
+ setTimeout(() => { hint.classList.add('show'); shown = true; }, 1800);
1608
+ window.addEventListener('scroll', () => {
1609
+ if (window.scrollY > 200 && shown) { hint.classList.remove('show'); shown = false; }
1610
+ });
1611
+ })();
1612
+
1613
+ /* ─────────────────────────────────────────────
1614
+ MOUSE-TRACKED BUTTON GLOW
1615
+ ───────────────────────────────────────────── */
1616
+ (() => {
1617
+ document.querySelectorAll('.btn-primary').forEach(btn => {
1618
+ btn.addEventListener('mousemove', (e) => {
1619
+ const r = btn.getBoundingClientRect();
1620
+ btn.style.setProperty('--mx', `${((e.clientX - r.left) / r.width) * 100}%`);
1621
+ btn.style.setProperty('--my', `${((e.clientY - r.top) / r.height) * 100}%`);
1622
+ });
1623
+ });
1624
+ })();
1625
+
1626
+ /* ─────────────────────────────────────────────
1627
+ DRO FAKE TELEMETRY
1628
+ ───────────────────────────────────────────── */
1629
+ (() => {
1630
+ const el = document.querySelector('.dro-val');
1631
+ if (!el) return;
1632
+ let x = 1.204, y = 0.872, z = 0.5, a = 20.3, b = 63.4;
1633
+ setInterval(() => {
1634
+ x += (Math.random() - 0.5) * 0.02;
1635
+ y += (Math.random() - 0.5) * 0.01;
1636
+ el.textContent = `X ${x.toFixed(3)} Y ${y.toFixed(3)}`;
1637
+ }, 900);
1638
+ })();
1639
+
1640
+ /* ─────────────────────────────────────────────
1641
+ PARALLAX ON VISUALS
1642
+ ───────────────────────────────────────────── */
1643
+ (() => {
1644
+ const visuals = document.querySelectorAll('.visual');
1645
+ let scrollY = window.scrollY;
1646
+ let ticking = false;
1647
+ window.addEventListener('scroll', () => {
1648
+ scrollY = window.scrollY;
1649
+ if (!ticking) {
1650
+ requestAnimationFrame(() => {
1651
+ visuals.forEach(v => {
1652
+ const r = v.getBoundingClientRect();
1653
+ if (r.bottom > 0 && r.top < window.innerHeight) {
1654
+ const pct = (window.innerHeight - r.top) / (window.innerHeight + r.height);
1655
+ v.style.setProperty('transform', `translateY(${(pct - 0.5) * -24}px)`);
1656
+ }
1657
+ });
1658
+ ticking = false;
1659
+ });
1660
+ ticking = true;
1661
+ }
1662
+ });
1663
+ })();
1664
+
1665
+ /* ─────────────────────────────────────────────
1666
+ END-TO-END JOURNEY CYCLING
1667
+ Each journey cycles through 6 steps every 15s (2.5s per step).
1668
+ Rows are offset from each other so something is always animating.
1669
+ ───────────────────────────────────────────── */
1670
+ (() => {
1671
+ const STEP_DURATION = 2500; // ms per step
1672
+ const STEP_COUNT = 6;
1673
+ const OFFSETS = { bell: 0, flange: 1, opener: 2 }; // which step each starts on
1674
+ const STEP_NAMES = ['Ideate', 'Design', 'Market', 'Sell', 'Manufacture', 'Feedback'];
1675
+
1676
+ function setActiveStep(journey, stepIdx) {
1677
+ const steps = journey.querySelectorAll('.jstep');
1678
+ steps.forEach((s, i) => {
1679
+ s.classList.remove('active', 'done');
1680
+ if (i < stepIdx) s.classList.add('done');
1681
+ if (i === stepIdx) s.classList.add('active');
1682
+ });
1683
+ const timer = journey.querySelector('.jstep-n');
1684
+ if (timer) timer.textContent = stepIdx + 1;
1685
+ }
1686
+
1687
+ function cycleJourney(journey, startStep = 0) {
1688
+ let step = startStep;
1689
+ setActiveStep(journey, step);
1690
+ const interval = setInterval(() => {
1691
+ step = (step + 1) % STEP_COUNT;
1692
+ setActiveStep(journey, step);
1693
+ }, STEP_DURATION);
1694
+ journey._interval = interval;
1695
+ }
1696
+
1697
+ // Start cycling only after the journeys section scrolls into view,
1698
+ // so the animation is ready when the user sees it.
1699
+ const journeysSection = document.querySelector('section.journeys');
1700
+ let started = false;
1701
+
1702
+ const startAll = () => {
1703
+ if (started) return;
1704
+ started = true;
1705
+ document.querySelectorAll('.journey').forEach(j => {
1706
+ const key = j.dataset.journey;
1707
+ const offset = OFFSETS[key] ?? 0;
1708
+ cycleJourney(j, offset);
1709
+ });
1710
+ };
1711
+
1712
+ if (journeysSection) {
1713
+ const obs = new IntersectionObserver((entries) => {
1714
+ entries.forEach(e => { if (e.isIntersecting) { startAll(); obs.disconnect(); } });
1715
+ }, { threshold: 0.25 });
1716
+ obs.observe(journeysSection);
1717
+ }
1718
+
1719
+ // Pause on hover over any journey
1720
+ document.querySelectorAll('.journey').forEach(j => {
1721
+ j.addEventListener('mouseenter', () => { if (j._interval) { clearInterval(j._interval); j._interval = null; } });
1722
+ j.addEventListener('mouseleave', () => {
1723
+ if (!j._interval) {
1724
+ const activeIdx = [...j.querySelectorAll('.jstep')].findIndex(s => s.classList.contains('active'));
1725
+ cycleJourney(j, activeIdx >= 0 ? activeIdx : 0);
1726
+ }
1727
+ });
1728
+ // Click a step to jump to it
1729
+ j.querySelectorAll('.jstep').forEach((s, i) => {
1730
+ s.addEventListener('click', () => {
1731
+ if (j._interval) { clearInterval(j._interval); j._interval = null; }
1732
+ setActiveStep(j, i);
1733
+ });
1734
+ });
1735
+ });
1736
+ })();
1737
+
1738
+ console.log(
1739
+ '%ccycleCAD Suite · Animated Mockup',
1740
+ 'font-family:Fraunces,serif;font-size:18px;color:#D4A843;font-weight:700'
1741
+ );
1742
+ console.log('%cThis is a wireframe. Feedback welcome before the production page is built.', 'color:#8B9AB5');
1743
+ </script>
1744
+
1745
+ </body>
1746
+ </html>