@idp.global/catalog 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/changelog.md +18 -1
  2. package/dist_bundle/bundle.js +1507 -960
  3. package/dist_ts_web/00_commitinfo_data.js +3 -3
  4. package/dist_ts_web/elements/idp-admin-shell.d.ts +38 -0
  5. package/dist_ts_web/elements/idp-admin-shell.js +130 -6
  6. package/dist_ts_web/elements/idp-badge.js +9 -12
  7. package/dist_ts_web/elements/idp-button.d.ts +1 -1
  8. package/dist_ts_web/elements/idp-button.js +39 -16
  9. package/dist_ts_web/elements/idp-landing-hero.d.ts +1 -2
  10. package/dist_ts_web/elements/idp-landing-hero.js +63 -108
  11. package/dist_ts_web/elements/idp-landing-page.d.ts +5 -0
  12. package/dist_ts_web/elements/idp-landing-page.js +922 -391
  13. package/dist_ts_web/elements/idp-mobile-showcase.js +1 -1
  14. package/dist_ts_web/elements/idp-screenshot-placeholder.d.ts +23 -0
  15. package/dist_ts_web/elements/idp-screenshot-placeholder.js +192 -0
  16. package/dist_ts_web/elements/index.d.ts +1 -0
  17. package/dist_ts_web/elements/index.js +2 -1
  18. package/dist_ts_web/elements/tokens.d.ts +1 -1
  19. package/dist_ts_web/elements/tokens.js +129 -115
  20. package/package.json +5 -6
  21. package/readme.md +4 -3
  22. package/ts_web/00_commitinfo_data.ts +2 -2
  23. package/ts_web/elements/idp-admin-shell.ts +148 -4
  24. package/ts_web/elements/idp-badge.ts +8 -11
  25. package/ts_web/elements/idp-button.ts +39 -16
  26. package/ts_web/elements/idp-landing-hero.ts +62 -107
  27. package/ts_web/elements/idp-landing-page.ts +932 -389
  28. package/ts_web/elements/idp-mobile-showcase.ts +1 -1
  29. package/ts_web/elements/idp-screenshot-placeholder.ts +126 -0
  30. package/ts_web/elements/index.ts +1 -0
  31. package/ts_web/elements/tokens.ts +128 -114
  32. package/dist_watch/bundle.js +0 -120699
  33. package/dist_watch/bundle.js.map +0 -7
  34. package/dist_watch/index.html +0 -29
@@ -3,6 +3,7 @@ import { idpElementStyles } from './tokens.js';
3
3
  import './idp-badge.js';
4
4
  import './idp-button.js';
5
5
  import './idp-icon.js';
6
+ import './idp-screenshot-placeholder.js';
6
7
  import './idp-landing-hero.js';
7
8
 
8
9
  declare global {
@@ -14,565 +15,753 @@ declare global {
14
15
  @customElement('idp-landing-page')
15
16
  export class IdpLandingPage extends DeesElement {
16
17
  public static demo = () => html`<idp-landing-page></idp-landing-page>`;
17
- public static demoGroups = ['idp.global v3 full pages'];
18
+ public static demoGroups = ['idp.global v5 full pages'];
18
19
 
19
20
  public static styles = [
20
21
  ...idpElementStyles,
21
22
  css`
22
23
  :host {
23
24
  display: block;
24
- background: var(--idp-bg);
25
+ background: var(--idp-card);
25
26
  color: var(--idp-fg);
26
27
  }
27
28
  .page {
28
29
  min-height: 100vh;
29
- background: var(--idp-bg);
30
+ background: var(--idp-card);
30
31
  }
31
- nav {
32
- position: sticky;
33
- top: 0;
34
- z-index: 20;
35
- display: flex;
36
- align-items: center;
37
- justify-content: space-between;
38
- gap: 24px;
39
- height: 56px;
32
+ .wrap {
33
+ max-width: 1024px;
34
+ margin: 0 auto;
35
+ padding: 0 22px;
36
+ }
37
+ .wrap-wide {
40
38
  max-width: 1240px;
41
39
  margin: 0 auto;
42
- padding: 0 32px;
43
- border-bottom: 1px solid var(--idp-border-soft);
44
- background: color-mix(in srgb, var(--idp-bg), transparent 14%);
45
- backdrop-filter: blur(14px) saturate(140%);
40
+ padding: 0 22px;
46
41
  }
42
+
43
+ /* Nav */
47
44
  .nav-shell {
48
45
  position: sticky;
49
46
  top: 0;
50
- z-index: 20;
51
- border-bottom: 1px solid var(--idp-border-soft);
52
- background: color-mix(in srgb, var(--idp-bg), transparent 14%);
47
+ z-index: 50;
48
+ border-bottom: 0.5px solid var(--idp-border-soft);
49
+ background: var(--idp-nav-bg);
50
+ backdrop-filter: saturate(180%) blur(20px);
51
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
52
+ }
53
+ nav {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: space-between;
57
+ height: 48px;
58
+ max-width: 1024px;
59
+ margin: 0 auto;
60
+ padding: 0 22px;
53
61
  }
54
62
  .logo {
55
63
  display: inline-flex;
56
64
  align-items: center;
57
- gap: 8px;
58
- font-family: var(--idp-display);
59
- font-size: 16px;
60
- font-weight: 700;
61
- letter-spacing: -0.015em;
65
+ font-size: 19px;
66
+ font-weight: 600;
67
+ letter-spacing: -0.02em;
68
+ color: var(--idp-fg);
69
+ text-decoration: none;
62
70
  }
63
71
  .logo-dot {
64
72
  width: 6px;
65
73
  height: 6px;
66
- border-radius: 999px;
74
+ margin: 0 1px 5px;
75
+ border-radius: 50%;
67
76
  background: var(--idp-accent);
68
- box-shadow: 0 0 12px var(--idp-accent);
77
+ align-self: flex-end;
69
78
  }
70
- .links, .actions {
79
+ .nav-links {
71
80
  display: flex;
72
- align-items: center;
73
- gap: 6px;
81
+ gap: 4px;
74
82
  }
75
- .links a {
76
- padding: 6px 12px;
77
- border-radius: 5px;
83
+ .nav-links a {
84
+ padding: 4px 11px;
85
+ border-radius: 6px;
78
86
  color: var(--idp-fg-3);
79
87
  font-size: 13px;
80
88
  text-decoration: none;
81
89
  }
82
- .links a:hover {
83
- background: var(--idp-muted);
90
+ .nav-links a:hover {
84
91
  color: var(--idp-fg);
85
92
  }
86
- .status {
87
- display: inline-flex;
93
+ .actions {
94
+ display: flex;
88
95
  align-items: center;
89
- gap: 6px;
90
- margin-right: 8px;
91
- color: var(--idp-muted-fg);
92
- font-family: var(--idp-mono);
93
- font-size: 11px;
94
- }
95
- .live-dot {
96
- width: 6px;
97
- height: 6px;
98
- border-radius: 50%;
99
- background: var(--idp-ok);
100
- box-shadow: 0 0 8px var(--idp-ok);
96
+ gap: 8px;
101
97
  }
102
- .wrap {
103
- max-width: 1240px;
104
- margin: 0 auto;
105
- padding: 0 32px;
98
+ .nav-signin {
99
+ color: var(--idp-accent);
100
+ font-size: 13px;
101
+ cursor: pointer;
106
102
  }
107
- .proof, .section, .manifesto, .cta, footer {
108
- border-bottom: 1px solid var(--idp-border-soft);
103
+ .nav-signin:hover {
104
+ text-decoration: underline;
109
105
  }
106
+
107
+ /* Proof */
110
108
  .proof {
111
- padding: 56px 0;
109
+ padding: 64px 0;
110
+ text-align: center;
112
111
  }
113
112
  .proof-label {
114
113
  margin-bottom: 28px;
115
- color: var(--idp-muted-fg);
116
- text-align: center;
117
- font-family: var(--idp-mono);
118
- font-size: 11px;
119
- letter-spacing: 0.12em;
120
- text-transform: uppercase;
114
+ color: var(--idp-fg-3);
115
+ font-size: 14px;
121
116
  }
122
117
  .proof-row {
123
- display: grid;
124
- grid-template-columns: repeat(6, 1fr);
125
- gap: 24px;
126
- place-items: center;
127
- opacity: 0.72;
118
+ display: flex;
119
+ flex-wrap: wrap;
120
+ justify-content: center;
121
+ gap: 16px 48px;
128
122
  }
129
123
  .proof-name {
130
124
  color: var(--idp-fg-3);
131
- font-family: var(--idp-display);
132
- font-size: 18px;
133
- font-weight: 700;
125
+ font-size: 22px;
126
+ font-weight: 600;
134
127
  letter-spacing: -0.02em;
128
+ opacity: 0.82;
135
129
  }
130
+
131
+ /* Sections */
136
132
  .section {
137
- padding: 120px 0;
133
+ padding: 110px 0;
138
134
  }
139
135
  .section.alt {
140
- background: var(--idp-bg-2);
136
+ background: var(--idp-bg);
141
137
  }
142
138
  .section-head {
143
- max-width: 760px;
139
+ max-width: 720px;
144
140
  margin: 0 auto 64px;
145
141
  text-align: center;
146
142
  }
147
143
  .eyebrow {
148
- display: inline-flex;
149
- align-items: center;
150
- gap: 8px;
151
- margin-bottom: 16px;
152
- color: var(--idp-muted-fg);
153
- font-family: var(--idp-mono);
154
- font-size: 11px;
155
- letter-spacing: 0.1em;
156
- text-transform: uppercase;
144
+ margin-bottom: 6px;
145
+ color: var(--idp-accent);
146
+ font-size: 19px;
147
+ font-weight: 600;
148
+ letter-spacing: -0.01em;
157
149
  }
158
- .eyebrow::before, .eyebrow::after {
159
- content: '';
160
- width: 24px;
161
- height: 1px;
162
- background: var(--idp-border-strong);
150
+ .eyebrow.sm {
151
+ color: var(--idp-fg-3);
152
+ font-size: 12px;
153
+ font-weight: 600;
154
+ letter-spacing: 0.06em;
155
+ text-transform: uppercase;
163
156
  }
164
- h2, h3, q {
157
+ h2 {
165
158
  margin: 0;
166
159
  font-family: var(--idp-display);
167
- letter-spacing: -0.03em;
168
- }
169
- h2 {
170
160
  font-size: clamp(36px, 4.5vw, 56px);
171
- line-height: 1.05;
172
- }
173
- em {
174
- color: var(--idp-accent-hover);
175
- font-family: var(--idp-serif);
176
- font-style: italic;
177
- font-weight: 400;
161
+ font-weight: 700;
162
+ line-height: 1.07;
163
+ letter-spacing: -0.025em;
178
164
  }
179
165
  .lede {
180
- max-width: 640px;
181
- margin: 20px auto 0;
166
+ margin-top: 18px;
182
167
  color: var(--idp-fg-3);
183
- font-size: 17px;
184
- line-height: 1.55;
168
+ font-size: clamp(18px, 1.6vw, 21px);
169
+ line-height: 1.45;
185
170
  }
171
+ em {
172
+ color: var(--idp-accent);
173
+ font-style: normal;
174
+ }
175
+
176
+ /* Bento */
186
177
  .bento {
187
178
  display: grid;
188
179
  grid-template-columns: repeat(6, 1fr);
189
180
  gap: 16px;
190
181
  }
191
- .tile, .tier, .chain-panel, .terminal {
192
- border: 1px solid var(--idp-border-soft);
193
- border-radius: 12px;
194
- background: var(--idp-bg-2);
195
- }
196
182
  .tile {
197
- padding: 28px;
183
+ display: flex;
184
+ flex-direction: column;
185
+ padding: 34px;
186
+ border: 0.5px solid var(--idp-border-soft);
187
+ border-radius: 28px;
188
+ background: var(--idp-card);
189
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0, 0, 0, 0.04);
190
+ }
191
+ .tile.col-3 {
192
+ grid-column: span 3;
193
+ }
194
+ .tile.col-2 {
195
+ grid-column: span 2;
196
+ }
197
+ .tile.tall {
198
+ grid-row: span 1;
198
199
  }
199
- .tile.col-2 { grid-column: span 2; }
200
- .tile.col-3 { grid-column: span 3; }
201
- .tile.tall { grid-row: span 2; }
202
200
  .tile-tag {
203
- display: inline-flex;
204
- align-items: center;
205
- gap: 6px;
206
- margin-bottom: 14px;
201
+ margin-bottom: 10px;
207
202
  color: var(--idp-accent-hover);
208
- font-family: var(--idp-mono);
209
- font-size: 10.5px;
203
+ font-size: 13px;
210
204
  font-weight: 600;
211
- letter-spacing: 0.06em;
212
- text-transform: uppercase;
213
- }
214
- .tile-tag::before {
215
- content: '';
216
- width: 6px;
217
- height: 6px;
218
- border-radius: 999px;
219
- background: var(--idp-accent);
205
+ letter-spacing: -0.01em;
220
206
  }
221
207
  .tile h3 {
222
- margin-bottom: 10px;
223
- font-size: 24px;
224
- line-height: 1.15;
208
+ margin: 0 0 10px;
209
+ font-family: var(--idp-display);
210
+ font-size: 28px;
211
+ font-weight: 700;
212
+ line-height: 1.1;
213
+ letter-spacing: -0.025em;
225
214
  }
226
- .tile p, .tier li, .chain-step p {
215
+ .tile p {
216
+ max-width: 42ch;
217
+ margin: 0;
227
218
  color: var(--idp-fg-3);
228
- font-size: 14px;
229
- line-height: 1.55;
219
+ font-size: 16px;
220
+ line-height: 1.45;
230
221
  }
231
- .approval-stack {
232
- display: grid;
233
- gap: 6px;
222
+ .tile-visual {
234
223
  margin-top: 22px;
235
224
  }
236
- .approval-row {
237
- display: grid;
238
- grid-template-columns: 28px 1fr auto;
239
- gap: 12px;
240
- align-items: center;
241
- padding: 10px 12px;
242
- border: 1px solid var(--idp-border-soft);
243
- border-left: 2px solid var(--idp-accent);
244
- border-radius: 6px;
245
- background: var(--idp-bg);
246
- }
247
- .avatar {
248
- width: 28px;
249
- height: 28px;
250
- display: grid;
251
- place-items: center;
252
- border: 1px solid var(--idp-border);
253
- border-radius: 50%;
254
- background: var(--idp-card-2);
255
- color: var(--idp-muted-fg);
256
- font-family: var(--idp-mono);
257
- font-size: 10px;
258
- font-weight: 700;
259
- }
260
- .approval-row strong {
261
- display: block;
262
- color: var(--idp-fg);
263
- font-size: 12.5px;
225
+ .tile-foot {
226
+ margin-top: auto;
227
+ padding-top: 16px;
228
+ color: var(--idp-fg-3);
229
+ font-size: 13px;
264
230
  font-weight: 500;
265
231
  }
266
- .approval-row span.meta {
267
- color: color-mix(in srgb, var(--idp-muted-fg), transparent 30%);
268
- font-family: var(--idp-mono);
269
- font-size: 10.5px;
270
- }
271
- .identity-card {
272
- position: relative;
273
- overflow: hidden;
274
- margin-top: 22px;
275
- border: 1px solid var(--idp-border);
276
- border-radius: 10px;
277
- padding: 20px;
278
- background: linear-gradient(140deg, var(--idp-card) 0%, var(--idp-bg) 100%);
279
- }
280
- .identity-card::after {
281
- content: '';
282
- position: absolute;
283
- top: -100px;
284
- right: -80px;
285
- width: 240px;
286
- height: 240px;
287
- border-radius: 50%;
288
- background: radial-gradient(circle, rgba(0,105,242,0.4), transparent 65%);
289
- }
290
- .identity-card > * {
291
- position: relative;
292
- z-index: 1;
293
- }
294
- .chip {
295
- width: 32px;
296
- height: 24px;
297
- margin: 18px 0 14px;
298
- border-radius: 3px;
299
- background: linear-gradient(135deg, #93bbfd 0%, #0050b9 80%);
300
- }
301
- .mono {
302
- color: var(--idp-muted-fg);
303
- font-family: var(--idp-mono);
304
- font-size: 10.5px;
305
- }
306
- .metric {
307
- margin-top: 8px;
308
- background: linear-gradient(180deg, var(--idp-fg) 0%, var(--idp-muted-fg) 110%);
309
- background-clip: text;
310
- color: transparent;
232
+ .tile-metric {
233
+ margin-top: auto;
234
+ padding-top: 18px;
311
235
  font-family: var(--idp-display);
312
236
  font-size: 64px;
313
237
  font-weight: 700;
314
238
  letter-spacing: -0.04em;
315
239
  line-height: 1;
316
240
  }
317
- .metric span {
241
+ .tile-metric .unit {
242
+ margin-left: 2px;
243
+ color: var(--idp-fg-3);
318
244
  font-size: 24px;
245
+ font-weight: 600;
319
246
  }
320
247
  .devices-row {
321
248
  display: grid;
322
249
  grid-template-columns: repeat(4, 1fr);
323
- gap: 8px;
250
+ gap: 10px;
324
251
  margin-top: 22px;
325
252
  }
326
253
  .dev-cell {
327
- padding: 14px 10px;
328
- border: 1px solid var(--idp-border-soft);
329
- border-radius: 6px;
330
- background: var(--idp-bg);
254
+ padding: 16px 8px;
255
+ border: 0.5px solid var(--idp-border-soft);
256
+ border-radius: 16px;
257
+ background: var(--idp-bg-2);
331
258
  text-align: center;
332
259
  }
333
260
  .dev-icon {
334
- width: 32px;
335
- height: 32px;
336
- display: inline-flex;
337
- align-items: center;
261
+ display: flex;
338
262
  justify-content: center;
339
263
  margin-bottom: 8px;
340
- border: 1px solid rgba(96,165,250,0.35);
341
- border-radius: 9px;
342
- color: var(--idp-accent-hover);
264
+ color: var(--idp-accent);
343
265
  }
344
266
  .dev-name {
345
- color: var(--idp-fg);
346
- font-size: 12px;
347
- font-weight: 500;
267
+ font-size: 14px;
268
+ font-weight: 600;
348
269
  }
349
270
  .dev-sub {
350
- color: var(--idp-muted-fg);
351
- font-family: var(--idp-mono);
352
- font-size: 10px;
271
+ margin-top: 1px;
272
+ color: var(--idp-fg-3);
273
+ font-size: 11px;
353
274
  }
354
- .chain-grid, .dev-grid {
275
+
276
+ /* On-chain */
277
+ .chain-grid {
355
278
  display: grid;
356
- grid-template-columns: 1fr 1fr;
279
+ grid-template-columns: 1.05fr 1fr;
357
280
  gap: 48px;
358
- }
359
- .chain-steps {
360
- display: grid;
361
- gap: 28px;
281
+ align-items: start;
362
282
  }
363
283
  .chain-step {
364
284
  display: grid;
365
- grid-template-columns: 70px 1fr;
285
+ grid-template-columns: 52px 1fr;
366
286
  gap: 16px;
367
- padding-bottom: 24px;
368
- border-bottom: 1px solid var(--idp-border-soft);
287
+ padding-bottom: 26px;
369
288
  }
370
- .chain-step > div {
289
+ .chain-step + .chain-step {
290
+ border-top: 0.5px solid var(--idp-border-soft);
291
+ padding-top: 26px;
292
+ }
293
+ .chain-step .num {
294
+ padding-top: 4px;
371
295
  color: var(--idp-accent-hover);
372
- font-family: var(--idp-mono);
373
- font-size: 11px;
374
- font-weight: 600;
375
- letter-spacing: 0.08em;
296
+ font-size: 13px;
297
+ font-weight: 700;
298
+ letter-spacing: 0.02em;
299
+ }
300
+ .chain-step h4 {
301
+ margin: 0 0 6px;
302
+ font-family: var(--idp-display);
303
+ font-size: 24px;
304
+ font-weight: 700;
305
+ letter-spacing: -0.02em;
306
+ }
307
+ .chain-step p {
308
+ margin: 0;
309
+ color: var(--idp-fg-3);
310
+ font-size: 16px;
311
+ line-height: 1.5;
376
312
  }
377
313
  .chain-panel {
378
314
  overflow: hidden;
379
- background: var(--idp-bg);
315
+ border: 0.5px solid var(--idp-border-soft);
316
+ border-radius: 22px;
317
+ background: var(--idp-bg-2);
318
+ box-shadow: 0 10px 30px -14px rgba(0, 0, 0, 0.12);
380
319
  }
381
- .chain-head {
320
+ .chain-panel-head {
382
321
  display: flex;
322
+ align-items: center;
383
323
  justify-content: space-between;
384
- padding: 14px 18px;
385
- border-bottom: 1px solid var(--idp-border-soft);
386
- color: var(--idp-muted-fg);
387
- font-family: var(--idp-mono);
388
- font-size: 11px;
389
- letter-spacing: 0.08em;
324
+ padding: 16px 18px;
325
+ border-bottom: 0.5px solid var(--idp-border-soft);
326
+ }
327
+ .chain-panel-head .ttl {
328
+ color: var(--idp-fg-3);
329
+ font-size: 12px;
330
+ font-weight: 600;
331
+ letter-spacing: 0.04em;
390
332
  text-transform: uppercase;
391
333
  }
392
334
  .chain-block {
393
- display: grid;
394
- grid-template-columns: auto 1fr auto;
335
+ display: flex;
336
+ align-items: center;
395
337
  gap: 12px;
396
- margin: 8px 14px;
397
- padding: 14px 16px;
398
- border: 1px solid var(--idp-border-soft);
399
- border-radius: 8px;
400
- color: var(--idp-muted-fg);
338
+ padding: 12px 18px;
401
339
  font-family: var(--idp-mono);
402
- font-size: 11px;
340
+ font-size: 12px;
341
+ }
342
+ .chain-block + .chain-block {
343
+ border-top: 0.5px solid var(--idp-border-soft);
403
344
  }
404
- .chain-block.idp {
405
- border-left: 2px solid var(--idp-accent);
345
+ .chain-block.is-idp {
406
346
  background: var(--idp-accent-soft);
407
347
  }
348
+ .blk-num {
349
+ width: 88px;
350
+ flex-shrink: 0;
351
+ color: var(--idp-fg-3);
352
+ }
353
+ .blk-hash {
354
+ flex: 1;
355
+ min-width: 0;
356
+ display: inline-flex;
357
+ align-items: center;
358
+ gap: 6px;
359
+ color: var(--idp-fg);
360
+ }
361
+ .blk-tag {
362
+ padding: 2px 8px;
363
+ border-radius: var(--idp-radius-pill);
364
+ font-family: var(--idp-font);
365
+ font-size: 10px;
366
+ font-weight: 700;
367
+ }
368
+ .blk-tag.cnf {
369
+ background: var(--idp-ok-bg);
370
+ color: var(--idp-ok);
371
+ }
372
+ .blk-tag.idp {
373
+ background: var(--idp-accent-soft);
374
+ color: var(--idp-accent-hover);
375
+ }
376
+ .chain-foot {
377
+ padding: 20px;
378
+ border-top: 0.5px solid var(--idp-border-soft);
379
+ background: var(--idp-card);
380
+ }
381
+ .chain-foot .lab {
382
+ margin-bottom: 8px;
383
+ color: var(--idp-accent-hover);
384
+ font-size: 11px;
385
+ font-weight: 600;
386
+ letter-spacing: 0.04em;
387
+ text-transform: uppercase;
388
+ }
389
+ .chain-foot .quote {
390
+ color: var(--idp-fg);
391
+ font-size: 18px;
392
+ font-weight: 500;
393
+ line-height: 1.5;
394
+ letter-spacing: -0.01em;
395
+ }
396
+
397
+ /* Pricing */
408
398
  .tiers {
409
399
  display: grid;
410
400
  grid-template-columns: repeat(3, 1fr);
411
- gap: 16px;
401
+ gap: 20px;
402
+ align-items: start;
412
403
  }
413
404
  .tier {
414
405
  position: relative;
415
- display: flex;
416
- flex-direction: column;
417
- padding: 28px;
406
+ padding: 34px 30px;
407
+ border: 0.5px solid var(--idp-border-soft);
408
+ border-radius: 24px;
409
+ background: var(--idp-card);
410
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.05);
418
411
  }
419
412
  .tier.featured {
420
- border-color: var(--idp-accent);
421
- background: linear-gradient(180deg, var(--idp-accent-soft) 0%, var(--idp-bg-2) 40%);
413
+ border: 1.5px solid var(--idp-accent);
414
+ box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.22);
415
+ }
416
+ .tier-ribbon {
417
+ position: absolute;
418
+ top: -12px;
419
+ left: 30px;
420
+ padding: 4px 12px;
421
+ border-radius: var(--idp-radius-pill);
422
+ background: var(--idp-accent);
423
+ color: var(--idp-accent-fg);
424
+ font-size: 12px;
425
+ font-weight: 600;
422
426
  }
423
427
  .tier-name {
424
- margin-bottom: 10px;
425
- color: var(--idp-muted-fg);
426
- font-family: var(--idp-mono);
427
- font-size: 11px;
428
- letter-spacing: 0.08em;
429
- text-transform: uppercase;
428
+ color: var(--idp-accent-hover);
429
+ font-size: 13px;
430
+ font-weight: 600;
431
+ letter-spacing: -0.01em;
432
+ }
433
+ .tier h3 {
434
+ margin: 6px 0 18px;
435
+ font-family: var(--idp-display);
436
+ font-size: 24px;
437
+ font-weight: 700;
438
+ letter-spacing: -0.02em;
430
439
  }
431
440
  .price {
432
- margin: 12px 0 20px;
433
441
  font-family: var(--idp-display);
434
- font-size: 40px;
442
+ font-size: 48px;
435
443
  font-weight: 700;
444
+ letter-spacing: -0.04em;
436
445
  }
437
- .tier ul {
438
- flex: 1;
439
- margin: 0 0 24px;
440
- padding-left: 20px;
446
+ .price .sub {
447
+ color: var(--idp-fg-3);
448
+ font-size: 15px;
449
+ font-weight: 500;
450
+ letter-spacing: -0.01em;
451
+ }
452
+ .price-note {
453
+ margin: 6px 0 20px;
454
+ color: var(--idp-fg-3);
455
+ font-size: 13px;
456
+ }
457
+ .tier-list {
458
+ list-style: none;
459
+ display: flex;
460
+ flex-direction: column;
461
+ gap: 11px;
462
+ margin: 0 0 26px;
463
+ padding: 0;
464
+ }
465
+ .tier-list li {
466
+ position: relative;
467
+ padding-left: 26px;
468
+ color: var(--idp-fg-3);
469
+ font-size: 15px;
470
+ line-height: 1.4;
471
+ }
472
+ .tier-list li::before {
473
+ content: '';
474
+ position: absolute;
475
+ left: 0;
476
+ top: 5px;
477
+ width: 16px;
478
+ height: 16px;
479
+ border-radius: 50%;
480
+ background: var(--idp-ok);
481
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/13px no-repeat;
482
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/13px no-repeat;
483
+ }
484
+ .tier idp-button {
485
+ display: block;
486
+ }
487
+ .tier idp-button::part(button) {
488
+ width: 100%;
489
+ }
490
+
491
+ /* Developers */
492
+ .dev-grid {
493
+ display: grid;
494
+ grid-template-columns: 1fr 1.05fr;
495
+ gap: 56px;
496
+ align-items: center;
497
+ }
498
+ .dev-text h3 {
499
+ margin: 0 0 16px;
500
+ font-family: var(--idp-display);
501
+ font-size: clamp(30px, 3.4vw, 42px);
502
+ font-weight: 700;
503
+ line-height: 1.1;
504
+ letter-spacing: -0.025em;
441
505
  }
442
506
  .dev-text p {
507
+ max-width: 46ch;
508
+ margin: 0 0 14px;
443
509
  color: var(--idp-fg-3);
510
+ font-size: 17px;
511
+ line-height: 1.5;
444
512
  }
445
- .tags {
513
+ .dev-tags {
446
514
  display: flex;
447
515
  flex-wrap: wrap;
448
- gap: 6px;
449
- margin: 18px 0 22px;
516
+ gap: 8px;
517
+ margin: 22px 0 26px;
450
518
  }
451
- .tags span {
452
- padding: 4px 10px;
453
- border: 1px solid var(--idp-border);
454
- border-radius: 999px;
519
+ .dev-tag {
520
+ padding: 5px 12px;
521
+ border: 0.5px solid var(--idp-border-soft);
522
+ border-radius: var(--idp-radius-pill);
455
523
  background: var(--idp-bg-2);
456
524
  color: var(--idp-fg-3);
457
- font-family: var(--idp-mono);
458
- font-size: 10.5px;
525
+ font-size: 12px;
526
+ font-weight: 500;
527
+ white-space: nowrap;
528
+ }
529
+ .dev-actions {
530
+ display: flex;
531
+ gap: 18px;
532
+ flex-wrap: wrap;
533
+ align-items: center;
459
534
  }
460
535
  .terminal {
461
536
  overflow: hidden;
462
- background: var(--idp-bg);
537
+ border: 0.5px solid rgba(255, 255, 255, 0.08);
538
+ border-radius: 18px;
539
+ background: var(--idp-term-bg);
540
+ box-shadow: 0 30px 70px -24px rgba(0, 0, 0, 0.45);
463
541
  }
464
542
  .term-bar {
465
543
  display: flex;
466
- gap: 6px;
467
- padding: 10px 14px;
468
- border-bottom: 1px solid var(--idp-border-soft);
544
+ align-items: center;
545
+ gap: 8px;
546
+ padding: 12px 14px;
547
+ border-bottom: 0.5px solid rgba(255, 255, 255, 0.08);
548
+ background: rgba(255, 255, 255, 0.04);
469
549
  }
470
550
  .tdot {
471
- width: 11px;
472
- height: 11px;
551
+ width: 12px;
552
+ height: 12px;
473
553
  border-radius: 50%;
474
554
  }
475
- .red { background: #ff5f57; }
476
- .yellow { background: #ffbd2e; }
477
- .green { background: #28c840; }
478
- pre {
479
- min-height: 300px;
480
- margin: 0;
481
- padding: 22px 24px;
482
- color: var(--idp-fg-3);
555
+ .term-bar .name {
556
+ margin-left: 8px;
557
+ color: rgba(255, 255, 255, 0.5);
558
+ font-family: var(--idp-mono);
559
+ font-size: 11px;
560
+ }
561
+ .term-bar .shell {
562
+ margin-left: auto;
563
+ color: rgba(255, 255, 255, 0.35);
564
+ font-family: var(--idp-mono);
565
+ font-size: 10px;
566
+ }
567
+ .term-body {
568
+ padding: 20px;
569
+ color: rgba(255, 255, 255, 0.85);
483
570
  font-family: var(--idp-mono);
484
571
  font-size: 13px;
485
572
  line-height: 1.85;
486
573
  }
487
- .manifesto, .cta {
488
- padding: 120px 0;
574
+ .t-dim {
575
+ color: rgba(255, 255, 255, 0.4);
576
+ }
577
+ .t-acc {
578
+ color: #6cb6ff;
579
+ }
580
+ .t-w {
581
+ color: #fff;
582
+ }
583
+ .t-ok {
584
+ color: #41d97e;
585
+ }
586
+ .t-am {
587
+ color: #ffb340;
588
+ }
589
+ .t-cur {
590
+ display: inline-block;
591
+ width: 8px;
592
+ height: 15px;
593
+ background: #6cb6ff;
594
+ vertical-align: -2px;
595
+ animation: blink 1.1s steps(1) infinite;
596
+ }
597
+ @keyframes blink {
598
+ 50% {
599
+ opacity: 0;
600
+ }
601
+ }
602
+
603
+ /* Manifesto */
604
+ .manifesto {
605
+ padding: 130px 0;
606
+ background: var(--idp-bg);
489
607
  text-align: center;
490
608
  }
491
- q {
609
+ .manifesto q {
492
610
  display: block;
493
- max-width: 980px;
611
+ max-width: 16ch;
494
612
  margin: 0 auto;
495
- font-family: var(--idp-serif);
496
- font-size: clamp(32px, 4vw, 48px);
497
- font-style: italic;
498
- line-height: 1.2;
613
+ font-family: var(--idp-display);
614
+ font-size: clamp(28px, 3.6vw, 46px);
615
+ font-weight: 600;
616
+ line-height: 1.18;
617
+ letter-spacing: -0.025em;
499
618
  quotes: none;
500
619
  }
501
- q::before, q::after {
620
+ .manifesto q::before,
621
+ .manifesto q::after {
502
622
  content: none;
503
623
  }
624
+ .manifesto-cite {
625
+ margin-top: 28px;
626
+ color: var(--idp-fg-3);
627
+ font-size: 14px;
628
+ }
629
+
630
+ /* CTA */
504
631
  .cta {
505
- position: relative;
506
- overflow: hidden;
632
+ padding: 130px 0;
633
+ text-align: center;
507
634
  }
508
- .cta::before {
509
- content: '';
510
- position: absolute;
511
- left: 50%;
512
- top: 50%;
513
- width: 800px;
514
- height: 600px;
515
- transform: translate(-50%, -50%);
516
- background: radial-gradient(ellipse, rgba(59,130,246,0.15) 0%, transparent 60%);
517
- }
518
- .cta .wrap {
519
- position: relative;
635
+ .cta h2 {
636
+ font-size: clamp(40px, 5vw, 64px);
637
+ line-height: 1.05;
520
638
  }
521
639
  .cta p {
522
640
  max-width: 560px;
523
- margin: 24px auto 32px;
641
+ margin: 20px auto 32px;
524
642
  color: var(--idp-fg-3);
643
+ font-size: 19px;
644
+ line-height: 1.45;
645
+ }
646
+ .cta-actions {
647
+ display: flex;
648
+ gap: 26px;
649
+ flex-wrap: wrap;
650
+ align-items: center;
651
+ justify-content: center;
525
652
  }
653
+
654
+ /* Footer */
526
655
  footer {
527
- padding: 64px 0 28px;
528
- border-bottom: 0;
656
+ padding: 48px 0 36px;
657
+ border-top: 0.5px solid var(--idp-border-soft);
658
+ background: var(--idp-bg);
659
+ color: var(--idp-fg-3);
660
+ font-size: 12px;
529
661
  }
530
662
  .footer-cols {
531
663
  display: grid;
532
664
  grid-template-columns: 2fr 1fr 1fr 1fr;
533
- gap: 48px;
534
- margin-bottom: 48px;
665
+ gap: 32px;
666
+ padding-bottom: 32px;
535
667
  }
536
- .footer-brand p, .footer-col a, .footer-bottom {
537
- color: var(--idp-muted-fg);
668
+ .footer-brand p {
669
+ max-width: 36ch;
670
+ margin: 14px 0;
671
+ color: var(--idp-fg-3);
538
672
  font-size: 13px;
673
+ line-height: 1.5;
539
674
  }
540
- .footer-col {
541
- display: grid;
542
- gap: 9px;
675
+ .footer-status {
676
+ display: inline-flex;
677
+ align-items: center;
678
+ gap: 7px;
679
+ color: var(--idp-fg-3);
680
+ font-size: 12px;
543
681
  }
544
682
  .footer-col h4 {
683
+ margin: 0 0 12px;
684
+ color: var(--idp-fg);
685
+ font-size: 12px;
686
+ font-weight: 600;
687
+ }
688
+ .footer-col ul {
689
+ list-style: none;
690
+ display: flex;
691
+ flex-direction: column;
692
+ gap: 9px;
545
693
  margin: 0;
694
+ padding: 0;
695
+ }
696
+ .footer-col a {
546
697
  color: var(--idp-fg-3);
547
- font-family: var(--idp-mono);
548
- font-size: 11px;
549
- letter-spacing: 0.1em;
550
- text-transform: uppercase;
698
+ text-decoration: none;
699
+ cursor: pointer;
700
+ }
701
+ .footer-col a:hover {
702
+ color: var(--idp-fg);
551
703
  }
552
704
  .footer-bottom {
553
705
  display: flex;
706
+ align-items: center;
554
707
  justify-content: space-between;
555
- padding-top: 22px;
556
- border-top: 1px solid var(--idp-border-soft);
557
- font-family: var(--idp-mono);
558
- font-size: 11px;
708
+ gap: 12px;
709
+ padding-top: 24px;
710
+ border-top: 0.5px solid var(--idp-border-soft);
711
+ flex-wrap: wrap;
712
+ }
713
+ .footer-bottom .links {
714
+ display: flex;
715
+ gap: 18px;
716
+ }
717
+ .footer-bottom .links a {
718
+ color: var(--idp-fg-3);
719
+ text-decoration: none;
720
+ cursor: pointer;
721
+ }
722
+ .footer-bottom .links a:hover {
723
+ color: var(--idp-fg);
724
+ }
725
+
726
+ .live-dot {
727
+ width: 7px;
728
+ height: 7px;
729
+ border-radius: 50%;
730
+ background: var(--idp-ok);
731
+ display: inline-block;
559
732
  }
560
- @media (max-width: 1100px) {
561
- .links { display: none; }
562
- .bento { grid-template-columns: repeat(2, 1fr); }
563
- .tile.col-2, .tile.col-3 { grid-column: span 2; }
564
- .chain-grid, .dev-grid { grid-template-columns: 1fr; }
565
- .tiers { grid-template-columns: 1fr; max-width: 520px; margin: 0 auto; }
566
- .footer-cols { grid-template-columns: 1fr 1fr; }
567
- }
568
- @media (max-width: 720px) {
569
- nav, .wrap { padding-left: 20px; padding-right: 20px; }
570
- .status, .actions .ghost { display: none; }
571
- .proof-row { grid-template-columns: repeat(2, 1fr); }
572
- .bento { grid-template-columns: 1fr; }
573
- .tile.col-2, .tile.col-3 { grid-column: span 1; }
574
- .section, .manifesto, .cta { padding: 80px 0; }
575
- .footer-cols { grid-template-columns: 1fr; }
733
+
734
+ @media (max-width: 940px) {
735
+ .nav-links {
736
+ display: none;
737
+ }
738
+ .bento {
739
+ grid-template-columns: 1fr;
740
+ }
741
+ .tile.col-3,
742
+ .tile.col-2 {
743
+ grid-column: span 1;
744
+ }
745
+ .chain-grid,
746
+ .dev-grid,
747
+ .tiers {
748
+ grid-template-columns: 1fr;
749
+ }
750
+ .footer-cols {
751
+ grid-template-columns: 1fr 1fr;
752
+ }
753
+ }
754
+ @media (max-width: 640px) {
755
+ .section {
756
+ padding: 80px 0;
757
+ }
758
+ .manifesto,
759
+ .cta {
760
+ padding: 90px 0;
761
+ }
762
+ .footer-cols {
763
+ grid-template-columns: 1fr;
764
+ }
576
765
  }
577
766
  `,
578
767
  ];
@@ -581,31 +770,127 @@ export class IdpLandingPage extends DeesElement {
581
770
  return html`
582
771
  <div class="nav-shell">
583
772
  <nav>
584
- <div class="logo">idp<span class="logo-dot"></span>global</div>
585
- <div class="links"><a href="#product">Product</a><a href="#features">Features</a><a href="#chain">On-chain</a><a href="#pricing">Pricing</a><a href="#developers">Developers</a></div>
586
- <div class="actions"><span class="status"><span class="live-dot"></span>All systems normal</span><idp-button variant="ghost" size="sm">Sign in</idp-button><idp-button variant="accent" size="sm">Claim identity</idp-button></div>
773
+ <a class="logo" href="#">idp<span class="logo-dot"></span>global</a>
774
+ <div class="nav-links">
775
+ <a href="#product">Product</a>
776
+ <a href="#features">Features</a>
777
+ <a href="#chain">On-chain</a>
778
+ <a href="#pricing">Pricing</a>
779
+ <a href="#developers">Developers</a>
780
+ </div>
781
+ <div class="actions">
782
+ <a class="nav-signin">Sign in</a>
783
+ <idp-button variant="accent" size="sm">Claim identity</idp-button>
784
+ </div>
587
785
  </nav>
588
786
  </div>
589
787
  `;
590
788
  }
591
789
 
790
+ private renderProof() {
791
+ const names = ['Lossless', 'design.estate', 'Holopin', 'Cardano', 'Spotter', 'Catalyst'];
792
+ return html`
793
+ <section class="proof">
794
+ <div class="wrap-wide">
795
+ <div class="proof-label">Trusted by teams shipping identity at every scale</div>
796
+ <div class="proof-row">${names.map((nameArg) => html`<div class="proof-name">${nameArg}</div>`)}</div>
797
+ </div>
798
+ </section>
799
+ `;
800
+ }
801
+
592
802
  private renderFeatures() {
803
+ const devices = [
804
+ ['iPhone', 'lucide:smartphone', 'Push · NFC'],
805
+ ['Watch', 'lucide:watch', '⌘↩ approve'],
806
+ ['iPad', 'lucide:tablet', 'Split-view'],
807
+ ['Mac', 'lucide:laptop', 'Menu-bar'],
808
+ ];
593
809
  return html`
594
- <section class="section" id="features">
595
- <div class="wrap">
596
- <div class="section-head"><div class="eyebrow">Capabilities</div><h2>Native on every screen <em>you already carry.</em></h2><p class="lede">Approvals on iPhone. Tap-to-auth via NFC. Lock-screen actions on Apple Watch. The same identity, one tap away on any device.</p></div>
810
+ <section class="section alt" id="features">
811
+ <div class="wrap-wide">
812
+ <div class="section-head">
813
+ <div class="eyebrow">Capabilities</div>
814
+ <h2>Native on every screen you already carry.</h2>
815
+ <p class="lede">
816
+ Approvals on iPhone. Tap-to-auth via NFC. Lock-screen actions on Apple Watch. The same identity, one tap
817
+ away on any device.
818
+ </p>
819
+ </div>
597
820
  <div class="bento">
598
- <div class="tile col-3 tall"><div class="tile-tag">Push approvals</div><h3>Approve or deny <em>in one tap.</em></h3><p>Every login, OAuth grant, and sensitive action triggers a real-time approval.</p><div class="approval-stack">${['GitHub OAuth|repo:read - 2 min ago|approved|ok', 'CLI login - MacBook Pro|Berlin - just now|pending|accent', 'Unknown device|Lagos - 1 hr ago|denied|error', 'NFC tap - door 4F|HQ - 12 min ago|approved|ok'].map((rowArg) => { const row = rowArg.split('|'); return html`<div class="approval-row"><div class="avatar">${row[0].slice(0,2).toUpperCase()}</div><div><strong>${row[0]}</strong><span class="meta">${row[1]}</span></div><idp-badge variant=${row[3] as any}>${row[2]}</idp-badge></div>`; })}</div></div>
599
- <div class="tile col-3"><div class="tile-tag">NFC tap-to-auth</div><h3>Tap to <em>authenticate.</em></h3><p>Hold your phone to any compatible reader. Identity token exchanges in under a second.</p><div class="identity-card"><h3>Alex Mercer</h3><div class="mono">@alexmercer - Personal</div><div class="chip"></div><div class="mono">did:idp:0x4a3f...c819</div></div></div>
600
- <div class="tile col-3"><div class="tile-tag">Four platforms</div><h3>iPhone, Watch, iPad, Mac.</h3><p>Every device you carry is a trusted authenticator.</p><div class="devices-row">${[
601
- ['iPhone', 'phone'],
602
- ['Watch', 'smartphone-nfc'],
603
- ['iPad', 'device'],
604
- ['Mac', 'monitor'],
605
- ].map((deviceArg) => html`<div class="dev-cell"><div class="dev-icon"><idp-icon name=${deviceArg[1] as any} size="18"></idp-icon></div><div class="dev-name">${deviceArg[0]}</div><div class="dev-sub">trusted</div></div>`)}</div><div class="mono" style="margin-top:14px">One approval, anywhere - synchronized end-to-end.</div></div>
606
- <div class="tile col-2"><div class="tile-tag">Average approval</div><h3>Sub-second auth.</h3><p>Push delivery, biometric prompt, and signed response under a second.</p><div class="metric">0.8<span>sec</span></div></div>
607
- <div class="tile col-2"><div class="tile-tag">Audit-grade</div><h3>Every action, <em>on the record.</em></h3><p>Tamper-evident audit trail per identity and organization.</p></div>
608
- <div class="tile col-2"><div class="tile-tag">Recovery</div><h3>Lose a phone? Not your identity.</h3><p>Multi-device recovery or social-recovery quorum. No vendor lockout.</p></div>
821
+ <div class="tile col-3 tall">
822
+ <div class="tile-tag">Push approvals</div>
823
+ <h3>Approve or deny in one tap.</h3>
824
+ <p>
825
+ Every login, OAuth grant, and sensitive action triggers a real-time approval. Full context — who, where,
826
+ why — before you decide.
827
+ </p>
828
+ <div class="tile-visual">
829
+ <idp-screenshot-placeholder
830
+ variant="tile"
831
+ label="Approval inbox"
832
+ meta="push approval list UI"
833
+ ></idp-screenshot-placeholder>
834
+ </div>
835
+ </div>
836
+
837
+ <div class="tile col-3">
838
+ <div class="tile-tag">NFC tap-to-auth</div>
839
+ <h3>Tap to authenticate.</h3>
840
+ <p>
841
+ Hold your iPhone to any compatible reader. Identity token exchanges in under a second, signed by your
842
+ on-device key.
843
+ </p>
844
+ <div class="tile-visual">
845
+ <idp-screenshot-placeholder
846
+ variant="tile-short"
847
+ label="Identity card"
848
+ meta="NFC tap-to-auth credential"
849
+ ></idp-screenshot-placeholder>
850
+ </div>
851
+ </div>
852
+
853
+ <div class="tile col-3">
854
+ <div class="tile-tag">Four platforms</div>
855
+ <h3>iPhone, Watch, iPad, Mac.</h3>
856
+ <p>
857
+ Every device you carry is a trusted authenticator. Approve from a complication on your wrist or a popover
858
+ in your menu bar.
859
+ </p>
860
+ <div class="devices-row">
861
+ ${devices.map(
862
+ (deviceArg) => html`
863
+ <div class="dev-cell">
864
+ <div class="dev-icon"><idp-icon name=${deviceArg[1] as any} .size=${22}></idp-icon></div>
865
+ <div class="dev-name">${deviceArg[0]}</div>
866
+ <div class="dev-sub">${deviceArg[2]}</div>
867
+ </div>
868
+ `,
869
+ )}
870
+ </div>
871
+ <div class="tile-foot">One approval, anywhere — synchronised end-to-end.</div>
872
+ </div>
873
+
874
+ <div class="tile col-2">
875
+ <div class="tile-tag">Average approval</div>
876
+ <h3>Sub-second auth.</h3>
877
+ <p>Push delivery, biometric prompt, and signed response — under a second, ninety-fifth percentile.</p>
878
+ <div class="tile-metric">0.8<span class="unit">sec</span></div>
879
+ </div>
880
+
881
+ <div class="tile col-2">
882
+ <div class="tile-tag">Audit-grade</div>
883
+ <h3>Every action, on the record.</h3>
884
+ <p>Tamper-evident audit trail per identity, per org. Filter, export, and replay. Cryptographically signed.</p>
885
+ <div class="tile-foot">SOC 2 · ISO 27001 · GDPR-aligned</div>
886
+ </div>
887
+
888
+ <div class="tile col-2">
889
+ <div class="tile-tag">Recovery</div>
890
+ <h3>Lose a phone? Not your identity.</h3>
891
+ <p>Multi-device recovery via your other authenticators or a social-recovery quorum. The Cardano ledger is your safety net.</p>
892
+ <div class="tile-foot">No vendor can lock you out.</div>
893
+ </div>
609
894
  </div>
610
895
  </div>
611
896
  </section>
@@ -613,29 +898,284 @@ export class IdpLandingPage extends DeesElement {
613
898
  }
614
899
 
615
900
  private renderChain() {
901
+ const steps = [
902
+ [
903
+ '01 / 03',
904
+ 'Immutable record',
905
+ 'Your identity hash is written to Cardano at creation and on every key rotation. The ledger is tamper-proof by design and replicated across thousands of nodes.',
906
+ ],
907
+ [
908
+ '02 / 03',
909
+ 'Synced on every change',
910
+ 'Profile updates, device additions, and revocations are anchored to the chain — not just stored on idp.global servers. The chain is the source of truth.',
911
+ ],
912
+ [
913
+ '03 / 03',
914
+ 'Independently verifiable',
915
+ 'Anyone — any wallet, any resolver, any client — can verify your identity directly against the public ledger. No dependency on us.',
916
+ ],
917
+ ];
616
918
  return html`
617
- <section class="section alt" id="chain"><div class="wrap"><div class="section-head"><div class="eyebrow">Cardano-anchored</div><h2>Your identity outlives <em>any single server.</em></h2><p class="lede">Every identity is anchored to the Cardano mainnet, independently verifiable and recoverable.</p></div><div class="chain-grid"><div class="chain-steps">${[['01 / 03', 'Immutable record', 'Your identity hash is written to Cardano at creation and on every key rotation.'], ['02 / 03', 'Synced on every change', 'Profile updates, device additions, and revocations are anchored to the chain.'], ['03 / 03', 'Independently verifiable', 'Any compatible resolver can verify your identity directly against the public ledger.']].map((stepArg) => html`<div class="chain-step"><div>${stepArg[0]}</div><section><h3>${stepArg[1]}</h3><p>${stepArg[2]}</p></section></div>`)}</div><div class="chain-panel"><div class="chain-head"><span>Cardano mainnet</span><idp-badge variant="accent">live</idp-badge></div>${['#9 841 220', '#9 841 221', '#9 841 222', '#9 841 223'].map((blockArg, indexArg) => html`<div class="chain-block ${indexArg === 1 || indexArg === 2 ? 'idp' : ''}"><span>${blockArg}</span><span>${indexArg === 1 ? 'did:idp:0x4a3f...c819' : indexArg === 2 ? 'did:idp:0x9b12...f034' : 'confirmed block'}</span><strong>${indexArg === 1 || indexArg === 2 ? 'idp.global' : 'confirmed'}</strong></div>`)}</div></div></div></section>
919
+ <section class="section" id="chain">
920
+ <div class="wrap-wide">
921
+ <div class="section-head">
922
+ <div class="eyebrow">Cardano-anchored</div>
923
+ <h2>Your identity outlives any single server.</h2>
924
+ <p class="lede">
925
+ Every identity is anchored to the Cardano mainnet — independently verifiable, independently recoverable,
926
+ immune to a single point of failure.
927
+ </p>
928
+ </div>
929
+ <div class="chain-grid">
930
+ <div>
931
+ ${steps.map(
932
+ (stepArg) => html`
933
+ <div class="chain-step">
934
+ <div class="num">${stepArg[0]}</div>
935
+ <div><h4>${stepArg[1]}</h4><p>${stepArg[2]}</p></div>
936
+ </div>
937
+ `,
938
+ )}
939
+ </div>
940
+ <div class="chain-panel">
941
+ <div class="chain-panel-head">
942
+ <span class="ttl">Cardano mainnet</span>
943
+ <idp-badge variant="accent"><span class="live-dot"></span>block #9 841 223</idp-badge>
944
+ </div>
945
+ <div style="padding: 6px 0;">
946
+ <div class="chain-block">
947
+ <span class="blk-num">#9 841 220</span><span class="blk-hash">a3f8d2c19…4e712b</span
948
+ ><span class="blk-tag cnf">confirmed</span>
949
+ </div>
950
+ <div class="chain-block is-idp">
951
+ <span class="blk-num">#9 841 221</span>
952
+ <span class="blk-hash">did:idp:0x4a3f…c819 <idp-badge variant="accent">key rotation</idp-badge></span>
953
+ <span class="blk-tag idp">idp.global</span>
954
+ </div>
955
+ <div class="chain-block is-idp">
956
+ <span class="blk-num">#9 841 222</span>
957
+ <span class="blk-hash">did:idp:0x9b12…f034 <idp-badge variant="accent">identity created</idp-badge></span>
958
+ <span class="blk-tag idp">idp.global</span>
959
+ </div>
960
+ <div class="chain-block">
961
+ <span class="blk-num">#9 841 223</span><span class="blk-hash">e7c412a88…91d3f</span
962
+ ><span class="blk-tag cnf">confirmed</span>
963
+ </div>
964
+ </div>
965
+ <div class="chain-foot">
966
+ <div class="lab">If we disappear?</div>
967
+ <div class="quote">
968
+ Your identity record stays on Cardano. Any compatible resolver can verify and recover it. There is no
969
+ lock-in.
970
+ </div>
971
+ </div>
972
+ </div>
973
+ </div>
974
+ </div>
975
+ </section>
618
976
  `;
619
977
  }
620
978
 
621
979
  private renderPricing() {
622
980
  const tiers = [
623
- ['Personal', 'For one person.', '$0', ['One portable identity', 'Push approval on devices', 'NFC tap-to-authenticate', 'Anchored on Cardano'], 'Claim your identity'],
624
- ['Family & Org', 'For teams under 1,000.', '$0', ['Multi-member organization', 'Role-based access control', 'Shared OAuth client registry', 'Full audit trail'], 'Start an organization'],
625
- ['Enterprise', 'Above $1M ARR.', 'Fair', ['Self-hosted and air-gap deployable', 'Compliance and audit support', 'Global admin across orgs', 'Priority SLA'], 'Talk to us'],
981
+ {
982
+ name: 'Personal',
983
+ headline: 'For one person.',
984
+ price: '$0',
985
+ sub: ' / forever',
986
+ note: 'No credit card. No upgrades. Yours.',
987
+ items: [
988
+ 'One portable identity across every service',
989
+ 'Push approval on iPhone, Watch, iPad, Mac',
990
+ 'NFC tap-to-authenticate',
991
+ 'Anchored on Cardano permanently',
992
+ 'Recovery via your other devices',
993
+ ],
994
+ cta: 'Claim your identity',
995
+ variant: 'tint',
996
+ featured: false,
997
+ },
998
+ {
999
+ name: 'Family & Org',
1000
+ headline: 'For teams under 1,000.',
1001
+ price: '$0',
1002
+ sub: ' / up to 1k users',
1003
+ note: 'Households, hobby projects, growing teams.',
1004
+ items: [
1005
+ 'Multi-member organisation with shared namespace',
1006
+ 'Role-based access control & delegated permissions',
1007
+ 'Shared OAuth client registry',
1008
+ 'Full audit trail per organisation',
1009
+ 'SSO & SCIM included, no upsell',
1010
+ ],
1011
+ cta: 'Start an organisation',
1012
+ variant: 'accent',
1013
+ featured: true,
1014
+ },
1015
+ {
1016
+ name: 'Enterprise',
1017
+ headline: 'Above $1M ARR.',
1018
+ price: 'Fair',
1019
+ sub: ' contribution',
1020
+ note: 'Free until your org passes one million ARR.',
1021
+ items: [
1022
+ 'Self-hosted & air-gap deployable',
1023
+ 'Compliance & audit support (SOC 2, ISO 27001)',
1024
+ 'Global admin across orgs',
1025
+ 'Identity recovery service for end users',
1026
+ 'Priority engineering & SLA',
1027
+ ],
1028
+ cta: 'Talk to us',
1029
+ variant: 'tint',
1030
+ featured: false,
1031
+ },
626
1032
  ];
627
- return html`<section class="section" id="pricing"><div class="wrap"><div class="section-head"><div class="eyebrow">Pricing</div><h2>The same identity, <em>at every scale.</em></h2><p class="lede">Free for the first thousand users. Fair contribution above that. No hard paywalls.</p></div><div class="tiers">${tiers.map((tierArg, indexArg) => html`<div class="tier ${indexArg === 1 ? 'featured' : ''}"><div class="tier-name">${tierArg[0]}</div><h3>${tierArg[1]}</h3><div class="price">${tierArg[2]}</div><ul>${(tierArg[3] as string[]).map((itemArg) => html`<li>${itemArg}</li>`)}</ul><idp-button variant=${indexArg === 1 ? 'accent' : 'ghost'}>${tierArg[4]}</idp-button></div>`)}</div></div></section>`;
1033
+ return html`
1034
+ <section class="section alt" id="pricing">
1035
+ <div class="wrap-wide">
1036
+ <div class="section-head">
1037
+ <div class="eyebrow">Pricing</div>
1038
+ <h2>The same identity, at every scale.</h2>
1039
+ <p class="lede">
1040
+ From a solo developer to a thirty-thousand-person enterprise. Free for the first thousand users. Fair
1041
+ contribution above that. No hard paywalls.
1042
+ </p>
1043
+ </div>
1044
+ <div class="tiers">
1045
+ ${tiers.map(
1046
+ (tierArg) => html`
1047
+ <div class="tier ${tierArg.featured ? 'featured' : ''}">
1048
+ ${tierArg.featured ? html`<div class="tier-ribbon">Most popular</div>` : html``}
1049
+ <div class="tier-name">${tierArg.name}</div>
1050
+ <h3>${tierArg.headline}</h3>
1051
+ <div class="price">${tierArg.price}<span class="sub">${tierArg.sub}</span></div>
1052
+ <div class="price-note">${tierArg.note}</div>
1053
+ <ul class="tier-list">${tierArg.items.map((itemArg) => html`<li>${itemArg}</li>`)}</ul>
1054
+ <idp-button variant=${tierArg.variant as any}>${tierArg.cta}</idp-button>
1055
+ </div>
1056
+ `,
1057
+ )}
1058
+ </div>
1059
+ </div>
1060
+ </section>
1061
+ `;
628
1062
  }
629
1063
 
630
1064
  private renderDevelopers() {
1065
+ const tags = ['MIT licensed', 'OAuth 2 / OIDC', 'Self-hostable', 'Air-gappable', 'Cardano native', 'SOC 2'];
1066
+ return html`
1067
+ <section class="section" id="developers">
1068
+ <div class="wrap-wide">
1069
+ <div class="dev-grid">
1070
+ <div class="dev-text">
1071
+ <div class="eyebrow">For developers</div>
1072
+ <h3>No black boxes in your identity stack.</h3>
1073
+ <p>
1074
+ idp.global is fully open source and MIT licensed. Read the cryptography. Verify the Cardano sync. Run it
1075
+ on your own metal.
1076
+ </p>
1077
+ <p>One CLI. Standard OAuth 2 &amp; OIDC. Native SDKs for Node, Python, Swift, Kotlin, Go, Rust.</p>
1078
+ <div class="dev-tags">${tags.map((tagArg) => html`<span class="dev-tag">${tagArg}</span>`)}</div>
1079
+ <div class="dev-actions">
1080
+ <idp-button variant="accent" icon="lucide:github">View on GitHub</idp-button>
1081
+ <idp-button variant="link">Read the docs</idp-button>
1082
+ </div>
1083
+ </div>
1084
+ <div class="terminal">
1085
+ <div class="term-bar">
1086
+ <span class="tdot" style="background:#ff5f57"></span>
1087
+ <span class="tdot" style="background:#ffbd2e"></span>
1088
+ <span class="tdot" style="background:#28c840"></span>
1089
+ <span class="name">~/idp-cli</span>
1090
+ <span class="shell">zsh</span>
1091
+ </div>
1092
+ <div class="term-body">
1093
+ <div><span class="t-dim">$</span> <span class="t-acc">idp</span> <span class="t-w">identity create</span></div>
1094
+ <div><span class="t-dim">›</span> Generating Ed25519 keypair…</div>
1095
+ <div><span class="t-ok">✓</span> Identity created · <span class="t-acc">did:idp:0x4a3f…c819</span></div>
1096
+ <div><span class="t-dim">›</span> Anchoring to Cardano mainnet…</div>
1097
+ <div><span class="t-acc">◆</span> tx submitted · <span class="t-dim">block #9 841 222</span></div>
1098
+ <div><span class="t-ok">✓</span> Confirmed on-chain · <span class="t-w">permanent</span></div>
1099
+ <div>&nbsp;</div>
1100
+ <div><span class="t-dim">$</span> <span class="t-acc">idp</span> <span class="t-w">login github.com</span></div>
1101
+ <div><span class="t-ok">✓</span> Push sent · <span class="t-am">iPhone 15 Pro</span></div>
1102
+ <div><span class="t-ok">✓</span> Approved · <span class="t-dim">⌘↩ on Watch · 0.8s</span></div>
1103
+ <div>
1104
+ <span class="t-ok">✓</span> Token issued · <span class="t-acc">scope</span><span class="t-dim">:</span>
1105
+ <span class="t-w">openid profile</span>
1106
+ </div>
1107
+ <div><span class="t-dim">$</span> <span class="t-cur"></span></div>
1108
+ </div>
1109
+ </div>
1110
+ </div>
1111
+ </div>
1112
+ </section>
1113
+ `;
1114
+ }
1115
+
1116
+ private renderManifesto() {
1117
+ return html`
1118
+ <section class="manifesto">
1119
+ <div class="wrap">
1120
+ <div class="eyebrow sm" style="margin-bottom: 24px;">Why we built this</div>
1121
+ <q>Identity should not be a product the user is sold. It should be a permanent <em>fact</em>, owned by the person it describes.</q>
1122
+ <div class="manifesto-cite">— Editorial · vol. III · idp.global</div>
1123
+ </div>
1124
+ </section>
1125
+ `;
1126
+ }
1127
+
1128
+ private renderCta() {
631
1129
  return html`
632
- <section class="section alt" id="developers"><div class="wrap dev-grid"><div class="dev-text"><div class="eyebrow">For developers</div><h2>No black boxes <em>in your identity stack.</em></h2><p>idp.global is fully open source and MIT licensed. Read the cryptography. Verify the Cardano sync. Run it on your own metal.</p><div class="tags">${['MIT licensed', 'OAuth 2 / OIDC', 'Self-hostable', 'Air-gappable', 'Cardano native', 'SOC 2'].map((tagArg) => html`<span>${tagArg}</span>`)}</div><idp-button variant="accent">View source</idp-button></div><div class="terminal"><div class="term-bar"><span class="tdot red"></span><span class="tdot yellow"></span><span class="tdot green"></span></div><pre><code>$ idp identity create
633
- OK Identity created - did:idp:0x4a3f...c819
634
- OK Confirmed on-chain - permanent
1130
+ <section class="cta">
1131
+ <div class="wrap">
1132
+ <h2>Claim your identity.<br />Free, forever.</h2>
1133
+ <p>
1134
+ Sixty seconds to claim, anchored to Cardano on submission. No credit card. No vendor lock-in. Yours, even if
1135
+ we disappear.
1136
+ </p>
1137
+ <div class="cta-actions">
1138
+ <idp-button variant="accent" size="lg">Claim your identity</idp-button>
1139
+ <idp-button variant="link" size="lg">Read the manifesto</idp-button>
1140
+ </div>
1141
+ </div>
1142
+ </section>
1143
+ `;
1144
+ }
635
1145
 
636
- $ idp login github.com
637
- OK Push sent - iPhone 15 Pro
638
- OK Approved - Watch - 0.8s</code></pre></div></div></section>
1146
+ private renderFooter() {
1147
+ const cols = [
1148
+ ['Product', ['For individuals', 'For organisations', 'Enterprise', 'Cardano sync', 'Changelog']],
1149
+ ['Developers', ['Documentation', 'API reference', 'Self-hosting', 'SDKs', 'GitHub']],
1150
+ ['Company', ['Manifesto', 'Blog', 'Security', 'Privacy', 'Terms']],
1151
+ ] as const;
1152
+ return html`
1153
+ <footer>
1154
+ <div class="wrap-wide">
1155
+ <div class="footer-cols">
1156
+ <div class="footer-brand">
1157
+ <a class="logo" href="#">idp<span class="logo-dot"></span>global</a>
1158
+ <p>
1159
+ An open identity provider for everyone — from individuals to enterprises. Anchored on Cardano. Built in
1160
+ the open. Yours forever.
1161
+ </p>
1162
+ <div class="footer-status"><span class="live-dot"></span>All systems normal · 99.99%</div>
1163
+ </div>
1164
+ ${cols.map(
1165
+ (colArg) => html`
1166
+ <div class="footer-col">
1167
+ <h4>${colArg[0]}</h4>
1168
+ <ul>${colArg[1].map((linkArg) => html`<li><a>${linkArg}</a></li>`)}</ul>
1169
+ </div>
1170
+ `,
1171
+ )}
1172
+ </div>
1173
+ <div class="footer-bottom">
1174
+ <span>© 2026 idp.global · MIT · Anchored to Cardano</span>
1175
+ <span class="links"><a>Status</a><a>Twitter</a><a>GitHub</a><a>Discord</a></span>
1176
+ </div>
1177
+ </div>
1178
+ </footer>
639
1179
  `;
640
1180
  }
641
1181
 
@@ -644,11 +1184,14 @@ OK Approved - Watch - 0.8s</code></pre></div></div></section>
644
1184
  <div class="page">
645
1185
  ${this.renderNav()}
646
1186
  <idp-landing-hero></idp-landing-hero>
647
- <section class="proof"><div class="wrap"><div class="proof-label">Built for identity at every scale</div><div class="proof-row">${['Open Source', 'Self-hostable', 'Cardano anchored', 'OIDC ready', 'Passkey first', 'Free for everyone'].map((nameArg) => html`<div class="proof-name">${nameArg}</div>`)}</div></div></section>
648
- ${this.renderFeatures()}${this.renderChain()}${this.renderPricing()}${this.renderDevelopers()}
649
- <section class="manifesto"><div class="wrap"><div class="eyebrow">Why we built this</div><q>Identity should not be a product the user is sold.<br/>It should be a permanent <em>fact</em>, owned by the person it describes.</q></div></section>
650
- <section class="cta"><div class="wrap"><h2>Claim your identity.<br/><em>Free, forever.</em></h2><p>Sixty seconds to claim, anchored to Cardano on submission. No credit card. No vendor lock-in.</p><idp-button variant="accent" size="lg">Claim your identity</idp-button></div></section>
651
- <footer><div class="wrap"><div class="footer-cols"><div class="footer-brand"><div class="logo">idp<span class="logo-dot"></span>global</div><p>An open identity provider for everyone. Anchored on Cardano. Built in the open. Yours forever.</p></div><div class="footer-col"><h4>Product</h4><a>For individuals</a><a>For organizations</a><a>Cardano sync</a></div><div class="footer-col"><h4>Developers</h4><a>Documentation</a><a>Self-hosting</a><a>SDKs</a></div><div class="footer-col"><h4>Company</h4><a>Manifesto</a><a>Security</a><a>Privacy</a></div></div><div class="footer-bottom"><span>© 2026 idp.global - MIT - Anchored to Cardano</span><span>Source - Community</span></div></div></footer>
1187
+ ${this.renderProof()}
1188
+ ${this.renderFeatures()}
1189
+ ${this.renderChain()}
1190
+ ${this.renderPricing()}
1191
+ ${this.renderDevelopers()}
1192
+ ${this.renderManifesto()}
1193
+ ${this.renderCta()}
1194
+ ${this.renderFooter()}
652
1195
  </div>
653
1196
  `;
654
1197
  }