@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
@@ -163,6 +163,24 @@ export interface IIdpAdminPassportEnrollment {
163
163
  expiresAt: number;
164
164
  }
165
165
 
166
+ export interface IIdpAdminPasskey {
167
+ id: string;
168
+ label: string;
169
+ credentialId?: string;
170
+ status: string;
171
+ backedUp?: boolean;
172
+ deviceType?: string;
173
+ transports?: string[];
174
+ createdAt: number;
175
+ lastUsedAt?: number | null;
176
+ }
177
+
178
+ export interface IIdpAdminTotpEnrollment {
179
+ credentialId: string;
180
+ secret: string;
181
+ otpauthUrl: string;
182
+ }
183
+
166
184
  export interface IIdpAdminSessionEventDetail {
167
185
  sessionId: string;
168
186
  }
@@ -237,6 +255,23 @@ export interface IIdpAdminPassportDeviceEventDetail {
237
255
  deviceId: string;
238
256
  }
239
257
 
258
+ export interface IIdpAdminTotpVerifyEventDetail {
259
+ credentialId: string;
260
+ code: string;
261
+ }
262
+
263
+ export interface IIdpAdminTotpCodeEventDetail {
264
+ code: string;
265
+ }
266
+
267
+ export interface IIdpAdminPasskeyRegistrationEventDetail {
268
+ label: string;
269
+ }
270
+
271
+ export interface IIdpAdminPasskeyEventDetail {
272
+ passkeyId: string;
273
+ }
274
+
240
275
  @customElement('idp-admin-shell')
241
276
  export class IdpAdminShell extends DeesElement {
242
277
  public static demo = () => html`<idp-admin-shell global-admin></idp-admin-shell>`;
@@ -1239,6 +1274,18 @@ export class IdpAdminShell extends DeesElement {
1239
1274
  @property({ type: Object })
1240
1275
  public accessor passportEnrollment: IIdpAdminPassportEnrollment | null = null;
1241
1276
 
1277
+ @property({ type: Boolean, attribute: 'totp-enabled' })
1278
+ public accessor totpEnabled = false;
1279
+
1280
+ @property({ type: Number, attribute: 'backup-codes-remaining' })
1281
+ public accessor backupCodesRemaining = 0;
1282
+
1283
+ @property({ type: Object })
1284
+ public accessor totpEnrollment: IIdpAdminTotpEnrollment | null = null;
1285
+
1286
+ @property({ type: Array })
1287
+ public accessor passkeys: IIdpAdminPasskey[] = [];
1288
+
1242
1289
  @property({ type: String, attribute: 'credential-message' })
1243
1290
  public accessor credentialMessage = '';
1244
1291
 
@@ -1523,6 +1570,51 @@ export class IdpAdminShell extends DeesElement {
1523
1570
  });
1524
1571
  }
1525
1572
 
1573
+ private requestTotpEnrollment() {
1574
+ this.dispatchShellEvent('idp-admin-totp-start', {});
1575
+ }
1576
+
1577
+ private verifyTotpEnrollment() {
1578
+ if (!this.totpEnrollment) {
1579
+ return;
1580
+ }
1581
+ const code = globalThis.prompt?.('Authenticator code')?.trim();
1582
+ if (!code) {
1583
+ return;
1584
+ }
1585
+ this.dispatchShellEvent<IIdpAdminTotpVerifyEventDetail>('idp-admin-totp-verify', {
1586
+ credentialId: this.totpEnrollment.credentialId,
1587
+ code,
1588
+ });
1589
+ }
1590
+
1591
+ private disableTotp() {
1592
+ const code = globalThis.prompt?.('Enter your current authenticator code to disable TOTP')?.trim();
1593
+ if (!code) {
1594
+ return;
1595
+ }
1596
+ this.dispatchShellEvent<IIdpAdminTotpCodeEventDetail>('idp-admin-totp-disable', { code });
1597
+ }
1598
+
1599
+ private regenerateBackupCodes() {
1600
+ const code = globalThis.prompt?.('Enter your current authenticator code to regenerate backup codes')?.trim();
1601
+ if (!code) {
1602
+ return;
1603
+ }
1604
+ this.dispatchShellEvent<IIdpAdminTotpCodeEventDetail>('idp-admin-backup-codes-regenerate', { code });
1605
+ }
1606
+
1607
+ private requestPasskeyRegistration() {
1608
+ const fallbackLabel = typeof navigator !== 'undefined'
1609
+ ? navigator.userAgent.includes('Mobile') ? 'Mobile passkey' : 'Desktop passkey'
1610
+ : 'Passkey';
1611
+ const label = globalThis.prompt?.('Passkey label', fallbackLabel)?.trim();
1612
+ if (!label) {
1613
+ return;
1614
+ }
1615
+ this.dispatchShellEvent<IIdpAdminPasskeyRegistrationEventDetail>('idp-admin-passkey-register', { label });
1616
+ }
1617
+
1526
1618
  private setPage(pageArg: TIdpAdminPage) {
1527
1619
  this.page = pageArg;
1528
1620
  this.orgMenuOpen = false;
@@ -2172,6 +2264,23 @@ export class IdpAdminShell extends DeesElement {
2172
2264
  html`<div class="cell-actions"><button class="table-action destructive" @click=${() => this.dispatchShellEvent<IIdpAdminPassportDeviceEventDetail>('idp-admin-passport-revoke', { deviceId: deviceArg.id })}>Revoke</button></div>`,
2173
2265
  ],
2174
2266
  }));
2267
+ const passkeyRows = this.passkeys.map((passkeyArg) => ({
2268
+ cells: [
2269
+ html`
2270
+ <div class="identity-cell">
2271
+ <span class="identity-avatar">${this.getInitials(passkeyArg.label)}</span>
2272
+ <div>
2273
+ <div class="identity-primary">${passkeyArg.label}</div>
2274
+ <div class="identity-secondary">${passkeyArg.deviceType || 'passkey'}${passkeyArg.backedUp ? ' - backed up' : ''}</div>
2275
+ </div>
2276
+ </div>
2277
+ `,
2278
+ html`<idp-badge variant=${passkeyArg.status === 'active' ? 'ok' : 'error'}>${passkeyArg.status}</idp-badge>`,
2279
+ (passkeyArg.transports || []).join(', ') || '-',
2280
+ passkeyArg.lastUsedAt ? this.formatTimeAgo(passkeyArg.lastUsedAt) : 'never',
2281
+ html`<div class="cell-actions"><button class="table-action destructive" @click=${() => this.dispatchShellEvent<IIdpAdminPasskeyEventDetail>('idp-admin-passkey-revoke', { passkeyId: passkeyArg.id })}>Revoke</button></div>`,
2282
+ ],
2283
+ }));
2175
2284
 
2176
2285
  return html`
2177
2286
  ${this.renderPageHeader('Security', 'Manage how you authenticate and protect your account.')}
@@ -2190,6 +2299,45 @@ export class IdpAdminShell extends DeesElement {
2190
2299
  <div class="divider"></div>
2191
2300
  <button class="plain-button primary" @click=${() => this.submitPasswordChange()}>Update password</button>
2192
2301
  `)}
2302
+ ${this.renderSectionCard('Authenticator app', 'TOTP protects password and magic-link sign-ins with a six-digit code from an authenticator app.', html`
2303
+ <div class="split-row"><div><div class="section-title">Status</div><div class="muted">${this.totpEnabled ? `${this.backupCodesRemaining} backup codes remaining.` : 'No authenticator app is enrolled.'}</div></div><idp-badge variant=${this.totpEnabled ? 'ok' : 'warn'}>${this.totpEnabled ? 'Enabled' : 'Disabled'}</idp-badge></div>
2304
+ ${this.totpEnrollment ? html`
2305
+ <div class="divider"></div>
2306
+ <div class="notice-card"><idp-icon name="qr" size="16"></idp-icon><div><div class="section-title">TOTP setup pending</div><div class="muted">Scan the otpauth URL or enter the manual secret, then verify the current code.</div></div></div>
2307
+ ${this.renderFormRow('Manual secret', '', this.renderCodeBlock(this.totpEnrollment.secret))}
2308
+ ${this.renderFormRow('otpauth URL', '', this.renderCodeBlock(this.totpEnrollment.otpauthUrl))}
2309
+ <button class="plain-button primary" @click=${() => this.verifyTotpEnrollment()}>Verify setup code</button>
2310
+ ` : html`
2311
+ <div class="divider"></div>
2312
+ ${this.totpEnabled ? html`
2313
+ <div class="cell-actions" style="justify-content:flex-start">
2314
+ <button class="plain-button outline" @click=${() => this.regenerateBackupCodes()}>Regenerate backup codes</button>
2315
+ <button class="plain-button ghost" style="color:var(--idp-error)" @click=${() => this.disableTotp()}>Disable TOTP</button>
2316
+ </div>
2317
+ ` : html`<button class="plain-button primary" @click=${() => this.requestTotpEnrollment()}>Enable authenticator app</button>`}
2318
+ `}
2319
+ `)}
2320
+ <idp-data-table
2321
+ title="Passkeys"
2322
+ subtitle="WebAuthn credentials for passwordless login and MFA step-up."
2323
+ badge=${`${this.passkeys.length} total`}
2324
+ empty-title="No passkeys"
2325
+ empty-description="Register a passkey to sign in with platform authenticators or security keys."
2326
+ .columns=${[
2327
+ { label: 'Passkey' },
2328
+ { label: 'Status' },
2329
+ { label: 'Transports', hideBelow: 'mobile' },
2330
+ { label: 'Last used', mono: true, hideBelow: 'mobile' },
2331
+ { label: 'Action', align: 'right' },
2332
+ ]}
2333
+ .rows=${passkeyRows}
2334
+ ></idp-data-table>
2335
+ <div class="section-card">
2336
+ <div class="section-headline">
2337
+ <div><div class="section-title">Register passkey</div><div class="section-description">Creates a WebAuthn registration challenge in this browser.</div></div>
2338
+ <button class="plain-button outline" @click=${() => this.requestPasskeyRegistration()}>Register passkey</button>
2339
+ </div>
2340
+ </div>
2193
2341
  <idp-data-table
2194
2342
  title="Passport devices"
2195
2343
  subtitle="Cryptographic IDP Passport devices registered for this account."
@@ -2217,10 +2365,6 @@ export class IdpAdminShell extends DeesElement {
2217
2365
  ${this.renderFormRow('Signing payload', '', this.renderCodeBlock(this.passportEnrollment.signingPayload))}
2218
2366
  ` : html`<div class="muted">No active enrollment challenge.</div>`}
2219
2367
  </div>
2220
- <div class="primary-grid">
2221
- ${this.renderStateCard('TOTP controls not connected', 'No TOTP secret, enrollment, or verification endpoints exist in this backend yet, so no fake TOTP toggle is shown.', 'lock')}
2222
- ${this.renderStateCard('WebAuthn passkeys not connected', 'No WebAuthn passkey credential model or assertion endpoints exist yet. Passport devices are the available cryptographic credential path.', 'key')}
2223
- </div>
2224
2368
  </div>
2225
2369
  `;
2226
2370
  }
@@ -20,7 +20,7 @@ export class IdpBadge extends DeesElement {
20
20
  <idp-badge variant="error">Denied</idp-badge>
21
21
  </div>
22
22
  `;
23
- public static demoGroups = ['idp.global v3 primitives'];
23
+ public static demoGroups = ['idp.global v5 primitives'];
24
24
 
25
25
  @property({ type: String })
26
26
  public accessor variant: TIdpBadgeVariant = 'default';
@@ -34,15 +34,15 @@ export class IdpBadge extends DeesElement {
34
34
  .badge {
35
35
  display: inline-flex;
36
36
  align-items: center;
37
- gap: 4px;
38
- padding: 2px 8px;
37
+ gap: 5px;
38
+ padding: 3px 9px;
39
39
  border: 1px solid transparent;
40
- border-radius: 999px;
41
- font-family: var(--idp-mono);
42
- font-size: 11px;
43
- font-weight: 600;
40
+ border-radius: var(--idp-radius-pill);
41
+ font-family: var(--idp-font);
42
+ font-size: 12px;
43
+ font-weight: 590;
44
44
  letter-spacing: -0.01em;
45
- line-height: 16px;
45
+ line-height: 15px;
46
46
  }
47
47
  .default {
48
48
  background: var(--idp-muted);
@@ -67,9 +67,6 @@ export class IdpBadge extends DeesElement {
67
67
  color: var(--idp-error);
68
68
  border-color: var(--idp-error-border);
69
69
  }
70
- .accent {
71
- border-color: var(--idp-info-border);
72
- }
73
70
  .outline {
74
71
  background: transparent;
75
72
  color: var(--idp-fg);
@@ -9,7 +9,7 @@ import {
9
9
  import { idpElementStyles } from './tokens.js';
10
10
  import './idp-icon.js';
11
11
 
12
- export type TIdpButtonVariant = 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'accent';
12
+ export type TIdpButtonVariant = 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'accent' | 'tint' | 'link';
13
13
  export type TIdpButtonSize = 'sm' | 'md' | 'lg';
14
14
 
15
15
  declare global {
@@ -21,15 +21,16 @@ declare global {
21
21
  @customElement('idp-button')
22
22
  export class IdpButton extends DeesElement {
23
23
  public static demo = () => html`
24
- <div style="display: flex; gap: 10px; flex-wrap: wrap;">
25
- <idp-button>Default</idp-button>
26
- <idp-button variant="accent">Approve</idp-button>
24
+ <div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center;">
25
+ <idp-button variant="accent">Claim identity</idp-button>
26
+ <idp-button variant="tint">Talk to us</idp-button>
27
27
  <idp-button variant="outline">Deny</idp-button>
28
28
  <idp-button variant="ghost">Ghost</idp-button>
29
+ <idp-button variant="link">See how it works</idp-button>
29
30
  <idp-button variant="destructive">Delete</idp-button>
30
31
  </div>
31
32
  `;
32
- public static demoGroups = ['idp.global v3 primitives'];
33
+ public static demoGroups = ['idp.global v5 primitives'];
33
34
 
34
35
  @property({ type: String })
35
36
  public accessor variant: TIdpButtonVariant = 'default';
@@ -64,9 +65,10 @@ export class IdpButton extends DeesElement {
64
65
  justify-content: center;
65
66
  gap: 6px;
66
67
  border: 1px solid transparent;
67
- border-radius: 6px;
68
+ border-radius: var(--idp-radius-pill);
68
69
  font-family: var(--idp-font);
69
70
  font-weight: 500;
71
+ line-height: 1.4;
70
72
  letter-spacing: -0.01em;
71
73
  white-space: nowrap;
72
74
  cursor: pointer;
@@ -84,19 +86,16 @@ export class IdpButton extends DeesElement {
84
86
  cursor: not-allowed;
85
87
  }
86
88
  .sm {
87
- height: 32px;
88
- padding: 0 12px;
89
- font-size: 13px;
89
+ padding: 6px 14px;
90
+ font-size: 14px;
90
91
  }
91
92
  .md {
92
- height: 38px;
93
- padding: 0 14px;
94
- font-size: 14px;
93
+ padding: 8px 18px;
94
+ font-size: 17px;
95
95
  }
96
96
  .lg {
97
- height: 44px;
98
- padding: 0 18px;
99
- font-size: 15px;
97
+ padding: 11px 24px;
98
+ font-size: 19px;
100
99
  }
101
100
  .default {
102
101
  background: var(--idp-primary);
@@ -108,11 +107,35 @@ export class IdpButton extends DeesElement {
108
107
  .accent {
109
108
  background: var(--idp-accent);
110
109
  color: var(--idp-accent-fg);
111
- box-shadow: 0 4px 14px color-mix(in srgb, var(--idp-accent), transparent 64%);
112
110
  }
113
111
  .accent:hover:not(:disabled) {
114
112
  background: var(--idp-accent-hover);
115
113
  }
114
+ .tint {
115
+ background: var(--idp-accent-soft);
116
+ color: var(--idp-accent);
117
+ }
118
+ .tint:hover:not(:disabled) {
119
+ background: color-mix(in srgb, var(--idp-accent-soft), var(--idp-accent) 12%);
120
+ }
121
+ .link {
122
+ background: transparent;
123
+ color: var(--idp-accent);
124
+ padding: 0;
125
+ border-radius: 0;
126
+ }
127
+ .link:hover:not(:disabled) {
128
+ text-decoration: underline;
129
+ }
130
+ .link::after {
131
+ content: '›';
132
+ font-size: 1.15em;
133
+ line-height: 0;
134
+ transition: transform 160ms ease;
135
+ }
136
+ .link:hover:not(:disabled)::after {
137
+ transform: translateX(2px);
138
+ }
116
139
  .secondary {
117
140
  background: var(--idp-muted);
118
141
  color: var(--idp-fg);
@@ -1,8 +1,7 @@
1
1
  import { DeesElement, html, customElement, css, type TemplateResult } from '@design.estate/dees-element';
2
2
  import { idpElementStyles } from './tokens.js';
3
3
  import './idp-button.js';
4
- import './idp-dashboard-window.js';
5
- import './idp-icon.js';
4
+ import './idp-screenshot-placeholder.js';
6
5
 
7
6
  declare global {
8
7
  interface HTMLElementTagNameMap {
@@ -13,128 +12,78 @@ declare global {
13
12
  @customElement('idp-landing-hero')
14
13
  export class IdpLandingHero extends DeesElement {
15
14
  public static demo = () => html`<idp-landing-hero></idp-landing-hero>`;
16
- public static demoGroups = ['idp.global v3 composed surfaces'];
15
+ public static demoGroups = ['idp.global v5 composed surfaces'];
17
16
 
18
17
  public static styles = [
19
18
  ...idpElementStyles,
20
19
  css`
21
20
  :host {
22
21
  display: block;
23
- }
24
- .hero {
25
- position: relative;
26
- overflow: hidden;
27
- background: var(--idp-bg);
22
+ background: var(--idp-card);
28
23
  color: var(--idp-fg);
29
- border-bottom: 1px solid var(--idp-border-soft);
30
- }
31
- .grid {
32
- position: absolute;
33
- inset: 0;
34
- background-image: linear-gradient(to right, color-mix(in srgb, var(--idp-fg), transparent 97%) 1px, transparent 1px), linear-gradient(to bottom, color-mix(in srgb, var(--idp-fg), transparent 97%) 1px, transparent 1px);
35
- background-size: 56px 56px;
36
- mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 30%, transparent 70%);
37
- pointer-events: none;
38
24
  }
39
- .glow {
40
- position: absolute;
41
- top: -220px;
42
- left: 50%;
43
- width: 900px;
44
- height: 600px;
45
- transform: translateX(-50%);
46
- background: radial-gradient(ellipse, rgba(59,130,246,0.18) 0%, transparent 60%);
47
- pointer-events: none;
48
- }
49
- .inner {
50
- position: relative;
51
- z-index: 1;
52
- max-width: 1240px;
53
- margin: 0 auto;
54
- padding: 96px 32px 0;
25
+ .hero {
26
+ padding: 84px 0 0;
55
27
  text-align: center;
56
28
  }
57
- .badge {
58
- display: inline-flex;
59
- align-items: center;
60
- gap: 7px;
61
- margin-bottom: 28px;
62
- padding: 5px 12px 5px 8px;
63
- border: 1px solid var(--idp-border);
64
- border-radius: 999px;
65
- background: var(--idp-muted);
66
- color: var(--idp-fg-3);
67
- font-size: 12px;
29
+ .wrap {
30
+ max-width: 1024px;
31
+ margin: 0 auto;
32
+ padding: 0 22px;
68
33
  }
69
- .pill {
70
- padding: 2px 7px;
71
- border-radius: 999px;
72
- background: rgba(59,130,246,0.18);
73
- color: var(--idp-accent-hover);
74
- font-family: var(--idp-mono);
75
- font-size: 10px;
34
+ .hero-tag {
35
+ margin-bottom: 6px;
36
+ color: var(--idp-accent);
37
+ font-size: 21px;
76
38
  font-weight: 600;
77
- letter-spacing: 0.04em;
39
+ letter-spacing: -0.02em;
78
40
  }
79
41
  h1 {
80
- margin: 0 0 24px;
81
- font-size: clamp(44px, 6.5vw, 78px);
42
+ max-width: 16ch;
43
+ margin: 0 auto 22px;
82
44
  font-family: var(--idp-display);
45
+ font-size: clamp(48px, 7vw, 96px);
83
46
  font-weight: 700;
84
- letter-spacing: -0.035em;
85
- line-height: 0.96;
86
- }
87
- h1 em {
88
- color: var(--idp-accent-hover);
89
- font-family: var(--idp-serif);
90
- font-style: italic;
91
- font-weight: 400;
47
+ line-height: 1.04;
48
+ letter-spacing: -0.025em;
92
49
  }
93
- .sub {
94
- max-width: 660px;
95
- margin: 0 auto 36px;
50
+ .hero-sub {
51
+ max-width: 600px;
52
+ margin: 0 auto 28px;
96
53
  color: var(--idp-fg-3);
97
- font-size: clamp(16px, 1.6vw, 19px);
98
- line-height: 1.55;
54
+ font-size: clamp(19px, 2vw, 24px);
55
+ font-weight: 400;
56
+ line-height: 1.4;
57
+ letter-spacing: -0.01em;
99
58
  }
100
- .actions {
59
+ .hero-actions {
101
60
  display: flex;
102
- gap: 12px;
61
+ gap: 26px;
103
62
  flex-wrap: wrap;
104
63
  align-items: center;
105
64
  justify-content: center;
106
- margin-bottom: 20px;
107
65
  }
108
- .fineprint {
109
- color: var(--idp-muted-fg);
110
- font-family: var(--idp-mono);
111
- font-size: 11px;
112
- letter-spacing: 0.04em;
66
+ .hero-fine {
67
+ display: flex;
68
+ flex-wrap: wrap;
69
+ justify-content: center;
70
+ margin-top: 22px;
71
+ color: var(--idp-fg-3);
72
+ font-size: 13px;
113
73
  }
114
- .fineprint span + span::before {
115
- content: '*';
74
+ .hero-fine span + span::before {
75
+ content: '·';
116
76
  margin: 0 10px;
77
+ color: var(--idp-fg-3);
117
78
  }
118
79
  .product {
119
- position: relative;
120
- max-width: 1180px;
121
- margin: 72px auto 0;
122
- padding: 0 32px;
123
- }
124
- .product-glow {
125
- position: absolute;
126
- inset: 30% 10% -10%;
127
- background: radial-gradient(ellipse, rgba(59,130,246,0.25) 0%, transparent 60%);
128
- filter: blur(40px);
129
- pointer-events: none;
130
- }
131
- idp-dashboard-window {
132
- position: relative;
133
- z-index: 1;
80
+ max-width: 1100px;
81
+ margin: 60px auto 0;
82
+ padding: 0 22px;
134
83
  }
135
84
  @media (max-width: 760px) {
136
- .inner {
137
- padding: 72px 20px 0;
85
+ .hero {
86
+ padding: 64px 0 0;
138
87
  }
139
88
  }
140
89
  `,
@@ -143,22 +92,28 @@ export class IdpLandingHero extends DeesElement {
143
92
  public render(): TemplateResult {
144
93
  return html`
145
94
  <section class="hero">
146
- <div class="grid"></div>
147
- <div class="glow"></div>
148
- <div class="inner">
149
- <div class="badge"><span class="pill">v3.81</span>Cardano-anchored identity, now self-hostable</div>
150
- <h1>One identity.<br/><em>Any scale.</em> Yours forever.</h1>
151
- <p class="sub">An open identity provider for everyone, from a single person to a global enterprise. Anchored to the Cardano blockchain so it can never be erased, taken away, or quietly deprecated.</p>
152
- <div class="actions">
153
- <idp-button variant="accent" size="lg" icon="shield">Claim your identity - free</idp-button>
154
- <idp-button variant="ghost" size="lg" icon="globe">View source</idp-button>
95
+ <div class="wrap">
96
+ <div class="hero-tag">idp.global</div>
97
+ <h1>One identity. Any scale.<br />Yours forever.</h1>
98
+ <p class="hero-sub">
99
+ An open identity provider for everyone — from a single person to a global enterprise.
100
+ Anchored to Cardano, so it can never be erased or taken away.
101
+ </p>
102
+ <div class="hero-actions">
103
+ <idp-button variant="accent" size="lg">Claim your identity</idp-button>
104
+ <idp-button variant="link" size="lg">See how it works</idp-button>
155
105
  </div>
156
- <div class="fineprint"><span>MIT licensed</span><span>Self-hostable</span><span>No credit card</span><span>Cardano mainnet</span></div>
157
- <div class="product">
158
- <div class="product-glow"></div>
159
- <idp-dashboard-window></idp-dashboard-window>
106
+ <div class="hero-fine">
107
+ <span>MIT licensed</span><span>Self-hostable</span><span>No credit card</span><span>Cardano mainnet</span>
160
108
  </div>
161
109
  </div>
110
+ <div class="product" id="product">
111
+ <idp-screenshot-placeholder
112
+ variant="hero"
113
+ label="Console dashboard"
114
+ meta="console.idp.global / overview · 1100 × 620"
115
+ ></idp-screenshot-placeholder>
116
+ </div>
162
117
  </section>
163
118
  `;
164
119
  }