juiceb0xc0de commited on
Commit
cf92bd1
Β·
1 Parent(s): ec942b9

Add landing page at / (CTA enters app at /index.html)

Browse files
Files changed (3) hide show
  1. forge/api.py +10 -1
  2. frontend/landing.css +777 -0
  3. frontend/landing.html +629 -0
forge/api.py CHANGED
@@ -15,7 +15,7 @@ from pathlib import Path
15
 
16
  from fastapi import Body, FastAPI, HTTPException, Query
17
  from fastapi.middleware.cors import CORSMiddleware
18
- from fastapi.responses import StreamingResponse
19
  from fastapi.staticfiles import StaticFiles
20
 
21
  from . import db, engine, scraper
@@ -37,6 +37,15 @@ def health():
37
  return {"ok": True, "llm_up": scraper._llm_up()}
38
 
39
 
 
 
 
 
 
 
 
 
 
40
  @app.get("/graph")
41
  def graph():
42
  """All nodes + edges for the initial force-graph render."""
 
15
 
16
  from fastapi import Body, FastAPI, HTTPException, Query
17
  from fastapi.middleware.cors import CORSMiddleware
18
+ from fastapi.responses import FileResponse, StreamingResponse
19
  from fastapi.staticfiles import StaticFiles
20
 
21
  from . import db, engine, scraper
 
37
  return {"ok": True, "llm_up": scraper._llm_up()}
38
 
39
 
40
+ @app.get("/")
41
+ def landing():
42
+ """Marketing landing page is the homepage; its CTA enters the app at /index.html."""
43
+ page = FRONTEND_DIR / "landing.html"
44
+ if page.is_file():
45
+ return FileResponse(str(page))
46
+ return FileResponse(str(FRONTEND_DIR / "index.html"))
47
+
48
+
49
  @app.get("/graph")
50
  def graph():
51
  """All nodes + edges for the initial force-graph render."""
frontend/landing.css ADDED
@@ -0,0 +1,777 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ============================================================================
2
+ FORGE β€” landing page specific styles. Layered on top of styles.css
3
+ ============================================================================ */
4
+
5
+ .lp {
6
+ min-height: 100vh;
7
+ position: relative;
8
+ z-index: 1;
9
+ }
10
+ .lp-shell {
11
+ max-width: 1180px;
12
+ margin: 0 auto;
13
+ padding: 0 32px;
14
+ }
15
+
16
+ /* ── Sticky top nav ───────────────────────────────────────────────────── */
17
+ .lp-nav {
18
+ position: sticky; top: 0;
19
+ z-index: 20;
20
+ background: linear-gradient(180deg, rgba(15,10,5,0.92) 0%, rgba(15,10,5,0.75) 100%);
21
+ backdrop-filter: blur(10px);
22
+ border-bottom: 1px solid rgba(212, 164, 68, 0.18);
23
+ box-shadow: 0 4px 16px rgba(0,0,0,0.5);
24
+ }
25
+ .lp-nav-inner {
26
+ max-width: 1180px;
27
+ margin: 0 auto;
28
+ padding: 14px 32px;
29
+ display: flex; align-items: center; gap: 24px;
30
+ }
31
+ .lp-nav .brand {
32
+ display: flex; align-items: center; gap: 12px;
33
+ }
34
+ .lp-nav .brand .mark {
35
+ width: 32px; height: 32px;
36
+ display: grid; place-items: center;
37
+ background: radial-gradient(circle at 50% 65%, #4a1c0a 0%, #0f0805 70%);
38
+ border: 1px solid #5a3010;
39
+ box-shadow: inset 0 0 12px rgba(255, 106, 31, 0.55), 0 0 10px rgba(255,106,31,0.20);
40
+ }
41
+ .lp-nav .brand .name {
42
+ font-family: var(--f-display);
43
+ font-size: 22px;
44
+ font-weight: 600;
45
+ letter-spacing: 0.18em;
46
+ color: #f6e4c8;
47
+ text-shadow: 0 1px 0 #000, 0 0 8px rgba(255, 138, 61, 0.25);
48
+ }
49
+ .lp-nav .links {
50
+ margin-left: auto;
51
+ display: flex; align-items: center; gap: 24px;
52
+ font-family: var(--f-display);
53
+ font-size: 11px;
54
+ letter-spacing: 0.22em;
55
+ text-transform: uppercase;
56
+ }
57
+ .lp-nav .links a {
58
+ color: var(--bone-3);
59
+ text-decoration: none;
60
+ padding: 6px 0;
61
+ border-bottom: 1px solid transparent;
62
+ transition: color 160ms ease, border 160ms ease;
63
+ }
64
+ .lp-nav .links a:hover { color: var(--brass-1); border-bottom-color: var(--brass-1); }
65
+ .lp-nav .cta-mini {
66
+ font-family: var(--f-display);
67
+ font-size: 11px;
68
+ letter-spacing: 0.22em;
69
+ text-transform: uppercase;
70
+ padding: 8px 16px;
71
+ color: #fff5e8;
72
+ background: linear-gradient(180deg, #ff8a3d 0%, #c46822 100%);
73
+ border: 1px solid #6a2a08;
74
+ text-decoration: none;
75
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 2px 6px rgba(0,0,0,0.5), 0 0 8px var(--ember-glow);
76
+ }
77
+ .lp-nav .cta-mini:hover {
78
+ background: linear-gradient(180deg, #ffba5e 0%, #ff8a3d 100%);
79
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 2px 8px rgba(0,0,0,0.6), 0 0 16px var(--ember-1);
80
+ }
81
+
82
+ /* ── Hero ─────────────────────────────────────────────────────────────── */
83
+ .lp-hero {
84
+ padding: 90px 0 100px;
85
+ position: relative;
86
+ display: grid;
87
+ grid-template-columns: 1.15fr 1fr;
88
+ gap: 60px;
89
+ align-items: center;
90
+ }
91
+ .lp-hero::before {
92
+ /* ember bloom under the hero */
93
+ content: "";
94
+ position: absolute; left: 50%; bottom: -40px;
95
+ width: 80%; height: 220px;
96
+ transform: translateX(-50%);
97
+ background: radial-gradient(ellipse at 50% 100%, rgba(255, 106, 31, 0.18), transparent 60%);
98
+ pointer-events: none;
99
+ }
100
+ .lp-eyebrow {
101
+ font-family: var(--f-mono);
102
+ font-size: 11px;
103
+ letter-spacing: 0.30em;
104
+ text-transform: uppercase;
105
+ color: var(--brass-2);
106
+ margin-bottom: 22px;
107
+ display: inline-flex; align-items: center; gap: 12px;
108
+ }
109
+ .lp-eyebrow::before, .lp-eyebrow::after {
110
+ content: "";
111
+ display: inline-block;
112
+ width: 28px; height: 1px;
113
+ background: linear-gradient(90deg, transparent, var(--brass-2));
114
+ }
115
+ .lp-eyebrow::after { background: linear-gradient(90deg, var(--brass-2), transparent); }
116
+
117
+ .lp-title {
118
+ font-family: var(--f-display);
119
+ font-size: 92px;
120
+ font-weight: 600;
121
+ line-height: 0.92;
122
+ letter-spacing: 0.04em;
123
+ color: #f6e4c8;
124
+ margin: 0 0 28px;
125
+ text-shadow:
126
+ 0 1px 0 #000,
127
+ 0 2px 0 #000,
128
+ 0 0 24px rgba(255, 138, 61, 0.25);
129
+ }
130
+ .lp-title em {
131
+ font-style: normal;
132
+ background: linear-gradient(180deg, #ffba5e 0%, #ff6a1f 70%, #8a3010 100%);
133
+ -webkit-background-clip: text;
134
+ background-clip: text;
135
+ -webkit-text-fill-color: transparent;
136
+ display: inline-block;
137
+ }
138
+ .lp-subtitle {
139
+ font-family: var(--f-serif);
140
+ font-style: italic;
141
+ font-size: 22px;
142
+ line-height: 1.45;
143
+ color: var(--bone-2);
144
+ margin: 0 0 38px;
145
+ max-width: 540px;
146
+ letter-spacing: 0.005em;
147
+ }
148
+ .lp-subtitle strong {
149
+ color: var(--brass-1);
150
+ font-style: normal;
151
+ font-weight: 500;
152
+ letter-spacing: 0.02em;
153
+ }
154
+ .lp-cta-row {
155
+ display: flex; align-items: center; gap: 18px;
156
+ margin-top: 8px;
157
+ }
158
+ .lp-cta-primary {
159
+ font-family: var(--f-display);
160
+ font-size: 13px;
161
+ letter-spacing: 0.26em;
162
+ text-transform: uppercase;
163
+ padding: 16px 28px;
164
+ color: #fff5e8;
165
+ background: linear-gradient(180deg, #ff8a3d 0%, #c46822 100%);
166
+ border: 1px solid #2a1a08;
167
+ text-decoration: none;
168
+ box-shadow:
169
+ inset 0 1px 0 rgba(255,255,255,0.30),
170
+ inset 0 -2px 0 rgba(0,0,0,0.30),
171
+ 0 4px 14px rgba(0,0,0,0.5),
172
+ 0 0 16px var(--ember-glow);
173
+ position: relative;
174
+ transition: transform 120ms ease, box-shadow 200ms ease;
175
+ cursor: pointer;
176
+ display: inline-flex; align-items: center; gap: 12px;
177
+ }
178
+ .lp-cta-primary::before, .lp-cta-primary::after {
179
+ content: "";
180
+ position: absolute; top: 50%; transform: translateY(-50%);
181
+ width: 6px; height: 6px;
182
+ background: #ffba5e;
183
+ box-shadow: 0 0 6px #ffba5e;
184
+ }
185
+ .lp-cta-primary::before { left: -3px; }
186
+ .lp-cta-primary::after { right: -3px; }
187
+ .lp-cta-primary:hover {
188
+ transform: translateY(-1px);
189
+ box-shadow:
190
+ inset 0 1px 0 rgba(255,255,255,0.40),
191
+ inset 0 -2px 0 rgba(0,0,0,0.30),
192
+ 0 6px 18px rgba(0,0,0,0.55),
193
+ 0 0 28px var(--ember-1);
194
+ }
195
+ .lp-cta-secondary {
196
+ font-family: var(--f-display);
197
+ font-size: 12px;
198
+ letter-spacing: 0.22em;
199
+ text-transform: uppercase;
200
+ padding: 16px 22px;
201
+ color: var(--bone-2);
202
+ background: transparent;
203
+ border: 1px solid var(--steel-2);
204
+ text-decoration: none;
205
+ }
206
+ .lp-cta-secondary:hover { color: var(--bone-1); border-color: var(--brass-2); }
207
+
208
+ /* ── Hero right: floating anvil + mini graph demo ────────────────────── */
209
+ .lp-hero-art {
210
+ position: relative;
211
+ min-height: 480px;
212
+ display: grid;
213
+ place-items: center;
214
+ }
215
+ .lp-hero-art::before {
216
+ /* glowing forge ring behind the demo */
217
+ content: "";
218
+ position: absolute;
219
+ width: 480px; height: 480px;
220
+ border-radius: 50%;
221
+ background:
222
+ radial-gradient(circle at 50% 60%, rgba(255, 106, 31, 0.18) 0%, transparent 60%);
223
+ pointer-events: none;
224
+ }
225
+ .lp-hero-art::after {
226
+ content: "";
227
+ position: absolute;
228
+ width: 360px; height: 360px;
229
+ border-radius: 50%;
230
+ border: 1px dashed rgba(212, 164, 68, 0.18);
231
+ animation: gentle-rotate 60s linear infinite;
232
+ }
233
+ .demo-svg {
234
+ position: relative;
235
+ width: 460px; height: 460px;
236
+ display: block;
237
+ }
238
+
239
+ /* ── Sections ─────────────────────────────────────────────────────────── */
240
+ section.lp-section { padding: 80px 0; position: relative; scroll-margin-top: 80px; }
241
+ .lp-section + .lp-section { border-top: 1px solid rgba(212, 164, 68, 0.08); }
242
+ .lp-section-head {
243
+ text-align: center;
244
+ margin-bottom: 56px;
245
+ }
246
+ .lp-section-eyebrow {
247
+ font-family: var(--f-mono);
248
+ font-size: 11px;
249
+ letter-spacing: 0.30em;
250
+ text-transform: uppercase;
251
+ color: var(--brass-1);
252
+ margin-bottom: 14px;
253
+ }
254
+ .lp-section-title {
255
+ font-family: var(--f-display);
256
+ font-size: 44px;
257
+ font-weight: 500;
258
+ letter-spacing: 0.03em;
259
+ color: #f6e4c8;
260
+ margin: 0 0 14px;
261
+ text-shadow: 0 1px 0 #000;
262
+ }
263
+ .lp-section-sub {
264
+ font-family: var(--f-serif);
265
+ font-style: italic;
266
+ font-size: 17px;
267
+ line-height: 1.5;
268
+ color: var(--bone-3);
269
+ max-width: 620px;
270
+ margin: 0 auto;
271
+ }
272
+
273
+ /* What it does β€” three carved tablets */
274
+ .lp-tablets {
275
+ display: grid;
276
+ grid-template-columns: repeat(3, 1fr);
277
+ gap: 24px;
278
+ }
279
+ .lp-tablet {
280
+ position: relative;
281
+ padding: 38px 28px 32px;
282
+ background:
283
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='p'><feTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='2' stitchTiles='stitch' seed='5'/><feColorMatrix values='0 0 0 0 0.30 0 0 0 0 0.22 0 0 0 0 0.12 0 0 0 0.14 0'/></filter><rect width='100%25' height='100%25' filter='url(%23p)'/></svg>"),
284
+ linear-gradient(180deg, rgba(40,30,18,0.45) 0%, rgba(15,12,8,0.85) 100%);
285
+ background-blend-mode: overlay, normal;
286
+ border: 1px solid rgba(70, 50, 28, 0.7);
287
+ border-top: 2px solid var(--brass-2);
288
+ box-shadow:
289
+ inset 0 1px 0 rgba(255,255,255,0.04),
290
+ 0 8px 24px rgba(0,0,0,0.5);
291
+ }
292
+ .lp-tablet::before, .lp-tablet::after {
293
+ /* brass corner ornaments top-left + top-right */
294
+ content: "";
295
+ position: absolute; top: -1px;
296
+ width: 8px; height: 8px;
297
+ border: 2px solid var(--brass-2);
298
+ }
299
+ .lp-tablet::before { left: -1px; border-right: none; border-bottom: none; }
300
+ .lp-tablet::after { right: -1px; border-left: none; border-bottom: none; }
301
+ .lp-tablet-icon {
302
+ width: 56px; height: 56px;
303
+ margin-bottom: 22px;
304
+ display: grid; place-items: center;
305
+ border: 1px solid rgba(212, 164, 68, 0.30);
306
+ background:
307
+ radial-gradient(circle at 50% 35%, rgba(255, 138, 61, 0.18) 0%, rgba(0,0,0,0) 70%),
308
+ #0a0805;
309
+ color: var(--brass-1);
310
+ position: relative;
311
+ }
312
+ .lp-tablet-icon::before, .lp-tablet-icon::after {
313
+ /* corner ornaments */
314
+ content: "";
315
+ position: absolute;
316
+ width: 4px; height: 4px;
317
+ border: 1px solid var(--brass-2);
318
+ }
319
+ .lp-tablet-icon::before { top: -1px; left: -1px; border-right: none; border-bottom: none; }
320
+ .lp-tablet-icon::after { bottom: -1px; right: -1px; border-left: none; border-top: none; }
321
+
322
+ .lp-tablet-num {
323
+ position: absolute; top: 18px; right: 22px;
324
+ font-family: var(--f-display);
325
+ font-size: 38px;
326
+ font-weight: 600;
327
+ color: rgba(212, 164, 68, 0.20);
328
+ letter-spacing: 0.02em;
329
+ line-height: 1;
330
+ }
331
+ .lp-tablet h3 {
332
+ font-family: var(--f-display);
333
+ font-size: 22px;
334
+ font-weight: 500;
335
+ letter-spacing: 0.02em;
336
+ margin: 0 0 12px;
337
+ color: #fff5e8;
338
+ }
339
+ .lp-tablet p {
340
+ font-family: var(--f-serif);
341
+ font-size: 15px;
342
+ line-height: 1.55;
343
+ color: var(--bone-2);
344
+ margin: 0;
345
+ }
346
+ .lp-tablet p em {
347
+ color: var(--brass-1);
348
+ font-style: italic;
349
+ }
350
+
351
+ /* How to use β€” alternating numbered rows */
352
+ .lp-steps { display: flex; flex-direction: column; gap: 60px; }
353
+ .lp-step {
354
+ display: grid;
355
+ grid-template-columns: 1fr 1fr;
356
+ gap: 60px;
357
+ align-items: center;
358
+ }
359
+ .lp-step:nth-child(even) .lp-step-text { order: 2; }
360
+ .lp-step:nth-child(even) .lp-step-art { order: 1; }
361
+ .lp-step-num {
362
+ display: inline-block;
363
+ font-family: var(--f-display);
364
+ font-size: 13px;
365
+ letter-spacing: 0.30em;
366
+ text-transform: uppercase;
367
+ color: var(--brass-1);
368
+ padding-bottom: 8px;
369
+ margin-bottom: 14px;
370
+ border-bottom: 1px solid var(--brass-2);
371
+ }
372
+ .lp-step h3 {
373
+ font-family: var(--f-display);
374
+ font-size: 36px;
375
+ font-weight: 500;
376
+ letter-spacing: 0.02em;
377
+ margin: 0 0 18px;
378
+ color: #fff5e8;
379
+ line-height: 1.05;
380
+ }
381
+ .lp-step p {
382
+ font-family: var(--f-serif);
383
+ font-size: 16.5px;
384
+ line-height: 1.6;
385
+ color: var(--bone-2);
386
+ margin: 0 0 14px;
387
+ max-width: 460px;
388
+ }
389
+ .lp-step .quote {
390
+ font-family: var(--f-serif);
391
+ font-style: italic;
392
+ font-size: 13px;
393
+ color: var(--bone-3);
394
+ border-left: 2px solid var(--brass-2);
395
+ padding-left: 14px;
396
+ margin: 18px 0 0;
397
+ max-width: 460px;
398
+ }
399
+ .lp-step-art {
400
+ position: relative;
401
+ min-height: 320px;
402
+ display: grid; place-items: center;
403
+ background:
404
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='p'><feTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='2' stitchTiles='stitch' seed='9'/><feColorMatrix values='0 0 0 0 0.25 0 0 0 0 0.20 0 0 0 0 0.10 0 0 0 0.10 0'/></filter><rect width='100%25' height='100%25' filter='url(%23p)'/></svg>"),
405
+ linear-gradient(180deg, rgba(20,14,10,0.6) 0%, rgba(8,6,4,0.85) 100%);
406
+ background-blend-mode: overlay, normal;
407
+ border: 1px solid rgba(60, 42, 22, 0.6);
408
+ padding: 32px;
409
+ }
410
+
411
+ /* Tier system explainer */
412
+ .lp-tiers {
413
+ display: grid;
414
+ grid-template-columns: repeat(3, 1fr);
415
+ gap: 22px;
416
+ }
417
+ .lp-tier {
418
+ padding: 30px 26px;
419
+ background: linear-gradient(180deg, rgba(20,14,10,0.5) 0%, rgba(8,6,4,0.8) 100%);
420
+ border: 1px solid rgba(60, 42, 22, 0.7);
421
+ border-left: 3px solid var(--lp-tier-color, var(--brass-2));
422
+ position: relative;
423
+ }
424
+ .lp-tier-1 { --lp-tier-color: var(--brass-1); }
425
+ .lp-tier-2 { --lp-tier-color: var(--brass-2); }
426
+ .lp-tier-3 { --lp-tier-color: var(--brass-3); }
427
+
428
+ .lp-tier-coin {
429
+ width: 48px; height: 48px;
430
+ border-radius: 50%;
431
+ margin-bottom: 18px;
432
+ border: 1px solid rgba(0,0,0,0.5);
433
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 1px 3px rgba(0,0,0,0.6);
434
+ display: grid; place-items: center;
435
+ font-family: var(--f-display);
436
+ font-size: 17px;
437
+ font-weight: 700;
438
+ color: var(--coal-0);
439
+ letter-spacing: 0.02em;
440
+ }
441
+ .lp-tier-1 .lp-tier-coin { background: radial-gradient(circle at 35% 30%, #ffd09a, #ff8a3d 50%, #6a2a08); box-shadow: 0 0 14px var(--tier1-glow), inset 0 1px 0 rgba(255,255,255,0.25); }
442
+ .lp-tier-2 .lp-tier-coin { background: radial-gradient(circle at 35% 30%, #b8d4f0, #5b9bd8 50%, #1c3a5a); box-shadow: 0 0 8px var(--tier2-glow), inset 0 1px 0 rgba(255,255,255,0.22); }
443
+ .lp-tier-3 .lp-tier-coin { background: radial-gradient(circle at 35% 30%, #cac4b6, #9a9285 50%, #3a3528); box-shadow: 0 0 4px var(--tier3-glow), inset 0 1px 0 rgba(255,255,255,0.18); }
444
+
445
+ .lp-tier-label {
446
+ font-family: var(--f-display);
447
+ font-size: 13px;
448
+ letter-spacing: 0.24em;
449
+ text-transform: uppercase;
450
+ color: var(--lp-tier-color);
451
+ margin-bottom: 6px;
452
+ }
453
+ .lp-tier h4 {
454
+ font-family: var(--f-display);
455
+ font-size: 22px;
456
+ font-weight: 500;
457
+ margin: 0 0 14px;
458
+ color: #fff5e8;
459
+ letter-spacing: 0.01em;
460
+ }
461
+ .lp-tier p {
462
+ font-family: var(--f-serif);
463
+ font-size: 14.5px;
464
+ line-height: 1.55;
465
+ color: var(--bone-2);
466
+ margin: 0 0 14px;
467
+ }
468
+ .lp-tier .example {
469
+ font-family: var(--f-mono);
470
+ font-size: 10.5px;
471
+ letter-spacing: 0.02em;
472
+ color: var(--bone-4);
473
+ padding: 8px 10px;
474
+ background: var(--coal-0);
475
+ border-left: 2px solid var(--lp-tier-color);
476
+ }
477
+
478
+ /* Scraper / live data section */
479
+ .lp-scraper {
480
+ display: grid;
481
+ grid-template-columns: 1.1fr 1fr;
482
+ gap: 60px;
483
+ align-items: center;
484
+ }
485
+ .lp-scraper p { font-family: var(--f-serif); font-size: 16px; line-height: 1.6; color: var(--bone-2); max-width: 520px; }
486
+ .lp-scraper p em { font-style: italic; color: var(--brass-2); }
487
+ .lp-pipeline {
488
+ display: flex; flex-direction: column; gap: 10px;
489
+ padding: 24px;
490
+ background: var(--coal-0);
491
+ border: 1px solid rgba(60, 42, 22, 0.6);
492
+ font-family: var(--f-mono);
493
+ font-size: 11.5px;
494
+ position: relative;
495
+ }
496
+ .lp-pipeline::before {
497
+ content: "scraper.log";
498
+ position: absolute; top: -10px; left: 16px;
499
+ background: var(--coal-0);
500
+ padding: 0 8px;
501
+ font-family: var(--f-display);
502
+ font-size: 10px;
503
+ letter-spacing: 0.20em;
504
+ text-transform: uppercase;
505
+ color: var(--brass-2);
506
+ }
507
+ .lp-pipeline-step {
508
+ display: grid;
509
+ grid-template-columns: auto 1fr auto;
510
+ gap: 12px;
511
+ padding: 8px 0;
512
+ border-bottom: 1px solid rgba(60,42,22,0.4);
513
+ color: var(--bone-2);
514
+ }
515
+ .lp-pipeline-step:last-child { border-bottom: none; }
516
+ .lp-pipeline-step .arrow { color: var(--ember-2); }
517
+ .lp-pipeline-step .src { color: var(--brass-2); }
518
+ .lp-pipeline-step .tier {
519
+ font-family: var(--f-display);
520
+ font-size: 9px;
521
+ padding: 1px 5px;
522
+ letter-spacing: 0.12em;
523
+ color: var(--coal-0);
524
+ text-transform: uppercase;
525
+ font-weight: 600;
526
+ }
527
+ .lp-pipeline-step .tier.t1 { background: var(--brass-1); }
528
+ .lp-pipeline-step .tier.t2 { background: var(--brass-2); color: #fff; }
529
+ .lp-pipeline-step .tier.t3 { background: var(--brass-3); }
530
+
531
+ /* Final CTA strip */
532
+ .lp-finale {
533
+ padding: 120px 0;
534
+ text-align: center;
535
+ position: relative;
536
+ }
537
+ .lp-finale::before {
538
+ content: "";
539
+ position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
540
+ width: 700px; height: 200px;
541
+ background: radial-gradient(ellipse, rgba(255, 106, 31, 0.18) 0%, transparent 70%);
542
+ pointer-events: none;
543
+ }
544
+ .lp-finale-title {
545
+ font-family: var(--f-display);
546
+ font-size: 64px;
547
+ font-weight: 500;
548
+ letter-spacing: 0.04em;
549
+ margin: 0 0 14px;
550
+ color: #f6e4c8;
551
+ position: relative;
552
+ text-shadow: 0 2px 0 #000, 0 0 22px rgba(255, 138, 61, 0.30);
553
+ }
554
+ .lp-finale-sub {
555
+ font-family: var(--f-serif);
556
+ font-style: italic;
557
+ font-size: 18px;
558
+ color: var(--bone-3);
559
+ margin: 0 0 38px;
560
+ position: relative;
561
+ }
562
+ .lp-finale .lp-cta-primary { font-size: 14px; padding: 18px 36px; }
563
+
564
+ .lp-foot {
565
+ border-top: 1px solid rgba(212, 164, 68, 0.10);
566
+ padding: 28px 0 40px;
567
+ text-align: center;
568
+ font-family: var(--f-mono);
569
+ font-size: 10.5px;
570
+ letter-spacing: 0.12em;
571
+ color: var(--bone-4);
572
+ }
573
+ .lp-foot a { color: var(--bone-3); text-decoration: none; border-bottom: 1px dotted var(--bone-4); }
574
+
575
+ /* ── Hero mini demo: 5 nodes, cyclic state animation ─────────────────── */
576
+ .demo-svg .lp-node { cursor: default; }
577
+ .demo-svg .lp-aura { fill: none; stroke: none; opacity: 0; }
578
+ .demo-svg .lp-frame-outer { fill: none; stroke: #2a2017; stroke-width: 2.2; }
579
+ .demo-svg .lp-plate { fill: var(--coal-2); stroke: rgba(0,0,0,0.5); stroke-width: 1.5; }
580
+ .demo-svg .lp-gem { fill: var(--type-color, #5fb3d4); opacity: 0.18; }
581
+ .demo-svg .lp-frame { fill: none; stroke: #6b5026; stroke-width: 1.2; }
582
+ .demo-svg .lp-stud { fill: #8a6a32; stroke: #2a2017; stroke-width: 0.6; }
583
+ .demo-svg .lp-icon { transition: stroke 240ms ease, opacity 240ms ease; opacity: 0.9; }
584
+ .demo-svg .lp-ribbon { fill: rgba(11,14,19,0.85); stroke: rgba(107, 80, 38, 0.7); stroke-width: 0.7; }
585
+ .demo-svg .lp-name {
586
+ fill: var(--bone-1);
587
+ font-family: var(--f-display);
588
+ font-size: 11.5px;
589
+ font-weight: 500;
590
+ letter-spacing: 0.04em;
591
+ }
592
+ .demo-svg .lp-lock { opacity: 0; transition: opacity 320ms ease; }
593
+ .demo-svg .lp-chip { opacity: 0; transition: opacity 320ms ease; }
594
+
595
+ /* type-color slots per node */
596
+ .demo-svg .lp-center { --type-color: var(--t-technique); }
597
+ .demo-svg .lp-outer-1 { --type-color: var(--t-technique); }
598
+ .demo-svg .lp-outer-2 { --type-color: var(--t-quantization); }
599
+ .demo-svg .lp-outer-3 { --type-color: var(--t-technique); }
600
+ .demo-svg .lp-outer-4 { --type-color: var(--t-architecture); }
601
+ .demo-svg .lp-outer-5 { --type-color: var(--t-technique); }
602
+
603
+ /* edges: base curves */
604
+ .demo-svg .lp-edge { fill: none; stroke-linecap: round; }
605
+ .demo-svg .lp-edge-breaks { stroke: rgba(200,64,60,0.4); stroke-width: 1.4; }
606
+ .demo-svg .lp-edge-requires,
607
+ .demo-svg .lp-edge-requires-2 { stroke: rgba(255,160,60,0.35); stroke-width: 1.4; }
608
+ .demo-svg .lp-edge-compatible,
609
+ .demo-svg .lp-edge-compatible-2 { stroke: rgba(212,164,68,0.20); stroke-width: 1.0; }
610
+
611
+ /* center β†’ selected (red-hot) */
612
+ .demo-svg .lp-center .lp-plate { animation: lp-plate-select 8s ease-in-out infinite; }
613
+ .demo-svg .lp-center .lp-frame { animation: lp-frame-select 8s ease-in-out infinite; }
614
+ .demo-svg .lp-center .lp-frame-outer { animation: lp-frame-outer-select 8s ease-in-out infinite; }
615
+ .demo-svg .lp-center .lp-aura { animation: lp-aura-select 8s ease-in-out infinite; }
616
+ .demo-svg .lp-center .lp-stud { animation: lp-stud-select 8s ease-in-out infinite; }
617
+ .demo-svg .lp-center .lp-gem { animation: lp-gem-select 8s ease-in-out infinite; }
618
+ .demo-svg .lp-center .lp-icon { animation: lp-icon-select 8s ease-in-out infinite; }
619
+ .demo-svg .lp-center .lp-name { animation: lp-name-select 8s ease-in-out infinite; }
620
+ .demo-svg .lp-center .lp-ribbon { animation: lp-ribbon-select 8s ease-in-out infinite; }
621
+
622
+ @keyframes lp-plate-select {
623
+ 0%, 12%, 92%, 100% { fill: var(--coal-2); filter: none; }
624
+ 18%, 86% { fill: url(#lp-molten); filter: url(#lp-ember); }
625
+ }
626
+ @keyframes lp-frame-select {
627
+ 0%, 12%, 92%, 100% { stroke: #6b5026; stroke-width: 1.2; }
628
+ 18%, 86% { stroke: #d4a049; stroke-width: 1.5; }
629
+ }
630
+ @keyframes lp-frame-outer-select {
631
+ 0%, 12%, 92%, 100% { stroke: #2a2017; }
632
+ 18%, 86% { stroke: #3a1a08; }
633
+ }
634
+ @keyframes lp-aura-select {
635
+ 0%, 12%, 92%, 100% { opacity: 0; stroke: var(--ember-1); stroke-width: 1.5; fill: none; }
636
+ 18% { opacity: 1; stroke: var(--ember-1); stroke-width: 2; fill: none; }
637
+ 50% { opacity: 0.4; stroke: var(--ember-1); stroke-width: 4; fill: none; }
638
+ 86% { opacity: 1; stroke: var(--ember-1); stroke-width: 2; fill: none; }
639
+ }
640
+ @keyframes lp-stud-select {
641
+ 0%, 12%, 92%, 100% { fill: #8a6a32; stroke: #2a2017; }
642
+ 18%, 86% { fill: #d4a049; stroke: #3a1a08; }
643
+ }
644
+ @keyframes lp-gem-select {
645
+ 0%, 12%, 92%, 100% { fill: var(--type-color); opacity: 0.18; }
646
+ 18%, 86% { fill: var(--ember-1); opacity: 0.55; }
647
+ }
648
+ @keyframes lp-icon-select {
649
+ 0%, 12%, 92%, 100% { stroke: var(--type-color); opacity: 0.9; }
650
+ 18%, 86% { stroke: #fff5e8; opacity: 1; }
651
+ }
652
+ @keyframes lp-name-select {
653
+ 0%, 12%, 92%, 100% { fill: var(--bone-1); }
654
+ 18%, 86% { fill: #fff5e8; }
655
+ }
656
+ @keyframes lp-ribbon-select {
657
+ 0%, 12%, 92%, 100% { fill: rgba(11,14,19,0.85); stroke: rgba(107, 80, 38, 0.7); }
658
+ 18%, 86% { fill: rgba(40,15,5,0.92); stroke: #d4a049; }
659
+ }
660
+
661
+ /* outer-1: BLOCKED */
662
+ .demo-svg .lp-outer-1 .lp-plate { animation: lp-plate-block 8s ease-in-out infinite; }
663
+ .demo-svg .lp-outer-1 .lp-frame { animation: lp-frame-block 8s ease-in-out infinite; }
664
+ .demo-svg .lp-outer-1 .lp-icon { animation: lp-icon-block 8s ease-in-out infinite; }
665
+ .demo-svg .lp-outer-1 .lp-aura { animation: lp-aura-block 8s ease-in-out infinite; }
666
+ .demo-svg .lp-outer-1 .lp-stud { animation: lp-stud-block 8s ease-in-out infinite; }
667
+ .demo-svg .lp-outer-1 .lp-gem { animation: lp-gem-fade 8s ease-in-out infinite; }
668
+ .demo-svg .lp-outer-1 .lp-name { animation: lp-name-block 8s ease-in-out infinite; }
669
+ .demo-svg .lp-outer-1 .lp-lock { animation: lp-lock-show 8s ease-in-out infinite; }
670
+
671
+ @keyframes lp-plate-block {
672
+ 0%, 12%, 92%, 100% { fill: var(--coal-2); filter: none; opacity: 1; }
673
+ 18%, 86% { fill: var(--coal-1); filter: grayscale(100%) brightness(0.55); opacity: 0.55; }
674
+ }
675
+ @keyframes lp-frame-block {
676
+ 0%, 12%, 92%, 100% { stroke: #6b5026; }
677
+ 18%, 86% { stroke: var(--rust-2); }
678
+ }
679
+ @keyframes lp-icon-block {
680
+ 0%, 12%, 92%, 100% { stroke: var(--type-color); opacity: 0.9; }
681
+ 18%, 86% { stroke: var(--rust); opacity: 0.45; }
682
+ }
683
+ @keyframes lp-aura-block {
684
+ 0%, 12%, 92%, 100% { opacity: 0; }
685
+ 18%, 86% { opacity: 0.85; stroke: var(--rust); stroke-width: 1.2; fill: none; }
686
+ }
687
+ @keyframes lp-stud-block {
688
+ 0%, 12%, 92%, 100% { fill: #8a6a32; }
689
+ 18%, 86% { fill: var(--rust-2); }
690
+ }
691
+ @keyframes lp-gem-fade {
692
+ 0%, 12%, 92%, 100% { opacity: 0.18; }
693
+ 18%, 86% { opacity: 0; }
694
+ }
695
+ @keyframes lp-name-block {
696
+ 0%, 12%, 92%, 100% { fill: var(--bone-1); }
697
+ 18%, 86% { fill: var(--rust); opacity: 0.7; }
698
+ }
699
+ @keyframes lp-lock-show {
700
+ 0%, 14%, 92%, 100% { opacity: 0; }
701
+ 20%, 86% { opacity: 1; }
702
+ }
703
+
704
+ /* outer-2: CONDITIONAL ("needs Β· add") */
705
+ .demo-svg .lp-outer-2 .lp-plate { animation: lp-plate-cond 8s ease-in-out infinite; }
706
+ .demo-svg .lp-outer-2 .lp-frame { animation: lp-frame-cond 8s ease-in-out infinite; }
707
+ .demo-svg .lp-outer-2 .lp-icon { animation: lp-icon-cond 8s ease-in-out infinite; }
708
+ .demo-svg .lp-outer-2 .lp-aura { animation: lp-aura-cond 8s ease-in-out infinite; }
709
+ .demo-svg .lp-outer-2 .lp-stud { animation: lp-stud-cond 8s ease-in-out infinite; }
710
+ .demo-svg .lp-outer-2 .lp-gem { animation: lp-gem-fade 8s ease-in-out infinite; }
711
+ .demo-svg .lp-outer-2 .lp-name { animation: lp-name-cond 8s ease-in-out infinite; }
712
+ .demo-svg .lp-outer-2 .lp-chip { animation: lp-chip-show 8s ease-in-out infinite; }
713
+
714
+ @keyframes lp-plate-cond {
715
+ 0%, 12%, 92%, 100% { fill: var(--coal-2); filter: none; opacity: 1; }
716
+ 18%, 86% { fill: var(--coal-1); filter: grayscale(85%) brightness(0.7); opacity: 0.55; }
717
+ }
718
+ @keyframes lp-frame-cond {
719
+ 0%, 12%, 92%, 100% { stroke: #6b5026; }
720
+ 18%, 86% { stroke: #3a2f1c; }
721
+ }
722
+ @keyframes lp-icon-cond {
723
+ 0%, 12%, 92%, 100% { stroke: var(--type-color); opacity: 0.9; }
724
+ 18%, 86% { stroke: var(--bone-4); opacity: 0.5; }
725
+ }
726
+ @keyframes lp-aura-cond {
727
+ 0%, 12%, 92%, 100% { opacity: 0; }
728
+ 18%, 86% { opacity: 0.7; stroke: var(--amber); stroke-width: 1; fill: none; stroke-dasharray: 3 4; }
729
+ }
730
+ @keyframes lp-stud-cond {
731
+ 0%, 12%, 92%, 100% { fill: #8a6a32; }
732
+ 18%, 86% { fill: #3a2f1c; }
733
+ }
734
+ @keyframes lp-name-cond {
735
+ 0%, 12%, 92%, 100% { fill: var(--bone-1); }
736
+ 18%, 86% { fill: var(--bone-3); }
737
+ }
738
+ @keyframes lp-chip-show {
739
+ 0%, 14%, 92%, 100% { opacity: 0; }
740
+ 22%, 86% { opacity: 1; }
741
+ }
742
+
743
+ /* Edges: glow during the selected window */
744
+ .demo-svg .lp-edge-breaks { animation: lp-edge-breaks-anim 8s ease-in-out infinite; }
745
+ .demo-svg .lp-edge-requires { animation: lp-edge-requires-anim 8s ease-in-out infinite; }
746
+ .demo-svg .lp-edge-requires-2 { animation: lp-edge-requires-anim 8s ease-in-out infinite; }
747
+ .demo-svg .lp-edge-compatible,
748
+ .demo-svg .lp-edge-compatible-2 { animation: lp-edge-compat-anim 8s ease-in-out infinite; }
749
+
750
+ @keyframes lp-edge-breaks-anim {
751
+ 0%, 12%, 92%, 100% { stroke: rgba(200,64,60,0.4); stroke-width: 1.4; filter: none; }
752
+ 18%, 86% { stroke: var(--rust); stroke-width: 2.4; filter: drop-shadow(0 0 7px rgba(200,64,60,1)); }
753
+ }
754
+ @keyframes lp-edge-requires-anim {
755
+ 0%, 12%, 92%, 100% { stroke: rgba(255,160,60,0.35); stroke-width: 1.4; filter: none; }
756
+ 18%, 86% { stroke: var(--ember-2); stroke-width: 2.2; filter: drop-shadow(0 0 6px var(--ember-glow)); }
757
+ }
758
+ @keyframes lp-edge-compat-anim {
759
+ 0%, 12%, 92%, 100% { stroke: rgba(212,164,68,0.20); stroke-width: 1.0; }
760
+ 18%, 86% { stroke: rgba(255,191,90,0.65); stroke-width: 1.6; filter: drop-shadow(0 0 4px rgba(255,138,61,0.4)); }
761
+ }
762
+
763
+ /* ── Responsive ──────────────────────────────────────────────────────── */
764
+ @media (max-width: 920px) {
765
+ .lp-shell { padding: 0 22px; }
766
+ .lp-hero { grid-template-columns: 1fr; gap: 30px; padding: 60px 0 70px; }
767
+ .lp-hero-art { min-height: 320px; }
768
+ .lp-title { font-size: 60px; }
769
+ .lp-section-title { font-size: 32px; }
770
+ .lp-tablets { grid-template-columns: 1fr; }
771
+ .lp-step { grid-template-columns: 1fr; gap: 20px; }
772
+ .lp-step:nth-child(even) .lp-step-text { order: 1; }
773
+ .lp-step:nth-child(even) .lp-step-art { order: 2; }
774
+ .lp-tiers { grid-template-columns: 1fr; }
775
+ .lp-scraper { grid-template-columns: 1fr; }
776
+ .lp-finale-title { font-size: 42px; }
777
+ }
frontend/landing.html ADDED
@@ -0,0 +1,629 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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">
6
+ <title>Forge β€” compatibility graph for ML training</title>
7
+ <meta name="description" content="Assemble a training recipe from real practitioner evidence. Watch incompatible tools dim. Forge what works.">
8
+
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600;700&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Geist:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
12
+
13
+ <link rel="stylesheet" href="styles.css">
14
+ <link rel="stylesheet" href="landing.css">
15
+
16
+ <style>
17
+ /* Override styles.css app-shell lock so the landing scrolls naturally */
18
+ html, body { height: auto !important; overflow: auto !important; }
19
+ html { scroll-behavior: smooth; }
20
+
21
+ /* More intense ember rain β€” bigger sparks, more of them, brighter trails */
22
+ .sparks { z-index: 0; }
23
+ .sparks span {
24
+ width: 3px; height: 3px;
25
+ background: var(--ember-2);
26
+ box-shadow:
27
+ 0 0 8px var(--ember-1),
28
+ 0 0 18px rgba(255, 106, 31, 0.55),
29
+ 0 0 2px #fff5e8;
30
+ opacity: 0;
31
+ }
32
+ .sparks span.big {
33
+ width: 4px; height: 4px;
34
+ box-shadow:
35
+ 0 0 12px var(--ember-1),
36
+ 0 0 28px var(--ember-2),
37
+ 0 0 3px #fff5e8;
38
+ }
39
+ .sparks span.trail {
40
+ width: 2px; height: 14px;
41
+ border-radius: 2px;
42
+ background: linear-gradient(180deg, transparent 0%, var(--ember-2) 60%, var(--ember-1) 100%);
43
+ box-shadow: 0 0 6px var(--ember-1);
44
+ }
45
+ @keyframes spark-fall {
46
+ 0% { transform: translateY(-8vh) translateX(0); opacity: 0; }
47
+ 8% { opacity: 0.9; }
48
+ 50% { transform: translateY(50vh) translateX(var(--drift, 0px)); opacity: 0.9; }
49
+ 100% { transform: translateY(110vh) translateX(calc(var(--drift, 0px) * 2)); opacity: 0; }
50
+ }
51
+ </style>
52
+ </head>
53
+ <body>
54
+ <div class="sparks">
55
+ <span style="left: 4%; animation-duration: 14s; animation-delay: -2s; --drift: -18px;"></span>
56
+ <span class="big" style="left: 9%; animation-duration: 18s; animation-delay: -10s; --drift: 8px;"></span>
57
+ <span style="left: 14%; animation-duration: 11s; animation-delay: -6s; --drift: -12px;"></span>
58
+ <span class="trail" style="left: 18%; animation-duration: 9s; animation-delay: -3s; --drift: 4px;"></span>
59
+ <span style="left: 23%; animation-duration: 16s; animation-delay: -14s; --drift: -20px;"></span>
60
+ <span class="big" style="left: 28%; animation-duration: 13s; animation-delay: -7s; --drift: 14px;"></span>
61
+ <span style="left: 33%; animation-duration: 19s; animation-delay: -1s; --drift: -8px;"></span>
62
+ <span class="trail" style="left: 38%; animation-duration: 8s; animation-delay: -5s; --drift: -10px;"></span>
63
+ <span style="left: 42%; animation-duration: 15s; animation-delay: -11s; --drift: 22px;"></span>
64
+ <span class="big" style="left: 47%; animation-duration: 12s; animation-delay: -8s; --drift: -6px;"></span>
65
+ <span style="left: 52%; animation-duration: 17s; animation-delay: -13s; --drift: 12px;"></span>
66
+ <span class="trail" style="left: 56%; animation-duration: 10s; animation-delay: -4s; --drift: -18px;"></span>
67
+ <span style="left: 60%; animation-duration: 14s; animation-delay: -9s; --drift: 6px;"></span>
68
+ <span class="big" style="left: 65%; animation-duration: 16s; animation-delay: -2s; --drift: -14px;"></span>
69
+ <span style="left: 70%; animation-duration: 11s; animation-delay: -12s; --drift: 18px;"></span>
70
+ <span class="trail" style="left: 75%; animation-duration: 9s; animation-delay: -6s; --drift: -10px;"></span>
71
+ <span style="left: 79%; animation-duration: 18s; animation-delay: -15s; --drift: 8px;"></span>
72
+ <span class="big" style="left: 83%; animation-duration: 13s; animation-delay: -3s; --drift: -22px;"></span>
73
+ <span style="left: 87%; animation-duration: 15s; animation-delay: -8s; --drift: 14px;"></span>
74
+ <span class="trail" style="left: 91%; animation-duration: 10s; animation-delay: -1s; --drift: -4px;"></span>
75
+ <span style="left: 95%; animation-duration: 17s; animation-delay: -11s; --drift: 16px;"></span>
76
+ <span class="big" style="left: 98%; animation-duration: 12s; animation-delay: -7s; --drift: -12px;"></span>
77
+ </div>
78
+
79
+ <div class="lp">
80
+
81
+ <!-- ── Sticky nav ──────────────────────────────────────────────────── -->
82
+ <nav class="lp-nav">
83
+ <div class="lp-nav-inner">
84
+ <div class="brand">
85
+ <div class="mark">
86
+ <svg width="20" height="20" viewBox="0 0 32 32" fill="none">
87
+ <path d="M5 14 h17 l3 -3 h4 v4 h-3 l-2 2 h-3 v4 h2 v3 h-13 v-3 h2 v-4 h-7 z" fill="#c4934e" stroke="#2a1a08" stroke-width="0.7" stroke-linejoin="round"/>
88
+ <rect x="10" y="25" width="13" height="2" fill="#2a1a08"/>
89
+ <circle cx="17" cy="15" r="1.2" fill="#ffba5e"/>
90
+ </svg>
91
+ </div>
92
+ <div class="name">FORGE</div>
93
+ </div>
94
+ <div class="links">
95
+ <a href="#what">What</a>
96
+ <a href="#how">How</a>
97
+ <a href="#tiers">Tiers</a>
98
+ <a href="#scraper">Scraper</a>
99
+ </div>
100
+ <a class="cta-mini" href="index.html">Enter the Forge β†’</a>
101
+ </div>
102
+ </nav>
103
+
104
+ <!-- ── Hero ────────────────────────────────────────────────────────── -->
105
+ <section class="lp-hero lp-shell">
106
+ <div class="lp-hero-text">
107
+ <div class="lp-eyebrow">a bright data hackathon submission Β· 2026</div>
108
+ <h1 class="lp-title">Forge a<br/><em>training recipe</em><br/>that actually runs.</h1>
109
+ <p class="lp-subtitle">
110
+ A live <strong>compatibility graph</strong> for ML training components.
111
+ Pick your optimizer, scheduler, quantization, technique. Incompatible tools
112
+ <strong>grey out instantly</strong> with cited evidence from real practitioner runs.
113
+ Greyed means <em>not&nbsp;yet&nbsp;satisfied</em>, not forbidden β€” add the missing
114
+ ingredient and watch it re-light.
115
+ </p>
116
+ <div class="lp-cta-row">
117
+ <a href="index.html" class="lp-cta-primary">
118
+ Enter the Forge
119
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round">
120
+ <path d="M5 12h14M13 6l6 6-6 6"/>
121
+ </svg>
122
+ </a>
123
+ <a href="#what" class="lp-cta-secondary">Read first</a>
124
+ </div>
125
+ </div>
126
+
127
+ <!-- Mini demo: 5 nodes, looped state animation -->
128
+ <div class="lp-hero-art">
129
+ <svg class="demo-svg" viewBox="0 0 460 460">
130
+ <defs>
131
+ <radialGradient id="lp-molten" cx="50%" cy="55%" r="65%">
132
+ <stop offset="0%" stop-color="#5a1f0a"/>
133
+ <stop offset="35%" stop-color="#3a1408"/>
134
+ <stop offset="70%" stop-color="#1a0807"/>
135
+ <stop offset="100%" stop-color="#0a0303"/>
136
+ </radialGradient>
137
+ <filter id="lp-ember" x="-50%" y="-50%" width="200%" height="200%">
138
+ <feGaussianBlur stdDeviation="2.4" result="b"/>
139
+ <feFlood flood-color="#ff6a1f" flood-opacity="0.55"/>
140
+ <feComposite in2="b" operator="in"/>
141
+ <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
142
+ </filter>
143
+ <radialGradient id="lp-brass-t1" cx="40%" cy="35%" r="75%">
144
+ <stop offset="0%" stop-color="#ffd09a"/>
145
+ <stop offset="45%" stop-color="#ff8a3d"/>
146
+ <stop offset="100%" stop-color="#6a2a08"/>
147
+ </radialGradient>
148
+ <radialGradient id="lp-brass-t2" cx="40%" cy="35%" r="75%">
149
+ <stop offset="0%" stop-color="#b8d4f0"/>
150
+ <stop offset="45%" stop-color="#5b9bd8"/>
151
+ <stop offset="100%" stop-color="#1c3a5a"/>
152
+ </radialGradient>
153
+ <radialGradient id="lp-brass-t3" cx="40%" cy="35%" r="75%">
154
+ <stop offset="0%" stop-color="#cac4b6"/>
155
+ <stop offset="45%" stop-color="#9a9285"/>
156
+ <stop offset="100%" stop-color="#3a3528"/>
157
+ </radialGradient>
158
+ </defs>
159
+
160
+ <!-- Curved edges (drawn first, behind nodes) -->
161
+ <g class="lp-edges">
162
+ <path class="lp-edge lp-edge-breaks" d="M 230 230 Q 270 100 320 90"/>
163
+ <path class="lp-edge lp-edge-requires" d="M 230 230 Q 350 220 380 250"/>
164
+ <path class="lp-edge lp-edge-compatible" d="M 230 230 Q 260 360 320 380"/>
165
+ <path class="lp-edge lp-edge-requires-2" d="M 230 230 Q 120 280 80 270"/>
166
+ <path class="lp-edge lp-edge-compatible-2" d="M 230 230 Q 110 130 130 90"/>
167
+ </g>
168
+
169
+ <!-- Center node β€” the "ingredient on the anvil" / selected -->
170
+ <g class="lp-node lp-center" transform="translate(230, 230)">
171
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
172
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
173
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
174
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
175
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
176
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
177
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
178
+ </g>
179
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
180
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
181
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
182
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
183
+ <g class="lp-seal" transform="translate(22, -22)">
184
+ <circle r="8.5" fill="url(#lp-brass-t1)" stroke="#1a1208"/>
185
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#1a1208">T1</text>
186
+ </g>
187
+ <path class="lp-ribbon" d="M -33 33 L -38 47 L -28 44 L -22 48 L -16 44 L -10 48 L -4 44 L 2 48 L 8 44 L 14 48 L 20 44 L 26 48 L 34 47 L 33 33 Z"/>
188
+ <text class="lp-name" y="44.5" text-anchor="middle">QLoRA</text>
189
+ </g>
190
+
191
+ <!-- Outer nodes -->
192
+ <g class="lp-node lp-outer-1" transform="translate(345, 90)"> <!-- BLOCKED (Full Fine-Tune) -->
193
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
194
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
195
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
196
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
197
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
198
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
199
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
200
+ </g>
201
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
202
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
203
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
204
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
205
+ <g class="lp-seal" transform="translate(22, -22)">
206
+ <circle r="8.5" fill="url(#lp-brass-t1)" stroke="#1a1208"/>
207
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#1a1208">T1</text>
208
+ </g>
209
+ <g class="lp-lock">
210
+ <path d="M -5 -2 v -4 a 5 5 0 0 1 10 0 v 4" fill="none" stroke="#cfc8b8" stroke-width="1.1" stroke-linecap="round"/>
211
+ <rect x="-7" y="-2" width="14" height="11" rx="1.5" fill="#8a2520" stroke="#cfc8b8" stroke-width="0.6"/>
212
+ <circle cx="0" cy="2" r="1.4" fill="#07090c"/>
213
+ </g>
214
+ <text class="lp-name" y="48" text-anchor="middle">Full FT</text>
215
+ </g>
216
+
217
+ <g class="lp-node lp-outer-2" transform="translate(385, 270)"> <!-- NEEDED β€” conditional (bnb 4-bit) -->
218
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
219
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
220
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
221
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
222
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
223
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
224
+ <rect x="4" y="13" width="3" height="7" rx="0.5"/><rect x="10.5" y="9" width="3" height="11" rx="0.5"/><rect x="17" y="5" width="3" height="15" rx="0.5"/>
225
+ </g>
226
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
227
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
228
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
229
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
230
+ <g class="lp-seal" transform="translate(22, -22)">
231
+ <circle r="8.5" fill="url(#lp-brass-t1)" stroke="#1a1208"/>
232
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#1a1208">T1</text>
233
+ </g>
234
+ <text class="lp-name" y="48" text-anchor="middle">bnb 4-bit</text>
235
+ <g class="lp-chip" transform="translate(0, 58)">
236
+ <rect x="-32" y="-7" width="64" height="14" fill="rgba(40,26,8,0.95)" stroke="#e0a13c" stroke-width="0.7"/>
237
+ <text y="2.5" text-anchor="middle" font-family="JetBrains Mono" font-size="7" fill="#e0a13c" letter-spacing="0.12em">needs Β· add</text>
238
+ </g>
239
+ </g>
240
+
241
+ <g class="lp-node lp-outer-3" transform="translate(330, 380)"> <!-- AVAILABLE β€” LoRA -->
242
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
243
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
244
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
245
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
246
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
247
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
248
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
249
+ </g>
250
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
251
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
252
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
253
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
254
+ <g class="lp-seal" transform="translate(22, -22)">
255
+ <circle r="8.5" fill="url(#lp-brass-t1)" stroke="#1a1208"/>
256
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#1a1208">T1</text>
257
+ </g>
258
+ <text class="lp-name" y="48" text-anchor="middle">LoRA</text>
259
+ </g>
260
+
261
+ <g class="lp-node lp-outer-4" transform="translate(70, 270)"> <!-- AVAILABLE β€” Llama-3 -->
262
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
263
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
264
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
265
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
266
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
267
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
268
+ <path d="M3 7l9-4 9 4"/><path d="M5 7v12M19 7v12M12 7v12"/><path d="M3 21h18"/>
269
+ </g>
270
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
271
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
272
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
273
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
274
+ <g class="lp-seal" transform="translate(22, -22)">
275
+ <circle r="8.5" fill="url(#lp-brass-t1)" stroke="#1a1208"/>
276
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#1a1208">T1</text>
277
+ </g>
278
+ <text class="lp-name" y="48" text-anchor="middle">Llama-3</text>
279
+ </g>
280
+
281
+ <g class="lp-node lp-outer-5" transform="translate(110, 90)"> <!-- AVAILABLE β€” Grad Ckpt -->
282
+ <polygon class="lp-aura" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3" transform="scale(1.3)"/>
283
+ <polygon class="lp-frame-outer" points="-13.3,-32 13.3,-32 32,-13.3 32,13.3 13.3,32 -13.3,32 -32,13.3 -32,-13.3"/>
284
+ <polygon class="lp-plate" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
285
+ <ellipse class="lp-gem" cx="0" cy="-2" rx="14" ry="11"/>
286
+ <polygon class="lp-frame" points="-11.2,-27 11.2,-27 27,-11.2 27,11.2 11.2,27 -11.2,27 -27,11.2 -27,-11.2"/>
287
+ <g class="lp-icon" stroke="#fff5e8" fill="none" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" transform="translate(-12,-14)">
288
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
289
+ </g>
290
+ <circle class="lp-stud" cx="-22.6" cy="-22.6" r="1.8"/>
291
+ <circle class="lp-stud" cx="22.6" cy="-22.6" r="1.8"/>
292
+ <circle class="lp-stud" cx="22.6" cy="22.6" r="1.8"/>
293
+ <circle class="lp-stud" cx="-22.6" cy="22.6" r="1.8"/>
294
+ <g class="lp-seal" transform="translate(22, -22)">
295
+ <circle r="8.5" fill="url(#lp-brass-t2)" stroke="#1a1208"/>
296
+ <text y="2.5" text-anchor="middle" font-family="Cinzel" font-size="8" font-weight="700" fill="#fff">T2</text>
297
+ </g>
298
+ <text class="lp-name" y="48" text-anchor="middle">Grad Ckpt</text>
299
+ </g>
300
+ </svg>
301
+ </div>
302
+ </section>
303
+
304
+ <!-- ── What ───────────────────────────────────────────────────────── -->
305
+ <section class="lp-section" id="what">
306
+ <div class="lp-shell">
307
+ <div class="lp-section-head">
308
+ <div class="lp-section-eyebrow">what it does</div>
309
+ <h2 class="lp-section-title">A loadout-builder for ML training.</h2>
310
+ <p class="lp-section-sub">
311
+ Pick optimizers, schedulers, quantization, techniques. The graph re-resolves
312
+ live and tells you what fits, what's missing, and what blows up β€” every fact
313
+ backed by a citation.
314
+ </p>
315
+ </div>
316
+
317
+ <div class="lp-tablets">
318
+ <div class="lp-tablet">
319
+ <div class="lp-tablet-num">I</div>
320
+ <div class="lp-tablet-icon">
321
+ <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
322
+ <circle cx="12" cy="12" r="3"/>
323
+ <path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/>
324
+ </svg>
325
+ </div>
326
+ <h3>Compatibility-aware</h3>
327
+ <p>Pick a component and every other one re-styles by status: <em>available</em>, <em>conditional</em>, or <em>blocked</em>. Greyed means not&nbsp;yet&nbsp;satisfied β€” add the missing ingredient and it re-lights in real time.</p>
328
+ </div>
329
+
330
+ <div class="lp-tablet">
331
+ <div class="lp-tablet-num">II</div>
332
+ <div class="lp-tablet-icon">
333
+ <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
334
+ <path d="M4 19V5a2 2 0 0 1 2-2h11l3 3v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/>
335
+ <path d="M8 8h7M8 12h7M8 16h5"/>
336
+ </svg>
337
+ </div>
338
+ <h3>Evidence-backed</h3>
339
+ <p>Every grey-out, every fix, every conflict carries its <em>cited source</em> β€” verbatim quote, URL, and tier badge. Hover anything to see where the claim comes from.</p>
340
+ </div>
341
+
342
+ <div class="lp-tablet">
343
+ <div class="lp-tablet-num">III</div>
344
+ <div class="lp-tablet-icon">
345
+ <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
346
+ <path d="M3 12h4l3 8 4-16 3 8h4"/>
347
+ </svg>
348
+ </div>
349
+ <h3>Benchmark-backed</h3>
350
+ <p>Scheduler picks aren't picked from a paper β€” they're picked from <em>real measured val_loss / val_acc</em> on distilbert / sst2, three seeds each. DLRS leads. OneCycle is flagged above cohort cutoff.</p>
351
+ </div>
352
+ </div>
353
+ </div>
354
+ </section>
355
+
356
+ <!-- ── How to use ─────────────────────────────────────────────────── -->
357
+ <section class="lp-section" id="how">
358
+ <div class="lp-shell">
359
+ <div class="lp-section-head">
360
+ <div class="lp-section-eyebrow">how to use it</div>
361
+ <h2 class="lp-section-title">Three strikes on the anvil.</h2>
362
+ <p class="lp-section-sub">
363
+ Sixty seconds, three motions. The demo path the team built it around.
364
+ </p>
365
+ </div>
366
+
367
+ <div class="lp-steps">
368
+
369
+ <div class="lp-step">
370
+ <div class="lp-step-text">
371
+ <span class="lp-step-num">Step One</span>
372
+ <h3>Pick from the inventory.</h3>
373
+ <p>
374
+ The left rail is your loadout. Tap any optimizer, scheduler, technique,
375
+ quantization, architecture, or inference engine. The instant you equip one,
376
+ the graph re-runs <code style="font-family: var(--f-mono); font-size: 0.92em; color: var(--brass-1);">POST /resolve</code> and re-styles every other node by status.
377
+ </p>
378
+ <div class="quote">
379
+ "Pick <strong style="color: var(--brass-1);">QLoRA</strong>. Full Fine-Tune slams to <strong style="color: var(--rust);">blocked</strong>.
380
+ bnb 4-bit shimmers <strong style="color: var(--amber);">conditional</strong> β€” &lsquo;needed by QLoRA&rsquo;."
381
+ </div>
382
+ </div>
383
+ <div class="lp-step-art">
384
+ <!-- Illustration: inventory card sample -->
385
+ <div style="width: 100%; max-width: 320px;">
386
+ <div class="inv-row tier-1 selected" style="--type-color: var(--t-technique);">
387
+ <div class="type-ic">
388
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
389
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
390
+ </svg>
391
+ </div>
392
+ <div>
393
+ <div class="inv-name">QLoRA</div>
394
+ <div class="inv-meta"><span style="color: var(--ember-2);">equipped</span></div>
395
+ </div>
396
+ <div class="tier-pip t1">T1</div>
397
+ </div>
398
+ <div class="inv-row tier-1 blocked" style="margin-top: 6px; --type-color: var(--t-technique);">
399
+ <div class="type-ic">
400
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
401
+ <path d="M12 3l9 16H3z"/><path d="M12 9l4 7H8z"/>
402
+ </svg>
403
+ </div>
404
+ <div>
405
+ <div class="inv-name">Full Fine-Tune</div>
406
+ <div class="inv-meta"><span style="color: var(--rust);">blocked Β· breaks with QLoRA</span></div>
407
+ </div>
408
+ <div class="tier-pip t1">T1</div>
409
+ </div>
410
+ <div class="inv-row tier-1 dim" style="margin-top: 6px; --type-color: var(--t-quantization);">
411
+ <div class="type-ic">
412
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
413
+ <rect x="4" y="13" width="3" height="7" rx="0.5"/>
414
+ <rect x="10.5" y="9" width="3" height="11" rx="0.5"/>
415
+ <rect x="17" y="5" width="3" height="15" rx="0.5"/>
416
+ </svg>
417
+ </div>
418
+ <div>
419
+ <div class="inv-name">bnb 4-bit</div>
420
+ <div class="inv-meta"><span style="color: var(--amber);">needed by QLoRA</span></div>
421
+ </div>
422
+ <div class="tier-pip t1">T1</div>
423
+ </div>
424
+ </div>
425
+ </div>
426
+ </div>
427
+
428
+ <div class="lp-step">
429
+ <div class="lp-step-text">
430
+ <span class="lp-step-num">Step Two</span>
431
+ <h3>Read the recipe.</h3>
432
+ <p>
433
+ The right rail is your crafting window. Conflicts are scored in
434
+ <strong style="color: var(--rust);">rust</strong>. Unmet requirements glow
435
+ <strong style="color: var(--amber);">amber</strong> with a one-tap
436
+ <em>+ add bnb 4-bit</em> button. Benchmark-backed scheduler picks list themselves
437
+ by measured val_loss with the leader marked with a star.
438
+ </p>
439
+ <div class="quote">
440
+ Every entry shows the <strong style="color: var(--brass-1);">tier badge</strong>
441
+ and a source link β€” so the credibility chain stays visible all the way through.
442
+ </div>
443
+ </div>
444
+ <div class="lp-step-art">
445
+ <div style="width: 100%; max-width: 360px;">
446
+ <div class="entry conflict" style="margin-bottom: 8px;">
447
+ <div class="title conflict">QLoRA <span style="color: var(--bone-4);">↔</span> Full Fine-Tune</div>
448
+ <div class="fix">QLoRA freezes the base model; Full Fine-Tune updates it. Pick one.</div>
449
+ <div class="meta">
450
+ <span class="tier-badge t1">T1</span>
451
+ <span style="color: var(--bone-4);">arxiv.org/abs/2305.14314</span>
452
+ </div>
453
+ </div>
454
+ <div class="entry unmet">
455
+ <div class="title unmet">QLoRA needs <strong style="color: #fff5e8;">bnb 4-bit</strong></div>
456
+ <div class="fix">QLoRA is defined as 4-bit NF4 base + LoRA adapters β€” load the base in bnb 4-bit.</div>
457
+ <button class="add-btn" type="button">
458
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 5v14M5 12h14"/></svg>
459
+ add bnb 4-bit
460
+ </button>
461
+ </div>
462
+ </div>
463
+ </div>
464
+ </div>
465
+
466
+ <div class="lp-step">
467
+ <div class="lp-step-text">
468
+ <span class="lp-step-num">Step Three</span>
469
+ <h3>Inspect the evidence.</h3>
470
+ <p>
471
+ Hover any node, edge, or recipe entry to surface the <em>verbatim quote</em> from
472
+ its source and the tier badge it earned. T1 is Rick's own verified runs
473
+ (immutable). T2 is community-corroborated. T3 is single-source β€” lives in
474
+ the review queue until something else agrees.
475
+ </p>
476
+ <div class="quote">
477
+ The point of the tooltip is the source URL. The point of the graph is the
478
+ decision. The point of the tier is so you know how much to trust both.
479
+ </div>
480
+ </div>
481
+ <div class="lp-step-art">
482
+ <div style="width: 100%; max-width: 320px;">
483
+ <div class="evidence-tip" style="position: static; box-shadow: 0 14px 30px rgba(0,0,0,0.6);">
484
+ <div class="tip-head">
485
+ <span class="tip-name">AdamW 8-bit</span>
486
+ <span class="tip-status blocked">blocked</span>
487
+ </div>
488
+ <div class="tip-reason">
489
+ <div class="tip-reason-label" style="color: var(--rust);">breaks with Per-Layer LR Rotation</div>
490
+ <div class="tip-reason-fix">Pass custom <code style="font-family: var(--f-mono);">optimizer_grouped_parameters</code> β€” adamw_8bit's default decay/no-decay split silently no-ops per-layer LR.</div>
491
+ <div class="quote">"adamw_8bit produces decay/no-decay param groups by default; per-layer LR rotation silently no-ops unless you pass them yourself."</div>
492
+ <div class="tip-foot">
493
+ <span class="src-link">mempalace Β· rick</span>
494
+ <span class="tier-badge t1">T1</span>
495
+ </div>
496
+ </div>
497
+ </div>
498
+ </div>
499
+ </div>
500
+ </div>
501
+
502
+ </div>
503
+ </div>
504
+ </section>
505
+
506
+ <!-- ── Tiers ──────────────────────────────────────────────────────── -->
507
+ <section class="lp-section" id="tiers">
508
+ <div class="lp-shell">
509
+ <div class="lp-section-head">
510
+ <div class="lp-section-eyebrow">trust model</div>
511
+ <h2 class="lp-section-title">Every claim earns its tier.</h2>
512
+ <p class="lp-section-sub">
513
+ We don't assert nonsense as fact. Three tiers, three colors, three weights.
514
+ The scraper feeds the bottom; corroboration promotes upward.
515
+ </p>
516
+ </div>
517
+
518
+ <div class="lp-tiers">
519
+ <div class="lp-tier lp-tier-1">
520
+ <div class="lp-tier-coin">T1</div>
521
+ <div class="lp-tier-label">Legendary Β· 1.0</div>
522
+ <h4>Verified runs</h4>
523
+ <p>Rick's own research notes and reproduced runs. <em>Immutable</em> β€” the scraper can never overwrite these, only add corroboration.</p>
524
+ <div class="example">e.g. <span style="color: var(--bone-2);">Per-Layer LR Rotation Γ— AdamW 8-bit</span> Β· mempalace://chaos-injection-trainer-notes</div>
525
+ </div>
526
+
527
+ <div class="lp-tier lp-tier-2">
528
+ <div class="lp-tier-coin">T2</div>
529
+ <div class="lp-tier-label">Rare Β· 0.8</div>
530
+ <h4>Community-confirmed</h4>
531
+ <p>Official docs, or two-plus independent sources agree. The bulk of the workable graph.</p>
532
+ <div class="example">e.g. <span style="color: var(--bone-2);">Muon β†’ AdamW 8-bit</span> Β· kellerjordan.github.io/posts/muon</div>
533
+ </div>
534
+
535
+ <div class="lp-tier lp-tier-3">
536
+ <div class="lp-tier-coin">T3</div>
537
+ <div class="lp-tier-label">Common Β· 0.5</div>
538
+ <h4>Single-source</h4>
539
+ <p>One scraped report, no corroboration yet. Lives in the review queue. Promotes when something else agrees, or when Rick signs off.</p>
540
+ <div class="example">e.g. <span style="color: var(--bone-2);">Lion Γ— bnb 8-bit divergence</span> Β· github.com/bitsandbytes issue</div>
541
+ </div>
542
+ </div>
543
+ </div>
544
+ </section>
545
+
546
+ <!-- ── Scraper ─────────────────────────────────────────────────────── -->
547
+ <section class="lp-section" id="scraper">
548
+ <div class="lp-shell">
549
+ <div class="lp-section-head">
550
+ <div class="lp-section-eyebrow">the live data layer</div>
551
+ <h2 class="lp-section-title">The graph grows itself.</h2>
552
+ <p class="lp-section-sub">
553
+ A Bright Data scraper hunts SERP results in English <em>and</em> Chinese,
554
+ extracts (A, relation, B, conditions, fix, quote) tuples with Haiku, resolves
555
+ them against canonical node aliases, and proposes them to the review queue.
556
+ </p>
557
+ </div>
558
+
559
+ <div class="lp-scraper">
560
+ <div>
561
+ <p>
562
+ Watch the <strong style="color: var(--brass-1); font-style: normal;">Live Discoveries</strong>
563
+ hearth at the bottom of the Forge while you work β€” new edges literally rise
564
+ out of it as the scraper corroborates them. The graph is alive.
565
+ </p>
566
+ <p>
567
+ English-only sources miss large chunks of the Chinese ML ecosystem. We
568
+ cover both. The scraper writes nothing to T1 β€” that's Rick's territory.
569
+ Single-source claims sit at T3 in the queue and only ascend with evidence.
570
+ </p>
571
+ </div>
572
+
573
+ <div class="lp-pipeline">
574
+ <div class="lp-pipeline-step">
575
+ <span>SERPΒ·en/zh</span>
576
+ <span class="arrow">β†’</span>
577
+ <span class="src">arxiv Β· github</span>
578
+ </div>
579
+ <div class="lp-pipeline-step">
580
+ <span>scrape_as_markdown</span>
581
+ <span class="arrow">β†’</span>
582
+ <span class="src">bright data</span>
583
+ </div>
584
+ <div class="lp-pipeline-step">
585
+ <span>extract tuple</span>
586
+ <span class="arrow">β†’</span>
587
+ <span class="src">haiku</span>
588
+ </div>
589
+ <div class="lp-pipeline-step">
590
+ <span>entity-resolve</span>
591
+ <span class="arrow">β†’</span>
592
+ <span class="src">canonical aliases</span>
593
+ </div>
594
+ <div class="lp-pipeline-step">
595
+ <span>review_queue</span>
596
+ <span class="arrow">β†’</span>
597
+ <span class="tier t3">T3</span>
598
+ </div>
599
+ <div class="lp-pipeline-step">
600
+ <span>corroborate</span>
601
+ <span class="arrow">β†’</span>
602
+ <span class="tier t2">T2</span>
603
+ </div>
604
+ </div>
605
+ </div>
606
+ </div>
607
+ </section>
608
+
609
+ <!-- ── Finale CTA ──────────────────────────────────────────────────── -->
610
+ <section class="lp-finale">
611
+ <h2 class="lp-finale-title">Light the forge.</h2>
612
+ <p class="lp-finale-sub">Ninety seconds. Ten components. One recipe that actually compiles.</p>
613
+ <a href="index.html" class="lp-cta-primary">
614
+ Enter the Forge
615
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round">
616
+ <path d="M5 12h14M13 6l6 6-6 6"/>
617
+ </svg>
618
+ </a>
619
+ </section>
620
+
621
+ <footer class="lp-foot lp-shell">
622
+ bright data Β· "web data unlocked" Β· 2026
623
+ &nbsp;Β·&nbsp;
624
+ <a href="index.html">launch app</a>
625
+ </footer>
626
+
627
+ </div>
628
+ </body>
629
+ </html>