@avora-labs/meta-forge 1.0.6 → 1.1.2

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.
package/README.md CHANGED
Binary file
@@ -29,8 +29,8 @@ class AmfAuthShellComponent {
29
29
  brandTagline;
30
30
  /** Override the card's max-width (default 560px) */
31
31
  maxWidth = '560px';
32
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfAuthShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: AmfAuthShellComponent, isStandalone: true, selector: "amf-auth-shell", inputs: { brandName: "brandName", brandTagline: "brandTagline", maxWidth: "maxWidth" }, ngImport: i0, template: `
32
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AmfAuthShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.15", type: AmfAuthShellComponent, isStandalone: true, selector: "amf-auth-shell", inputs: { brandName: "brandName", brandTagline: "brandTagline", maxWidth: "maxWidth" }, ngImport: i0, template: `
34
34
  <div class="auth-page">
35
35
  <!-- Animated Background Orbs -->
36
36
  <div class="bg-mesh" aria-hidden="true">
@@ -60,7 +60,7 @@ class AmfAuthShellComponent {
60
60
  </div>
61
61
  `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.auth-page{height:100%;background:#0a0f1e;position:relative;display:flex;flex-direction:column}.bg-mesh{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none}.orb{position:absolute;border-radius:50%;filter:blur(100px);opacity:.4;will-change:transform}.orb-1{width:clamp(200px,50vw,600px);height:clamp(200px,50vw,600px);background:var(--app-gradient-1, radial-gradient(circle, #6366f1, transparent));top:-20%;right:-10%;animation:blobMove1 18s ease-in-out infinite}.orb-2{width:clamp(160px,40vw,500px);height:clamp(160px,40vw,500px);background:var(--app-gradient-2, radial-gradient(circle, #c084fc, transparent));bottom:-15%;left:-10%;animation:blobMove2 22s ease-in-out infinite}.orb-3{width:clamp(100px,25vw,300px);height:clamp(100px,25vw,300px);background:var(--app-gradient-3, radial-gradient(circle, #38bdf8, transparent));top:50%;left:50%;animation:blobMove3 20s ease-in-out infinite}.orb-4{width:clamp(80px,16vw,200px);height:clamp(80px,16vw,200px);background:var(--app-primary, #6366f1);top:20%;left:20%;opacity:.2;animation:blobMove1 25s ease-in-out infinite reverse}.auth-scroll-wrapper{flex:1;display:flex;align-items:flex-start;justify-content:center;overflow-y:auto;overflow-x:hidden;padding:clamp(32px,5vw,56px) clamp(12px,4vw,24px);padding-top:max(env(safe-area-inset-top,0px),clamp(32px,5vw,56px));padding-bottom:max(env(safe-area-inset-bottom,0px),clamp(32px,5vw,56px));position:relative;z-index:1}.auth-card{background:#ffffff0d;backdrop-filter:blur(40px);-webkit-backdrop-filter:blur(40px);width:100%;max-width:600px;margin:auto;padding:clamp(16px,3vw,24px) clamp(24px,5vw,52px);border-radius:clamp(14px,2.5vw,20px);border:1px solid rgba(255,255,255,.1);box-shadow:0 25px 50px -12px #00000080,0 0 40px #0003,inset 0 1px #ffffff1a;animation:fadeInUp .5s ease-out both}.auth-card:before{content:\"\";position:absolute;inset:-1px;border-radius:inherit;background:linear-gradient(135deg,rgba(255,255,255,.1) 0%,transparent 50%,rgba(255,255,255,.05) 100%);z-index:-1;pointer-events:none}.brand{text-align:center;margin-bottom:clamp(10px,2vw,18px)}.brand-logo{width:clamp(40px,8vw,52px);height:clamp(40px,8vw,52px);background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;border-radius:14px;display:flex;align-items:center;justify-content:center;margin:0 auto clamp(8px,1.5vw,12px);box-shadow:0 0 24px var(--app-glow, rgba(99,102,241,.4));animation:float 4s ease-in-out infinite}.brand-logo svg{width:clamp(20px,4vw,26px);height:clamp(20px,4vw,26px);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.brand h1{font-size:clamp(1.2rem,3vw,1.65rem);font-weight:800;margin-bottom:3px;color:#f1f5f9;letter-spacing:-.02em}.brand p{color:#94a3b8;font-size:clamp(.75rem,1.8vw,.82rem)}@media(max-width:359px){.auth-card{border-radius:12px;backdrop-filter:none;-webkit-backdrop-filter:none;background:#0f1428f7}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(24px)}to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@keyframes blobMove1{0%,to{transform:translate(0) scale(1)}33%{transform:translate(30px,-40px) scale(1.05)}66%{transform:translate(-20px,20px) scale(.95)}}@keyframes blobMove2{0%,to{transform:translate(0) scale(1)}33%{transform:translate(-30px,30px) scale(1.05)}66%{transform:translate(20px,-20px) scale(.95)}}@keyframes blobMove3{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.2)}}@media(prefers-reduced-motion:reduce){.orb,.brand-logo,.auth-card{animation:none!important}}\n"] });
62
62
  }
63
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfAuthShellComponent, decorators: [{
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AmfAuthShellComponent, decorators: [{
64
64
  type: Component,
65
65
  args: [{ selector: 'amf-auth-shell', standalone: true, imports: [], template: `
66
66
  <div class="auth-page">
@@ -100,4 +100,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
100
100
  }] } });
101
101
 
102
102
  export { AmfAuthShellComponent as A };
103
- //# sourceMappingURL=avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs.map
103
+ //# sourceMappingURL=avora-labs-meta-forge-amf-auth-shell.component-C89gSPc9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/renderers/auth/amf-auth-shell.component.ts"],"sourcesContent":["/**\n * AvoraMetaForge — Auth Shell Component\n *\n * A reusable full-page auth card renderer providing the glassmorphism\n * background and card layout shared by Login, Forgot Password, Contact\n * Support, and any other auth screen built with AvoraMetaForge.\n *\n * ## Responsiveness\n * This shell is fully mobile-first. On small screens (< 480 px) the card\n * fills the viewport and scrolls naturally; on larger screens it is a\n * centered floating card capped at `maxWidth`.\n *\n * ## Usage\n * <amf-auth-shell [brandName]=\"'MyApp'\" [brandTagline]=\"'Enterprise platform'\">\n * <!-- your form, steps, or custom HTML here -->\n * </amf-auth-shell>\n *\n * ## Icon system\n * Use <span class=\"ms\">lock</span> (Material Symbols Rounded) anywhere inside\n * the shell. The .ms class is globally defined in index.html.\n */\nimport { Component, Input } from '@angular/core';\n\n\n@Component({\n selector: 'amf-auth-shell',\n standalone: true,\n imports: [],\n template: `\n <div class=\"auth-page\">\n <!-- Animated Background Orbs -->\n <div class=\"bg-mesh\" aria-hidden=\"true\">\n <div class=\"orb orb-1\"></div>\n <div class=\"orb orb-2\"></div>\n <div class=\"orb orb-3\"></div>\n <div class=\"orb orb-4\"></div>\n </div>\n\n <div class=\"auth-scroll-wrapper\">\n <div class=\"auth-card\" [style.max-width]=\"maxWidth\">\n <!-- Brand Header -->\n <div class=\"brand\">\n <div class=\"brand-logo\">\n <svg viewBox=\"0 0 24 24\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\"></path>\n </svg>\n </div>\n <h1>{{ brandName || 'AvoraMetaForge' }}</h1>\n <p>{{ brandTagline || 'The universal enterprise shell' }}</p>\n </div>\n\n <!-- Projected content slot -->\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n `,\n styles: [`\n /* ─── Host fills the full slot given by router-outlet ─── */\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n /* ─────────────────────────────────────────\n PAGE ROOT — fills parent, no overflow clip\n so the inner scroll wrapper can breathe\n ───────────────────────────────────────── */\n .auth-page {\n height: 100%;\n background: #0a0f1e;\n position: relative;\n display: flex;\n flex-direction: column;\n }\n\n /* ── Animated Background ── */\n .bg-mesh {\n position: fixed;\n inset: 0;\n z-index: 0;\n overflow: hidden;\n pointer-events: none;\n }\n .orb {\n position: absolute;\n border-radius: 50%;\n filter: blur(100px);\n opacity: 0.4;\n will-change: transform;\n }\n .orb-1 {\n width: clamp(200px, 50vw, 600px);\n height: clamp(200px, 50vw, 600px);\n background: var(--app-gradient-1, radial-gradient(circle, #6366f1, transparent));\n top: -20%; right: -10%;\n animation: blobMove1 18s ease-in-out infinite;\n }\n .orb-2 {\n width: clamp(160px, 40vw, 500px);\n height: clamp(160px, 40vw, 500px);\n background: var(--app-gradient-2, radial-gradient(circle, #c084fc, transparent));\n bottom: -15%; left: -10%;\n animation: blobMove2 22s ease-in-out infinite;\n }\n .orb-3 {\n width: clamp(100px, 25vw, 300px);\n height: clamp(100px, 25vw, 300px);\n background: var(--app-gradient-3, radial-gradient(circle, #38bdf8, transparent));\n top: 50%; left: 50%;\n animation: blobMove3 20s ease-in-out infinite;\n }\n .orb-4 {\n width: clamp(80px, 16vw, 200px);\n height: clamp(80px, 16vw, 200px);\n background: var(--app-primary, #6366f1);\n top: 20%; left: 20%;\n opacity: 0.2;\n animation: blobMove1 25s ease-in-out infinite reverse;\n }\n\n /* ─────────────────────────────────────────\n SCROLL WRAPPER\n On mobile the card can exceed the screen\n height — this wrapper makes it scrollable.\n ───────────────────────────────────────── */\n .auth-scroll-wrapper {\n flex: 1;\n display: flex;\n align-items: flex-start; /* always flex-start; card uses margin:auto to self-center */\n justify-content: center;\n overflow-y: auto;\n overflow-x: hidden;\n padding: clamp(32px, 5vw, 56px) clamp(12px, 4vw, 24px);\n padding-top: max(env(safe-area-inset-top, 0px), clamp(32px, 5vw, 56px));\n padding-bottom: max(env(safe-area-inset-bottom, 0px), clamp(32px, 5vw, 56px));\n position: relative;\n z-index: 1;\n }\n\n /* ── Auth Card ── */\n .auth-card {\n background: rgba(255, 255, 255, 0.05);\n backdrop-filter: blur(40px);\n -webkit-backdrop-filter: blur(40px);\n width: 100%;\n max-width: 600px;\n /* margin:auto centers the card when there is spare space in the scroll wrapper,\n but unlike align-items:center it does NOT clip the top when the card overflows —\n the wrapper's padding-top stays visible as the user scrolls up. */\n margin: auto;\n /* Vertical padding kept tight to reduce card height; horizontal generous for width */\n padding: clamp(16px, 3vw, 24px) clamp(24px, 5vw, 52px);\n border-radius: clamp(14px, 2.5vw, 20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow:\n 0 25px 50px -12px rgba(0, 0, 0, 0.5),\n 0 0 40px rgba(0, 0, 0, 0.2),\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\n animation: fadeInUp 0.5s ease-out both;\n }\n .auth-card::before {\n content: '';\n position: absolute;\n top: -1px; left: -1px; right: -1px; bottom: -1px;\n border-radius: inherit;\n background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%, rgba(255,255,255,0.05) 100%);\n z-index: -1;\n pointer-events: none;\n }\n\n /* ── Brand — compact horizontal layout on wide screens ── */\n .brand {\n text-align: center;\n margin-bottom: clamp(10px, 2vw, 18px);\n }\n .brand-logo {\n width: clamp(40px, 8vw, 52px);\n height: clamp(40px, 8vw, 52px);\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto clamp(8px, 1.5vw, 12px);\n box-shadow: 0 0 24px var(--app-glow, rgba(99,102,241,0.4));\n animation: float 4s ease-in-out infinite;\n }\n .brand-logo svg {\n width: clamp(20px, 4vw, 26px);\n height: clamp(20px, 4vw, 26px);\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n .brand h1 {\n font-size: clamp(1.2rem, 3vw, 1.65rem);\n font-weight: 800;\n margin-bottom: 3px;\n color: #f1f5f9;\n letter-spacing: -0.02em;\n }\n .brand p {\n color: #94a3b8;\n font-size: clamp(0.75rem, 1.8vw, 0.82rem);\n }\n\n /* ─────────────────────────────────────────\n EXTRA-SMALL SCREENS (< 360 px)\n Reduce border-radius and disable blur for\n performance on very low-end devices.\n ───────────────────────────────────────── */\n @media (max-width: 359px) {\n .auth-card {\n border-radius: 12px;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n background: rgba(15, 20, 40, 0.97);\n }\n }\n\n /* ─────────────────────────────────────────\n ANIMATIONS\n ───────────────────────────────────────── */\n @keyframes fadeInUp {\n from { opacity: 0; transform: translateY(24px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes float {\n 0%, 100% { transform: translateY(0px); }\n 50% { transform: translateY(-6px); }\n }\n @keyframes blobMove1 {\n 0%, 100% { transform: translate(0, 0) scale(1); }\n 33% { transform: translate(30px, -40px) scale(1.05); }\n 66% { transform: translate(-20px, 20px) scale(0.95); }\n }\n @keyframes blobMove2 {\n 0%, 100% { transform: translate(0, 0) scale(1); }\n 33% { transform: translate(-30px, 30px) scale(1.05); }\n 66% { transform: translate(20px, -20px) scale(0.95); }\n }\n @keyframes blobMove3 {\n 0%, 100% { transform: translate(-50%, -50%) scale(1); }\n 50% { transform: translate(-50%, -50%) scale(1.2); }\n }\n\n /* ── Reduce motion for accessibility ── */\n @media (prefers-reduced-motion: reduce) {\n .orb, .brand-logo, .auth-card {\n animation: none !important;\n }\n }\n `]\n})\nexport class AmfAuthShellComponent {\n /** App brand name shown in the card header */\n @Input() brandName?: string;\n /** Tagline shown below the brand name */\n @Input() brandTagline?: string;\n /** Override the card's max-width (default 560px) */\n @Input() maxWidth?: string = '560px';\n}\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;AAoBG;MA+OU,qBAAqB,CAAA;;AAEvB,IAAA,SAAS;;AAET,IAAA,YAAY;;IAEZ,QAAQ,GAAY,OAAO;wGANzB,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,YAAA,EAAA,cAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAvOtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,6kHAAA,CAAA,EAAA,CAAA;;4FA2MU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA3OjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,EAAA,UAAA,EACd,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,6kHAAA,CAAA,EAAA;;sBA6MA;;sBAEA;;sBAEA;;;;;"}
1
+ {"version":3,"file":"avora-labs-meta-forge-amf-auth-shell.component-C89gSPc9.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/renderers/auth/amf-auth-shell.component.ts"],"sourcesContent":["/**\n * AvoraMetaForge — Auth Shell Component\n *\n * A reusable full-page auth card renderer providing the glassmorphism\n * background and card layout shared by Login, Forgot Password, Contact\n * Support, and any other auth screen built with AvoraMetaForge.\n *\n * ## Responsiveness\n * This shell is fully mobile-first. On small screens (< 480 px) the card\n * fills the viewport and scrolls naturally; on larger screens it is a\n * centered floating card capped at `maxWidth`.\n *\n * ## Usage\n * <amf-auth-shell [brandName]=\"'MyApp'\" [brandTagline]=\"'Enterprise platform'\">\n * <!-- your form, steps, or custom HTML here -->\n * </amf-auth-shell>\n *\n * ## Icon system\n * Use <span class=\"ms\">lock</span> (Material Symbols Rounded) anywhere inside\n * the shell. The .ms class is globally defined in index.html.\n */\nimport { Component, Input } from '@angular/core';\n\n\n@Component({\n selector: 'amf-auth-shell',\n standalone: true,\n imports: [],\n template: `\n <div class=\"auth-page\">\n <!-- Animated Background Orbs -->\n <div class=\"bg-mesh\" aria-hidden=\"true\">\n <div class=\"orb orb-1\"></div>\n <div class=\"orb orb-2\"></div>\n <div class=\"orb orb-3\"></div>\n <div class=\"orb orb-4\"></div>\n </div>\n\n <div class=\"auth-scroll-wrapper\">\n <div class=\"auth-card\" [style.max-width]=\"maxWidth\">\n <!-- Brand Header -->\n <div class=\"brand\">\n <div class=\"brand-logo\">\n <svg viewBox=\"0 0 24 24\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\"></path>\n </svg>\n </div>\n <h1>{{ brandName || 'AvoraMetaForge' }}</h1>\n <p>{{ brandTagline || 'The universal enterprise shell' }}</p>\n </div>\n\n <!-- Projected content slot -->\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n `,\n styles: [`\n /* ─── Host fills the full slot given by router-outlet ─── */\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n /* ─────────────────────────────────────────\n PAGE ROOT — fills parent, no overflow clip\n so the inner scroll wrapper can breathe\n ───────────────────────────────────────── */\n .auth-page {\n height: 100%;\n background: #0a0f1e;\n position: relative;\n display: flex;\n flex-direction: column;\n }\n\n /* ── Animated Background ── */\n .bg-mesh {\n position: fixed;\n inset: 0;\n z-index: 0;\n overflow: hidden;\n pointer-events: none;\n }\n .orb {\n position: absolute;\n border-radius: 50%;\n filter: blur(100px);\n opacity: 0.4;\n will-change: transform;\n }\n .orb-1 {\n width: clamp(200px, 50vw, 600px);\n height: clamp(200px, 50vw, 600px);\n background: var(--app-gradient-1, radial-gradient(circle, #6366f1, transparent));\n top: -20%; right: -10%;\n animation: blobMove1 18s ease-in-out infinite;\n }\n .orb-2 {\n width: clamp(160px, 40vw, 500px);\n height: clamp(160px, 40vw, 500px);\n background: var(--app-gradient-2, radial-gradient(circle, #c084fc, transparent));\n bottom: -15%; left: -10%;\n animation: blobMove2 22s ease-in-out infinite;\n }\n .orb-3 {\n width: clamp(100px, 25vw, 300px);\n height: clamp(100px, 25vw, 300px);\n background: var(--app-gradient-3, radial-gradient(circle, #38bdf8, transparent));\n top: 50%; left: 50%;\n animation: blobMove3 20s ease-in-out infinite;\n }\n .orb-4 {\n width: clamp(80px, 16vw, 200px);\n height: clamp(80px, 16vw, 200px);\n background: var(--app-primary, #6366f1);\n top: 20%; left: 20%;\n opacity: 0.2;\n animation: blobMove1 25s ease-in-out infinite reverse;\n }\n\n /* ─────────────────────────────────────────\n SCROLL WRAPPER\n On mobile the card can exceed the screen\n height — this wrapper makes it scrollable.\n ───────────────────────────────────────── */\n .auth-scroll-wrapper {\n flex: 1;\n display: flex;\n align-items: flex-start; /* always flex-start; card uses margin:auto to self-center */\n justify-content: center;\n overflow-y: auto;\n overflow-x: hidden;\n padding: clamp(32px, 5vw, 56px) clamp(12px, 4vw, 24px);\n padding-top: max(env(safe-area-inset-top, 0px), clamp(32px, 5vw, 56px));\n padding-bottom: max(env(safe-area-inset-bottom, 0px), clamp(32px, 5vw, 56px));\n position: relative;\n z-index: 1;\n }\n\n /* ── Auth Card ── */\n .auth-card {\n background: rgba(255, 255, 255, 0.05);\n backdrop-filter: blur(40px);\n -webkit-backdrop-filter: blur(40px);\n width: 100%;\n max-width: 600px;\n /* margin:auto centers the card when there is spare space in the scroll wrapper,\n but unlike align-items:center it does NOT clip the top when the card overflows —\n the wrapper's padding-top stays visible as the user scrolls up. */\n margin: auto;\n /* Vertical padding kept tight to reduce card height; horizontal generous for width */\n padding: clamp(16px, 3vw, 24px) clamp(24px, 5vw, 52px);\n border-radius: clamp(14px, 2.5vw, 20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow:\n 0 25px 50px -12px rgba(0, 0, 0, 0.5),\n 0 0 40px rgba(0, 0, 0, 0.2),\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\n animation: fadeInUp 0.5s ease-out both;\n }\n .auth-card::before {\n content: '';\n position: absolute;\n top: -1px; left: -1px; right: -1px; bottom: -1px;\n border-radius: inherit;\n background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%, rgba(255,255,255,0.05) 100%);\n z-index: -1;\n pointer-events: none;\n }\n\n /* ── Brand — compact horizontal layout on wide screens ── */\n .brand {\n text-align: center;\n margin-bottom: clamp(10px, 2vw, 18px);\n }\n .brand-logo {\n width: clamp(40px, 8vw, 52px);\n height: clamp(40px, 8vw, 52px);\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto clamp(8px, 1.5vw, 12px);\n box-shadow: 0 0 24px var(--app-glow, rgba(99,102,241,0.4));\n animation: float 4s ease-in-out infinite;\n }\n .brand-logo svg {\n width: clamp(20px, 4vw, 26px);\n height: clamp(20px, 4vw, 26px);\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n .brand h1 {\n font-size: clamp(1.2rem, 3vw, 1.65rem);\n font-weight: 800;\n margin-bottom: 3px;\n color: #f1f5f9;\n letter-spacing: -0.02em;\n }\n .brand p {\n color: #94a3b8;\n font-size: clamp(0.75rem, 1.8vw, 0.82rem);\n }\n\n /* ─────────────────────────────────────────\n EXTRA-SMALL SCREENS (< 360 px)\n Reduce border-radius and disable blur for\n performance on very low-end devices.\n ───────────────────────────────────────── */\n @media (max-width: 359px) {\n .auth-card {\n border-radius: 12px;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n background: rgba(15, 20, 40, 0.97);\n }\n }\n\n /* ─────────────────────────────────────────\n ANIMATIONS\n ───────────────────────────────────────── */\n @keyframes fadeInUp {\n from { opacity: 0; transform: translateY(24px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes float {\n 0%, 100% { transform: translateY(0px); }\n 50% { transform: translateY(-6px); }\n }\n @keyframes blobMove1 {\n 0%, 100% { transform: translate(0, 0) scale(1); }\n 33% { transform: translate(30px, -40px) scale(1.05); }\n 66% { transform: translate(-20px, 20px) scale(0.95); }\n }\n @keyframes blobMove2 {\n 0%, 100% { transform: translate(0, 0) scale(1); }\n 33% { transform: translate(-30px, 30px) scale(1.05); }\n 66% { transform: translate(20px, -20px) scale(0.95); }\n }\n @keyframes blobMove3 {\n 0%, 100% { transform: translate(-50%, -50%) scale(1); }\n 50% { transform: translate(-50%, -50%) scale(1.2); }\n }\n\n /* ── Reduce motion for accessibility ── */\n @media (prefers-reduced-motion: reduce) {\n .orb, .brand-logo, .auth-card {\n animation: none !important;\n }\n }\n `]\n})\nexport class AmfAuthShellComponent {\n /** App brand name shown in the card header */\n @Input() brandName?: string;\n /** Tagline shown below the brand name */\n @Input() brandTagline?: string;\n /** Override the card's max-width (default 560px) */\n @Input() maxWidth?: string = '560px';\n}\n"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;AAoBG;MA+OU,qBAAqB,CAAA;;AAEvB,IAAA,SAAS;;AAET,IAAA,YAAY;;IAEZ,QAAQ,GAAY,OAAO;wGANzB,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,YAAA,EAAA,cAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAvOtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,6kHAAA,CAAA,EAAA,CAAA;;4FA2MU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA3OjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,EAAA,UAAA,EACd,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,6kHAAA,CAAA,EAAA;;sBA6MA;;sBAEA;;sBAEA;;;;;"}
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms';
4
4
  import * as i1 from '@angular/router';
5
5
  import { RouterModule } from '@angular/router';
6
6
  import { ActionDispatcherService, APP_META_CONFIG_TOKEN, FormRendererComponent } from './avora-labs-meta-forge.mjs';
7
- import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs';
7
+ import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-C89gSPc9.mjs';
8
8
 
9
9
  /**
10
10
  * Contact Support Component
@@ -131,8 +131,8 @@ class ContactSupportComponent {
131
131
  }
132
132
  }).finally(() => this.loading.set(false));
133
133
  }
134
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ContactSupportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
135
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ContactSupportComponent, isStandalone: true, selector: "amf-contact-support", ngImport: i0, template: `
134
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ContactSupportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
135
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ContactSupportComponent, isStandalone: true, selector: "amf-contact-support", ngImport: i0, template: `
136
136
  <amf-auth-shell
137
137
  [brandName]="meta.auth?.builtInUI?.brandName || meta.app.name"
138
138
  [brandTagline]="meta.auth?.builtInUI?.brandTagline || 'We\\'re here to help'"
@@ -206,7 +206,7 @@ class ContactSupportComponent {
206
206
  </amf-auth-shell>
207
207
  `, isInline: true, styles: [":host{display:block;height:100%}.cs-header{display:flex;align-items:center;gap:14px;margin-bottom:clamp(12px,2.5vw,20px);padding-bottom:clamp(10px,2vw,16px);border-bottom:1px solid rgba(255,255,255,.07)}.icon-ms{font-size:2.4rem!important;font-variation-settings:\"FILL\" 1,\"wght\" 300,\"GRAD\" 0,\"opsz\" 48;background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;flex-shrink:0}.cs-header-text{flex:1}.cs-header h2{font-size:clamp(1.1rem,3vw,1.35rem);font-weight:700;color:#f1f5f9;margin:0 0 3px}.cs-header p{font-size:clamp(.75rem,1.8vw,.82rem);color:#64748b;margin:0;line-height:1.4}.channels{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:clamp(12px,2.5vw,20px)}.channel-card{display:flex;flex-direction:column;align-items:center;gap:6px;padding:clamp(8px,1.5vw,10px) 4px;background:#ffffff0a;border:1px solid rgba(255,255,255,.07);border-radius:14px;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);text-align:center;width:100%;position:relative;overflow:hidden}.channel-card:before{content:\"\";position:absolute;inset:0;background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));opacity:0;transition:opacity .25s}.channel-card:hover{border-color:#6366f159;background:#6366f10f;transform:translateY(-3px);box-shadow:0 6px 24px #6366f12e}.channel-card:hover:before{opacity:.04}.channel-card.active{border-color:#6366f180;background:#6366f11a}.channel-icon{width:clamp(28px,6vw,34px);height:clamp(28px,6vw,34px);border-radius:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:1}.channel-icon-ms{font-size:1.15rem!important;font-variation-settings:\"FILL\" 1,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24;color:#fff}.channel-title{font-size:clamp(.7rem,1.5vw,.78rem);font-weight:600;color:#e2e8f0;position:relative;z-index:1;line-height:1.2}.badge{font-size:.55rem;font-weight:700;background:linear-gradient(135deg,#10b981,#059669);color:#fff;padding:1px 5px;border-radius:6px;letter-spacing:.03em;text-transform:uppercase;position:relative;z-index:1;white-space:nowrap}.quick-msg{margin-top:0}.divider{display:flex;align-items:center;gap:12px;margin-bottom:12px;color:#475569;font-size:.78rem}.divider:before,.divider:after{content:\"\";flex:1;height:1px;background:#ffffff12}.cs-form-body{display:flex;flex-direction:column;gap:clamp(10px,2vw,14px)}.msg-form-container{display:flex;flex-direction:column;gap:10px}::ng-deep .msg-form-container .amf-form{gap:16px}::ng-deep .msg-form-container .amf-form-fields{gap:16px;align-items:stretch}::ng-deep .msg-form-container .amf-field{display:flex;flex-direction:column;gap:5px}::ng-deep .msg-form-container .field-label{font-size:.8rem!important;font-weight:600!important;color:#94a3b8!important;margin-bottom:0!important}::ng-deep .msg-form-container .field-input-wrapper{border-radius:12px!important;border:1px solid rgba(255,255,255,.08)!important;background:#ffffff0a!important;transition:all .25s!important;overflow:hidden;box-shadow:none!important;flex:1;display:flex}::ng-deep .msg-form-container .field-input-wrapper:focus-within{border-color:var(--app-primary, #6366f1)!important;background:#ffffff0f!important;box-shadow:0 0 20px var(--app-glow, rgba(99,102,241,.3))!important}::ng-deep .msg-form-container .field-input{flex:1;min-width:0;padding:12px!important;border:none!important;background:transparent!important;font-size:clamp(.875rem,2vw,.9375rem)!important;color:#f1f5f9!important;resize:none!important;font-family:inherit!important;width:100%!important;height:100%!important}::ng-deep .msg-form-container .field-input::placeholder{color:#64748b!important}.auth-btn{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:clamp(11px,2.5vw,13px);border:none;border-radius:12px;font-size:clamp(.875rem,2vw,.9375rem);font-weight:600;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;gap:8px}.auth-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 10px 30px -5px var(--app-glow, rgba(99,102,241,.5))}.auth-btn:disabled{opacity:.6;cursor:not-allowed;transform:none}.btn-icon{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.success-banner{background:#10b9811a;border:1px solid rgba(16,185,129,.3);border-radius:12px;padding:14px 16px;font-size:.875rem;color:#6ee7b7;text-align:center;display:flex;align-items:center;justify-content:center;gap:8px}.action-row{display:flex;gap:10px;margin-top:0}.action-row>*{flex:1}.back-link-inline{padding:clamp(12px,2.5vw,15px) 16px;border-radius:12px;font-size:clamp(.875rem,2vw,.9375rem);font-weight:600;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;text-decoration:none;background:#ffffff0a;color:#94a3b8;border:1px solid rgba(255,255,255,.1)}.back-link-inline:hover{background:#ffffff14;color:#fff}.loader{width:18px;height:18px;border:2.5px solid rgba(255,255,255,.2);border-top-color:#fff;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@media(max-width:400px){.channels{grid-template-columns:1fr}.channel-card{flex-direction:row;text-align:left;gap:10px}}@media(max-width:500px){.cs-header{flex-direction:column;text-align:center;gap:8px}.cs-header-text{text-align:center}}@media(prefers-reduced-motion:reduce){.icon-wrap,.channel-card{animation:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AmfAuthShellComponent, selector: "amf-auth-shell", inputs: ["brandName", "brandTagline", "maxWidth"] }, { kind: "component", type: FormRendererComponent, selector: "amf-form-renderer", inputs: ["config", "context"], outputs: ["formSubmit", "formCancel", "formChange"] }] });
208
208
  }
209
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ContactSupportComponent, decorators: [{
209
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ContactSupportComponent, decorators: [{
210
210
  type: Component,
211
211
  args: [{ selector: 'amf-contact-support', standalone: true, imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent], template: `
212
212
  <amf-auth-shell
@@ -284,4 +284,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
284
284
  }] });
285
285
 
286
286
  export { ContactSupportComponent };
287
- //# sourceMappingURL=avora-labs-meta-forge-contact-support.page-CgcSAr0x.mjs.map
287
+ //# sourceMappingURL=avora-labs-meta-forge-contact-support.page-C_kdmzhL.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"avora-labs-meta-forge-contact-support.page-CgcSAr0x.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/contact-support.page.ts"],"sourcesContent":["/**\n * Contact Support Component\n *\n * A full-page, bookmarkable /contact-support route built with AmfAuthShellComponent.\n * Displays three contact channel cards:\n * - Email Support (mailto)\n * - Live Chat (extensible — can wire to any chat provider)\n * - Documentation (external URL)\n *\n * Optionally allows submitting a support ticket with a message, powered by\n * the mock-contact-support endpoint (replace with real endpoint in production).\n */\nimport { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\n\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\ninterface ContactChannel {\n id: string;\n icon: string;\n gradient: string;\n title: string;\n subtitle: string;\n badge?: string;\n action: () => void;\n}\n\n@Component({\n selector: 'amf-contact-support',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\"\n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'We\\\\'re here to help'\" \n maxWidth=\"660px\">\n <!-- Compact header: icon inline with title -->\n <div class=\"cs-header\">\n <span class=\"ms icon-ms\">support_agent</span>\n <div class=\"cs-header-text\">\n <h2>Contact Support</h2>\n <p>Choose the fastest way to reach us. We typically respond within 2 hours.</p>\n </div>\n </div>\n\n <!-- Contact Channel Cards — inline 3-col grid -->\n <div class=\"channels\">\n @for (channel of channels; track channel.id) {\n <button\n class=\"channel-card\"\n [id]=\"'cs-' + channel.id\"\n (click)=\"channel.action()\"\n [class.active]=\"activeChannel === channel.id\"\n >\n <div class=\"channel-icon\" [style.background]=\"channel.gradient\">\n <span class=\"ms channel-icon-ms\">{{ channel.icon }}</span>\n </div>\n <div class=\"channel-title\">{{ channel.title }}</div>\n @if (channel.badge) {\n <span class=\"badge\">{{ channel.badge }}</span>\n }\n </button>\n }\n </div>\n\n <!-- Quick Message Form -->\n <div class=\"quick-msg\">\n <div class=\"divider\"><span>or send a quick message</span></div>\n\n <!-- Form + actions unified container -->\n <div class=\"cs-form-body\">\n <div class=\"msg-form-container\">\n <amf-form-renderer \n [config]=\"supportForm\" \n (formSubmit)=\"onFormSubmit($event)\"\n (formChange)=\"onFormChange($event)\">\n </amf-form-renderer>\n </div>\n\n @if (successTicket()) {\n <div class=\"success-banner\">\n <span class=\"ms\" style=\"font-size:1.1rem;vertical-align:middle;margin-right:6px\">check_circle</span>\n Ticket <strong>{{ ticketId() }}</strong> created! We'll get back to you shortly.\n </div>\n }\n \n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading() || !ticketEmail || !ticketMessage || successTicket()\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Send Message</span>\n <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\"/></svg>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n &larr; Back to Sign In\n </a>\n </div>\n </div>\n </div>\n\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n /* ── Header — compact inline row ── */\n .cs-header {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n padding-bottom: clamp(10px, 2vw, 16px);\n border-bottom: 1px solid rgba(255,255,255,0.07);\n }\n .icon-ms {\n font-size: 2.4rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 48;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n flex-shrink: 0;\n }\n .cs-header-text { flex: 1; }\n .cs-header h2 {\n font-size: clamp(1.1rem, 3vw, 1.35rem);\n font-weight: 700;\n color: #f1f5f9;\n margin: 0 0 3px;\n }\n .cs-header p {\n font-size: clamp(0.75rem, 1.8vw, 0.82rem);\n color: #64748b;\n margin: 0;\n line-height: 1.4;\n }\n\n /* ── Channel Cards — inline 3-col grid ── */\n .channels {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 10px;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n }\n\n .channel-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: clamp(8px, 1.5vw, 10px) 4px;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 14px;\n cursor: pointer;\n transition: all 0.25s cubic-bezier(0.4,0,0.2,1);\n text-align: center;\n width: 100%;\n position: relative;\n overflow: hidden;\n }\n .channel-card::before {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n opacity: 0;\n transition: opacity 0.25s;\n }\n .channel-card:hover {\n border-color: rgba(99,102,241,0.35);\n background: rgba(99,102,241,0.06);\n transform: translateY(-3px);\n box-shadow: 0 6px 24px rgba(99,102,241,0.18);\n }\n .channel-card:hover::before { opacity: 0.04; }\n .channel-card.active {\n border-color: rgba(99,102,241,0.5);\n background: rgba(99,102,241,0.1);\n }\n\n .channel-icon {\n width: clamp(28px, 6vw, 34px);\n height: clamp(28px, 6vw, 34px);\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n position: relative;\n z-index: 1;\n }\n .channel-icon-ms {\n font-size: 1.15rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;\n color: white;\n }\n .channel-title {\n font-size: clamp(0.7rem, 1.5vw, 0.78rem);\n font-weight: 600;\n color: #e2e8f0;\n position: relative;\n z-index: 1;\n line-height: 1.2;\n }\n .badge {\n font-size: 0.55rem;\n font-weight: 700;\n background: linear-gradient(135deg, #10b981, #059669);\n color: white;\n padding: 1px 5px;\n border-radius: 6px;\n letter-spacing: 0.03em;\n text-transform: uppercase;\n position: relative;\n z-index: 1;\n white-space: nowrap;\n }\n\n /* ── Quick Message ── */\n .quick-msg { margin-top: 0; }\n .divider {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n color: #475569;\n font-size: 0.78rem;\n }\n .divider::before, .divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: rgba(255,255,255,0.07);\n }\n\n /* Unified form + actions container — mirrors .auth-form-container in forgot-password */\n .cs-form-body { display: flex; flex-direction: column; gap: clamp(10px, 2vw, 14px); }\n\n /* Two-field inline row for wider layout */\n .msg-form-container { display: flex; flex-direction: column; gap: 10px; }\n \n ::ng-deep .msg-form-container .amf-form { gap: 16px; }\n ::ng-deep .msg-form-container .amf-form-fields { gap: 16px; align-items: stretch; }\n ::ng-deep .msg-form-container .amf-field { display: flex; flex-direction: column; gap: 5px; }\n ::ng-deep .msg-form-container .field-label {\n font-size: 0.8rem !important;\n font-weight: 600 !important;\n color: #94a3b8 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .msg-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255,255,255,0.08) !important;\n background: rgba(255,255,255,0.04) !important;\n transition: all 0.25s !important;\n overflow: hidden;\n box-shadow: none !important;\n flex: 1;\n display: flex;\n }\n ::ng-deep .msg-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255,255,255,0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .msg-form-container .field-input {\n flex: 1;\n min-width: 0;\n padding: 12px 12px !important;\n border: none !important;\n background: transparent !important;\n font-size: clamp(0.875rem, 2vw, 0.9375rem) !important;\n color: #f1f5f9 !important;\n resize: none !important;\n font-family: inherit !important;\n width: 100% !important;\n height: 100% !important;\n }\n ::ng-deep .msg-form-container .field-input::placeholder { color: #64748b !important; }\n\n /* ── Button ── */\n .auth-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: clamp(11px, 2.5vw, 13px);\n border: none;\n border-radius: 12px;\n font-size: clamp(0.875rem, 2vw, 0.9375rem);\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n }\n .auth-btn:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n .auth-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }\n .btn-icon {\n width: 15px; height: 15px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n\n /* ── Success Banner ── */\n .success-banner {\n background: rgba(16,185,129,0.1);\n border: 1px solid rgba(16,185,129,0.3);\n border-radius: 12px;\n padding: 14px 16px;\n font-size: 0.875rem;\n color: #6ee7b7;\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n }\n\n /* ── Action Row ── */\n .action-row {\n display: flex;\n gap: 10px;\n margin-top: 0; /* spacing handled by .cs-form-body gap */\n }\n .action-row > * {\n flex: 1;\n }\n .back-link-inline {\n padding: clamp(12px, 2.5vw, 15px) 16px;\n border-radius: 12px;\n font-size: clamp(0.875rem, 2vw, 0.9375rem);\n font-weight: 600;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n text-decoration: none;\n background: rgba(255,255,255,0.04);\n color: #94a3b8;\n border: 1px solid rgba(255,255,255,0.1);\n }\n .back-link-inline:hover {\n background: rgba(255,255,255,0.08);\n color: white;\n }\n .loader {\n width: 18px; height: 18px;\n border: 2.5px solid rgba(255,255,255,0.2);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n\n /* ── Responsive: stack 3-col to single col on small screens ── */\n @media (max-width: 400px) {\n .channels { grid-template-columns: 1fr; }\n .channel-card { flex-direction: row; text-align: left; gap: 10px; }\n /* Kept .form-row as 2 columns per user request */\n }\n @media (max-width: 500px) {\n .cs-header { flex-direction: column; text-align: center; gap: 8px; }\n .cs-header-text { text-align: center; }\n }\n @media (prefers-reduced-motion: reduce) {\n .icon-wrap, .channel-card { animation: none !important; }\n }\n `]\n})\nexport class ContactSupportComponent {\n private readonly dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n successTicket = signal(false);\n ticketId = signal('');\n activeChannel = '';\n\n ticketEmail = '';\n ticketMessage = '';\n\n supportForm: FormMeta = {\n id: 'supportForm',\n layout: 'vertical',\n hideSubmit: true,\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Your Email',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'message',\n type: 'textarea',\n label: 'How can we help?',\n placeholder: 'Describe your issue...',\n rows: 3,\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n readonly channels: ContactChannel[] = [\n {\n id: 'email',\n icon: 'mail',\n gradient: 'linear-gradient(135deg, rgba(59,130,246,0.3), rgba(99,102,241,0.3))',\n title: 'Email Support',\n subtitle: 'Detailed help via email • Avg. 2h response',\n badge: 'Recommended',\n action: () => {\n this.activeChannel = 'email';\n // DEMO: opens mailto link. REAL: can open a support ticket form or redirect to helpdesk.\n this.dispatcher.dispatch({\n type: 'open-url',\n config: { url: 'mailto:support@avorametaforge.com?subject=Support Request', target: '_self' }\n });\n }\n },\n {\n id: 'chat',\n icon: 'chat_bubble',\n gradient: 'linear-gradient(135deg, rgba(16,185,129,0.3), rgba(5,150,105,0.3))',\n title: 'Live Chat',\n subtitle: 'Real-time help with our team • Now available',\n action: () => {\n this.activeChannel = 'chat';\n // DEMO: shows a notification. REAL: wire to Intercom, Crisp, Zendesk, etc.\n this.dispatcher.dispatch({\n type: 'notify',\n config: { type: 'info', message: 'Live chat integration is configurable. Wire to Intercom, Crisp, or any provider.' }\n });\n }\n },\n {\n id: 'docs',\n icon: 'menu_book',\n gradient: 'linear-gradient(135deg, rgba(245,158,11,0.3), rgba(217,119,6,0.3))',\n title: 'Documentation',\n subtitle: 'Browse guides, API reference & tutorials',\n action: () => {\n this.activeChannel = 'docs';\n this.dispatcher.dispatch({\n type: 'open-url',\n config: { url: 'https://github.com/AvoraLabs/avora-meta-forge', target: '_blank' }\n });\n }\n }\n ];\n\n onFormChange(values: any): void {\n this.ticketEmail = values.email || '';\n this.ticketMessage = values.message || '';\n }\n\n triggerSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'supportForm' } });\n }\n\n onFormSubmit(values: any): void {\n if (!values.email || !values.message) return;\n\n this.loading.set(true);\n\n // DEMO: calls mock-contact-support endpoint.\n // REAL: remove mock:true from 'mock-contact-support' and point to your helpdesk API.\n this.dispatcher.dispatch({\n type: 'api',\n config: {\n endpointId: 'mock-contact-support',\n body: { email: values.email, message: values.message },\n storeResultAs: 'supportResult'\n },\n then: {\n type: 'notify',\n config: { type: 'success', message: 'Your message has been sent! We\\'ll respond to ' + values.email }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Failed to send. Please try emailing us directly.' }\n }\n }).then((result: any) => {\n if (result?.ticketId) {\n this.ticketId.set(result.ticketId);\n this.successTicket.set(true);\n }\n }).finally(() => this.loading.set(false));\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"avora-labs-meta-forge-contact-support.page-C_kdmzhL.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/contact-support.page.ts"],"sourcesContent":["/**\n * Contact Support Component\n *\n * A full-page, bookmarkable /contact-support route built with AmfAuthShellComponent.\n * Displays three contact channel cards:\n * - Email Support (mailto)\n * - Live Chat (extensible — can wire to any chat provider)\n * - Documentation (external URL)\n *\n * Optionally allows submitting a support ticket with a message, powered by\n * the mock-contact-support endpoint (replace with real endpoint in production).\n */\nimport { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\n\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\ninterface ContactChannel {\n id: string;\n icon: string;\n gradient: string;\n title: string;\n subtitle: string;\n badge?: string;\n action: () => void;\n}\n\n@Component({\n selector: 'amf-contact-support',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\"\n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'We\\\\'re here to help'\" \n maxWidth=\"660px\">\n <!-- Compact header: icon inline with title -->\n <div class=\"cs-header\">\n <span class=\"ms icon-ms\">support_agent</span>\n <div class=\"cs-header-text\">\n <h2>Contact Support</h2>\n <p>Choose the fastest way to reach us. We typically respond within 2 hours.</p>\n </div>\n </div>\n\n <!-- Contact Channel Cards — inline 3-col grid -->\n <div class=\"channels\">\n @for (channel of channels; track channel.id) {\n <button\n class=\"channel-card\"\n [id]=\"'cs-' + channel.id\"\n (click)=\"channel.action()\"\n [class.active]=\"activeChannel === channel.id\"\n >\n <div class=\"channel-icon\" [style.background]=\"channel.gradient\">\n <span class=\"ms channel-icon-ms\">{{ channel.icon }}</span>\n </div>\n <div class=\"channel-title\">{{ channel.title }}</div>\n @if (channel.badge) {\n <span class=\"badge\">{{ channel.badge }}</span>\n }\n </button>\n }\n </div>\n\n <!-- Quick Message Form -->\n <div class=\"quick-msg\">\n <div class=\"divider\"><span>or send a quick message</span></div>\n\n <!-- Form + actions unified container -->\n <div class=\"cs-form-body\">\n <div class=\"msg-form-container\">\n <amf-form-renderer \n [config]=\"supportForm\" \n (formSubmit)=\"onFormSubmit($event)\"\n (formChange)=\"onFormChange($event)\">\n </amf-form-renderer>\n </div>\n\n @if (successTicket()) {\n <div class=\"success-banner\">\n <span class=\"ms\" style=\"font-size:1.1rem;vertical-align:middle;margin-right:6px\">check_circle</span>\n Ticket <strong>{{ ticketId() }}</strong> created! We'll get back to you shortly.\n </div>\n }\n \n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading() || !ticketEmail || !ticketMessage || successTicket()\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Send Message</span>\n <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\"/></svg>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n &larr; Back to Sign In\n </a>\n </div>\n </div>\n </div>\n\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n /* ── Header — compact inline row ── */\n .cs-header {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n padding-bottom: clamp(10px, 2vw, 16px);\n border-bottom: 1px solid rgba(255,255,255,0.07);\n }\n .icon-ms {\n font-size: 2.4rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 48;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n flex-shrink: 0;\n }\n .cs-header-text { flex: 1; }\n .cs-header h2 {\n font-size: clamp(1.1rem, 3vw, 1.35rem);\n font-weight: 700;\n color: #f1f5f9;\n margin: 0 0 3px;\n }\n .cs-header p {\n font-size: clamp(0.75rem, 1.8vw, 0.82rem);\n color: #64748b;\n margin: 0;\n line-height: 1.4;\n }\n\n /* ── Channel Cards — inline 3-col grid ── */\n .channels {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 10px;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n }\n\n .channel-card {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: clamp(8px, 1.5vw, 10px) 4px;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 14px;\n cursor: pointer;\n transition: all 0.25s cubic-bezier(0.4,0,0.2,1);\n text-align: center;\n width: 100%;\n position: relative;\n overflow: hidden;\n }\n .channel-card::before {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n opacity: 0;\n transition: opacity 0.25s;\n }\n .channel-card:hover {\n border-color: rgba(99,102,241,0.35);\n background: rgba(99,102,241,0.06);\n transform: translateY(-3px);\n box-shadow: 0 6px 24px rgba(99,102,241,0.18);\n }\n .channel-card:hover::before { opacity: 0.04; }\n .channel-card.active {\n border-color: rgba(99,102,241,0.5);\n background: rgba(99,102,241,0.1);\n }\n\n .channel-icon {\n width: clamp(28px, 6vw, 34px);\n height: clamp(28px, 6vw, 34px);\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n position: relative;\n z-index: 1;\n }\n .channel-icon-ms {\n font-size: 1.15rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;\n color: white;\n }\n .channel-title {\n font-size: clamp(0.7rem, 1.5vw, 0.78rem);\n font-weight: 600;\n color: #e2e8f0;\n position: relative;\n z-index: 1;\n line-height: 1.2;\n }\n .badge {\n font-size: 0.55rem;\n font-weight: 700;\n background: linear-gradient(135deg, #10b981, #059669);\n color: white;\n padding: 1px 5px;\n border-radius: 6px;\n letter-spacing: 0.03em;\n text-transform: uppercase;\n position: relative;\n z-index: 1;\n white-space: nowrap;\n }\n\n /* ── Quick Message ── */\n .quick-msg { margin-top: 0; }\n .divider {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n color: #475569;\n font-size: 0.78rem;\n }\n .divider::before, .divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: rgba(255,255,255,0.07);\n }\n\n /* Unified form + actions container — mirrors .auth-form-container in forgot-password */\n .cs-form-body { display: flex; flex-direction: column; gap: clamp(10px, 2vw, 14px); }\n\n /* Two-field inline row for wider layout */\n .msg-form-container { display: flex; flex-direction: column; gap: 10px; }\n \n ::ng-deep .msg-form-container .amf-form { gap: 16px; }\n ::ng-deep .msg-form-container .amf-form-fields { gap: 16px; align-items: stretch; }\n ::ng-deep .msg-form-container .amf-field { display: flex; flex-direction: column; gap: 5px; }\n ::ng-deep .msg-form-container .field-label {\n font-size: 0.8rem !important;\n font-weight: 600 !important;\n color: #94a3b8 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .msg-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255,255,255,0.08) !important;\n background: rgba(255,255,255,0.04) !important;\n transition: all 0.25s !important;\n overflow: hidden;\n box-shadow: none !important;\n flex: 1;\n display: flex;\n }\n ::ng-deep .msg-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255,255,255,0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .msg-form-container .field-input {\n flex: 1;\n min-width: 0;\n padding: 12px 12px !important;\n border: none !important;\n background: transparent !important;\n font-size: clamp(0.875rem, 2vw, 0.9375rem) !important;\n color: #f1f5f9 !important;\n resize: none !important;\n font-family: inherit !important;\n width: 100% !important;\n height: 100% !important;\n }\n ::ng-deep .msg-form-container .field-input::placeholder { color: #64748b !important; }\n\n /* ── Button ── */\n .auth-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: clamp(11px, 2.5vw, 13px);\n border: none;\n border-radius: 12px;\n font-size: clamp(0.875rem, 2vw, 0.9375rem);\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n }\n .auth-btn:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n .auth-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }\n .btn-icon {\n width: 15px; height: 15px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n\n /* ── Success Banner ── */\n .success-banner {\n background: rgba(16,185,129,0.1);\n border: 1px solid rgba(16,185,129,0.3);\n border-radius: 12px;\n padding: 14px 16px;\n font-size: 0.875rem;\n color: #6ee7b7;\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n }\n\n /* ── Action Row ── */\n .action-row {\n display: flex;\n gap: 10px;\n margin-top: 0; /* spacing handled by .cs-form-body gap */\n }\n .action-row > * {\n flex: 1;\n }\n .back-link-inline {\n padding: clamp(12px, 2.5vw, 15px) 16px;\n border-radius: 12px;\n font-size: clamp(0.875rem, 2vw, 0.9375rem);\n font-weight: 600;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n text-decoration: none;\n background: rgba(255,255,255,0.04);\n color: #94a3b8;\n border: 1px solid rgba(255,255,255,0.1);\n }\n .back-link-inline:hover {\n background: rgba(255,255,255,0.08);\n color: white;\n }\n .loader {\n width: 18px; height: 18px;\n border: 2.5px solid rgba(255,255,255,0.2);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n\n /* ── Responsive: stack 3-col to single col on small screens ── */\n @media (max-width: 400px) {\n .channels { grid-template-columns: 1fr; }\n .channel-card { flex-direction: row; text-align: left; gap: 10px; }\n /* Kept .form-row as 2 columns per user request */\n }\n @media (max-width: 500px) {\n .cs-header { flex-direction: column; text-align: center; gap: 8px; }\n .cs-header-text { text-align: center; }\n }\n @media (prefers-reduced-motion: reduce) {\n .icon-wrap, .channel-card { animation: none !important; }\n }\n `]\n})\nexport class ContactSupportComponent {\n private readonly dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n successTicket = signal(false);\n ticketId = signal('');\n activeChannel = '';\n\n ticketEmail = '';\n ticketMessage = '';\n\n supportForm: FormMeta = {\n id: 'supportForm',\n layout: 'vertical',\n hideSubmit: true,\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Your Email',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'message',\n type: 'textarea',\n label: 'How can we help?',\n placeholder: 'Describe your issue...',\n rows: 3,\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n readonly channels: ContactChannel[] = [\n {\n id: 'email',\n icon: 'mail',\n gradient: 'linear-gradient(135deg, rgba(59,130,246,0.3), rgba(99,102,241,0.3))',\n title: 'Email Support',\n subtitle: 'Detailed help via email • Avg. 2h response',\n badge: 'Recommended',\n action: () => {\n this.activeChannel = 'email';\n // DEMO: opens mailto link. REAL: can open a support ticket form or redirect to helpdesk.\n this.dispatcher.dispatch({\n type: 'open-url',\n config: { url: 'mailto:support@avorametaforge.com?subject=Support Request', target: '_self' }\n });\n }\n },\n {\n id: 'chat',\n icon: 'chat_bubble',\n gradient: 'linear-gradient(135deg, rgba(16,185,129,0.3), rgba(5,150,105,0.3))',\n title: 'Live Chat',\n subtitle: 'Real-time help with our team • Now available',\n action: () => {\n this.activeChannel = 'chat';\n // DEMO: shows a notification. REAL: wire to Intercom, Crisp, Zendesk, etc.\n this.dispatcher.dispatch({\n type: 'notify',\n config: { type: 'info', message: 'Live chat integration is configurable. Wire to Intercom, Crisp, or any provider.' }\n });\n }\n },\n {\n id: 'docs',\n icon: 'menu_book',\n gradient: 'linear-gradient(135deg, rgba(245,158,11,0.3), rgba(217,119,6,0.3))',\n title: 'Documentation',\n subtitle: 'Browse guides, API reference & tutorials',\n action: () => {\n this.activeChannel = 'docs';\n this.dispatcher.dispatch({\n type: 'open-url',\n config: { url: 'https://github.com/AvoraLabs/avora-meta-forge', target: '_blank' }\n });\n }\n }\n ];\n\n onFormChange(values: any): void {\n this.ticketEmail = values.email || '';\n this.ticketMessage = values.message || '';\n }\n\n triggerSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'supportForm' } });\n }\n\n onFormSubmit(values: any): void {\n if (!values.email || !values.message) return;\n\n this.loading.set(true);\n\n // DEMO: calls mock-contact-support endpoint.\n // REAL: remove mock:true from 'mock-contact-support' and point to your helpdesk API.\n this.dispatcher.dispatch({\n type: 'api',\n config: {\n endpointId: 'mock-contact-support',\n body: { email: values.email, message: values.message },\n storeResultAs: 'supportResult'\n },\n then: {\n type: 'notify',\n config: { type: 'success', message: 'Your message has been sent! We\\'ll respond to ' + values.email }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Failed to send. Please try emailing us directly.' }\n }\n }).then((result: any) => {\n if (result?.ticketId) {\n this.ticketId.set(result.ticketId);\n this.successTicket.set(true);\n }\n }).finally(() => this.loading.set(false));\n }\n}\n"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms';
4
4
  import * as i1 from '@angular/router';
5
5
  import { Router, RouterModule } from '@angular/router';
6
6
  import { ActionDispatcherService, MetaStateService, APP_META_CONFIG_TOKEN, FormRendererComponent } from './avora-labs-meta-forge.mjs';
7
- import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs';
7
+ import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-C89gSPc9.mjs';
8
8
 
9
9
  /**
10
10
  * Forgot Password Component
@@ -219,8 +219,8 @@ class ForgotPasswordComponent {
219
219
  }
220
220
  }).finally(() => this.loading.set(false));
221
221
  }
222
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ForgotPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
223
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ForgotPasswordComponent, isStandalone: true, selector: "amf-forgot-password", ngImport: i0, template: `
222
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ForgotPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
223
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ForgotPasswordComponent, isStandalone: true, selector: "amf-forgot-password", ngImport: i0, template: `
224
224
  <amf-auth-shell
225
225
  [brandName]="meta.auth?.builtInUI?.brandName || meta.app.name"
226
226
  [brandTagline]="meta.auth?.builtInUI?.brandTagline || 'Recover your account'"
@@ -340,7 +340,7 @@ class ForgotPasswordComponent {
340
340
  </amf-auth-shell>
341
341
  `, isInline: true, styles: [":host{display:block;height:100%}.steps{display:flex;align-items:center;justify-content:center;gap:0;margin-bottom:clamp(12px,2.5vw,20px)}.step{display:flex;flex-direction:column;align-items:center;gap:6px}.step-dot{width:32px;height:32px;border-radius:50%;border:2px solid rgba(255,255,255,.15);background:#ffffff0a;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:#64748b;transition:all .3s}.step.active .step-dot{border-color:var(--app-primary, #6366f1);background:#6366f126;color:var(--app-primary, #6366f1);box-shadow:0 0 16px var(--app-glow, rgba(99,102,241,.4))}.step.done .step-dot{border-color:#10b981;background:#10b98126;color:#10b981}.step-icon{font-size:1rem!important}.step-label{font-size:.7rem;color:#64748b;font-weight:600;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}.step.active .step-label{color:#94a3b8}.step-line{flex:1;height:2px;background:#ffffff14;margin:0 8px 22px;min-width:24px;transition:background .3s}.step-line.done{background:#10b98166}.screen-label{text-align:center;margin-bottom:clamp(10px,2vw,16px)}.screen-label-sm{display:flex;align-items:center;gap:12px;text-align:left;padding:10px 14px;background:#ffffff08;border:1px solid rgba(255,255,255,.07);border-radius:12px;margin-bottom:clamp(10px,2vw,14px)}.screen-label-sm h2{font-size:clamp(1rem,3vw,1.15rem)!important;margin-bottom:2px!important}.screen-label-sm p{font-size:clamp(.75rem,1.8vw,.82rem)!important;margin:0}.icon-ms-inline{font-size:1.75rem!important;flex-shrink:0;animation:float 3s ease-in-out infinite}.icon-wrap{margin-bottom:6px;display:flex;align-items:center;justify-content:center;animation:float 3s ease-in-out infinite}.icon-ms{font-size:2.1rem!important;font-variation-settings:\"FILL\" 1,\"wght\" 300,\"GRAD\" 0,\"opsz\" 48;background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.screen-label h2{font-size:clamp(1.15rem,4vw,1.4rem);font-weight:700;color:#f1f5f9;margin-bottom:6px}.screen-label p{font-size:clamp(.8rem,2vw,.875rem);color:#64748b;line-height:1.5}.pw-row{display:grid;grid-template-columns:1fr 1fr;gap:10px}@media(max-width:460px){.pw-row{grid-template-columns:1fr}.screen-label-sm{flex-direction:column;text-align:center}}.auth-form-container{display:flex;flex-direction:column;gap:clamp(10px,2vw,14px)}::ng-deep .auth-form-container .amf-form{gap:clamp(10px,2vw,14px)}::ng-deep .auth-form-container .amf-form-fields{gap:clamp(10px,2vw,14px)}::ng-deep .auth-form-container .amf-field{display:flex;flex-direction:column;gap:8px}::ng-deep .auth-form-container .field-label{font-size:.875rem!important;font-weight:600!important;color:#cbd5e1!important;margin-bottom:0!important}::ng-deep .auth-form-container .field-input-wrapper{border-radius:12px!important;border:1px solid rgba(255,255,255,.08)!important;background:#ffffff0a!important;transition:all .25s!important;overflow:hidden;box-shadow:none!important;display:flex;align-items:center}::ng-deep .auth-form-container .field-input-wrapper:focus-within{border-color:var(--app-primary, #6366f1)!important;background:#ffffff0f!important;box-shadow:0 0 20px var(--app-glow, rgba(99,102,241,.3))!important}::ng-deep .auth-form-container .field-input{flex:1;min-width:0;padding:13px 16px!important;border:none!important;background:transparent!important;font-size:clamp(.9rem,2vw,1rem)!important;color:#f1f5f9!important}::ng-deep .auth-form-container .field-input::placeholder{color:#64748b!important}::ng-deep .auth-form-container .pwd-toggle-btn{color:#64748b!important}::ng-deep .auth-form-container .pwd-toggle-btn:hover{color:var(--app-primary, #6366f1)!important}.field-error{font-size:.78rem;color:#ef4444}.strength-bar{display:flex;align-items:center;gap:10px}.strength-track{flex:1;height:4px;background:#ffffff12;border-radius:2px;overflow:hidden}.strength-fill{height:100%;border-radius:2px;transition:width .4s,background .4s}.strength-weak{background:#ef4444}.strength-fair{background:#f59e0b}.strength-good{background:#10b981}.strength-strong{background:#6366f1}.strength-label{font-size:.75rem;color:#64748b;white-space:nowrap}.auth-btn{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:clamp(11px,2.5vw,14px);border:none;border-radius:12px;font-size:clamp(.9rem,2vw,1rem);font-weight:600;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;gap:8px;flex:1;min-width:0;position:relative;overflow:hidden}.auth-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 10px 30px -5px var(--app-glow, rgba(99,102,241,.5))}.auth-btn:disabled{opacity:.6;cursor:not-allowed;transform:none}.btn-icon{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.error-banner{background:#ef44441a;border:1px solid rgba(239,68,68,.3);border-radius:10px;padding:12px 16px;font-size:.875rem;color:#fca5a5}.footer-note{text-align:center;margin-top:clamp(10px,2vw,18px)}.back-link{display:inline-flex;align-items:center;gap:6px;font-size:.875rem;color:#64748b;font-weight:500;transition:color .2s;text-decoration:none}.back-link svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}.back-link:hover{color:var(--app-primary, #6366f1)}.action-row{display:flex;align-items:stretch;gap:10px}.back-link-inline{display:flex;align-items:center;justify-content:center;gap:6px;flex:1;min-width:0;padding:clamp(11px,2.5vw,14px) 12px;border-radius:12px;border:1px solid rgba(255,255,255,.1);background:#ffffff0a;color:#94a3b8;font-size:clamp(.82rem,2vw,.9rem);font-weight:500;text-decoration:none;white-space:nowrap;transition:all .2s}.back-link-inline svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.back-link-inline:hover{color:#f1f5f9;border-color:#6366f159;background:#6366f10f}.loader{width:20px;height:20px;border:3px solid rgba(255,255,255,.2);border-top-color:#fff;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@media(max-width:400px){.steps{margin-bottom:14px}.step-line{margin:0 4px 22px;min-width:12px}.step-label{font-size:.6rem}.screen-label{margin-bottom:12px}.icon-ms{font-size:2.25rem!important}.auth-form{gap:12px}}@media(prefers-reduced-motion:reduce){.icon-wrap,.loader{animation:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AmfAuthShellComponent, selector: "amf-auth-shell", inputs: ["brandName", "brandTagline", "maxWidth"] }, { kind: "component", type: FormRendererComponent, selector: "amf-form-renderer", inputs: ["config", "context"], outputs: ["formSubmit", "formCancel", "formChange"] }] });
342
342
  }
343
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ForgotPasswordComponent, decorators: [{
343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ForgotPasswordComponent, decorators: [{
344
344
  type: Component,
345
345
  args: [{ selector: 'amf-forgot-password', standalone: true, imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent], template: `
346
346
  <amf-auth-shell
@@ -464,4 +464,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
464
464
  }], ctorParameters: () => [] });
465
465
 
466
466
  export { ForgotPasswordComponent };
467
- //# sourceMappingURL=avora-labs-meta-forge-forgot-password.page-CWdWX-mj.mjs.map
467
+ //# sourceMappingURL=avora-labs-meta-forge-forgot-password.page-PY9_K4M-.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"avora-labs-meta-forge-forgot-password.page-CWdWX-mj.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/forgot-password.page.ts"],"sourcesContent":["/**\n * Forgot Password Component\n *\n * Powered by AvoraMetaForge actions:\n * - Step 1: User enters email → fires mock-send-otp API → opens AMF OTP modal\n * - Modal verified → set-state marks otpVerified → page shows Step 2\n * - Step 2: User sets new password → mock-reset-password → back to login\n *\n * This component uses AmfAuthShellComponent for the shared visual shell.\n * Framework users can replicate this pattern by using AmfAuthShellComponent\n * with any custom content, or by building their own shell entirely.\n */\nimport { Component, inject, signal, OnDestroy, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\n\nimport { Subscription } from 'rxjs';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { MetaStateService } from '../../services/meta-state.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\ntype Step = 'email' | 'reset';\n\n@Component({\n selector: 'amf-forgot-password',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\"\n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Recover your account'\"\n maxWidth=\"620px\">\n <!-- Step Indicator -->\n <div class=\"steps\">\n <div class=\"step\" [class.active]=\"currentStep() === 'email'\" [class.done]=\"currentStep() === 'reset'\">\n <div class=\"step-dot\">\n @if (currentStep() === 'reset') {\n <span class=\"ms step-icon\">check</span>\n } @else {\n <span>1</span>\n }\n </div>\n <span class=\"step-label\">Email</span>\n </div>\n <div class=\"step-line\" [class.done]=\"currentStep() === 'reset'\"></div>\n <div class=\"step\" [class.active]=\"currentStep() === 'reset'\">\n <div class=\"step-dot\"><span>2</span></div>\n <span class=\"step-label\">New Password</span>\n </div>\n </div>\n\n <!-- ── STEP 1: Email ── -->\n @if (currentStep() === 'email') {\n <div class=\"form-section\">\n <div class=\"screen-label\">\n <div class=\"icon-wrap\"><span class=\"ms icon-ms\">lock</span></div>\n <h2>Forgot your password?</h2>\n <p>Enter your email and we'll send a verification code.</p>\n </div>\n\n <div class=\"auth-form-container\">\n <amf-form-renderer \n [config]=\"emailForm\" \n (formSubmit)=\"onEmailSubmit($event)\"\n (formChange)=\"onEmailChange($event)\">\n </amf-form-renderer>\n\n @if (errorMsg()) {\n <div class=\"error-banner\">{{ errorMsg() }}</div>\n }\n\n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerEmailSubmit()\" [disabled]=\"loading() || !email\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Send Verification Code</span>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 12H5M12 19l-7-7 7-7\"/></svg>\n Back to Sign In\n </a>\n </div>\n </div>\n </div>\n }\n\n <!-- ── STEP 2: New Password (after OTP verified) ── -->\n @if (currentStep() === 'reset') {\n <div class=\"form-section\">\n <!-- Compact inline header for step 2 -->\n <div class=\"screen-label screen-label-sm\">\n <span class=\"ms icon-ms icon-ms-inline\">key</span>\n <div>\n <h2>Set a new password</h2>\n <p>Identity verified — choose a strong password.</p>\n </div>\n </div>\n\n <div class=\"auth-form-container\">\n <amf-form-renderer \n [config]=\"resetForm\" \n (formSubmit)=\"onResetSubmit($event)\"\n (formChange)=\"onResetChange($event)\">\n </amf-form-renderer>\n\n @if (confirmError) {\n <span class=\"field-error\" style=\"margin-top: -10px; display: block;\">Passwords don't match</span>\n }\n\n <!-- Strength bar: only show once user starts typing -->\n @if (newPassword) {\n <div class=\"strength-bar\">\n <div class=\"strength-track\">\n <div class=\"strength-fill\" [style.width]=\"strengthPct + '%'\" [class]=\"'strength-' + strengthLevel\"></div>\n </div>\n <span class=\"strength-label\">{{ strengthLabel }}</span>\n </div>\n }\n\n @if (errorMsg()) {\n <div class=\"error-banner\">{{ errorMsg() }}</div>\n }\n\n <!-- Inline action row: equal-width Submit + Back -->\n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerResetSubmit()\" [disabled]=\"loading() || !newPassword || !confirmPassword || confirmError\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Update Password</span>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 12H5M12 19l-7-7 7-7\"/></svg>\n Back to Sign In\n </a>\n </div>\n </div>\n </div>\n }\n\n\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n /* ── Step Indicator ── */\n .steps {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n }\n .step {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n }\n .step-dot {\n width: 32px; height: 32px;\n border-radius: 50%;\n border: 2px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 700;\n color: #64748b;\n transition: all 0.3s;\n }\n .step.active .step-dot {\n border-color: var(--app-primary, #6366f1);\n background: rgba(99,102,241,0.15);\n color: var(--app-primary, #6366f1);\n box-shadow: 0 0 16px var(--app-glow, rgba(99,102,241,0.4));\n }\n .step.done .step-dot {\n border-color: #10b981;\n background: rgba(16,185,129,0.15);\n color: #10b981;\n }\n .step-icon { font-size: 1rem !important; }\n .step-label {\n font-size: 0.7rem;\n color: #64748b;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n white-space: nowrap;\n }\n .step.active .step-label { color: #94a3b8; }\n .step-line {\n flex: 1;\n height: 2px;\n background: rgba(255,255,255,0.08);\n margin: 0 8px;\n margin-bottom: 22px;\n min-width: 24px;\n transition: background 0.3s;\n }\n .step-line.done { background: rgba(16,185,129,0.4); }\n\n /* ── Screen Label ── */\n .screen-label {\n text-align: center;\n margin-bottom: clamp(10px, 2vw, 16px);\n }\n /* Step 2 compact inline variant */\n .screen-label-sm {\n display: flex;\n align-items: center;\n gap: 12px;\n text-align: left;\n padding: 10px 14px;\n background: rgba(255,255,255,0.03);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 12px;\n margin-bottom: clamp(10px, 2vw, 14px);\n }\n .screen-label-sm h2 {\n font-size: clamp(1rem, 3vw, 1.15rem) !important;\n margin-bottom: 2px !important;\n }\n .screen-label-sm p {\n font-size: clamp(0.75rem, 1.8vw, 0.82rem) !important;\n margin: 0;\n }\n .icon-ms-inline {\n font-size: 1.75rem !important;\n flex-shrink: 0;\n animation: float 3s ease-in-out infinite;\n }\n .icon-wrap {\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: float 3s ease-in-out infinite;\n }\n .icon-ms {\n font-size: 2.1rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 48;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n }\n .screen-label h2 {\n font-size: clamp(1.15rem, 4vw, 1.4rem);\n font-weight: 700;\n color: #f1f5f9;\n margin-bottom: 6px;\n }\n .screen-label p {\n font-size: clamp(0.8rem, 2vw, 0.875rem);\n color: #64748b;\n line-height: 1.5;\n }\n /* 2-col row for the two password fields */\n .pw-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n }\n @media (max-width: 460px) {\n .pw-row { grid-template-columns: 1fr; }\n .screen-label-sm { flex-direction: column; text-align: center; }\n }\n\n /* ── Form ── */\n .auth-form-container { display: flex; flex-direction: column; gap: clamp(10px, 2vw, 14px); }\n \n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .auth-form-container .amf-form { gap: clamp(10px, 2vw, 14px); }\n ::ng-deep .auth-form-container .amf-form-fields { gap: clamp(10px, 2vw, 14px); }\n ::ng-deep .auth-form-container .amf-field { display: flex; flex-direction: column; gap: 8px; }\n ::ng-deep .auth-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .auth-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255,255,255,0.08) !important;\n background: rgba(255,255,255,0.04) !important;\n transition: all 0.25s !important;\n overflow: hidden;\n box-shadow: none !important;\n display: flex;\n align-items: center;\n }\n ::ng-deep .auth-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255,255,255,0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .auth-form-container .field-input {\n flex: 1;\n min-width: 0;\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: clamp(0.9rem, 2vw, 1rem) !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .auth-form-container .field-input::placeholder { color: #64748b !important; }\n /* Eye toggle from FieldRendererComponent */\n ::ng-deep .auth-form-container .pwd-toggle-btn { color: #64748b !important; }\n ::ng-deep .auth-form-container .pwd-toggle-btn:hover { color: var(--app-primary, #6366f1) !important; }\n\n .field-error { font-size: 0.78rem; color: #ef4444; }\n\n /* ── Password Strength ── */\n .strength-bar { display: flex; align-items: center; gap: 10px; }\n .strength-track {\n flex: 1; height: 4px;\n background: rgba(255,255,255,0.07);\n border-radius: 2px;\n overflow: hidden;\n }\n .strength-fill {\n height: 100%;\n border-radius: 2px;\n transition: width 0.4s, background 0.4s;\n }\n .strength-weak { background: #ef4444; }\n .strength-fair { background: #f59e0b; }\n .strength-good { background: #10b981; }\n .strength-strong { background: #6366f1; }\n .strength-label { font-size: 0.75rem; color: #64748b; white-space: nowrap; }\n\n /* ── Button ── */\n .auth-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: clamp(11px, 2.5vw, 14px);\n border: none;\n border-radius: 12px;\n font-size: clamp(0.9rem, 2vw, 1rem);\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex: 1; /* grows in action-row, fills full width standalone */\n min-width: 0;\n position: relative;\n overflow: hidden;\n }\n .auth-btn:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n .auth-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }\n .btn-icon {\n width: 16px; height: 16px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n\n /* ── Error Banner ── */\n .error-banner {\n background: rgba(239,68,68,0.1);\n border: 1px solid rgba(239,68,68,0.3);\n border-radius: 10px;\n padding: 12px 16px;\n font-size: 0.875rem;\n color: #fca5a5;\n }\n\n /* ── Footer ── */\n .footer-note { text-align: center; margin-top: clamp(10px, 2vw, 18px); }\n .back-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 0.875rem;\n color: #64748b;\n font-weight: 500;\n transition: color 0.2s;\n text-decoration: none;\n }\n .back-link svg {\n width: 14px; height: 14px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n }\n .back-link:hover { color: var(--app-primary, #6366f1); }\n\n /* ── Inline action row — both steps ── */\n .action-row {\n display: flex;\n align-items: stretch; /* same height naturally */\n gap: 10px;\n }\n /* Ghost back button — equal width to the primary btn via flex:1 */\n .back-link-inline {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex: 1; /* equal width with .auth-btn */\n min-width: 0;\n padding: clamp(11px, 2.5vw, 14px) 12px;\n border-radius: 12px;\n border: 1px solid rgba(255,255,255,0.1);\n background: rgba(255,255,255,0.04);\n color: #94a3b8;\n font-size: clamp(0.82rem, 2vw, 0.9rem);\n font-weight: 500;\n text-decoration: none;\n white-space: nowrap;\n transition: all 0.2s;\n }\n .back-link-inline svg {\n width: 13px; height: 13px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n .back-link-inline:hover {\n color: #f1f5f9;\n border-color: rgba(99,102,241,0.35);\n background: rgba(99,102,241,0.06);\n }\n\n /* ── Loader ── */\n .loader {\n width: 20px; height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n\n /* ── Responsive: very small screens ── */\n @media (max-width: 400px) {\n .steps { margin-bottom: 14px; }\n .step-line { margin: 0 4px; margin-bottom: 22px; min-width: 12px; }\n .step-label { font-size: 0.6rem; }\n .screen-label { margin-bottom: 12px; }\n .icon-ms { font-size: 2.25rem !important; }\n .auth-form { gap: 12px; }\n }\n @media (prefers-reduced-motion: reduce) {\n .icon-wrap, .loader { animation: none !important; }\n }\n `]\n})\nexport class ForgotPasswordComponent implements OnDestroy {\n private readonly dispatcher = inject(ActionDispatcherService);\n private readonly stateService = inject(MetaStateService);\n private readonly router = inject(Router);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n private readonly sub: Subscription;\n\n currentStep = signal<Step>('email');\n loading = signal(false);\n errorMsg = signal('');\n\n email = '';\n newPassword = '';\n confirmPassword = '';\n confirmError = false;\n\n // AMF Form Definitions\n emailForm: FormMeta = {\n id: 'emailForm',\n hideSubmit: true,\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n resetForm: FormMeta = {\n id: 'resetForm',\n hideSubmit: true,\n fields: [\n {\n key: 'newPassword',\n type: 'password',\n label: 'New Password',\n placeholder: 'Minimum 8 characters',\n validators: [{ type: 'required' }, { type: 'minLength', value: 8 }]\n },\n {\n key: 'confirmPassword',\n type: 'password',\n label: 'Confirm Password',\n placeholder: 'Re-enter password',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor() {\n // Listen for modal events — when OTP is verified, advance to step 2\n this.sub = this.stateService.changes$.subscribe(change => {\n if (change.key === 'forgotPw.otpVerified' && change.newValue === true) {\n this.currentStep.set('reset');\n }\n });\n }\n\n ngOnDestroy() {\n this.sub.unsubscribe();\n this.stateService.clearNamespace('forgotPw');\n }\n\n get strengthPct(): number {\n const pw = this.newPassword;\n if (!pw) return 0;\n let score = 0;\n if (pw.length >= 8) score += 25;\n if (pw.length >= 12) score += 15;\n if (/[A-Z]/.test(pw)) score += 20;\n if (/[0-9]/.test(pw)) score += 20;\n if (/[^A-Za-z0-9]/.test(pw)) score += 20;\n return Math.min(score, 100);\n }\n get strengthLevel(): string {\n const p = this.strengthPct;\n if (p < 35) return 'weak';\n if (p < 60) return 'fair';\n if (p < 80) return 'good';\n return 'strong';\n }\n get strengthLabel(): string {\n const map: Record<string, string> = { weak: 'Weak', fair: 'Fair', good: 'Good', strong: 'Strong' };\n return this.strengthPct ? map[this.strengthLevel] : '';\n }\n\n checkConfirm(): void {\n this.confirmError = !!(this.confirmPassword && this.newPassword !== this.confirmPassword);\n }\n\n onEmailChange(values: any): void {\n this.email = values.email || '';\n }\n\n onResetChange(values: any): void {\n this.newPassword = values.newPassword || '';\n this.confirmPassword = values.confirmPassword || '';\n this.checkConfirm();\n }\n\n triggerEmailSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'emailForm' } });\n }\n\n triggerResetSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'resetForm' } });\n }\n\n onEmailSubmit(values: any): void {\n if (!values.email) return;\n\n this.loading.set(true);\n this.errorMsg.set('');\n\n // DEMO: calls mock-send-otp endpoint, then opens the OTP modal.\n // REAL: remove mock:true from 'mock-send-otp' and point it to your real endpoint.\n this.dispatcher.dispatch({\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'api', config: { endpointId: 'mock-send-otp', body: { email: this.email } } },\n {\n type: 'open-modal',\n config: {\n title: 'Enter Verification Code',\n size: 'sm',\n disableCloseOnBackdrop: true,\n content: {\n type: 'form',\n config: {\n fields: [\n {\n key: 'code',\n label: 'We sent a 6-digit code to ' + this.email,\n type: 'otp',\n otpLength: 6,\n validators: [{ type: 'required' }, { type: 'minLength', value: 6 }]\n }\n ],\n submitLabel: 'Verify Code',\n onSubmit: {\n type: 'api',\n config: {\n endpointId: 'mock-verify-otp',\n body: 'formValue',\n storeInState: 'forgotPw.verifyResult'\n },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'set-state', config: { key: 'forgotPw.otpVerified', value: true } },\n { type: 'close-modal', config: {} },\n { type: 'notify', config: { type: 'success', message: 'Code verified! Set your new password.' } }\n ]\n }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Invalid or expired code. Please try again.' }\n }\n }\n }\n }\n }\n }\n ]\n }\n }).finally(() => this.loading.set(false));\n }\n\n onResetSubmit(values: any): void {\n this.checkConfirm();\n if (!values.newPassword || this.confirmError) return;\n\n this.loading.set(true);\n this.errorMsg.set('');\n\n // DEMO: calls mock-reset-password endpoint.\n // REAL: remove mock:true from 'mock-reset-password' and point to your real endpoint.\n this.dispatcher.dispatch({\n type: 'api',\n config: {\n endpointId: 'mock-reset-password',\n body: { password: values.newPassword, resetToken: this.stateService.get('forgotPw.verifyResult.resetToken') }\n },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'Password updated! Please log in with your new password.' } },\n { type: 'delay', config: { duration: 800 } },\n { type: 'navigate', config: { path: '/login' } }\n ]\n }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Password reset failed. Please try again.' }\n }\n }).finally(() => this.loading.set(false));\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"avora-labs-meta-forge-forgot-password.page-PY9_K4M-.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/forgot-password.page.ts"],"sourcesContent":["/**\n * Forgot Password Component\n *\n * Powered by AvoraMetaForge actions:\n * - Step 1: User enters email → fires mock-send-otp API → opens AMF OTP modal\n * - Modal verified → set-state marks otpVerified → page shows Step 2\n * - Step 2: User sets new password → mock-reset-password → back to login\n *\n * This component uses AmfAuthShellComponent for the shared visual shell.\n * Framework users can replicate this pattern by using AmfAuthShellComponent\n * with any custom content, or by building their own shell entirely.\n */\nimport { Component, inject, signal, OnDestroy, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\n\nimport { Subscription } from 'rxjs';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { MetaStateService } from '../../services/meta-state.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\ntype Step = 'email' | 'reset';\n\n@Component({\n selector: 'amf-forgot-password',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\"\n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Recover your account'\"\n maxWidth=\"620px\">\n <!-- Step Indicator -->\n <div class=\"steps\">\n <div class=\"step\" [class.active]=\"currentStep() === 'email'\" [class.done]=\"currentStep() === 'reset'\">\n <div class=\"step-dot\">\n @if (currentStep() === 'reset') {\n <span class=\"ms step-icon\">check</span>\n } @else {\n <span>1</span>\n }\n </div>\n <span class=\"step-label\">Email</span>\n </div>\n <div class=\"step-line\" [class.done]=\"currentStep() === 'reset'\"></div>\n <div class=\"step\" [class.active]=\"currentStep() === 'reset'\">\n <div class=\"step-dot\"><span>2</span></div>\n <span class=\"step-label\">New Password</span>\n </div>\n </div>\n\n <!-- ── STEP 1: Email ── -->\n @if (currentStep() === 'email') {\n <div class=\"form-section\">\n <div class=\"screen-label\">\n <div class=\"icon-wrap\"><span class=\"ms icon-ms\">lock</span></div>\n <h2>Forgot your password?</h2>\n <p>Enter your email and we'll send a verification code.</p>\n </div>\n\n <div class=\"auth-form-container\">\n <amf-form-renderer \n [config]=\"emailForm\" \n (formSubmit)=\"onEmailSubmit($event)\"\n (formChange)=\"onEmailChange($event)\">\n </amf-form-renderer>\n\n @if (errorMsg()) {\n <div class=\"error-banner\">{{ errorMsg() }}</div>\n }\n\n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerEmailSubmit()\" [disabled]=\"loading() || !email\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Send Verification Code</span>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 12H5M12 19l-7-7 7-7\"/></svg>\n Back to Sign In\n </a>\n </div>\n </div>\n </div>\n }\n\n <!-- ── STEP 2: New Password (after OTP verified) ── -->\n @if (currentStep() === 'reset') {\n <div class=\"form-section\">\n <!-- Compact inline header for step 2 -->\n <div class=\"screen-label screen-label-sm\">\n <span class=\"ms icon-ms icon-ms-inline\">key</span>\n <div>\n <h2>Set a new password</h2>\n <p>Identity verified — choose a strong password.</p>\n </div>\n </div>\n\n <div class=\"auth-form-container\">\n <amf-form-renderer \n [config]=\"resetForm\" \n (formSubmit)=\"onResetSubmit($event)\"\n (formChange)=\"onResetChange($event)\">\n </amf-form-renderer>\n\n @if (confirmError) {\n <span class=\"field-error\" style=\"margin-top: -10px; display: block;\">Passwords don't match</span>\n }\n\n <!-- Strength bar: only show once user starts typing -->\n @if (newPassword) {\n <div class=\"strength-bar\">\n <div class=\"strength-track\">\n <div class=\"strength-fill\" [style.width]=\"strengthPct + '%'\" [class]=\"'strength-' + strengthLevel\"></div>\n </div>\n <span class=\"strength-label\">{{ strengthLabel }}</span>\n </div>\n }\n\n @if (errorMsg()) {\n <div class=\"error-banner\">{{ errorMsg() }}</div>\n }\n\n <!-- Inline action row: equal-width Submit + Back -->\n <div class=\"action-row\">\n <button type=\"button\" class=\"auth-btn\" (click)=\"triggerResetSubmit()\" [disabled]=\"loading() || !newPassword || !confirmPassword || confirmError\">\n @if (loading()) {\n <div class=\"loader\"></div>\n } @else {\n <span>Update Password</span>\n }\n </button>\n <a routerLink=\"/login\" class=\"back-link-inline\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 12H5M12 19l-7-7 7-7\"/></svg>\n Back to Sign In\n </a>\n </div>\n </div>\n </div>\n }\n\n\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n /* ── Step Indicator ── */\n .steps {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0;\n margin-bottom: clamp(12px, 2.5vw, 20px);\n }\n .step {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n }\n .step-dot {\n width: 32px; height: 32px;\n border-radius: 50%;\n border: 2px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 700;\n color: #64748b;\n transition: all 0.3s;\n }\n .step.active .step-dot {\n border-color: var(--app-primary, #6366f1);\n background: rgba(99,102,241,0.15);\n color: var(--app-primary, #6366f1);\n box-shadow: 0 0 16px var(--app-glow, rgba(99,102,241,0.4));\n }\n .step.done .step-dot {\n border-color: #10b981;\n background: rgba(16,185,129,0.15);\n color: #10b981;\n }\n .step-icon { font-size: 1rem !important; }\n .step-label {\n font-size: 0.7rem;\n color: #64748b;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n white-space: nowrap;\n }\n .step.active .step-label { color: #94a3b8; }\n .step-line {\n flex: 1;\n height: 2px;\n background: rgba(255,255,255,0.08);\n margin: 0 8px;\n margin-bottom: 22px;\n min-width: 24px;\n transition: background 0.3s;\n }\n .step-line.done { background: rgba(16,185,129,0.4); }\n\n /* ── Screen Label ── */\n .screen-label {\n text-align: center;\n margin-bottom: clamp(10px, 2vw, 16px);\n }\n /* Step 2 compact inline variant */\n .screen-label-sm {\n display: flex;\n align-items: center;\n gap: 12px;\n text-align: left;\n padding: 10px 14px;\n background: rgba(255,255,255,0.03);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 12px;\n margin-bottom: clamp(10px, 2vw, 14px);\n }\n .screen-label-sm h2 {\n font-size: clamp(1rem, 3vw, 1.15rem) !important;\n margin-bottom: 2px !important;\n }\n .screen-label-sm p {\n font-size: clamp(0.75rem, 1.8vw, 0.82rem) !important;\n margin: 0;\n }\n .icon-ms-inline {\n font-size: 1.75rem !important;\n flex-shrink: 0;\n animation: float 3s ease-in-out infinite;\n }\n .icon-wrap {\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: float 3s ease-in-out infinite;\n }\n .icon-ms {\n font-size: 2.1rem !important;\n font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 48;\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n }\n .screen-label h2 {\n font-size: clamp(1.15rem, 4vw, 1.4rem);\n font-weight: 700;\n color: #f1f5f9;\n margin-bottom: 6px;\n }\n .screen-label p {\n font-size: clamp(0.8rem, 2vw, 0.875rem);\n color: #64748b;\n line-height: 1.5;\n }\n /* 2-col row for the two password fields */\n .pw-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n }\n @media (max-width: 460px) {\n .pw-row { grid-template-columns: 1fr; }\n .screen-label-sm { flex-direction: column; text-align: center; }\n }\n\n /* ── Form ── */\n .auth-form-container { display: flex; flex-direction: column; gap: clamp(10px, 2vw, 14px); }\n \n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .auth-form-container .amf-form { gap: clamp(10px, 2vw, 14px); }\n ::ng-deep .auth-form-container .amf-form-fields { gap: clamp(10px, 2vw, 14px); }\n ::ng-deep .auth-form-container .amf-field { display: flex; flex-direction: column; gap: 8px; }\n ::ng-deep .auth-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .auth-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255,255,255,0.08) !important;\n background: rgba(255,255,255,0.04) !important;\n transition: all 0.25s !important;\n overflow: hidden;\n box-shadow: none !important;\n display: flex;\n align-items: center;\n }\n ::ng-deep .auth-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255,255,255,0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .auth-form-container .field-input {\n flex: 1;\n min-width: 0;\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: clamp(0.9rem, 2vw, 1rem) !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .auth-form-container .field-input::placeholder { color: #64748b !important; }\n /* Eye toggle from FieldRendererComponent */\n ::ng-deep .auth-form-container .pwd-toggle-btn { color: #64748b !important; }\n ::ng-deep .auth-form-container .pwd-toggle-btn:hover { color: var(--app-primary, #6366f1) !important; }\n\n .field-error { font-size: 0.78rem; color: #ef4444; }\n\n /* ── Password Strength ── */\n .strength-bar { display: flex; align-items: center; gap: 10px; }\n .strength-track {\n flex: 1; height: 4px;\n background: rgba(255,255,255,0.07);\n border-radius: 2px;\n overflow: hidden;\n }\n .strength-fill {\n height: 100%;\n border-radius: 2px;\n transition: width 0.4s, background 0.4s;\n }\n .strength-weak { background: #ef4444; }\n .strength-fair { background: #f59e0b; }\n .strength-good { background: #10b981; }\n .strength-strong { background: #6366f1; }\n .strength-label { font-size: 0.75rem; color: #64748b; white-space: nowrap; }\n\n /* ── Button ── */\n .auth-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: clamp(11px, 2.5vw, 14px);\n border: none;\n border-radius: 12px;\n font-size: clamp(0.9rem, 2vw, 1rem);\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4,0,0.2,1);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex: 1; /* grows in action-row, fills full width standalone */\n min-width: 0;\n position: relative;\n overflow: hidden;\n }\n .auth-btn:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n .auth-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }\n .btn-icon {\n width: 16px; height: 16px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n\n /* ── Error Banner ── */\n .error-banner {\n background: rgba(239,68,68,0.1);\n border: 1px solid rgba(239,68,68,0.3);\n border-radius: 10px;\n padding: 12px 16px;\n font-size: 0.875rem;\n color: #fca5a5;\n }\n\n /* ── Footer ── */\n .footer-note { text-align: center; margin-top: clamp(10px, 2vw, 18px); }\n .back-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 0.875rem;\n color: #64748b;\n font-weight: 500;\n transition: color 0.2s;\n text-decoration: none;\n }\n .back-link svg {\n width: 14px; height: 14px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n }\n .back-link:hover { color: var(--app-primary, #6366f1); }\n\n /* ── Inline action row — both steps ── */\n .action-row {\n display: flex;\n align-items: stretch; /* same height naturally */\n gap: 10px;\n }\n /* Ghost back button — equal width to the primary btn via flex:1 */\n .back-link-inline {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex: 1; /* equal width with .auth-btn */\n min-width: 0;\n padding: clamp(11px, 2.5vw, 14px) 12px;\n border-radius: 12px;\n border: 1px solid rgba(255,255,255,0.1);\n background: rgba(255,255,255,0.04);\n color: #94a3b8;\n font-size: clamp(0.82rem, 2vw, 0.9rem);\n font-weight: 500;\n text-decoration: none;\n white-space: nowrap;\n transition: all 0.2s;\n }\n .back-link-inline svg {\n width: 13px; height: 13px;\n fill: none; stroke: currentColor; stroke-width: 2.5;\n stroke-linecap: round; stroke-linejoin: round;\n flex-shrink: 0;\n }\n .back-link-inline:hover {\n color: #f1f5f9;\n border-color: rgba(99,102,241,0.35);\n background: rgba(99,102,241,0.06);\n }\n\n /* ── Loader ── */\n .loader {\n width: 20px; height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n\n /* ── Responsive: very small screens ── */\n @media (max-width: 400px) {\n .steps { margin-bottom: 14px; }\n .step-line { margin: 0 4px; margin-bottom: 22px; min-width: 12px; }\n .step-label { font-size: 0.6rem; }\n .screen-label { margin-bottom: 12px; }\n .icon-ms { font-size: 2.25rem !important; }\n .auth-form { gap: 12px; }\n }\n @media (prefers-reduced-motion: reduce) {\n .icon-wrap, .loader { animation: none !important; }\n }\n `]\n})\nexport class ForgotPasswordComponent implements OnDestroy {\n private readonly dispatcher = inject(ActionDispatcherService);\n private readonly stateService = inject(MetaStateService);\n private readonly router = inject(Router);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n private readonly sub: Subscription;\n\n currentStep = signal<Step>('email');\n loading = signal(false);\n errorMsg = signal('');\n\n email = '';\n newPassword = '';\n confirmPassword = '';\n confirmError = false;\n\n // AMF Form Definitions\n emailForm: FormMeta = {\n id: 'emailForm',\n hideSubmit: true,\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n resetForm: FormMeta = {\n id: 'resetForm',\n hideSubmit: true,\n fields: [\n {\n key: 'newPassword',\n type: 'password',\n label: 'New Password',\n placeholder: 'Minimum 8 characters',\n validators: [{ type: 'required' }, { type: 'minLength', value: 8 }]\n },\n {\n key: 'confirmPassword',\n type: 'password',\n label: 'Confirm Password',\n placeholder: 'Re-enter password',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor() {\n // Listen for modal events — when OTP is verified, advance to step 2\n this.sub = this.stateService.changes$.subscribe(change => {\n if (change.key === 'forgotPw.otpVerified' && change.newValue === true) {\n this.currentStep.set('reset');\n }\n });\n }\n\n ngOnDestroy() {\n this.sub.unsubscribe();\n this.stateService.clearNamespace('forgotPw');\n }\n\n get strengthPct(): number {\n const pw = this.newPassword;\n if (!pw) return 0;\n let score = 0;\n if (pw.length >= 8) score += 25;\n if (pw.length >= 12) score += 15;\n if (/[A-Z]/.test(pw)) score += 20;\n if (/[0-9]/.test(pw)) score += 20;\n if (/[^A-Za-z0-9]/.test(pw)) score += 20;\n return Math.min(score, 100);\n }\n get strengthLevel(): string {\n const p = this.strengthPct;\n if (p < 35) return 'weak';\n if (p < 60) return 'fair';\n if (p < 80) return 'good';\n return 'strong';\n }\n get strengthLabel(): string {\n const map: Record<string, string> = { weak: 'Weak', fair: 'Fair', good: 'Good', strong: 'Strong' };\n return this.strengthPct ? map[this.strengthLevel] : '';\n }\n\n checkConfirm(): void {\n this.confirmError = !!(this.confirmPassword && this.newPassword !== this.confirmPassword);\n }\n\n onEmailChange(values: any): void {\n this.email = values.email || '';\n }\n\n onResetChange(values: any): void {\n this.newPassword = values.newPassword || '';\n this.confirmPassword = values.confirmPassword || '';\n this.checkConfirm();\n }\n\n triggerEmailSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'emailForm' } });\n }\n\n triggerResetSubmit(): void {\n this.dispatcher.dispatch({ type: 'submit-form', config: { formId: 'resetForm' } });\n }\n\n onEmailSubmit(values: any): void {\n if (!values.email) return;\n\n this.loading.set(true);\n this.errorMsg.set('');\n\n // DEMO: calls mock-send-otp endpoint, then opens the OTP modal.\n // REAL: remove mock:true from 'mock-send-otp' and point it to your real endpoint.\n this.dispatcher.dispatch({\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'api', config: { endpointId: 'mock-send-otp', body: { email: this.email } } },\n {\n type: 'open-modal',\n config: {\n title: 'Enter Verification Code',\n size: 'sm',\n disableCloseOnBackdrop: true,\n content: {\n type: 'form',\n config: {\n fields: [\n {\n key: 'code',\n label: 'We sent a 6-digit code to ' + this.email,\n type: 'otp',\n otpLength: 6,\n validators: [{ type: 'required' }, { type: 'minLength', value: 6 }]\n }\n ],\n submitLabel: 'Verify Code',\n onSubmit: {\n type: 'api',\n config: {\n endpointId: 'mock-verify-otp',\n body: 'formValue',\n storeInState: 'forgotPw.verifyResult'\n },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'set-state', config: { key: 'forgotPw.otpVerified', value: true } },\n { type: 'close-modal', config: {} },\n { type: 'notify', config: { type: 'success', message: 'Code verified! Set your new password.' } }\n ]\n }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Invalid or expired code. Please try again.' }\n }\n }\n }\n }\n }\n }\n ]\n }\n }).finally(() => this.loading.set(false));\n }\n\n onResetSubmit(values: any): void {\n this.checkConfirm();\n if (!values.newPassword || this.confirmError) return;\n\n this.loading.set(true);\n this.errorMsg.set('');\n\n // DEMO: calls mock-reset-password endpoint.\n // REAL: remove mock:true from 'mock-reset-password' and point to your real endpoint.\n this.dispatcher.dispatch({\n type: 'api',\n config: {\n endpointId: 'mock-reset-password',\n body: { password: values.newPassword, resetToken: this.stateService.get('forgotPw.verifyResult.resetToken') }\n },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'sequential',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'Password updated! Please log in with your new password.' } },\n { type: 'delay', config: { duration: 800 } },\n { type: 'navigate', config: { path: '/login' } }\n ]\n }\n },\n onError: {\n type: 'notify',\n config: { type: 'error', message: 'Password reset failed. Please try again.' }\n }\n }).finally(() => this.loading.set(false));\n }\n}\n"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms';
5
5
  import * as i1 from '@angular/router';
6
6
  import { RouterModule } from '@angular/router';
7
7
  import { AuthService, ActionDispatcherService, APP_META_CONFIG_TOKEN, FormRendererComponent } from './avora-labs-meta-forge.mjs';
8
- import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs';
8
+ import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-C89gSPc9.mjs';
9
9
 
10
10
  class LoginComponent {
11
11
  router;
@@ -97,8 +97,8 @@ class LoginComponent {
97
97
  });
98
98
  }, 1200);
99
99
  }
100
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LoginComponent, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component });
101
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: LoginComponent, isStandalone: true, selector: "amf-login", ngImport: i0, template: `
100
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: LoginComponent, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component });
101
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: LoginComponent, isStandalone: true, selector: "amf-login", ngImport: i0, template: `
102
102
  <amf-auth-shell
103
103
  [brandName]="meta.auth?.builtInUI?.brandName || meta.app.name"
104
104
  [brandTagline]="meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'">
@@ -136,7 +136,7 @@ class LoginComponent {
136
136
  </amf-auth-shell>
137
137
  `, isInline: true, styles: [":host{display:block;height:100%}.login-form-container{display:flex;flex-direction:column;gap:24px}::ng-deep .login-form-container .amf-form{gap:24px}::ng-deep .login-form-container .amf-form-fields{gap:24px}::ng-deep .login-form-container .amf-field{display:flex;flex-direction:column;gap:8px}::ng-deep .login-form-container .field-label{font-size:.875rem!important;font-weight:600!important;color:#cbd5e1!important;margin-bottom:0!important}::ng-deep .login-form-container .field-input-wrapper{border-radius:12px!important;border:1px solid rgba(255,255,255,.08)!important;background:#ffffff0a!important;transition:all .3s!important;overflow:hidden;box-shadow:none!important}::ng-deep .login-form-container .field-input-wrapper:focus-within{border-color:var(--app-primary, #6366f1)!important;background:#ffffff0f!important;box-shadow:0 0 20px var(--app-glow, rgba(99,102,241,.3))!important}::ng-deep .login-form-container .field-input{padding:13px 16px!important;border:none!important;background:transparent!important;font-size:1rem!important;color:#f1f5f9!important}::ng-deep .login-form-container .field-input::placeholder{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn:hover{color:var(--app-primary, #6366f1)!important}.form-options{display:flex;align-items:center;justify-content:space-between;font-size:.875rem}.remember-me{display:flex;align-items:center;gap:8px;cursor:pointer;color:#94a3b8}.remember-me input{display:none}.custom-check{width:16px;height:16px;border-radius:4px;border:1px solid rgba(255,255,255,.15);background:#ffffff0a;position:relative;transition:all .2s}.remember-me input:checked+.custom-check{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));border-color:transparent}.remember-me input:checked+.custom-check:after{content:\"\";position:absolute;left:5px;top:2px;width:4px;height:7px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.forgot-link{color:var(--app-primary, #6366f1);font-weight:500;transition:all .2s;text-decoration:none}.forgot-link:hover{text-shadow:0 0 12px var(--app-glow, rgba(99,102,241,.3))}.login-btn{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:14px;border:none;border-radius:12px;font-size:1rem;font-weight:600;cursor:pointer;transition:all .3s;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden}.login-btn:hover{transform:translateY(-2px);box-shadow:0 10px 30px -5px var(--app-glow, rgba(99,102,241,.5))}.login-btn:disabled{opacity:.7;cursor:not-allowed;transform:none}.auth-footer-note{text-align:center;margin-top:32px;font-size:.875rem;color:#64748b}.auth-footer-note a{color:var(--app-primary, #6366f1);font-weight:600;text-decoration:none}.loader{width:20px;height:20px;border:3px solid rgba(255,255,255,.2);border-top:3px solid white;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AmfAuthShellComponent, selector: "amf-auth-shell", inputs: ["brandName", "brandTagline", "maxWidth"] }, { kind: "component", type: FormRendererComponent, selector: "amf-form-renderer", inputs: ["config", "context"], outputs: ["formSubmit", "formCancel", "formChange"] }] });
138
138
  }
139
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LoginComponent, decorators: [{
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: LoginComponent, decorators: [{
140
140
  type: Component,
141
141
  args: [{ selector: 'amf-login', standalone: true, imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent], template: `
142
142
  <amf-auth-shell
@@ -178,4 +178,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
178
178
  }], ctorParameters: () => [{ type: i1.Router }] });
179
179
 
180
180
  export { LoginComponent };
181
- //# sourceMappingURL=avora-labs-meta-forge-login.page-LCW-ofz1.mjs.map
181
+ //# sourceMappingURL=avora-labs-meta-forge-login.page-BW-RWCQM.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"avora-labs-meta-forge-login.page-LCW-ofz1.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/login.page.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\nimport { AuthService } from '../../../core/auth/auth.service';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\n@Component({\n selector: 'amf-login',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\" \n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'\">\n \n <div class=\"login-form-container\">\n <!-- AMF Data-Driven Form Definition -->\n <amf-form-renderer \n #renderer\n [config]=\"loginForm\" \n (formSubmit)=\"onFormSubmit($event)\">\n </amf-form-renderer>\n\n <!-- Custom Inline Options Row -->\n <div class=\"form-options\">\n <label class=\"remember-me\">\n <input type=\"checkbox\" name=\"remember\" [(ngModel)]=\"rememberMe\">\n <span class=\"custom-check\"></span>\n <span>Remember me</span>\n </label>\n <a routerLink=\"/forgot-password\" class=\"forgot-link\">Forgot password?</a>\n </div>\n\n <button type=\"button\" class=\"login-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading()\">\n @if (!loading()) {\n <span>Sign In</span>\n } @else {\n <div class=\"loader\"></div>\n }\n </button>\n </div>\n\n <div class=\"auth-footer-note\">\n Don't have an account? <a routerLink=\"/contact-support\">Contact Support</a>\n </div>\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n .login-form-container {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .login-form-container .amf-form {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-form-fields {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n ::ng-deep .login-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255, 255, 255, 0.08) !important;\n background: rgba(255, 255, 255, 0.04) !important;\n transition: all 0.3s !important;\n overflow: hidden;\n box-shadow: none !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255, 255, 255, 0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .login-form-container .field-input {\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: 1rem !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .login-form-container .field-input::placeholder {\n color: #64748b !important;\n }\n /* Adjust password eye toggle specifically for this glass look */\n ::ng-deep .login-form-container .pwd-toggle-btn {\n color: #64748b !important;\n }\n ::ng-deep .login-form-container .pwd-toggle-btn:hover {\n color: var(--app-primary, #6366f1) !important;\n }\n\n .form-options {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 0.875rem;\n }\n\n .remember-me {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n color: #94a3b8;\n }\n\n .remember-me input { display: none; }\n\n .custom-check {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n position: relative;\n transition: all 0.2s;\n }\n\n .remember-me input:checked + .custom-check {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n border-color: transparent;\n }\n\n .remember-me input:checked + .custom-check::after {\n content: '';\n position: absolute;\n left: 5px; top: 2px;\n width: 4px; height: 7px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .forgot-link {\n color: var(--app-primary, #6366f1);\n font-weight: 500;\n transition: all 0.2s;\n text-decoration: none;\n }\n\n .forgot-link:hover {\n text-shadow: 0 0 12px var(--app-glow, rgba(99,102,241,0.3));\n }\n\n .login-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: 14px;\n border: none;\n border-radius: 12px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .login-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n\n .login-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n transform: none;\n }\n\n .auth-footer-note {\n text-align: center;\n margin-top: 32px;\n font-size: 0.875rem;\n color: #64748b;\n }\n\n .auth-footer-note a {\n color: var(--app-primary, #6366f1);\n font-weight: 600;\n text-decoration: none;\n }\n\n .loader {\n width: 20px;\n height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top: 3px solid white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `]\n})\nexport class LoginComponent {\n private auth = inject(AuthService);\n private dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n rememberMe = false;\n\n // JSON Meta Definition replacing the hardcoded HTML fields\n loginForm: FormMeta = {\n id: 'loginForm',\n hideSubmit: true, // We provide our own exact-match custom button below\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'password',\n type: 'password',\n label: 'Password',\n placeholder: '••••••••',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor(private router: Router) { }\n\n triggerSubmit(): void {\n // Dispatches standard AMF action to submit the specific form\n this.dispatcher.dispatch({\n type: 'submit-form',\n config: { formId: 'loginForm' }\n });\n }\n\n onFormSubmit(values: any): void {\n if (!values.email || !values.password) return;\n\n this.loading.set(true);\n\n setTimeout(() => {\n this.loading.set(false);\n \n this.dispatcher.dispatch({\n type: 'open-modal',\n config: {\n title: 'Two-Step Verification',\n size: 'sm',\n content: {\n type: 'form',\n config: {\n fields: [\n {\n name: 'otp',\n label: 'Enter 6-digit PIN',\n type: 'otp',\n required: true,\n otpLength: 6,\n validation: { minLength: 6, maxLength: 6 }\n }\n ],\n submitLabel: 'Verify & Login',\n loadingLabel: 'Verifying...',\n onSubmit: {\n type: 'api',\n config: { endpointId: 'mock-login-otp', body: 'formValue' },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'parallel',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },\n { type: 'close-modal' },\n { \n type: 'delay', \n config: { duration: 600 }, \n then: { type: 'navigate', config: { path: '/dashboard' } } \n }\n ]\n }\n },\n onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }\n }\n }\n }\n }\n });\n }, 1200);\n }\n}\n"],"names":["i2"],"mappings":"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"}
1
+ {"version":3,"file":"avora-labs-meta-forge-login.page-BW-RWCQM.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/login.page.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\nimport { AuthService } from '../../../core/auth/auth.service';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\n@Component({\n selector: 'amf-login',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\" \n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'\">\n \n <div class=\"login-form-container\">\n <!-- AMF Data-Driven Form Definition -->\n <amf-form-renderer \n #renderer\n [config]=\"loginForm\" \n (formSubmit)=\"onFormSubmit($event)\">\n </amf-form-renderer>\n\n <!-- Custom Inline Options Row -->\n <div class=\"form-options\">\n <label class=\"remember-me\">\n <input type=\"checkbox\" name=\"remember\" [(ngModel)]=\"rememberMe\">\n <span class=\"custom-check\"></span>\n <span>Remember me</span>\n </label>\n <a routerLink=\"/forgot-password\" class=\"forgot-link\">Forgot password?</a>\n </div>\n\n <button type=\"button\" class=\"login-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading()\">\n @if (!loading()) {\n <span>Sign In</span>\n } @else {\n <div class=\"loader\"></div>\n }\n </button>\n </div>\n\n <div class=\"auth-footer-note\">\n Don't have an account? <a routerLink=\"/contact-support\">Contact Support</a>\n </div>\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n .login-form-container {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .login-form-container .amf-form {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-form-fields {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n ::ng-deep .login-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255, 255, 255, 0.08) !important;\n background: rgba(255, 255, 255, 0.04) !important;\n transition: all 0.3s !important;\n overflow: hidden;\n box-shadow: none !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255, 255, 255, 0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .login-form-container .field-input {\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: 1rem !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .login-form-container .field-input::placeholder {\n color: #64748b !important;\n }\n /* Adjust password eye toggle specifically for this glass look */\n ::ng-deep .login-form-container .pwd-toggle-btn {\n color: #64748b !important;\n }\n ::ng-deep .login-form-container .pwd-toggle-btn:hover {\n color: var(--app-primary, #6366f1) !important;\n }\n\n .form-options {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 0.875rem;\n }\n\n .remember-me {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n color: #94a3b8;\n }\n\n .remember-me input { display: none; }\n\n .custom-check {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n position: relative;\n transition: all 0.2s;\n }\n\n .remember-me input:checked + .custom-check {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n border-color: transparent;\n }\n\n .remember-me input:checked + .custom-check::after {\n content: '';\n position: absolute;\n left: 5px; top: 2px;\n width: 4px; height: 7px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .forgot-link {\n color: var(--app-primary, #6366f1);\n font-weight: 500;\n transition: all 0.2s;\n text-decoration: none;\n }\n\n .forgot-link:hover {\n text-shadow: 0 0 12px var(--app-glow, rgba(99,102,241,0.3));\n }\n\n .login-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: 14px;\n border: none;\n border-radius: 12px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .login-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n\n .login-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n transform: none;\n }\n\n .auth-footer-note {\n text-align: center;\n margin-top: 32px;\n font-size: 0.875rem;\n color: #64748b;\n }\n\n .auth-footer-note a {\n color: var(--app-primary, #6366f1);\n font-weight: 600;\n text-decoration: none;\n }\n\n .loader {\n width: 20px;\n height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top: 3px solid white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `]\n})\nexport class LoginComponent {\n private auth = inject(AuthService);\n private dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n rememberMe = false;\n\n // JSON Meta Definition replacing the hardcoded HTML fields\n loginForm: FormMeta = {\n id: 'loginForm',\n hideSubmit: true, // We provide our own exact-match custom button below\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'password',\n type: 'password',\n label: 'Password',\n placeholder: '••••••••',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor(private router: Router) { }\n\n triggerSubmit(): void {\n // Dispatches standard AMF action to submit the specific form\n this.dispatcher.dispatch({\n type: 'submit-form',\n config: { formId: 'loginForm' }\n });\n }\n\n onFormSubmit(values: any): void {\n if (!values.email || !values.password) return;\n\n this.loading.set(true);\n\n setTimeout(() => {\n this.loading.set(false);\n \n this.dispatcher.dispatch({\n type: 'open-modal',\n config: {\n title: 'Two-Step Verification',\n size: 'sm',\n content: {\n type: 'form',\n config: {\n fields: [\n {\n name: 'otp',\n label: 'Enter 6-digit PIN',\n type: 'otp',\n required: true,\n otpLength: 6,\n validation: { minLength: 6, maxLength: 6 }\n }\n ],\n submitLabel: 'Verify & Login',\n loadingLabel: 'Verifying...',\n onSubmit: {\n type: 'api',\n config: { endpointId: 'mock-login-otp', body: 'formValue' },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'parallel',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },\n { type: 'close-modal' },\n { \n type: 'delay', \n config: { duration: 600 }, \n then: { type: 'navigate', config: { path: '/dashboard' } } \n }\n ]\n }\n },\n onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }\n }\n }\n }\n }\n });\n }, 1200);\n }\n}\n"],"names":["i2"],"mappings":"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"}