import { DeesElement, html, customElement, css, type TemplateResult } from '@design.estate/dees-element'; import { idpElementStyles } from './tokens.js'; import './idp-badge.js'; import './idp-button.js'; import './idp-icon.js'; import './idp-landing-hero.js'; declare global { interface HTMLElementTagNameMap { 'idp-landing-page': IdpLandingPage; } } @customElement('idp-landing-page') export class IdpLandingPage extends DeesElement { public static demo = () => html``; public static demoGroups = ['idp.global v3 full pages']; public static styles = [ ...idpElementStyles, css` :host { display: block; --idp-bg: #0a0a0a; --idp-bg-2: #111111; --idp-card: #121212; --idp-card-2: #161616; --idp-fg: #fafafa; --idp-fg-2: #d4d4d8; --idp-fg-3: hsl(0 0% 70%); --idp-muted-fg: hsl(0 0% 55%); --idp-border: #262626; --idp-border-soft: #1c1c1c; --idp-border-strong: #333333; --idp-accent: #3b82f6; --idp-accent-hover: #60a5fa; background: var(--idp-bg); color: var(--idp-fg); } .page { min-height: 100vh; background: var(--idp-bg); } nav { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between; gap: 24px; height: 56px; max-width: 1240px; margin: 0 auto; padding: 0 32px; border-bottom: 1px solid var(--idp-border-soft); background: rgba(10,10,10,0.86); backdrop-filter: blur(14px) saturate(140%); } .nav-shell { position: sticky; top: 0; z-index: 20; border-bottom: 1px solid var(--idp-border-soft); background: rgba(10,10,10,0.86); } .logo { display: inline-flex; align-items: center; gap: 8px; font-family: var(--idp-display); font-size: 16px; font-weight: 700; letter-spacing: -0.015em; } .logo-dot { width: 6px; height: 6px; border-radius: 999px; background: var(--idp-accent); box-shadow: 0 0 12px var(--idp-accent); } .links, .actions { display: flex; align-items: center; gap: 6px; } .links a { padding: 6px 12px; border-radius: 5px; color: var(--idp-fg-3); font-size: 13px; text-decoration: none; } .links a:hover { background: rgba(255,255,255,0.04); color: var(--idp-fg); } .status { display: inline-flex; align-items: center; gap: 6px; margin-right: 8px; color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 11px; } .live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--idp-ok); box-shadow: 0 0 8px var(--idp-ok); } .wrap { max-width: 1240px; margin: 0 auto; padding: 0 32px; } .proof, .section, .manifesto, .cta, footer { border-bottom: 1px solid var(--idp-border-soft); } .proof { padding: 56px 0; } .proof-label { margin-bottom: 28px; color: var(--idp-muted-fg); text-align: center; font-family: var(--idp-mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; } .proof-row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 24px; place-items: center; opacity: 0.72; } .proof-name { color: var(--idp-fg-3); font-family: var(--idp-display); font-size: 18px; font-weight: 700; letter-spacing: -0.02em; } .section { padding: 120px 0; } .section.alt { background: var(--idp-bg-2); } .section-head { max-width: 760px; margin: 0 auto 64px; text-align: center; } .eyebrow { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 16px; color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; } .eyebrow::before, .eyebrow::after { content: ''; width: 24px; height: 1px; background: var(--idp-border-strong); } h2, h3, q { margin: 0; font-family: var(--idp-display); letter-spacing: -0.03em; } h2 { font-size: clamp(36px, 4.5vw, 56px); line-height: 1.05; } em { color: var(--idp-accent-hover); font-family: var(--idp-serif); font-style: italic; font-weight: 400; } .lede { max-width: 640px; margin: 20px auto 0; color: var(--idp-fg-3); font-size: 17px; line-height: 1.55; } .bento { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; } .tile, .tier, .chain-panel, .terminal { border: 1px solid var(--idp-border-soft); border-radius: 12px; background: var(--idp-bg-2); } .tile { padding: 28px; } .tile.col-2 { grid-column: span 2; } .tile.col-3 { grid-column: span 3; } .tile.tall { grid-row: span 2; } .tile-tag { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 14px; color: var(--idp-accent-hover); font-family: var(--idp-mono); font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; } .tile-tag::before { content: ''; width: 6px; height: 6px; border-radius: 999px; background: var(--idp-accent); } .tile h3 { margin-bottom: 10px; font-size: 24px; line-height: 1.15; } .tile p, .tier li, .chain-step p { color: var(--idp-fg-3); font-size: 14px; line-height: 1.55; } .approval-stack { display: grid; gap: 6px; margin-top: 22px; } .approval-row { display: grid; grid-template-columns: 28px 1fr auto; gap: 12px; align-items: center; padding: 10px 12px; border: 1px solid var(--idp-border-soft); border-left: 2px solid var(--idp-accent); border-radius: 6px; background: var(--idp-bg); } .avatar { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--idp-border); border-radius: 50%; background: var(--idp-card-2); color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 10px; font-weight: 700; } .approval-row strong { display: block; color: var(--idp-fg); font-size: 12.5px; font-weight: 500; } .approval-row span.meta { color: color-mix(in srgb, var(--idp-muted-fg), transparent 30%); font-family: var(--idp-mono); font-size: 10.5px; } .identity-card { position: relative; overflow: hidden; margin-top: 22px; border: 1px solid var(--idp-border); border-radius: 10px; padding: 20px; background: linear-gradient(140deg, #1a1a1a 0%, #0a0a0a 100%); } .identity-card::after { content: ''; position: absolute; top: -100px; right: -80px; width: 240px; height: 240px; border-radius: 50%; background: radial-gradient(circle, rgba(0,105,242,0.4), transparent 65%); } .identity-card > * { position: relative; z-index: 1; } .chip { width: 32px; height: 24px; margin: 18px 0 14px; border-radius: 3px; background: linear-gradient(135deg, #93bbfd 0%, #0050b9 80%); } .mono { color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 10.5px; } .metric { margin-top: 8px; background: linear-gradient(180deg, var(--idp-fg) 0%, var(--idp-muted-fg) 110%); background-clip: text; color: transparent; font-family: var(--idp-display); font-size: 64px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } .metric span { font-size: 24px; } .devices-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 22px; } .dev-cell { padding: 14px 10px; border: 1px solid var(--idp-border-soft); border-radius: 6px; background: var(--idp-bg); text-align: center; } .dev-icon { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 8px; border: 1px solid rgba(96,165,250,0.35); border-radius: 9px; color: var(--idp-accent-hover); } .dev-name { color: var(--idp-fg); font-size: 12px; font-weight: 500; } .dev-sub { color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 10px; } .chain-grid, .dev-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; } .chain-steps { display: grid; gap: 28px; } .chain-step { display: grid; grid-template-columns: 70px 1fr; gap: 16px; padding-bottom: 24px; border-bottom: 1px solid var(--idp-border-soft); } .chain-step > div { color: var(--idp-accent-hover); font-family: var(--idp-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.08em; } .chain-panel { overflow: hidden; background: var(--idp-bg); } .chain-head { display: flex; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--idp-border-soft); color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; } .chain-block { display: grid; grid-template-columns: auto 1fr auto; gap: 12px; margin: 8px 14px; padding: 14px 16px; border: 1px solid var(--idp-border-soft); border-radius: 8px; color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 11px; } .chain-block.idp { border-left: 2px solid var(--idp-accent); background: rgba(0,80,185,0.08); } .tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; } .tier { position: relative; display: flex; flex-direction: column; padding: 28px; } .tier.featured { border-color: var(--idp-accent); background: linear-gradient(180deg, rgba(59,130,246,0.06) 0%, var(--idp-bg-2) 40%); } .tier-name { margin-bottom: 10px; color: var(--idp-muted-fg); font-family: var(--idp-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; } .price { margin: 12px 0 20px; font-family: var(--idp-display); font-size: 40px; font-weight: 700; } .tier ul { flex: 1; margin: 0 0 24px; padding-left: 20px; } .dev-text p { color: var(--idp-fg-3); } .tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 18px 0 22px; } .tags span { padding: 4px 10px; border: 1px solid var(--idp-border); border-radius: 999px; background: var(--idp-bg-2); color: var(--idp-fg-3); font-family: var(--idp-mono); font-size: 10.5px; } .terminal { overflow: hidden; background: var(--idp-bg); } .term-bar { display: flex; gap: 6px; padding: 10px 14px; border-bottom: 1px solid var(--idp-border-soft); } .tdot { width: 11px; height: 11px; border-radius: 50%; } .red { background: #ff5f57; } .yellow { background: #ffbd2e; } .green { background: #28c840; } pre { min-height: 300px; margin: 0; padding: 22px 24px; color: var(--idp-fg-3); font-family: var(--idp-mono); font-size: 13px; line-height: 1.85; } .manifesto, .cta { padding: 120px 0; text-align: center; } q { display: block; max-width: 980px; margin: 0 auto; font-family: var(--idp-serif); font-size: clamp(32px, 4vw, 48px); font-style: italic; line-height: 1.2; quotes: none; } q::before, q::after { content: none; } .cta { position: relative; overflow: hidden; } .cta::before { content: ''; position: absolute; left: 50%; top: 50%; width: 800px; height: 600px; transform: translate(-50%, -50%); background: radial-gradient(ellipse, rgba(59,130,246,0.15) 0%, transparent 60%); } .cta .wrap { position: relative; } .cta p { max-width: 560px; margin: 24px auto 32px; color: var(--idp-fg-3); } footer { padding: 64px 0 28px; border-bottom: 0; } .footer-cols { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 48px; margin-bottom: 48px; } .footer-brand p, .footer-col a, .footer-bottom { color: var(--idp-muted-fg); font-size: 13px; } .footer-col { display: grid; gap: 9px; } .footer-col h4 { margin: 0; color: var(--idp-fg-3); font-family: var(--idp-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; } .footer-bottom { display: flex; justify-content: space-between; padding-top: 22px; border-top: 1px solid var(--idp-border-soft); font-family: var(--idp-mono); font-size: 11px; } @media (max-width: 1100px) { .links { display: none; } .bento { grid-template-columns: repeat(2, 1fr); } .tile.col-2, .tile.col-3 { grid-column: span 2; } .chain-grid, .dev-grid { grid-template-columns: 1fr; } .tiers { grid-template-columns: 1fr; max-width: 520px; margin: 0 auto; } .footer-cols { grid-template-columns: 1fr 1fr; } } @media (max-width: 720px) { nav, .wrap { padding-left: 20px; padding-right: 20px; } .status, .actions .ghost { display: none; } .proof-row { grid-template-columns: repeat(2, 1fr); } .bento { grid-template-columns: 1fr; } .tile.col-2, .tile.col-3 { grid-column: span 1; } .section, .manifesto, .cta { padding: 80px 0; } .footer-cols { grid-template-columns: 1fr; } } `, ]; private renderNav() { return html` `; } private renderFeatures() { return html`
Capabilities

Native on every screen you already carry.

Approvals on iPhone. Tap-to-auth via NFC. Lock-screen actions on Apple Watch. The same identity, one tap away on any device.

Push approvals

Approve or deny in one tap.

Every login, OAuth grant, and sensitive action triggers a real-time approval.

${['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`
${row[0].slice(0,2).toUpperCase()}
${row[0]}${row[1]}
${row[2]}
`; })}
NFC tap-to-auth

Tap to authenticate.

Hold your phone to any compatible reader. Identity token exchanges in under a second.

Alex Mercer

@alexmercer - Personal
did:idp:0x4a3f...c819
Four platforms

iPhone, Watch, iPad, Mac.

Every device you carry is a trusted authenticator.

${[ ['iPhone', 'phone'], ['Watch', 'smartphone-nfc'], ['iPad', 'device'], ['Mac', 'monitor'], ].map((deviceArg) => html`
${deviceArg[0]}
trusted
`)}
One approval, anywhere - synchronized end-to-end.
Average approval

Sub-second auth.

Push delivery, biometric prompt, and signed response under a second.

0.8sec
Audit-grade

Every action, on the record.

Tamper-evident audit trail per identity and organization.

Recovery

Lose a phone? Not your identity.

Multi-device recovery or social-recovery quorum. No vendor lockout.

`; } private renderChain() { return html`
Cardano-anchored

Your identity outlives any single server.

Every identity is anchored to the Cardano mainnet, independently verifiable and recoverable.

${[['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`
${stepArg[0]}

${stepArg[1]}

${stepArg[2]}

`)}
Cardano mainnetlive
${['#9 841 220', '#9 841 221', '#9 841 222', '#9 841 223'].map((blockArg, indexArg) => html`
${blockArg}${indexArg === 1 ? 'did:idp:0x4a3f...c819' : indexArg === 2 ? 'did:idp:0x9b12...f034' : 'confirmed block'}${indexArg === 1 || indexArg === 2 ? 'idp.global' : 'confirmed'}
`)}
`; } private renderPricing() { const tiers = [ ['Personal', 'For one person.', '$0', ['One portable identity', 'Push approval on devices', 'NFC tap-to-authenticate', 'Anchored on Cardano'], 'Claim your identity'], ['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'], ['Enterprise', 'Above $1M ARR.', 'Fair', ['Self-hosted and air-gap deployable', 'Compliance and audit support', 'Global admin across orgs', 'Priority SLA'], 'Talk to us'], ]; return html`
Pricing

The same identity, at every scale.

Free for the first thousand users. Fair contribution above that. No hard paywalls.

${tiers.map((tierArg, indexArg) => html`
${tierArg[0]}

${tierArg[1]}

${tierArg[2]}
    ${(tierArg[3] as string[]).map((itemArg) => html`
  • ${itemArg}
  • `)}
${tierArg[4]}
`)}
`; } private renderDevelopers() { return html`
For developers

No black boxes in your identity stack.

idp.global is fully open source and MIT licensed. Read the cryptography. Verify the Cardano sync. Run it on your own metal.

${['MIT licensed', 'OAuth 2 / OIDC', 'Self-hostable', 'Air-gappable', 'Cardano native', 'SOC 2'].map((tagArg) => html`${tagArg}`)}
View source
$ idp identity create
OK Identity created - did:idp:0x4a3f...c819
OK Confirmed on-chain - permanent

$ idp login github.com
OK Push sent - iPhone 15 Pro
OK Approved - Watch - 0.8s
`; } public render(): TemplateResult { return html`
${this.renderNav()}
Built for identity at every scale
${['Open Source', 'Self-hostable', 'Cardano anchored', 'OIDC ready', 'Passkey first', 'Free for everyone'].map((nameArg) => html`
${nameArg}
`)}
${this.renderFeatures()}${this.renderChain()}${this.renderPricing()}${this.renderDevelopers()}
Why we built this
Identity should not be a product the user is sold.
It should be a permanent fact, owned by the person it describes.

Claim your identity.
Free, forever.

Sixty seconds to claim, anchored to Cardano on submission. No credit card. No vendor lock-in.

Claim your identity
`; } }