-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathecosystem.html
More file actions
455 lines (439 loc) · 42.7 KB
/
Copy pathecosystem.html
File metadata and controls
455 lines (439 loc) · 42.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
<!DOCTYPE html>
<html lang="en">
<head>
<!-- TikTok Pixel Code Start -->
<script>
!function (w, d, t) {
w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(
var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js",o=n&&n.partner;ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=r,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};n=document.createElement("script")
;n.type="text/javascript",n.async=!0,n.src=r+"?sdkid="+e+"&lib="+t;e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(n,e)};
ttq.load('DABS2BBC77U98E0UJH30');
ttq.page();
}(window, document, 'ttq');
</script>
<!-- TikTok Pixel Code End -->
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-K4TKPMG9');</script>
<!-- End Google Tag Manager -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>What Is The First Spark? — The Ecosystem, Explained</title>
<meta name="description" content="The First Spark reads the pattern in your birth name and date, then hands you tools, stories and a community built to work with it. Here is the whole world on one screen.">
<meta property="og:title" content="What Is The First Spark? — The Ecosystem, Explained">
<meta property="og:description" content="Every part of The First Spark on one screen, and how each part hands you to the next.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://thefirstspark.shop/ecosystem.html">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@OGplayerone">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Orbitron:wght@500;700;900&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--void:#050508; --spark:#fbbf24; --nebula:#8b5cf6; --cyan:#22d3ee; --hot-pink:#ec4899; --green:#34d399;
--white:#f5f5f7; --dim:rgba(255,255,255,.55); --dimmer:rgba(255,255,255,.28); --line:rgba(255,255,255,.08);
--l-code:var(--spark); --l-reading:var(--cyan); --l-tools:var(--nebula); --l-stories:var(--hot-pink); --l-world:var(--green); --l-studio:#e2e8f0;
}
html{scroll-behavior:smooth}
body{background:var(--void);color:var(--white);font-family:'Space Mono','Courier New',monospace;line-height:1.65;overflow-x:hidden;-webkit-font-smoothing:antialiased}
.orb{font-family:'Orbitron',sans-serif;letter-spacing:.14em;text-transform:uppercase}
a{color:inherit}
/* backdrop */
.aurora{position:fixed;inset:-20%;z-index:0;pointer-events:none;filter:blur(60px);opacity:.55;
background:radial-gradient(40% 35% at 20% 25%,rgba(139,92,246,.35),transparent 70%),radial-gradient(35% 30% at 80% 20%,rgba(34,211,238,.25),transparent 70%),radial-gradient(45% 35% at 60% 85%,rgba(236,72,153,.22),transparent 70%),radial-gradient(30% 30% at 30% 80%,rgba(251,191,36,.18),transparent 70%);
animation:drift 40s ease-in-out infinite alternate}
@keyframes drift{to{transform:translate(3%,-2%) rotate(3deg)}}
.stars{position:fixed;inset:0;z-index:0;pointer-events:none}
.stars i{position:absolute;width:2px;height:2px;background:#fff;border-radius:50%;animation:tw 3.5s infinite}
@keyframes tw{0%,100%{opacity:.12}50%{opacity:.75}}
.wrap{position:relative;z-index:1;max-width:1180px;margin:0 auto;padding:0 20px}
/* nav */
nav{display:flex;justify-content:space-between;align-items:center;padding:22px 0;gap:14px;flex-wrap:wrap}
nav .brand{font-size:.72rem;color:var(--spark);text-decoration:none;font-weight:700}
nav .links{display:flex;gap:18px;flex-wrap:wrap}
nav .links a{font-size:.6rem;color:var(--dim);text-decoration:none}
nav .links a:hover{color:var(--white)}
/* hero */
.hero{text-align:center;padding:56px 0 30px}
.kicker{font-size:.62rem;color:var(--cyan);margin-bottom:18px}
.hero h1{font-family:'Orbitron',sans-serif;font-weight:900;font-size:clamp(1.7rem,4.6vw,3.2rem);letter-spacing:.04em;line-height:1.15;text-transform:none}
.hero h1 em{font-style:normal;color:var(--spark);text-shadow:0 0 28px rgba(251,191,36,.45)}
.hero .one{max-width:720px;margin:22px auto 0;font-size:1.02rem;color:var(--white)}
.hero .not{max-width:640px;margin:14px auto 0;font-size:.82rem;color:var(--dim)}
/* section titles */
.sec{padding:54px 0 10px}
.sec-title{font-family:'Orbitron',sans-serif;font-weight:700;font-size:clamp(1.05rem,2.4vw,1.5rem);letter-spacing:.08em;text-transform:uppercase}
.sec-sub{color:var(--dim);font-size:.86rem;max-width:720px;margin-top:8px}
.sec-num{font-size:.6rem;color:var(--dimmer);letter-spacing:.3em;margin-bottom:8px}
/* path picker */
.paths{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin-top:22px}
.path{background:rgba(255,255,255,.03);border:1px solid var(--line);border-radius:12px;padding:14px 14px 12px;cursor:pointer;text-align:left;color:var(--white);font-family:inherit;transition:.25s;position:relative;overflow:hidden}
.path:hover{border-color:rgba(255,255,255,.25);transform:translateY(-2px)}
.path .pk{font-size:.55rem;color:var(--dimmer);letter-spacing:.28em}
.path .pq{font-size:.86rem;margin-top:6px;font-weight:700}
.path .pn{font-size:.7rem;color:var(--dim);margin-top:6px}
.path.on{border-color:var(--pc);box-shadow:0 0 0 1px var(--pc) inset,0 0 26px color-mix(in srgb,var(--pc) 35%,transparent)}
.path.on .pk{color:var(--pc)}
.path::after{content:"";position:absolute;inset:auto -30% -60% -30%;height:80%;background:radial-gradient(closest-side,color-mix(in srgb,var(--pc) 22%,transparent),transparent);opacity:0;transition:.4s}
.path.on::after{opacity:1}
.path-clear{margin-top:12px;font-size:.6rem;color:var(--dim);background:none;border:1px solid var(--line);border-radius:999px;padding:7px 14px;cursor:pointer;font-family:'Orbitron',sans-serif;letter-spacing:.16em;text-transform:uppercase}
.path-clear:hover{color:var(--white);border-color:rgba(255,255,255,.3)}
/* stage */
.stage-wrap{margin-top:26px;display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:26px;align-items:start}
#stage{position:relative;aspect-ratio:1/1;width:calc(100% - 56px);max-width:820px;margin:28px auto;border-radius:50%;overflow:visible;
background:radial-gradient(circle at 50% 50%,rgba(251,191,36,.10),transparent 18%),radial-gradient(circle,rgba(255,255,255,.02),transparent 70%)}
#stage .ring{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);border-radius:50%;border:1px dashed color-mix(in srgb,var(--rc) 28%,transparent);pointer-events:none}
#lines{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible}
#lines line{stroke-width:1.5;stroke-linecap:round;opacity:0;transition:opacity .5s}
#lines line.on{opacity:.9;stroke-dasharray:6 6;animation:flow 1.4s linear infinite}
@keyframes flow{to{stroke-dashoffset:-24}}
.node{position:absolute;transform:translate(-50%,-50%);width:60px;height:60px;border-radius:50%;border:1px solid color-mix(in srgb,var(--nc) 55%,transparent);
background:radial-gradient(circle at 35% 30%,rgba(255,255,255,.12),rgba(5,5,8,.9) 65%);color:var(--white);cursor:pointer;font-family:'Orbitron',sans-serif;font-weight:700;font-size:.44rem;letter-spacing:.1em;text-transform:uppercase;line-height:1.25;text-align:center;padding:4px;
box-shadow:0 0 18px color-mix(in srgb,var(--nc) 22%,transparent),inset 0 0 12px color-mix(in srgb,var(--nc) 12%,transparent);transition:.3s;z-index:2}
.node:hover{transform:translate(-50%,-50%) scale(1.08);border-color:var(--nc);box-shadow:0 0 30px color-mix(in srgb,var(--nc) 55%,transparent)}
.node .ico{display:block;font-size:1.05rem;line-height:1;margin-bottom:3px;filter:drop-shadow(0 0 8px var(--nc))}
.node.core{width:100px;height:100px;font-size:.55rem;border-color:var(--spark);background:radial-gradient(circle at 40% 35%,rgba(251,191,36,.35),rgba(5,5,8,.95) 70%);box-shadow:0 0 50px rgba(251,191,36,.35);animation:pulse 4s ease-in-out infinite}
@keyframes pulse{50%{box-shadow:0 0 70px rgba(251,191,36,.55)}}
.node.core .ico{font-size:1.5rem}
.node.dimmed{opacity:.18;filter:grayscale(.6)}
.node.lit{opacity:1;border-color:var(--nc);box-shadow:0 0 34px color-mix(in srgb,var(--nc) 65%,transparent)}
.node.lit .step{position:absolute;top:-8px;right:-8px;width:20px;height:20px;border-radius:50%;background:var(--nc);color:var(--void);font-size:.55rem;display:flex;align-items:center;justify-content:center;font-weight:900}
.node .step{display:none}
.node.lit .step{display:flex}
.node.sel{outline:2px solid var(--white);outline-offset:3px}
.node.soon{border-style:dashed}
/* panel */
#panel{background:rgba(10,10,18,.78);border:1px solid var(--line);border-radius:16px;padding:22px 22px 18px;backdrop-filter:blur(10px);position:sticky;top:18px;min-height:300px;--pc:var(--spark)}
#panel::before{content:"";position:absolute;inset:0;border-radius:16px;pointer-events:none;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--pc) 35%,transparent),0 0 40px color-mix(in srgb,var(--pc) 12%,transparent)}
#panel .ptag{font-size:.55rem;letter-spacing:.3em;color:var(--pc);font-family:'Orbitron',sans-serif;text-transform:uppercase}
#panel h3{font-family:'Orbitron',sans-serif;font-weight:700;font-size:1.05rem;letter-spacing:.06em;margin-top:8px;text-transform:none}
#panel .what{margin-top:12px;font-size:.9rem}
#panel .meta{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:14px}
#panel .meta div{background:rgba(255,255,255,.03);border:1px solid var(--line);border-radius:10px;padding:9px 11px;font-size:.74rem}
#panel .meta b{display:block;font-family:'Orbitron',sans-serif;font-weight:500;font-size:.5rem;letter-spacing:.26em;color:var(--dim);margin-bottom:4px;text-transform:uppercase}
#panel .hs{margin-top:14px;font-size:.76rem}
#panel .hs b{display:block;font-family:'Orbitron',sans-serif;font-weight:500;font-size:.5rem;letter-spacing:.26em;color:var(--dim);margin:12px 0 5px;text-transform:uppercase}
#panel .hs span{display:inline-block;background:rgba(255,255,255,.04);border:1px solid var(--line);border-radius:999px;padding:3px 10px;margin:2px 4px 2px 0;font-size:.68rem;cursor:pointer}
#panel .hs span:hover{border-color:var(--pc);color:var(--pc)}
#panel .go{display:inline-block;margin-top:18px;background:var(--spark);color:var(--void);text-decoration:none;font-family:'Orbitron',sans-serif;font-weight:700;font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;padding:11px 20px;border-radius:999px;box-shadow:0 0 22px rgba(251,191,36,.35)}
#panel .go:hover{filter:brightness(1.08)}
#panel .go.soon{background:transparent;color:var(--dim);border:1px dashed var(--dimmer);box-shadow:none;cursor:default}
#panel .route{margin-top:14px;padding-top:14px;border-top:1px solid var(--line);font-size:.74rem;color:var(--dim)}
#panel .route ol{margin:8px 0 0 18px}
#panel .route li{margin:4px 0}
#panel .route li strong{color:var(--white);font-weight:400;cursor:pointer}
#panel .route li strong:hover{color:var(--pc)}
.legend{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:16px;font-size:.62rem;color:var(--dim)}
.legend i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;background:var(--c);box-shadow:0 0 8px var(--c);vertical-align:middle}
/* handshake table */
.hs-controls{display:flex;gap:8px;flex-wrap:wrap;margin-top:18px}
.chip{font-family:'Orbitron',sans-serif;font-size:.55rem;letter-spacing:.18em;text-transform:uppercase;color:var(--dim);background:rgba(255,255,255,.03);border:1px solid var(--line);border-radius:999px;padding:7px 13px;cursor:pointer}
.chip.on{color:var(--void);background:var(--white);border-color:var(--white)}
.hs-list{margin-top:16px;display:grid;gap:8px}
.hsr{display:grid;grid-template-columns:76px minmax(0,1fr) auto;gap:14px;align-items:center;background:rgba(255,255,255,.025);border:1px solid var(--line);border-radius:12px;padding:12px 14px;transition:.25s}
.hsr:hover{border-color:rgba(255,255,255,.22)}
.hsr.hide{display:none}
.hsr .id{font-family:'Orbitron',sans-serif;font-size:.55rem;letter-spacing:.2em;color:var(--dim)}
.hsr .fromto{font-size:.8rem;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.hsr .fromto em{font-style:normal;padding:2px 9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--c) 50%,transparent);color:var(--c);font-size:.7rem;background:color-mix(in srgb,var(--c) 8%,transparent)}
.hsr .fromto s{text-decoration:none;color:var(--dimmer)}
.hsr .carry{font-size:.72rem;color:var(--dim);margin-top:5px}
.hsr .carry b{color:var(--white);font-weight:400}
.hsr .cost{font-family:'Orbitron',sans-serif;font-size:.6rem;letter-spacing:.12em;color:var(--spark);white-space:nowrap;text-align:right}
.hsr .cost.free{color:var(--green)}
/* say it */
.say{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:22px}
.card{background:rgba(255,255,255,.03);border:1px solid var(--line);border-radius:16px;padding:20px;position:relative}
.card .ct{font-family:'Orbitron',sans-serif;font-size:.55rem;letter-spacing:.28em;color:var(--cyan);text-transform:uppercase}
.card p{margin-top:10px;font-size:.9rem}
.card .copy{position:absolute;top:14px;right:14px;font-family:'Orbitron',sans-serif;font-size:.5rem;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);background:none;border:1px solid var(--line);border-radius:999px;padding:5px 10px;cursor:pointer}
.card .copy:hover{color:var(--white);border-color:rgba(255,255,255,.3)}
/* layers strip */
.layers{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin-top:22px}
.layer{border:1px solid color-mix(in srgb,var(--c) 40%,transparent);border-radius:14px;padding:16px 14px;background:linear-gradient(180deg,color-mix(in srgb,var(--c) 10%,transparent),transparent)}
.layer .ln{font-family:'Orbitron',sans-serif;font-weight:700;font-size:.62rem;letter-spacing:.24em;color:var(--c);text-transform:uppercase}
.layer .lq{font-size:.8rem;margin-top:8px}
.layer .li{font-size:.68rem;color:var(--dim);margin-top:8px}
/* cta + footer */
.cta{text-align:center;padding:60px 0 30px}
.cta a{display:inline-block;margin:6px;background:var(--spark);color:var(--void);text-decoration:none;font-family:'Orbitron',sans-serif;font-weight:700;font-size:.64rem;letter-spacing:.18em;text-transform:uppercase;padding:13px 24px;border-radius:999px;box-shadow:0 0 24px rgba(251,191,36,.35)}
.cta a.ghost{background:transparent;color:var(--white);border:1px solid rgba(255,255,255,.25);box-shadow:none}
footer{text-align:center;padding:30px 0 40px;font-size:.66rem;color:var(--dim);border-top:1px solid var(--line);margin-top:30px}
footer a{color:var(--spark);text-decoration:none}
/* mobile: orbit becomes stacked list */
@media(max-width:980px){
.stage-wrap{grid-template-columns:1fr}
#panel{position:static}
#stage{aspect-ratio:auto;border-radius:0;background:none;max-width:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:10px}
#stage .ring,#lines{display:none}
.node{position:relative;left:auto!important;top:auto!important;transform:none;width:auto;height:auto;border-radius:12px;padding:10px 6px;font-size:.5rem;aspect-ratio:1/1;display:flex;flex-direction:column;align-items:center;justify-content:center}
.node:hover{transform:none}
.node.core{width:auto;height:auto;grid-column:1/-1;aspect-ratio:auto;padding:16px;flex-direction:row;gap:12px;font-size:.6rem}
.node.lit .step{top:-6px;right:-6px}
.hsr{grid-template-columns:1fr;gap:6px}
.hsr .cost{text-align:left}
}
</style>
<script>!function(w,d,s,u,n,a,b){if(w[n])return;a=w[n]={q:[],t:+new Date,s:[],o:u,track:function(){a.q.push([+new Date].concat([].slice.call(arguments)))},setScope:function(){a.s=[].slice.call(arguments).filter(function(x){return typeof x==="string"});a.q.push([+new Date,"setScope"].concat(a.s))},scope:function(){var c=[].slice.call(arguments);return{track:function(){a.q.push([+new Date].concat([].slice.call(arguments)).concat([{__scope:c}]))}}}};b=d.createElement(s);b.async=1;b.src=u+"/s.js";d.getElementsByTagName(s)[0].parentNode.insertBefore(b,d.getElementsByTagName(s)[0])}(window,document,"script","https://t.whop.tw","whop");whop.setScope("biz_0xcayhWXVnKO9y");whop.track("page");</script>
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K4TKPMG9" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<div class="aurora"></div>
<div class="stars" id="stars"></div>
<div class="wrap">
<nav>
<a class="brand orb" href="/">The First Spark</a>
<div class="links orb">
<a href="map.html">Soul Map · $22</a>
<a href="shop.html">Shop</a>
<a href="free-tools.html">Free Tools</a>
<a href="https://sparkverse.thefirstspark.shop/" target="_blank" rel="noopener noreferrer">Sparkverse</a>
<a href="https://links.thefirstspark.shop" target="_blank" rel="noopener noreferrer">All Links</a>
</div>
</nav>
<section class="hero">
<div class="kicker orb">System Map · Read this first</div>
<h1>The First Spark reads <em>the code you were born with</em>,<br>then gives you a world to run it in.</h1>
<p class="one">Your birth name and birth date make a pattern. We calculate it, write it up as a personal reading, and build tools, stories and a community around working with it. Everything on this site is one of those four things: <b>the Code</b>, <b>a Reading</b>, <b>a Tool</b>, <b>a Story</b>, or <b>the World</b> they live in.</p>
<p class="not">It is not a horoscope app and it is not a course. It is a reading of your pattern, and a game world built around it.</p>
</section>
<section class="sec" id="layers">
<div class="sec-num orb">01 · The five layers</div>
<h2 class="sec-title">Everything is one of these</h2>
<p class="sec-sub">If a page confuses you, ask which layer it belongs to. That is the whole map.</p>
<div class="layers">
<div class="layer" style="--c:var(--l-code)"><div class="ln">The Code</div><div class="lq">The idea underneath everything.</div><div class="li">Selector Model · SELECT / RELEASE / WITNESS · the Spark Canon</div><div class="li" style="margin-top:6px"><a href="framework.html" style="color:var(--spark);text-decoration:none;border-bottom:1px solid rgba(251,191,36,.35)">The 7-layer framework →</a></div></div>
<div class="layer" style="--c:var(--l-reading)"><div class="ln">Readings</div><div class="lq">Your pattern, written up for you.</div><div class="li">Soul Map · Pattern Key · Soul Card · free preview</div></div>
<div class="layer" style="--c:var(--l-tools)"><div class="ln">Tools</div><div class="lq">Things you use on your pattern.</div><div class="li">Freq Match · Sigilcraft · Rituals · 7-Day Protocol · the Engine</div></div>
<div class="layer" style="--c:var(--l-stories)"><div class="ln">Stories</div><div class="lq">Where the code came from.</div><div class="li">Origin · Dark Shadows · Genesis · Mythos · Book Zero</div></div>
<div class="layer" style="--c:var(--l-world)"><div class="ln">The World</div><div class="lq">The people running the same code.</div><div class="li">Sparkverse Lobby · Players Lounge · Initiation Engine</div></div>
</div>
</section>
<section class="sec" id="map">
<div class="sec-num orb">02 · The map</div>
<h2 class="sec-title">Pick what you came for</h2>
<p class="sec-sub">Choose one. The map lights the route, in order, and shows what each stop hands you. Or tap any node to read it on its own.</p>
<div class="paths" id="paths"></div>
<button class="path-clear" id="clearPath">Show everything</button>
<div class="stage-wrap">
<div id="stage"><svg id="lines"></svg></div>
<aside id="panel"></aside>
</div>
<div class="legend">
<span style="--c:var(--l-code)"><i></i>Code</span>
<span style="--c:var(--l-reading)"><i></i>Readings</span>
<span style="--c:var(--l-tools)"><i></i>Tools</span>
<span style="--c:var(--l-stories)"><i></i>Stories</span>
<span style="--c:var(--l-world)"><i></i>World</span>
<span style="--c:var(--l-studio)"><i></i>Studio</span>
<span style="color:var(--dimmer)">dashed = not live yet</span>
</div>
</section>
<section class="sec" id="handshakes">
<div class="sec-num orb">03 · Handshake protocols</div>
<h2 class="sec-title">How one part hands you to the next</h2>
<p class="sec-sub">A handshake is the moment you cross from one part of The First Spark to another: what you carry across, what triggers it, and what it costs. Nothing here is a dead end. Every door leads back to your code.</p>
<div class="hs-controls" id="hsFilters"></div>
<div class="hs-list" id="hsList"></div>
</section>
<section class="sec" id="say">
<div class="sec-num orb">04 · Say it in one breath</div>
<h2 class="sec-title">When someone asks "so what is it?"</h2>
<p class="sec-sub">Three lengths. Tap to copy.</p>
<div class="say">
<div class="card"><div class="ct">8 words</div><p id="s1">We read the code you were born with.</p><button class="copy" data-t="s1">Copy</button></div>
<div class="card"><div class="ct">25 words</div><p id="s2">The First Spark reads the pattern in your birth name and date, then hands you tools, stories and a community built to work with it.</p><button class="copy" data-t="s2">Copy</button></div>
<div class="card"><div class="ct">60 words</div><p id="s3">The First Spark started when DNA solved my mother's 29-year cold case by reading what was there all along. I built a studio on that instinct: your code is already written. A Soul Map ($22) reads it from your birth name and date. Free tools let you work with it. The Sparkverse is the community running the same code.</p><button class="copy" data-t="s3">Copy</button></div>
</div>
</section>
<div class="cta">
<a href="soul-pattern-generator.html">Weave your Soul Pattern free</a>
<a href="map.html">Get your Soul Map · $22</a>
<a class="ghost" href="https://whop.com/sparkverse-511c/the-sparkverse-lobby/" target="_blank" rel="noopener noreferrer">Join the Lobby · Free</a>
</div>
<footer>
<p>The First Spark · Kate's Paint LLC · Akron, Ohio</p>
<p style="margin-top:6px"><a href="https://thefirstspark.shop">thefirstspark.shop</a> · <a href="mailto:kate@thefirstspark.shop">kate@thefirstspark.shop</a> · <a href="ecosystem-map.html">Investor revenue map →</a></p>
</footer>
</div>
<script>
/* ---------- DATA ---------- */
const LAYERS={
code:{name:'Code',color:'var(--l-code)',r:0},
reading:{name:'Readings',color:'var(--l-reading)',r:.40},
tools:{name:'Tools',color:'var(--l-tools)',r:.56},
stories:{name:'Stories',color:'var(--l-stories)',r:.72},
world:{name:'World',color:'var(--l-world)',r:.87},
studio:{name:'Studio',color:'var(--l-studio)',r:1.0}
};
const N=[
{id:'code',layer:'code',ico:'✦',name:'Your Code',what:'Your birth name and birth date, run through the Selector Model. Every product on this site either reads that code, works on it, tells the story of where it came from, or gathers the people who share it.',who:'Everyone. It is the centre of the map.',cost:'—',url:'selector-model-ip.html',cta:'Read the Selector Model'},
// readings
{id:'preview',layer:'reading',a:-95,ico:'◌',name:'Free Preview',what:'Type your name and birth date and watch your pattern weave itself as you type. Your core numbers, drawn. No account, no email.',who:'First-timers who want proof before paying.',cost:'Free',url:'soul-pattern-generator.html',cta:'Weave your pattern'},
{id:'pattern',layer:'reading',a:-45,ico:'✺',name:'Soul Pattern',what:'Your numbers drawn as a weave you can share as a story image or a link. Includes a "collide" button that opens Freq Match with you pre-filled.',who:'People who want something to post.',cost:'Free',url:'soul-pattern-generator.html',cta:'Weave your pattern'},
{id:'soulmap',layer:'reading',a:5,ico:'◆',name:'Soul Map',what:'Your full reading: who you are, what you are built for, the pattern you keep repeating. Delivered as your own private page you keep forever. Mints your Soul Card ID.',who:'Anyone ready to see the whole thing.',cost:'$22 once',url:'map.html',cta:'Get your Soul Map'},
{id:'card',layer:'reading',a:55,ico:'▣',name:'Soul Card',what:'The permanent ID minted with every paid Soul Map. It is how Freq Match knows who you are, and how two people compare without retyping anything.',who:'Soul Map holders.',cost:'Included with map',url:'https://soul-maps.thefirstspark.shop/',ext:1,cta:'Browse the archive'},
{id:'patternkey',layer:'reading',a:105,ico:'⚿',name:'Pattern Key',what:'A frequency journal. Log the signal daily and watch your pattern surface. One self-contained app that lives on your device: no account, no cloud, one file you keep forever.',who:'Map holders who want to track it over time.',cost:'$22',url:'shop.html',cta:'Open the shop'},
{id:'codex',layer:'reading',a:160,ico:'❖',name:'Codex & Tree of Life',what:'The colour tiers every map is written in, and the Tree of Life ebook that explains them. Read this and every badge on every map makes sense.',who:'The curious, and map holders decoding theirs.',cost:'Free',url:'https://soul-maps.thefirstspark.shop/color-codex.html',ext:1,cta:'Open the codex'},
// tools
{id:'freq',layer:'tools',a:-70,ico:'∿',name:'Freq Match',what:'Two birth dates, one compatibility score. Paste two Soul Card IDs and it fills itself in. Same code, or not.',who:'Couples, friends, co-founders, anyone curious about a pairing.',cost:'Free · Pro $4.99/mo',url:'https://frequency.thefirstspark.shop',ext:1,cta:'Test a match'},
{id:'protocol',layer:'tools',a:-15,ico:'☀',name:'7-Day Starter Protocol',what:'Seven days, three checkpoints a day: boot, run, save. Print it and run the week. The cheapest paid thing here on purpose.',who:'People who read their map and asked "now what?"',cost:'$7.77',url:'shop.html',cta:'Open the shop'},
{id:'sigil',layer:'tools',a:35,ico:'⌖',name:'Sigilcraft',what:'Forge a personal sigil from your intent. Free forge on the subdomain, full system bundle in the shop.',who:'Makers who want a symbol they own.',cost:'Free · Bundle $33',url:'https://sigilcraft.thefirstspark.shop',ext:1,cta:'Open the forge'},
{id:'rituals',layer:'tools',a:85,ico:'◐',name:'Rituals',what:'Interactive ceremonies you walk through in the browser. Slow pages on purpose.',who:'Anyone who wants a reset that is not a to-do list.',cost:'Free',url:'https://rituals.thefirstspark.shop',ext:1,cta:'Enter a ritual'},
{id:'karma',layer:'tools',a:135,ico:'⟲',name:'Karma Debugger',what:'Trace the pattern, patch the loop. Find the repeating code in your life and rewrite it on purpose.',who:'People stuck in a repeat.',cost:'Free to try · $6.99',url:'shop.html',cta:'Open the shop'},
{id:'engine',layer:'tools',a:190,ico:'⚙',name:'The Engine',what:'A holographic wheel that asks what you carry and places you on one of twelve archetype seats. Same seats the Canon and the community use.',who:'Anyone. Two minutes, no input but choices.',cost:'Free',url:'engine.html',cta:'Run the Engine'},
// stories
{id:'origin',layer:'stories',a:-100,ico:'⌁',name:'Origin',what:'In 2020 DNA solved a 29-year cold case in my family by reading what had been there all along. This is why the site exists.',who:'Anyone asking "why should I trust this?"',cost:'Free',url:'origin.html',cta:'Read the origin'},
{id:'dark',layer:'stories',a:-40,ico:'☾',name:'Dark Shadows',what:'A serialised story, five chapters online free. The print edition unlocks at the end of chapter five.',who:'Readers. The easiest way in if you like fiction.',cost:'Free · Print PDF $11.11',url:'dark-shadows/',cta:'Start chapter one'},
{id:'genesis',layer:'stories',a:20,ico:'✧',name:'Genesis',what:'The 75,000-word novel that builds the Sparkverse. Every archetype, gate and seat in the tools is canon from this book.',who:'People who want the full world.',cost:'$11.11',url:'shop.html',cta:'Open the shop'},
{id:'mythos',layer:'stories',a:80,ico:'✵',name:'Mythos',what:'Chapter pages that read like scripture for the world. Short, dense, free.',who:'Lore readers.',cost:'Free',url:'mythos/',cta:'Open the Mythos'},
{id:'bookzero',layer:'stories',a:140,ico:'▢',name:'Book Zero',what:'The memoir. Two Fires, One Match. The tour pages are live, the book is being written.',who:'People who want the real story behind the origin.',cost:'Coming',soon:1,url:'book-zero-tour.html',cta:'Book Zero tour'},
{id:'canon',layer:'stories',a:200,ico:'⚖',name:'The Framework',what:'The rule book every engine on this site conforms to: seven layers from Thesis to Numerology, how colours are assigned, what a karmic debt can and cannot say. Public so nothing here is arbitrary. The cosmology behind it lives in the Core Canon.',who:'Builders and sceptics.',cost:'Free',url:'framework.html',cta:'Read the Framework'},
// world
{id:'lobby',layer:'world',a:-80,ico:'⬡',name:'Sparkverse Lobby',what:'The free front room on Whop. Post, read, get the ebook funnel, meet people running the same code.',who:'Everyone. Zero cost to walk in.',cost:'Free',url:'https://whop.com/sparkverse-511c/the-sparkverse-lobby/',ext:1,cta:'Join free'},
{id:'hub',layer:'world',a:-20,ico:'☉',name:'Sparkverse Hub',what:'A solar-system map of every tool: Core, Lumina, the Forge, the Void. The visual home of the world.',who:'Explorers.',cost:'Free',url:'https://sparkverse.thefirstspark.shop/',ext:1,cta:'Enter the Sparkverse'},
{id:'lounge',layer:'world',a:45,ico:'♛',name:'Players Lounge',what:'The inner circle. Live drops, member-only tools, and the room where the next things ship first.',who:'Members ready to go deeper.',cost:'$33/mo · 3 days free',url:'shop.html',cta:'Open the shop'},
{id:'initiation',layer:'world',a:115,ico:'⧉',name:'Initiation Engine',what:'A Whop app other creators install. Their new members answer six questions and get a permanent archetype card. The same code, sold as a tool to other communities.',who:'Whop creators.',cost:'Coming · creator-pays',soon:1,url:'https://initiation-engine.vercel.app',ext:1,cta:'Preview'},
{id:'links',layer:'world',a:185,ico:'⇶',name:'All Links',what:'One page with every door on it, for socials.',who:'Anyone coming from a bio.',cost:'Free',url:'https://links.thefirstspark.shop',ext:1,cta:'Open links'},
// studio
{id:'shop',layer:'studio',a:-60,ico:'▤',name:'Item Shop',what:'Every paid item on one screen, direct checkout. Nothing is behind a chat wall.',who:'Buyers.',cost:'$7.77 to $33',url:'shop.html',cta:'Open the shop'},
{id:'affiliate',layer:'studio',a:0,ico:'⇄',name:'Affiliate Kit',what:'Share a Soul Map link, keep 35% of every sale. Copy, images and links ready.',who:'Creators and friends who refer.',cost:'Pays you',url:'affiliate-kit.html',cta:'Get the kit'},
{id:'kate',layer:'studio',a:75,ico:'☆',name:'Katelin (KJP)',what:'Solo founder, builder and sole maintainer. Business grad, mother of two, built all of this alone.',who:'Anyone who wants to know who is behind it.',cost:'—',url:'katelin.html',cta:'Meet Kate'},
{id:'invest',layer:'studio',a:150,ico:'◈',name:'Invest',what:'The raise, the deck, the revenue map and the IP list.',who:'Investors and press.',cost:'—',url:'invest.html',cta:'See the raise'}
];
const PATHS=[
{id:'know',color:'var(--l-reading)',q:'I want to understand myself.',n:'Preview → Soul Map → Codex → Pattern Key',steps:['preview','soulmap','codex','patternkey','protocol']},
{id:'match',color:'var(--l-tools)',q:'I want to know if we match.',n:'Pattern → Freq Match → Soul Cards → Lobby',steps:['pattern','freq','soulmap','card','lobby']},
{id:'story',color:'var(--l-stories)',q:'I want the story.',n:'Origin → Dark Shadows → Genesis → Mythos → Book Zero',steps:['origin','dark','genesis','mythos','bookzero']},
{id:'daily',color:'var(--spark)',q:'I want a daily practice.',n:'Engine → 7-Day Protocol → Sigilcraft → Rituals → Karma',steps:['engine','protocol','sigil','rituals','karma']},
{id:'join',color:'var(--l-world)',q:'I want to find my people.',n:'Lobby → Hub → Engine → Players Lounge',steps:['lobby','hub','engine','lounge']},
{id:'build',color:'var(--l-studio)',q:'I want to build or back this.',n:'Code → Canon → Initiation Engine → Affiliates → Invest',steps:['code','canon','initiation','affiliate','invest']}
];
const HS=[
{from:'preview',to:'soulmap',carry:'Your name, date and the numbers you just saw',trigger:'You want the reading behind the numbers',cost:'$22'},
{from:'soulmap',to:'card',carry:'A permanent quantum ID minted with your map',trigger:'Automatic at purchase',cost:'Included'},
{from:'card',to:'freq',carry:'Two card IDs in the link. Names and dates pre-fill',trigger:'You send someone your collide link',cost:'Free'},
{from:'pattern',to:'freq',carry:'Your name and date via the collide button',trigger:'You tap "collide"',cost:'Free'},
{from:'freq',to:'soulmap',carry:'The pairing score and what it pointed at',trigger:'You want your own full reading',cost:'$22'},
{from:'freq',to:'lobby',carry:'Two people who now share a score',trigger:'You want to talk about it with others',cost:'Free'},
{from:'soulmap',to:'codex',carry:'Your tier colour and archetype seat',trigger:'You want to know what the badge means',cost:'Free'},
{from:'codex',to:'patternkey',carry:'Your tier and what it asks of you',trigger:'You want to log it, not just read it',cost:'$22'},
{from:'soulmap',to:'patternkey',carry:'The pattern your map named',trigger:'You want to track it daily, not just know it',cost:'$22'},
{from:'patternkey',to:'protocol',carry:'A pattern you have been logging',trigger:'You want a week of structure',cost:'$7.77'},
{from:'engine',to:'lounge',carry:'Your archetype seat',trigger:'You want to meet the others in your seat',cost:'$33/mo · trial'},
{from:'engine',to:'initiation',carry:'The same twelve seats, offered to other communities',trigger:'You run a community and want the rite',cost:'Creator-pays'},
{from:'protocol',to:'sigil',carry:'The intent you set on day one',trigger:'You want a symbol to keep it',cost:'Free · $33'},
{from:'sigil',to:'rituals',carry:'Your sigil',trigger:'You want to use it, not just have it',cost:'Free'},
{from:'rituals',to:'karma',carry:'The loop the ritual surfaced',trigger:'You want to debug it properly',cost:'$6.99'},
{from:'origin',to:'dark',carry:'Why the site exists',trigger:'You want the story as fiction',cost:'Free'},
{from:'dark',to:'genesis',carry:'A taste for the world',trigger:'Chapter five ends. Print edition offered',cost:'$11.11 each'},
{from:'genesis',to:'mythos',carry:'The world you now know',trigger:'You want more canon',cost:'Free'},
{from:'genesis',to:'engine',carry:'Archetypes you met in the book',trigger:'You want to know which one you are',cost:'Free'},
{from:'mythos',to:'bookzero',carry:'The myth',trigger:'You want the true story under it',cost:'Coming'},
{from:'lobby',to:'lounge',carry:'Your account and posts',trigger:'Lobby pinned post offers a three-day trial',cost:'$33/mo'},
{from:'lobby',to:'dark',carry:'Your account',trigger:'Lobby offers the print edition',cost:'$11.11'},
{from:'hub',to:'engine',carry:'Nothing. Just curiosity',trigger:'You tap the Core in the solar system',cost:'Free'},
{from:'code',to:'canon',carry:'The Selector Model',trigger:'You want all seven layers written down',cost:'Free'},
{from:'canon',to:'initiation',carry:'The archetype and tier rules',trigger:'You want to ship them in your own community',cost:'Creator-pays'},
{from:'soulmap',to:'affiliate',carry:'Your map link',trigger:'You share it. You keep 35%',cost:'Pays you'},
{from:'affiliate',to:'invest',carry:'Proof the machine sells',trigger:'You want a bigger stake than 35%',cost:'—'},
{from:'links',to:'preview',carry:'Nothing yet',trigger:'You came from a bio and want to try it',cost:'Free'},
{from:'shop',to:'soulmap',carry:'Direct checkout link',trigger:'You pick the map card',cost:'$22'}
];
const byId=Object.fromEntries(N.map(n=>[n.id,n]));
/* ---------- STARS ---------- */
(()=>{const s=document.getElementById('stars');let h='';for(let i=0;i<140;i++){h+=`<i style="left:${Math.random()*100}%;top:${Math.random()*100}%;width:${(Math.random()*1.6+.5).toFixed(1)}px;height:${(Math.random()*1.6+.5).toFixed(1)}px;animation-delay:${(Math.random()*4).toFixed(1)}s"></i>`}s.innerHTML=h})();
/* ---------- STAGE ---------- */
const stage=document.getElementById('stage'),lines=document.getElementById('lines');
Object.entries(LAYERS).filter(([k,l])=>l.r>0).forEach(([k,l],i)=>{
const d=document.createElement('div');d.className='ring r'+(i+1);d.style.setProperty('--rc',l.color);
d.style.width=d.style.height=(l.r*100)+'%';stage.appendChild(d);
});
N.forEach(n=>{
const b=document.createElement('button');b.className='node'+(n.layer==='code'?' core':'')+(n.soon?' soon':'');
b.dataset.id=n.id;b.style.setProperty('--nc',LAYERS[n.layer].color);
b.innerHTML=`<span class="ico">${n.ico}</span>${n.name}<span class="step"></span>`;
b.title=n.name;b.addEventListener('click',()=>select(n.id,true));stage.appendChild(b);n.el=b;
});
function layout(){
const w=stage.clientWidth;const mobile=window.matchMedia('(max-width:980px)').matches;
N.forEach(n=>{const L=LAYERS[n.layer];if(mobile||L.r===0){n.el.style.left=n.el.style.top='50%';n.x=n.y=w/2;return}
const rad=(n.a-90)*Math.PI/180,r=L.r*w/2;n.x=w/2+Math.cos(rad)*r;n.y=w/2+Math.sin(rad)*r;
n.el.style.left=n.x+'px';n.el.style.top=n.y+'px'});
lines.setAttribute('viewBox',`0 0 ${w} ${w}`);drawLines();
}
let activePath=null,selected='code';
function drawLines(){
lines.innerHTML='';if(!activePath)return;
const p=PATHS.find(p=>p.id===activePath);
for(let i=0;i<p.steps.length-1;i++){const a=byId[p.steps[i]],b=byId[p.steps[i+1]];
const l=document.createElementNS('http://www.w3.org/2000/svg','line');
l.setAttribute('x1',a.x);l.setAttribute('y1',a.y);l.setAttribute('x2',b.x);l.setAttribute('y2',b.y);
l.style.stroke=p.color;l.classList.add('on');lines.appendChild(l)}
}
window.addEventListener('resize',layout);
/* ---------- PATHS ---------- */
const pathsEl=document.getElementById('paths');
PATHS.forEach(p=>{const b=document.createElement('button');b.className='path';b.dataset.id=p.id;b.style.setProperty('--pc',p.color);
b.innerHTML=`<div class="pk orb">Path</div><div class="pq">${p.q}</div><div class="pn">${p.n}</div>`;
b.addEventListener('click',()=>setPath(p.id));pathsEl.appendChild(b)});
document.getElementById('clearPath').addEventListener('click',()=>setPath(null));
function setPath(id){
activePath=id===activePath?null:id;
document.querySelectorAll('.path').forEach(b=>b.classList.toggle('on',b.dataset.id===activePath));
N.forEach(n=>{n.el.classList.remove('dimmed','lit');n.el.querySelector('.step').textContent=''});
if(activePath){const p=PATHS.find(p=>p.id===activePath);
N.forEach(n=>{const i=p.steps.indexOf(n.id);if(i<0){if(n.id!=='code')n.el.classList.add('dimmed')}else{n.el.classList.add('lit');n.el.querySelector('.step').textContent=i+1}});
select(p.steps[0],false);
filterHS(null);
} else select('code',false);
drawLines();
}
/* ---------- PANEL ---------- */
const panel=document.getElementById('panel');
function select(id,fromClick){
selected=id;const n=byId[id],L=LAYERS[n.layer];
N.forEach(m=>m.el.classList.toggle('sel',m.id===id));
panel.style.setProperty('--pc',L.color);
const ins=HS.filter(h=>h.to===id),outs=HS.filter(h=>h.from===id);
const chip=(h,dir)=>`<span data-go="${dir==='in'?h.from:h.to}">${dir==='in'?'← ':''}${byId[dir==='in'?h.from:h.to].name}${dir==='out'?' →':''}</span>`;
let route='';
if(activePath){const p=PATHS.find(p=>p.id===activePath);const i=p.steps.indexOf(id);
route=`<div class="route">Route: <b style="color:${p.color};font-weight:400">${p.q}</b><ol>${p.steps.map((s,j)=>`<li><strong data-go="${s}">${byId[s].name}</strong>${j===i?' ← you are here':''}${j<p.steps.length-1?`<div style="font-size:.66rem;color:var(--dimmer)">hands you: ${(HS.find(h=>h.from===s&&h.to===p.steps[j+1])||{carry:'your code'}).carry}</div>`:''}</li>`).join('')}</ol></div>`}
panel.innerHTML=`<div class="ptag">${L.name}${n.soon?' · not live yet':''}</div><h3>${n.ico} ${n.name}</h3>
<p class="what">${n.what}</p>
<div class="meta"><div><b>For</b>${n.who}</div><div><b>Cost</b>${n.cost}</div></div>
<div class="hs">${ins.length?`<b>Handshake in</b>${ins.map(h=>chip(h,'in')).join('')}`:''}${outs.length?`<b>Handshake out</b>${outs.map(h=>chip(h,'out')).join('')}`:''}</div>
<a class="go${n.soon?' soon':''}" href="${n.url}"${n.ext?' target="_blank" rel="noopener noreferrer"':''}>${n.cta}${n.ext?' ↗':''}</a>${route}`;
panel.querySelectorAll('[data-go]').forEach(el=>el.addEventListener('click',()=>select(el.dataset.go,true)));
if(fromClick&&window.matchMedia('(max-width:980px)').matches)panel.scrollIntoView({behavior:'smooth',block:'nearest'});
}
/* ---------- HANDSHAKES ---------- */
const hsList=document.getElementById('hsList'),hsF=document.getElementById('hsFilters');
const filters=[{id:null,l:'All'},...Object.entries(LAYERS).filter(([k])=>k!=='code').map(([k,l])=>({id:k,l:l.name}))];
filters.forEach(f=>{const b=document.createElement('button');b.className='chip'+(f.id===null?' on':'');b.textContent=f.l;b.dataset.f=f.id??'';b.addEventListener('click',()=>filterHS(f.id));hsF.appendChild(b)});
HS.forEach((h,i)=>{const a=byId[h.from],b=byId[h.to];const free=/free|included|pays|coming|—/i.test(h.cost);
const r=document.createElement('div');r.className='hsr';r.dataset.from=a.layer;r.dataset.to=b.layer;r.dataset.a=h.from;r.dataset.b=h.to;
r.innerHTML=`<div class="id">HS-${String(i+1).padStart(2,'0')}</div><div><div class="fromto"><em style="--c:${LAYERS[a.layer].color}">${a.name}</em><s>→</s><em style="--c:${LAYERS[b.layer].color}">${b.name}</em></div><div class="carry"><b>Carries:</b> ${h.carry}. <b>Trigger:</b> ${h.trigger}.</div></div><div class="cost${free?' free':''}">${h.cost}</div>`;
r.addEventListener('click',()=>{select(h.to,true);document.getElementById('map').scrollIntoView({behavior:'smooth'})});hsList.appendChild(r)});
function filterHS(layer){
document.querySelectorAll('.chip').forEach(c=>c.classList.toggle('on',(c.dataset.f||null)===layer));
const p=activePath?PATHS.find(p=>p.id===activePath):null;
document.querySelectorAll('.hsr').forEach(r=>{let show=true;
if(layer)show=r.dataset.from===layer||r.dataset.to===layer;
else if(p){const i=p.steps.indexOf(r.dataset.a);show=i>-1&&p.steps[i+1]===r.dataset.b}
r.classList.toggle('hide',!show)});
}
/* ---------- COPY ---------- */
document.querySelectorAll('.copy').forEach(b=>b.addEventListener('click',()=>{navigator.clipboard.writeText(document.getElementById(b.dataset.t).textContent).then(()=>{b.textContent='Copied';setTimeout(()=>b.textContent='Copy',1400)})}));
/* ---------- INIT ---------- */
layout();select('code',false);
</script>
</body>
</html>