{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "login-01",
  "title": "Console SSO Login",
  "type": "registry:page",
  "description": "Split-screen developer console authentication suite featuring brand telemetry showcases, OAuth providers, passkey biometric sign-in, and automatic enterprise SAML SSO domain detection.",
  "categories": [
    "auth"
  ],
  "files": [
    {
      "path": "packages/elements-lit/src/blocks/login-01/login-01.ts",
      "content": "import { LitElement, css, html, nothing } from 'lit'\nimport { ArrowRight, CheckCircle2, Fingerprint, KeyRound, Lock, Mail, ShieldCheck, Terminal, Zap } from 'lucide'\nimport { cn } from '../../lib/utils'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\nimport { icon } from '../../lib/icon'\n// Side-effect imports: register the composed elements for standalone use\n// (consumers who install only this block still get working primitives).\nimport '../../components/badge/badge'\nimport '../../components/button/button'\nimport '../../components/input/input'\nimport type { UipInput } from '../../components/input/input'\nimport '../../components/label/label'\nimport '../../components/separator/separator'\nimport '../../components/tabs/tabs'\n\nexport type LoginMethod = 'password' | 'passkey' | 'sso'\n\nexport interface LoginSubmitPayload {\n  method: LoginMethod\n  email: string\n  password?: string\n  domain?: string\n}\n\n/**\n * <uip-login-01> — the registry Login01 block as a web component.\n *\n * Class strings are React's Login01 verbatim. React state (useState) becomes\n * @state fields; `onSubmit` (payload) / `onForgotPassword` / `onSignUp` /\n * `onOAuth` (provider) become `submit` / `forgot-password` / `sign-up` /\n * `oauth` CustomEvents (bubbles, composed). The Mail/Lock field icons move\n * from React's absolute overlay into <uip-input>'s prefix slot (same visual\n * result, no overlay positioning to maintain).\n */\nexport class UipLogin01 extends LitElement {\n  static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n  // :host display can't be a utility class (the host has no template of its own).\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  static properties = {\n    authMethod: { state: true },\n    email: { state: true },\n    password: { state: true },\n    ssoDomain: { state: true },\n    isLoading: { state: true },\n  }\n\n  private authMethod: LoginMethod = 'password'\n  private email = ''\n  private password = ''\n  private ssoDomain = ''\n  private isLoading = false\n  private timer?: number\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'login-01')\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback()\n    if (this.timer) window.clearTimeout(this.timer)\n  }\n\n  private get isEnterpriseEmail(): boolean {\n    const parts = this.email.split('@')\n    if (parts.length < 2) return false\n    const domain = parts[1].toLowerCase()\n    return !!domain && !['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com'].includes(domain) && domain.includes('.')\n  }\n\n  private handleSubmit(e: Event) {\n    e.preventDefault()\n    if (this.isLoading) return\n    this.isLoading = true\n    this.timer = window.setTimeout(() => {\n      this.isLoading = false\n      this.dispatchEvent(\n        new CustomEvent<LoginSubmitPayload>('submit', {\n          detail: { method: this.authMethod, email: this.email, password: this.password, domain: this.ssoDomain },\n          bubbles: true,\n          composed: true,\n        }),\n      )\n    }, 800)\n  }\n\n  render() {\n    return html`\n      <div data-slot=\"login-01\" class=${cn('bg-background grid min-h-screen w-full grid-cols-1 lg:grid-cols-12')}>\n        <div\n          class=\"border-border bg-muted/30 relative hidden flex-col justify-between overflow-hidden border-r p-12 lg:col-span-6 lg:flex xl:col-span-7\"\n        >\n          <div class=\"relative z-10 flex items-center gap-2.5\">\n            <div class=\"bg-primary text-primary-foreground flex size-9 items-center justify-center rounded-lg font-bold shadow-xs\">\n              ${icon(Zap, 'zap', 'size-5 fill-current')}\n            </div>\n            <span class=\"text-foreground text-lg font-bold tracking-tight\">UIPKGE Studio</span>\n          </div>\n\n          <div class=\"relative z-10 my-auto max-w-xl space-y-6\">\n            <div class=\"space-y-3\">\n              <div\n                class=\"border-primary/20 bg-primary/10 text-primary inline-flex items-center gap-2 rounded-full border px-3 py-1 font-mono text-xs font-semibold\"\n              >\n                ${icon(Terminal, 'terminal', 'size-3.5')}\n                <span>Developer Cloud Console v4.8</span>\n              </div>\n              <h1 class=\"text-foreground text-3xl leading-tight font-bold tracking-tight xl:text-4xl\">\n                The dual-framework UI registry for mission-critical software.\n              </h1>\n              <p class=\"text-muted-foreground text-sm leading-relaxed\">\n                Own your source code without runtime dependency lock-in. Built with Tailwind CSS v4, OKLCH color spaces,\n                and headless accessibility primitives.\n              </p>\n            </div>\n\n            <div class=\"border-border bg-card overflow-hidden rounded-xl border shadow-lg\">\n              <div class=\"border-border bg-muted/40 flex items-center justify-between border-b px-4 py-2.5\">\n                <div class=\"flex items-center gap-2\">\n                  <span class=\"bg-destructive/60 size-2.5 rounded-full\"></span>\n                  <span class=\"bg-warning/60 size-2.5 rounded-full\"></span>\n                  <span class=\"bg-success/60 size-2.5 rounded-full\"></span>\n                  <span class=\"text-muted-foreground ml-2 font-mono text-xs\">auth-session-init.ts</span>\n                </div>\n                <uip-badge variant=\"outline\" class=\"font-mono text-xs\">mTLS Encrypted</uip-badge>\n              </div>\n              <div class=\"bg-card/90 space-y-1 p-4 font-mono text-xs leading-relaxed\">\n                <p class=\"text-muted-foreground\">// Validating SAML 2.0 / WebAuthn identity assertion</p>\n                <p class=\"text-foreground\">\n                  <span class=\"text-primary font-bold\">const</span> session =\n                  <span class=\"text-primary font-bold\">await</span> auth.<span class=\"text-foreground font-semibold\"\n                    >verifyCredentials</span\n                  >({\n                </p>\n                <p class=\"text-foreground pl-4\">tenant: <span class=\"text-success\">'cyberdyne-systems.internal'</span>,</p>\n                <p class=\"text-foreground pl-4\">\n                  protocols: [<span class=\"text-success\">'webauthn-fido2'</span>,\n                  <span class=\"text-success\">'saml2-okta'</span>]\n                </p>\n                <p class=\"text-foreground\">});</p>\n                <p class=\"text-success flex items-center gap-1.5 pt-1 font-medium\">\n                  ${icon(CheckCircle2, 'circle-check', 'size-3.5')}\n                  <span>✓ Cryptographic identity handshaking verified (0.8ms)</span>\n                </p>\n              </div>\n            </div>\n\n            <div class=\"border-border grid grid-cols-3 gap-4 border-t pt-4 text-xs\">\n              <div>\n                <p class=\"text-foreground font-mono text-lg font-bold\">99.95%</p>\n                <p class=\"text-muted-foreground\">Auth Uptime SLA</p>\n              </div>\n              <div>\n                <p class=\"text-foreground font-mono text-lg font-bold\">FIDO2</p>\n                <p class=\"text-muted-foreground\">Passkey Standard</p>\n              </div>\n              <div>\n                <p class=\"text-foreground font-mono text-lg font-bold\">SOC 2 Type II</p>\n                <p class=\"text-muted-foreground\">Certified Cloud</p>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"text-muted-foreground relative z-10 flex items-center justify-between text-xs\">\n            <span>© 2026 UIPKGE Inc.</span>\n            <div class=\"flex gap-4\">\n              <a href=\"#\" class=\"hover:text-foreground transition-colors\">Privacy Policy</a>\n              <a href=\"#\" class=\"hover:text-foreground transition-colors\">Terms of Service</a>\n              <a href=\"#\" class=\"hover:text-foreground transition-colors\">Trust Center</a>\n            </div>\n          </div>\n        </div>\n\n        <div class=\"flex flex-col items-center justify-center p-6 sm:p-12 lg:col-span-6 xl:col-span-5\">\n          <div class=\"w-full max-w-md space-y-6\">\n            <div class=\"mb-4 flex items-center gap-2 lg:hidden\">\n              <div class=\"bg-primary text-primary-foreground flex size-8 items-center justify-center rounded-lg font-bold shadow-xs\">\n                ${icon(Zap, 'zap', 'size-4 fill-current')}\n              </div>\n              <span class=\"text-foreground font-bold tracking-tight\">UIPKGE Studio</span>\n            </div>\n\n            <div class=\"space-y-2\">\n              <h2 class=\"text-foreground text-2xl font-bold tracking-tight\">Sign in to console</h2>\n              <p class=\"text-muted-foreground text-xs\">Enter your credentials, passkey or company Single Sign-On.</p>\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-3\">\n              <uip-button\n                variant=\"outline\"\n                type=\"button\"\n                class=\"h-10 gap-2 text-xs font-semibold\"\n                @click=${() =>\n                  this.dispatchEvent(new CustomEvent('oauth', { detail: 'github', bubbles: true, composed: true }))}\n              >\n                <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" width=\"16\" height=\"16\">\n                  <path\n                    d=\"M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.3.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.4-1.3-1.7-1.3-1.7-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.8 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.3 1.2a11.4 11.4 0 016 0C17 4.7 18 5 18 5c.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.5-2.7 5.5-5.3 5.8.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z\"\n                  />\n                </svg>\n                <span>GitHub</span>\n              </uip-button>\n              <uip-button\n                variant=\"outline\"\n                type=\"button\"\n                class=\"h-10 gap-2 text-xs font-semibold\"\n                @click=${() =>\n                  this.dispatchEvent(new CustomEvent('oauth', { detail: 'google', bubbles: true, composed: true }))}\n              >\n                <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" aria-hidden=\"true\">\n                  <path\n                    fill=\"#4285F4\"\n                    d=\"M22.5 12.27c0-.79-.07-1.54-.2-2.27H12v4.51h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.32z\"\n                  />\n                  <path\n                    fill=\"#34A853\"\n                    d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.99.66-2.25 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n                  />\n                  <path\n                    fill=\"#FBBC05\"\n                    d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l2.85-2.22.81-.63z\"\n                  />\n                  <path\n                    fill=\"#EA4335\"\n                    d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z\"\n                  />\n                </svg>\n                <span>Google</span>\n              </uip-button>\n            </div>\n\n            <div class=\"relative\">\n              <uip-separator></uip-separator>\n              <span\n                class=\"bg-background text-muted-foreground absolute -top-2.5 left-1/2 -translate-x-1/2 px-3 font-mono text-xs tracking-wider uppercase\"\n                >Or continue with</span\n              >\n            </div>\n\n            <uip-tabs\n              class=\"w-full\"\n              value=${this.authMethod}\n              @value-change=${(e: CustomEvent<{ value: string }>) => {\n                this.authMethod = e.detail.value as LoginMethod\n              }}\n            >\n              <span slot=\"trigger\" data-value=\"password\" class=\"text-xs font-medium\">Password</span>\n              <span slot=\"trigger\" data-value=\"passkey\" class=\"text-xs font-medium\">Passkey</span>\n              <span slot=\"trigger\" data-value=\"sso\" class=\"text-xs font-medium\">SAML SSO</span>\n\n              <div slot=\"content\" data-value=\"password\" class=\"mt-4 space-y-4\">\n                <form class=\"space-y-4\" @submit=${this.handleSubmit}>\n                  <div class=\"space-y-1.5\">\n                    <uip-label for=\"lit-email-input\" class=\"text-xs font-medium\">Work Email</uip-label>\n                    <uip-input\n                      id=\"lit-email-input\"\n                      class=\"text-xs\"\n                      .value=${this.email}\n                      type=\"email\"\n                      placeholder=\"alex@company.com\"\n                      autocomplete=\"email\"\n                      required\n                      @input=${(e: Event) => {\n                        this.email = (e.target as UipInput).value\n                      }}\n                    >\n                      <span slot=\"prefix\">${icon(Mail, 'mail', 'size-4')}</span>\n                    </uip-input>\n                    ${this.isEnterpriseEmail\n                      ? html`<div class=\"text-primary mt-1 flex items-center gap-1.5 text-xs font-medium\">\n                          ${icon(ShieldCheck, 'shield-check', 'size-3.5')}\n                          <span>Enterprise domain detected. Single Sign-On available.</span>\n                        </div>`\n                      : nothing}\n                  </div>\n\n                  <div class=\"space-y-1.5\">\n                    <div class=\"flex items-center justify-between\">\n                      <uip-label for=\"lit-pass-input\" class=\"text-xs font-medium\">Password</uip-label>\n                      <button\n                        type=\"button\"\n                        class=\"text-muted-foreground hover:text-foreground text-xs transition-colors\"\n                        @click=${() => this.dispatchEvent(new CustomEvent('forgot-password', { bubbles: true, composed: true }))}\n                      >\n                        Forgot password?\n                      </button>\n                    </div>\n                    <uip-input\n                      id=\"lit-pass-input\"\n                      class=\"text-xs\"\n                      .value=${this.password}\n                      type=\"password\"\n                      placeholder=\"••••••••••••\"\n                      autocomplete=\"current-password\"\n                      required\n                      @input=${(e: Event) => {\n                        this.password = (e.target as UipInput).value\n                      }}\n                    >\n                      <span slot=\"prefix\">${icon(Lock, 'lock', 'size-4')}</span>\n                    </uip-input>\n                  </div>\n\n                  <uip-button type=\"submit\" class=\"h-10 w-full gap-2 text-xs font-semibold\" ?disabled=${this.isLoading}>\n                    ${this.isLoading\n                      ? html`<span class=\"border-primary-foreground size-3.5 animate-spin rounded-full border-2 border-t-transparent\"></span>`\n                      : html`<span>Continue with Password</span>`}\n                    ${icon(ArrowRight, 'arrow-right', 'size-3.5')}\n                  </uip-button>\n                </form>\n              </div>\n\n              <div slot=\"content\" data-value=\"passkey\" class=\"mt-4 space-y-4\">\n                <div class=\"border-border bg-card space-y-4 rounded-xl border p-6 text-center\">\n                  <div class=\"bg-primary/10 text-primary mx-auto flex size-12 items-center justify-center rounded-full\">\n                    ${icon(Fingerprint, 'fingerprint', 'size-6')}\n                  </div>\n                  <div class=\"space-y-1\">\n                    <p class=\"text-foreground text-sm font-semibold\">Passwordless Biometric Login</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Use Touch ID, Face ID, or a FIDO2 hardware security key for zero-friction sign in.\n                    </p>\n                  </div>\n                  <uip-button\n                    type=\"button\"\n                    class=\"h-10 w-full gap-2 text-xs font-semibold\"\n                    ?disabled=${this.isLoading}\n                    @click=${this.handleSubmit}\n                  >\n                    ${icon(Fingerprint, 'fingerprint', 'size-4')}\n                    <span>${this.isLoading ? 'Authenticating...' : 'Sign in with Passkey'}</span>\n                  </uip-button>\n                </div>\n              </div>\n\n              <div slot=\"content\" data-value=\"sso\" class=\"mt-4 space-y-4\">\n                <form class=\"space-y-4\" @submit=${this.handleSubmit}>\n                  <div class=\"space-y-1.5\">\n                    <uip-label for=\"lit-sso-domain\" class=\"text-xs font-medium\">Enterprise Domain</uip-label>\n                    <uip-input\n                      id=\"lit-sso-domain\"\n                      class=\"font-mono text-xs\"\n                      .value=${this.ssoDomain}\n                      type=\"text\"\n                      placeholder=\"company.okta.com or domain.com\"\n                      required\n                      @input=${(e: Event) => {\n                        this.ssoDomain = (e.target as UipInput).value\n                      }}\n                    ></uip-input>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Redirects to your corporate Identity Provider (Okta, Azure AD, Ping Identity).\n                    </p>\n                  </div>\n\n                  <uip-button type=\"submit\" class=\"h-10 w-full gap-2 text-xs font-semibold\" ?disabled=${this.isLoading}>\n                    ${icon(KeyRound, 'key-round', 'size-3.5')}\n                    <span>Continue with SAML SSO</span>\n                    ${icon(ArrowRight, 'arrow-right', 'size-3.5')}\n                  </uip-button>\n                </form>\n              </div>\n            </uip-tabs>\n\n            <div class=\"text-muted-foreground text-center text-xs\">\n              Don't have a workspace account?\n              <button\n                type=\"button\"\n                class=\"text-primary ml-1 font-semibold hover:underline\"\n                @click=${() => this.dispatchEvent(new CustomEvent('sign-up', { bubbles: true, composed: true }))}\n              >\n                Create free trial\n              </button>\n            </div>\n          </div>\n        </div>\n      </div>\n    `\n  }\n}\n\ncustomElements.get('uip-login-01') || customElements.define('uip-login-01', UipLogin01)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-login-01': UipLogin01\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/blocks/login-01/login-01.ts"
    }
  ],
  "dependencies": [
    "lit",
    "lucide"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/badge.json",
    "https://uipkge.dev/r/lit/button.json",
    "https://uipkge.dev/r/lit/input.json",
    "https://uipkge.dev/r/lit/label.json",
    "https://uipkge.dev/r/lit/lit-core.json",
    "https://uipkge.dev/r/lit/separator.json",
    "https://uipkge.dev/r/lit/tabs.json"
  ]
}
