PageSourceSearch

https://www.comfyaicloud.com/generate/

html comfyaicloud.com collected 2026-10-02 01:26:03 UTC 269,699 bytes, 3,732 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8">
5<title>Comfy AI - Professional AI Image Generation Tool & Cloud Workflows</title>
6<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
7<meta name="theme-color" content="#faf8f4">
8<!-- ── SEO & Social Meta Tags ── -->
9<meta name="description" content="Experience Comfy AI online. The ultimate cloud-based ComfyUI image generation tool. Create AI images, UGC lip-sync videos, social media visuals, and deconstruct prompts instantly in your browser. Start free today!">
10<meta name="keywords" content="comfy ai, comfyai, comfy ai image generation tool, comfy ai tool website, comfyui workflows online, ai art generator">
11<link rel="canonical" href="https://www.comfyaicloud.com/">
12
13<!-- Open Graph / Facebook -->
14<meta property="og:type" content="website">
15<meta property="og:url" content="https://www.comfyaicloud.com/">
16<meta property="og:title" content="Comfy AI - Professional AI Image Generation & Cloud Workflows">
17<meta property="og:description" content="Generate high-fidelity AI art with professional ComfyUI workflows online. Generate images, UGC lip-sync videos, social media content, and deconstruct creative prompts.">
18<meta property="og:image" content="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/screenshot.jpg">
19
20<!-- Twitter -->
21<meta property="twitter:card" content="summary_large_image">
22<meta property="twitter:url" content="https://www.comfyaicloud.com/">
23<meta property="twitter:title" content="Comfy AI - Professional AI Image Generation">
24<meta property="twitter:description" content="Professional ComfyUI workflows in the browser. Generate images, UGC videos, social media content, and deconstruct prompts with creative precision.">
25<meta property="twitter:image" content="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/screenshot.jpg">
26
27<meta name="robots" content="index,follow">
28
29<!-- ── Resource Hints ── -->
30<link rel="preconnect" href="https://fonts.googleapis.com">
31<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
32<!-- accounts.google.com preconnect removed — GIS loads async on demand -->
33
34<!-- ── Google Fonts: Standard High-Priority Loading ── -->
35<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700;800&family=Outfit:wght@300;400;500;600;700;800;900&display=optional">
36<style>
37  /* Use Inter as the base, with local system fallbacks to prevent jumps */
38  :root {
39    --font-primary: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
40  }
41</style>
42
43
44<!-- ── FAQ Schema ── -->
45<script type="application/ld+json">
46{
47  "@context": "https://schema.org",
48  "@type": "FAQPage",
49  "mainEntity": [{
50    "@type": "Question",
51    "name": "What is Comfy AI?",
52    "acceptedAnswer": {
53      "@type": "Answer",
54      "text": "Comfy AI is a professional cloud-based image generation tool that brings ComfyUI workflows to the browser. It allows users to create AI images, UGC lip-sync videos, social media content, and deconstruct visual prompts using advanced cloud workflows."
55    }
56  }, {
57    "@type": "Question",
58    "name": "How does the Comfy AI image generation tool work?",
59    "acceptedAnswer": {
60      "@type": "Answer",
61      "text": "It utilizes powerful GPU clusters to run ComfyUI workflows online. Simply enter a prompt, choose your resolution, and our neural engine generates high-fidelity art in seconds."
62    }
63  }, {
64    "@type": "Question",
65    "name": "Can I use ComfyUI workflows online here?",
66    "acceptedAnswer": {
67      "@type": "Answer",
68      "text": "Yes! Our platform is built to support complex ComfyUI nodes and workflows, giving you the same control as local installations with cloud speed."
69    }
70  }, {
71    "@type": "Question",
72    "name": "Is there a free version of ComfyAI?",
73    "acceptedAnswer": {
74      "@type": "Answer",
75      "text": "We offer free credits to new users so you can try the Comfy AI tool website and its features before choosing a premium plan."
76    }
77  }]
78}
79</script>
79
80
81<link rel="preload" as="image" href="https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png" fetchpriority="high" type="image/webp">
82<!-- Google tag (gtag.js) -->
vendor: 64 bytes, lines 82-83
82
83<script async src="https://www.googletagmanager.com/gtag/js?id=
83AW-18226387043
vendor: 12 bytes, line 83
83"></script>
84<script>
85  
vendor: 134 bytes, lines 85-89
85window.dataLayer = window.dataLayer || [];
86  function gtag(){dataLayer.push(arguments);}
87  gtag('js', new Date());
88
89  gtag('config', '
89AW-18226387043
vendor: 4 bytes, line 89
89');
90</script>
90
91    <meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' />
92<link rel="preload" href="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/css/app.css?ver=69.9.7" as="style" onload="this.onload=null;this.rel='stylesheet'">
93<noscript><link rel="stylesheet" href="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/css/app.css?ver=69.9.7"></noscript>
94<link rel="preload" href="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/css/redesign.css?ver=69.9.7" as="style" onload="this.onload=null;this.rel='stylesheet'">
95<noscript><link rel="stylesheet" href="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/css/redesign.css?ver=69.9.7"></noscript>
96<link rel="preload" href="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/js/app.js?ver=69.9.7" as="script">
97<link rel="dns-prefetch" href="https://ui-avatars.com">
98
99	<!-- This site is optimized with the Yoast SEO plugin v28.5 - https://yoast.com/product/yoast-seo-wordpress/ -->
100	<title>Generate - ComfyAI Cloud</title>
101	<link rel="canonical" href="https://www.comfyaicloud.com/generate/" />
102	<meta property="og:locale" content="en_US" />
103	<meta property="og:type" content="article" />
104	<meta property="og:title" content="Generate - ComfyAI Cloud" />
105	<meta property="og:url" content="https://www.comfyaicloud.com/generate/" />
106	<meta property="og:site_name" content="ComfyAI Cloud" />
107	<meta name="twitter:card" content="summary_large_image" />
108	
108<script type="application/ld+json" class="yoast-schema-graph">{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.comfyaicloud.com\/generate\/","url":"https:\/\/www.comfyaicloud.com\/generate\/","name":"Generate - ComfyAI Cloud","isPartOf":{"@id":"https:\/\/www.comfyaicloud.com\/#website"},"datePublished":"2026-02-24T06:33:58+00:00","breadcrumb":{"@id":"https:\/\/www.comfyaicloud.com\/generate\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.comfyaicloud.com\/generate\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.comfyaicloud.com\/generate\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.comfyaicloud.com\/"},{"@type":"ListItem","position":2,"name":"Generate"}]},{"@type":"WebSite","@id":"https:\/\/www.comfyaicloud.com\/#website","url":"https:\/\/www.comfyaicloud.com\/","name":"comfyaicloud.com","description":"Easy AI Art Generator | Text to Image AI and Image To prompt Deconstruction","publisher":{"@id":"https:\/\/www.comfyaicloud.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.comfyaicloud.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.comfyaicloud.com\/#organization","name":"comfyaicloud.com","url":"https:\/\/www.comfyaicloud.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.comfyaicloud.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.comfyaicloud.com\/wp-content\/uploads\/2026\/02\/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png","contentUrl":"https:\/\/www.comfyaicloud.com\/wp-content\/uploads\/2026\/02\/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png","width":512,"height":512,"caption":"comfyaicloud.com"},"image":{"@id":"https:\/\/www.comfyaicloud.com\/#\/schema\/logo\/image\/"}}]}</script>
108
109	<!-- / Yoast SEO plugin. -->
110
111
112<link rel='dns-prefetch' href='//accounts.google.com' />
113<style id="ca-critical">
114.ambient-orb{position:absolute;border-radius:50%;filter:blur(80px);opacity:.45;
115             animation:orbFloat 18s ease-in-out infinite}
116.orb-1{width:55vw;height:55vw;background:radial-gradient(circle,rgba(201,106,0,.28),transparent 70%);
117       top:-10%;left:-8%;animation-duration:20s}
118.orb-2{width:50vw;height:50vw;background:radial-gradient(circle,rgba(10,124,114,.22),transparent 70%);
119       bottom:-8%;right:-6%;animation-duration:24s;animation-delay:-8s}
120.orb-3{width:40vw;height:40vw;background:radial-gradient(circle,rgba(124,58,237,.20),transparent 70%);
121       top:35%;left:38%;animation-duration:28s;animation-delay:-14s}
122@keyframes orbFloat{0%,100%{transform:translate(0,0) scale(1)}
123  33%{transform:translate(3%,4%) scale(1.04)}
124  66%{transform:translate(-3%,2%) scale(.97)}}
125</style>
126<style>[consent-id]:not(.rcb-content-blocker):not([consent-transaction-complete]):not([consent-visual-use-parent^="children:"]):not([consent-confirm]){opacity:0!important;}
127.rcb-content-blocker+.rcb-content-blocker-children-fallback~*{display:none!important;}</style><link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/759423483.js?ver=cfdeb40e786de82f627323f9550f905f" as="script" />
128<link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/310029799.js?ver=a461abd4da73b58a" as="script" />
129<link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/105151384.js?ver=3beded15e3161a384bd6fee18bc701ed" as="script" />
130<link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/1152005345.js?ver=d8d98fe4485b96b8" as="script" />
131<link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/1449571649.js?ver=0e07f769291f8010" as="script" />
132<link rel="preload" href="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/1825734372.js?ver=ad214e746d8dc6dc245f584439d27fff" as="script" />
133<script data-cfasync="false" id="real-cookie-banner-vendor-real-cookie-banner-banner-js" defer src="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/759423483.js?ver=cfdeb40e786de82f627323f9550f905f"></script>
vendor: 1 bytes, line 133
133
134<script type="application/json" data-skip-lazy-load="js-extra" data-skip-moving="true" data-no-defer nitro-exclude data-alt-type="application/ld+json" data-dont-merge data-wpmeteor-nooptimize="true" data-cfasync="false" id="ac9e0062d7262f1f111ce168d77613e681-js-extra">{"slug":"real-cookie-banner","textDomain":"real-cookie-banner","version":"5.3.0","restUrl":"https:\/\/www.comfyaicloud.com\/wp-json\/real-cookie-banner\/v1\/","restNamespace":"real-cookie-banner\/v1","restPathObfuscateOffset":"e9211e5f6388c232","restRoot":"https:\/\/www.comfyaicloud.com\/wp-json\/","restQuery":{"_v":"5.3.0","_locale":"user"},"restNonce":"6e91e8eb3f","restRecreateNonceEndpoint":"https:\/\/www.comfyaicloud.com\/wp-admin\/admin-ajax.php?action=rest-nonce","publicUrl":"https:\/\/www.comfyaicloud.com\/wp-content\/plugins\/real-cookie-banner\/public\/","chunkFolder":"dist","chunksLanguageFolder":"https:\/\/www.comfyaicloud.com\/wp-content\/plugins\/real-cookie-banner\/public\/languages\/json\/","chunks":{},"others":{"customizeValuesBanner":"{\"layout\":{\"type\":\"dialog\",\"maxHeightEnabled\":true,\"maxHeight\":740,\"dialogMaxWidth\":530,\"dialogPosition\":\"middleCenter\",\"dialogMargin\":[0,0,0,0],\"bannerPosition\":\"bottom\",\"bannerMaxWidth\":1024,\"dialogBorderRadius\":3,\"borderRadius\":5,\"animationIn\":\"slideInUp\",\"animationInDuration\":500,\"animationInOnlyMobile\":true,\"animationOut\":\"none\",\"animationOutDuration\":500,\"animationOutOnlyMobile\":true,\"overlay\":true,\"overlayBg\":\"#000000\",\"overlayBgAlpha\":50,\"overlayBlur\":2},\"decision\":{\"acceptAll\":\"button\",\"acceptEssentials\":\"button\",\"showCloseIcon\":false,\"acceptIndividual\":\"link\",\"buttonOrder\":\"all,essential,save,individual\",\"showGroups\":false,\"groupsFirstView\":false,\"saveButton\":\"always\"},\"design\":{\"bg\":\"#ffffff\",\"textAlign\":\"center\",\"linkTextDecoration\":\"underline\",\"borderWidth\":0,\"borderColor\":\"#ffffff\",\"fontSize\":13,\"fontColor\":\"#2b2b2b\",\"fontInheritFamily\":true,\"fontFamily\":\"Arial, Helvetica, sans-serif\",\"fontWeight\":\"normal\",\"boxShadowEnabled\":true,\"boxShadowOffsetX\":0,\"boxShadowOffsetY\":5,\"boxShadowBlurRadius\":13,\"boxShadowSpreadRadius\":0,\"boxShadowColor\":\"#000000\",\"boxShadowColorAlpha\":20},\"headerDesign\":{\"inheritBg\":true,\"bg\":\"#f4f4f4\",\"inheritTextAlign\":true,\"textAlign\":\"center\",\"padding\":[17,20,15,20],\"logo\":\"\",\"logoRetina\":\"\",\"logoMaxHeight\":40,\"logoPosition\":\"left\",\"logoMargin\":[5,15,5,15],\"fontSize\":20,\"fontColor\":\"#2b2b2b\",\"fontInheritFamily\":true,\"fontFamily\":\"Arial, Helvetica, sans-serif\",\"fontWeight\":\"normal\",\"borderWidth\":1,\"borderColor\":\"#efefef\"},\"bodyDesign\":{\"padding\":[15,20,5,20],\"descriptionInheritFontSize\":true,\"descriptionFontSize\":13,\"dottedGroupsInheritFontSize\":true,\"dottedGroupsFontSize\":13,\"dottedGroupsBulletColor\":\"#15779b\",\"teachingsInheritTextAlign\":true,\"teachingsTextAlign\":\"center\",\"teachingsSeparatorActive\":true,\"teachingsSeparatorWidth\":50,\"teachingsSeparatorHeight\":1,\"teachingsSeparatorColor\":\"#15779b\",\"teachingsInheritFontSize\":false,\"teachingsFontSize\":12,\"teachingsInheritFontColor\":false,\"teachingsFontColor\":\"#757575\",\"accordionMargin\":[10,0,5,0],\"accordionPadding\":[5,10,5,10],\"accordionArrowType\":\"outlined\",\"accordionArrowColor\":\"#15779b\",\"accordionBg\":\"#ffffff\",\"accordionActiveBg\":\"#f9f9f9\",\"accordionHoverBg\":\"#efefef\",\"accordionBorderWidth\":1,\"accordionBorderColor\":\"#efefef\",\"accordionTitleFontSize\":12,\"accordionTitleFontColor\":\"#2b2b2b\",\"accordionTitleFontWeight\":\"normal\",\"accordionDescriptionMargin\":[5,0,0,0],\"accordionDescriptionFontSize\":12,\"accordionDescriptionFontColor\":\"#757575\",\"accordionDescriptionFontWeight\":\"normal\",\"acceptAllOneRowLayout\":false,\"acceptAllPadding\":[10,10,10,10],\"acceptAllBg\":\"#15779b\",\"acceptAllTextAlign\":\"center\",\"acceptAllFontSize\":18,\"acceptAllFontColor\":\"#ffffff\",\"acceptAllFontWeight\":\"normal\",\"acceptAllBorderWidth\":0,\"acceptAllBorderColor\":\"#000000\",\"acceptAllHoverBg\":\"#11607d\",\"acceptAllHoverFontColor\":\"#ffffff\",\"acceptAllHoverBorderColor\":\"#000000\",\"acceptEssentialsUseAcceptAll\":true,\"acceptEssentialsButtonType\":\"\",\"acceptEssentialsPadding\":[10,10,10,10],\"acceptEssentialsBg\":\"#efefef\",\"acceptEssentialsTextAlign\":\"center\",\"acceptEssentialsFontSize\":18,\"acceptEssentialsFontColor\":\"#0a0a0a\",\"acceptEssentialsFontWeight\":\"normal\",\"acceptEssentialsBorderWidth\":0,\"acceptEssentialsBorderColor\":\"#000000\",\"acceptEssentialsHoverBg\":\"#e8e8e8\",\"acceptEssentialsHoverFontColor\":\"#000000\",\"acceptEssentialsHoverBorderColor\":\"#000000\",\"acceptIndividualPadding\":[5,5,5,5],\"acceptIndividualBg\":\"#ffffff\",\"acceptIndividualTextAlign\":\"center\",\"acceptIndividualFontSize\":16,\"acceptIndividualFontColor\":\"#15779b\",\"acceptIndividualFontWeight\":\"normal\",\"acceptIndividualBorderWidth\":0,\"acceptIndividualBorderColor\":\"#000000\",\"acceptIndividualHoverBg\":\"#ffffff\",\"acceptIndividualHoverFontColor\":\"#11607d\",\"acceptIndividualHoverBorderColor\":\"#000000\"},\"footerDesign\":{\"poweredByLink\":true,\"inheritBg\":false,\"bg\":\"#fcfcfc\",\"inheritTextAlign\":true,\"textAlign\":\"center\",\"padding\":[10,20,15,20],\"fontSize\":14,\"fontColor\":\"#757474\",\"fontInheritFamily\":true,\"fontFamily\":\"Arial, Helvetica, sans-serif\",\"fontWeight\":\"normal\",\"hoverFontColor\":\"#2b2b2b\",\"borderWidth\":1,\"borderColor\":\"#efefef\",\"languageSwitcher\":\"flags\"},\"texts\":{\"headline\":\"Privacy preferences\",\"description\":\"We use cookies and similar technologies on our website and process your personal data (e.g. IP address), for example, to personalize content and ads, to integrate media from third-party providers or to analyze traffic on our website. Data processing may al
134so happen as a result of cookies being set. We share this data with third parties that we name in the privacy settings.<br \\\/><br \\\/>The data processing may take place with your consent or on the basis of a legitimate interest, which you can object to in the privacy settings. You have the right not to consent and to change or revoke your consent at a later time. This revocation takes effect immediately but does not affect data already processed. For more information on the use of your data, please visit our {{privacyPolicy}}privacy policy{{\\\/privacyPolicy}}.\",\"acceptAll\":\"Accept all\",\"acceptEssentials\":\"Continue without consent\",\"acceptIndividual\":\"Set privacy settings individually\",\"poweredBy\":\"1\",\"dataProcessingInUnsafeCountries\":\"Some services process personal data in unsafe third countries. By consenting, you also consent to data processing of labeled services per {{legalBasis}}, with risks like inadequate legal remedies, unauthorized access by authorities without information or possibility of objection, unauthorised transfer to third parties, and inadequate data security measures.\",\"ageNoticeBanner\":\"You are under {{minAge}} years old? Then you cannot consent to optional services. Ask your parents or legal guardians to agree to these services with you.\",\"ageNoticeBlocker\":\"You are under {{minAge}} years old? Unfortunately, you are not permitted to consent to this service to view this content. Please ask your parents or guardians to agree to the service with you!\",\"listServicesNotice\":\"By accepting all services, you allow {{services}} to be loaded. These services are divided into groups {{serviceGroups}} according to their purpose (belonging marked with superscript numbers).\",\"listServicesLegitimateInterestNotice\":\"In addition, {{services}} are loaded based on a legitimate interest.\",\"consentForwardingExternalHosts\":\"Your consent is also applicable on {{websites}}.\",\"blockerHeadline\":\"{{name}} blocked due to privacy settings\",\"blockerLinkShowMissing\":\"Show all services you still need to agree to\",\"blockerLoadButton\":\"Accept services and load content\",\"blockerAcceptInfo\":\"Loading the blocked content will adjust your privacy settings. Content from this service will not be blocked in the future.\",\"stickyHistory\":\"Privacy settings history\",\"stickyRevoke\":\"Revoke consents\",\"stickyRevokeSuccessMessage\":\"You have successfully revoked consent for services with its cookies and personal data processing. The page will be reloaded now!\",\"stickyChange\":\"Change privacy settings\"},\"individualLayout\":{\"inheritDialogMaxWidth\":false,\"dialogMaxWidth\":970,\"inheritBannerMaxWidth\":true,\"bannerMaxWidth\":1980,\"descriptionTextAlign\":\"left\"},\"group\":{\"checkboxBg\":\"#f0f0f0\",\"checkboxBorderWidth\":1,\"checkboxBorderColor\":\"#d2d2d2\",\"checkboxActiveColor\":\"#ffffff\",\"checkboxActiveBg\":\"#15779b\",\"checkboxActiveBorderColor\":\"#11607d\",\"groupInheritBg\":true,\"groupBg\":\"#f4f4f4\",\"groupPadding\":[15,15,15,15],\"groupSpacing\":10,\"groupBorderRadius\":5,\"groupBorderWidth\":1,\"groupBorderColor\":\"#f4f4f4\",\"headlineFontSize\":16,\"headlineFontWeight\":\"normal\",\"headlineFontColor\":\"#2b2b2b\",\"descriptionFontSize\":14,\"descriptionFontColor\":\"#757575\",\"linkColor\":\"#757575\",\"linkHoverColor\":\"#2b2b2b\",\"detailsHideLessRelevant\":true},\"saveButton\":{\"useAcceptAll\":true,\"type\":\"button\",\"padding\":[10,10,10,10],\"bg\":\"#efefef\",\"textAlign\":\"center\",\"fontSize\":18,\"fontColor\":\"#0a0a0a\",\"fontWeight\":\"normal\",\"borderWidth\":0,\"borderColor\":\"#000000\",\"hoverBg\":\"#e8e8e8\",\"hoverFontColor\":\"#000000\",\"hoverBorderColor\":\"#000000\"},\"individualTexts\":{\"headline\":\"Individual privacy preferences\",\"description\":\"We use cookies and similar technologies on our website and process your personal data (e.g. IP address), for example, to personalize content and ads, to integrate media from third-party providers or to analyze traffic on our website. Data processing may al
134so happen as a result of cookies being set. We share this data with third parties that we name in the privacy settings.<br \\\/><br \\\/>The data processing may take place with your consent or on the basis of a legitimate interest, which you can object to in the privacy settings. You have the right not to consent and to change or revoke your consent at a later time. This revocation takes effect immediately but does not affect data already processed. For more information on the use of your data, please visit our {{privacyPolicy}}privacy policy{{\\\/privacyPolicy}}.<br \\\/><br \\\/>Below you will find an overview of all services used by this website. You can view detailed information about each service and agree to them individually or exercise your right to object.\",\"save\":\"Save custom choices\",\"showMore\":\"Show service information\",\"hideMore\":\"Hide service information\",\"postamble\":\"\"},\"mobile\":{\"enabled\":true,\"maxHeight\":400,\"hideHeader\":false,\"alignment\":\"bottom\",\"scalePercent\":90,\"scalePercentVertical\":-50},\"sticky\":{\"enabled\":false,\"animationsEnabled\":true,\"alignment\":\"left\",\"bubbleBorderRadius\":50,\"icon\":\"fingerprint\",\"iconCustom\":\"\",\"iconCustomRetina\":\"\",\"iconSize\":30,\"iconColor\":\"#ffffff\",\"bubbleMargin\":[10,20,20,20],\"bubblePadding\":15,\"bubbleBg\":\"#15779b\",\"bubbleBorderWidth\":0,\"bubbleBorderColor\":\"#10556f\",\"boxShadowEnabled\":true,\"boxShadowOffsetX\":0,\"boxShadowOffsetY\":2,\"boxShadowBlurRadius\":5,\"boxShadowSpreadRadius\":1,\"boxShadowColor\":\"#105b77\",\"boxShadowColorAlpha\":40,\"bubbleHoverBg\":\"#ffffff\",\"bubbleHoverBorderColor\":\"#000000\",\"hoverIconColor\":\"#000000\",\"hoverIconCustom\":\"\",\"hoverIconCustomRetina\":\"\",\"menuFontSize\":16,\"menuBorderRadius\":5,\"menuItemSpacing\":10,\"menuItemPadding\":[5,10,5,10]},\"customCss\":{\"css\":\"\",\"antiAdBlocker\":\"y\"}}","animateCss":":root{--animate-duration:1s;--animate-delay:1s;--animate-repeat:1}.animate__animated{animation-duration:var(--animate-duration);animation-fill-mode:both}@media (prefers-reduced-motion:reduce){.animate__animated{animation-duration:1ms!important;transition-duration:1ms!important;animation-iteration-count:1!important}.animate__animated[class*=Out]{opacity:0}}@keyframes slideInUp{from{transform:translate3d(0,100%,0);visibility:visible;}to{transform:translate3d(0,0,0);}}.animate__slideInUp{animation-name:slideInUp;}","isPro":false,"showProHints":false,"proUrl":"https:\/\/devowl.io\/go\/real-cookie-banner?source=rcb-lite","showLiteNotice":true,"frontend":{"groups":"[{\"id\":84,\"name\":\"Essential\",\"slug\":\"essential\",\"description\":\"Essential services are required for the basic functionality of the website. They only contain technically necessary services. These services cannot be objected to.\",\"isEssential\":true,\"isDefault\":true,\"items\":[{\"id\":4666,\"name\":\"Real Cookie Banner\",\"purpose\":\"Real Cookie Banner asks website visitors for consent to set cookies and process personal data. For this purpose, a UUID (pseudonymous identification of the user) is assigned to each website visitor, which is valid until the cookie expires to store the consent. Cookies are used to test whether cookies can be set, to store reference to documented consent, to store which services from which service groups the visitor has consented to, and, if consent is obtained under the Transparency & Consent Framework (TCF), to store consent in TCF partners, purposes, special purposes, features and special features. As part of the obligation to disclose according to GDPR, the collected consent is fully documented. This includes, in addition to the services and service groups to which the visitor has consented, and if consent is obtained according to the TCF standard, to which TCF partners, purposes and features the visitor has consented, all cookie banner settings at the time of consent as well as the technical circumstances (e.g. size of the displayed area at the time of consent) and the user interactions (e.g. clicking on buttons) that led to consent. Consent is collected once per language.\",\"providerContact\":{\"phone\":\"\",\"email\":\"\",\"link\":\"\"},\"isProviderCurrentWebsite\":true,\"provider\":\"\",\"uniqueName\":\"\",\"isEmbeddingOnlyExternalResources\":false,\"legalBasis\":\"legal-requirement\",\"dataProcessingInCountries\":[],\"dataProcessingInCountriesSpecialTreatments\":[],\"technicalDefinitions\":[{\"type\":\"http\",\"name\":\"real_cookie_banner*\",\"host\":\".comfyaicloud.com\",\"duration\":365,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Unique identifier for the consent, but not for the website visitor. Revision hash for settings of cookie banner (texts, colors, features, service groups, services, content blockers etc.). IDs for consented services and service groups.\"},{\"type\":\"http\",\"name\":\"real_cookie_banner*-tcf\",\"host\":\".comfyaicloud.com\",\"duration\":365,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Consents collected under TCF stored in TC String format, including TCF vendors, purposes, special purposes, features, and special features.\"},{\"type\":\"http\",\"name\":\"real_cookie_banner*-gcm\",\"host\":\".comfyaicloud.com\",\"duration\":365,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Consents into consent types (purposes)  collected under Google Consent Mode stored for all Google Consent Mode compatible services.\"},{\"type\":\"http\",\"name\":\"real_cookie_banner-test\",\"host\":\".comfyaicloud.com\",\"duration\":365,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Cookie set to test HTTP cookie functionality. Deleted immediately after test.\"},{\"type\":\"local\",\"name\":\"real_cookie_banner*\",\"host\":\"https:\\\/\\\/www.comfyaicloud.com\",\"duration\":1,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Unique identifier for the consent, but not for the website visitor. Revision hash for settings of cookie banner (texts, colors, features, service groups, services, content blockers etc.). IDs for consented services and service groups. Is only stored until consent is documented on the website server.\"},{\"type\":\"local\",\"name\":\"real_cookie_banner*-tcf\",\"host\":\"https:\\\/\\\/www.comfyaicloud.com\",\"duration\":1,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Consents collected under TCF stored in TC String format, including TCF vendors, purposes, special purposes, features, and special features. Is only stored until consent is documented on the website server.\"},{\"type\":\"local\",\"name\":\"real_cookie_banner*-gcm\",\"host\":\"https:\\\/\\\/www.comfyaicloud.com\",\"duration\":1,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Consents collected under Google Consent Mode stored in consent types (purposes) for all Google Consent Mode compatible services. Is only stored until consent is documented on the website server.\"},{\"type\":\"local\",\"name\":\"real_cookie_banner-consent-queue*\",\"host\":\"https:\\\/\\\/www.comfyaicloud.com\",\"duration\":1,\"durationUnit\":\"d\",\"isSessionDuration\":false,\"purpose\":\"Local caching of selection in cookie banner until server documents consent; documentation periodic or at page switches attempted if server is unavailable or overloaded.\"}],\"codeDynamics\":[],\"providerPrivacyPolicyUrl\":\"\",\"providerLegalNoticeUrl\":\"\",\"tagManagerOptInEventName\":\"\",\"tagManagerOptOutEventName\":\"\",\"googleConsentModeConsentTypes\":[],\"executePriority\":10,\"codeOptIn\":\"\",\"executeCodeOptInWhenNoTagManagerConsentIsGiven\":false,\"codeOptOut\":\"\",\"executeCodeOptOutWhenNoTagManagerConsentIsGiven\":false,\"deleteTechnicalDefinitionsAfterOptOut\":false,\"codeOnPageLoad\":\"\",\"presetId\":\"real-cookie-banner\"}]}]","links":[{"id":4665,"label":"Privacy policy","pageType":"privacyPolicy","isExternalUrl":false,"pageId":3,"url":"https:\/\/www.comfyaicloud.com\/privacy-policy\/","hideCookieBanner":true,"isTargetBlank":true}],"websiteOperator":{"address":"ComfyAI Cloud","country":"US","contactEmail":"base64-encoded:Y29tZnlhaWNsb3VkQGdtYWlsLmNvbQ==","contactPhone":"06703004989","contactFormUrl":"https:\/\/www.comfyaicloud.com\/terms\/"},"blocker":[],"languageSwitcher":[],"predefinedDataProcessingInSafeCountriesLists":{"GDPR":["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IS","IT","LI","LV","LT","LU","MT","NL","NO","PL","PT","RO","SK","SI","ES","SE"],"DSG":["CH"],"GDPR+DSG":[],"ADEQUACY_EU":["AD","AR","CA","FO","GG","IL","IM","JP","JE","NZ","KR","CH","GB","UY","US"],"ADEQUACY_CH":["DE","AD","AR","AT","BE","BG","CA","CY","HR","DK","ES","EE","FI","FR","GI","GR","GG","HU","IM","FO","IE","IS","IL","IT","JE","LV","LI","LT","LU","MT","MC","NO","NZ","NL","PL","PT","CZ","RO","GB","SK","SI","SE","UY","US"]},"decisionCookieName":"real_cookie_banner-v:3_blog:1_path:83b756c","revisionH
134ash":"e72015600206c17dff4495bb1a829242","territorialLegalBasis":["gdpr-eprivacy"],"setCookiesViaManager":"none","isRespectDoNotTrack":false,"failedConsentDocumentationHandling":"essentials","isAcceptAllForBots":true,"isDataProcessingInUnsafeCountries":false,"isAgeNotice":true,"ageNoticeAgeLimit":16,"isListServicesNotice":true,"isBannerLessConsent":false,"isTcf":false,"isGcm":false,"isGcmListPurposes":false,"hasLazyData":false},"anonymousContentUrl":"https:\/\/www.comfyaicloud.com\/wp-content\/d38d8888893f702ea2b35cf6df393b10\/dist\/","anonymousHash":"d38d8888893f702ea2b35cf6df393b10","hasDynamicPreDecisions":false,"isLicensed":true,"isDevLicense":false,"multilingualSkipHTMLForTag":"","isCurrentlyInTranslationEditorPreview":false,"defaultLanguage":"","currentLanguage":"","activeLanguages":[],"context":"","iso3166OneAlpha2":{"AF":"Afghanistan","AX":"Aland Islands","AL":"Albania","DZ":"Algeria","AS":"American Samoa","AD":"Andorra","AO":"Angola","AI":"Anguilla","AQ":"Antarctica","AG":"Antigua And Barbuda","AR":"Argentina","AM":"Armenia","AW":"Aruba","AU":"Australia","AT":"Austria","AZ":"Azerbaijan","BS":"Bahamas","BH":"Bahrain","BD":"Bangladesh","BB":"Barbados","BY":"Belarus","BE":"Belgium","BZ":"Belize","BJ":"Benin","BM":"Bermuda","BT":"Bhutan","BO":"Bolivia","BA":"Bosnia And Herzegovina","BW":"Botswana","BV":"Bouvet Island","BR":"Brazil","IO":"British Indian Ocean Territory","BN":"Brunei Darussalam","BG":"Bulgaria","BF":"Burkina Faso","BI":"Burundi","KH":"Cambodia","CM":"Cameroon","CA":"Canada","CV":"Cape Verde","BQ":"Caribbean Netherlands","KY":"Cayman Islands","CF":"Central African Republic","TD":"Chad","CL":"Chile","CN":"China","CX":"Christmas Island","CC":"Cocos (Keeling) Islands","CO":"Colombia","KM":"Comoros","CG":"Congo","CD":"Congo, Democratic Republic","CK":"Cook Islands","CR":"Costa Rica","CI":"Cote D'Ivoire","HR":"Croatia","CU":"Cuba","CW":"Cura\u00e7ao","CY":"Cyprus","CZ":"Czech Republic","DK":"Denmark","DJ":"Djibouti","DM":"Dominica","DO":"Dominican Republic","EC":"Ecuador","EG":"Egypt","SV":"El Salvador","GQ":"Equatorial Guinea","ER":"Eritrea","EE":"Estonia","ET":"Ethiopia","FK":"Falkland Islands (Malvinas)","FO":"Faroe Islands","FM":"Federated States Of Micronesia","FJ":"Fiji","FI":"Finland","FR":"France","GF":"French Guiana","PF":"French Polynesia","TF":"French Southern and Antarctic Lands","GA":"Gabon","GM":"Gambia","GE":"Georgia","DE":"Germany","GH":"Ghana","GI":"Gibraltar","GR":"Greece","GL":"Greenland","GD":"Grenada","GP":"Guadeloupe","GU":"Guam","GT":"Guatemala","GG":"Guernsey","GN":"Guinea","GW":"Guinea-Bissau","GY":"Guyana","HT":"Haiti","HM":"Heard Island & Mcdonald Islands","VA":"Holy See (Vatican City State)","HN":"Honduras","HK":"Hong Kong","HU":"Hungary","IS":"Iceland","IN":"India","ID":"Indonesia","IR":"Iran, Islamic Republic Of","IQ":"Iraq","IE":"Ireland","IM":"Isle Of Man","IL":"Israel","IT":"Italy","JM":"Jamaica","JP":"Japan","JE":"Jersey","JO":"Jordan","KZ":"Kazakhstan","KE":"Kenya","KI":"Kiribati","KR":"Korea","XK":"Kosovo","KW":"Kuwait","KG":"Kyrgyzstan","LA":"Lao People's Democratic Republic","LV":"Latvia","LB":"Lebanon","LS":"Lesotho","LR":"Liberia","LY":"Libyan Arab Jamahiriya","LI":"Liechtenstein","LT":"Lithuania","LU":"Luxembourg","MO":"Macao","MK":"Macedonia","MG":"Madagascar","MW":"Malawi","MY":"Malaysia","MV":"Maldives","ML":"Mali","MT":"Malta","MH":"Marshall Islands","MQ":"Martinique","MR":"Mauritania","MU":"Mauritius","YT":"Mayotte","MX":"Mexico","MD":"Moldova","MC":"Monaco","MN":"Mongolia","ME":"Montenegro","MS":"Montserrat","MA":"Morocco","MZ":"Mozambique","MM":"Myanmar","NA":"Namibia","NR":"Nauru","NP":"Nepal","NL":"Netherlands","AN":"Netherlands Antilles","NC":"New Caledonia","NZ":"New Zealand","NI":"Nicaragua","NE":"Niger","NG":"Nigeria","NU":"Niue","NF":"Norfolk Island","KP":"North Korea","MP":"Northern Mariana Islands","NO":"Norway","OM":"Oman","PK":"Pakistan","PW":"Palau","PS":"Palestinian Territory, Occupied","PA":"Panama","PG":"Papua New Guinea","PY":"Paraguay","PE":"Peru","PH":"Philippines","PN":"Pitcairn","PL":"Poland","PT":"Portugal","PR":"Puerto Rico","QA":"Qatar","RE":"Reunion","RO":"Romania","RU":"Russian Federation","RW":"Rwanda","BL":"Saint Barthelemy","SH":"Saint Helena","KN":"Saint Kitts And Nevis","LC":"Saint Lucia","MF":"Saint Martin","PM":"Saint Pierre And Miquelon","VC":"Saint Vincent And Grenadines","WS":"Samoa","SM":"San Marino","ST":"Sao Tome And Principe","SA":"Saudi Arabia","SN":"Senegal","RS":"Serbia","SC":"Seychelles","SL":"Sierra Leone","SG":"Singapore","SX":"Sint Maarten","SK":"Slovakia","SI":"Slovenia","SB":"Solomon Islands","SO":"Somalia","ZA":"South Africa","GS":"South Georgia And Sandwich Isl.","SS":"South Sudan","ES":"Spain","LK":"Sri Lanka","SD":"Sudan","SR":"Suriname","SJ":"Svalbard And Jan Mayen","SZ":"Swaziland","SE":"Sweden","CH":"Switzerland","SY":"Syrian Arab Republic","TW":"Taiwan","TJ":"Tajikistan","TZ":"Tanzania","TH":"Thailand","TL":"Timor-Leste","TG":"Togo","TK":"Tokelau","TO":"Tonga","TT":"Trinidad And Tobago","TN":"Tunisia","TR":"Turkey","TM":"Turkmenistan","TC":"Turks And Caicos Islands","TV":"Tuvalu","UG":"Uganda","UA":"Ukraine","AE":"United Arab Emirates","GB":"United Kingdom","US":"United States","UM":"United States Outlying Islands","UY":"Uruguay","UZ":"Uzbekistan","VU":"Vanuatu","VE":"Venezuela","VN":"Vietnam","VG":"Virgin Islands, British","VI":"Virgin Islands, U.S.","WF":"Wallis And Futuna","EH":"Western Sahara","YE":"Yemen","ZM":"Zambia","ZW":"Zimbabwe"},"visualParentSelectors":{".et_pb_video_box":1,".et_pb_video_slider:has(>.et_pb_slider_carousel %s)":"self",".ast-oembed-container":1,".wpb_video_wrapper":1,".gdlr-core-pbf-background-wrap":1},"isPreventPreDecision":false,"isInvalidateImplicitUserConsent":false,"dependantVisibilityContainers":["[role=\"tabpanel\"]",".eael-tab-content-item",".wpcs_content_inner",".op3-contenttoggleitem-content",".op3-popoverlay-content",".pum-overlay","[data-elementor-type=\"popup\"]",".wp-block-ub-content-toggle-accordion-content-wrap",".w-popup-wrap",".oxy-lightbox_inner[data-inner-content=true]",".oxy-pro-accordion_body",".oxy-tab-content",".kt-accordion-panel",".vc_tta-panel-body",".mfp-hide","div[id^=\"tve_thrive_lightbox_\"]",".brxe-xpromodalnestable",".evcal_eventcard",".divioverlay",".et_pb_toggle_content"],"disableDeduplicateE
134xceptions":[".et_pb_video_slider"],"bannerDesignVersion":12,"bannerI18n":{"showMore":"Show more","hideMore":"Hide","showLessRelevantDetails":"Show more details (%s)","hideLessRelevantDetails":"Hide more details (%s)","other":"Other","legalBasis":{"label":"Use on legal basis of","consentPersonalData":"Consent for processing personal data","consentStorage":"Consent for storing or accessing information on the terminal equipment of the user","legitimateInterestPersonalData":"Legitimate interest for the processing of personal data","legitimateInterestStorage":"Provision of explicitly requested digital service for storing or accessing information on the terminal equipment of the user","legalRequirementPersonalData":"Compliance with a legal obligation for processing of personal data"},"territorialLegalBasisArticles":{"gdpr-eprivacy":{"dataProcessingInUnsafeCountries":"Art. 49 (1) (a) GDPR"},"dsg-switzerland":{"dataProcessingInUnsafeCountries":"Art. 17 (1) (a) DSG (Switzerland)"}},"legitimateInterest":"Legitimate interest","consent":"Consent","crawlerLinkAlert":"We have recognized that you are a crawler\/bot. Only natural persons must consent to cookies and processing of personal data. Therefore, the link has no function for you.","technicalCookieDefinitions":"Technical cookie definitions","technicalCookieName":"Technical cookie name","usesCookies":"Uses cookies","cookieRefresh":"Cookie refresh","usesNonCookieAccess":"Uses cookie-like information (LocalStorage, SessionStorage, IndexDB, etc.)","host":"Host","duration":"Duration","noExpiration":"No expiration","type":"Type","purpose":"Purpose","purposes":"Purposes","description":"Description","optOut":"Opt-out","optOutDesc":"Cookie can be set to store opt-out of the described behaviour.","headerTitlePrivacyPolicyHistory":"History of your privacy settings","skipToConsentChoices":"Skip to consent choices","historyLabel":"Show consent from","historyItemLoadError":"Reading the consent has failed. Please try again later!","historySelectNone":"Not yet consented to","provider":"Provider","providerContactPhone":"Phone","providerContactEmail":"Email","providerContactLink":"Contact form","providerPrivacyPolicyUrl":"Privacy Policy","providerLegalNoticeUrl":"Legal notice","nonStandard":"Non-standardized data processing","nonStandardDesc":"Some services set cookies and\/or process personal data without complying with consent communication standards. These services are divided into several groups. So-called \"essential services\" are used based on legitimate interest and cannot be opted out (an objection may have to be made by email or letter in accordance with the privacy policy), while all other services are used only after consent has been given.","dataProcessingInThirdCountries":"Data processing in third countries","safetyMechanisms":{"label":"Safety mechanisms for data transmission","standardContractualClauses":"Standard contractual clauses","adequacyDecision":"Adequacy decision","eu":"EU","switzerland":"Switzerland","bindingCorporateRules":"Binding corporate rules","contractualGuaranteeSccSubprocessors":"Contractual guarantee for standard contractual clauses with sub-processors"},"durationUnit":{"n1":{"s":"second","m":"minute","h":"hour","d":"day","mo":"month","y":"year"},"nx":{"s":"seconds","m":"minutes","h":"hours","d":"days","mo":"months","y":"years"}},"close":"Close","closeWithoutSaving":"Close without saving","yes":"Yes","no":"No","unknown":"Unknown","none":"None","noLicense":"No license activated - not for production use!","devLicense":"Product license not for production use!","devLicenseLearnMore":"Learn more","devLicenseLink":"https:\/\/devowl.io\/knowledge-base\/license-installation-type\/","andSeparator":" and ","deprecated":{"appropriateSafeguard":"Appropriate safeguard","dataProcessingInUnsafeCountries":"Data processing in unsafe third countries","legalRequirement":"Compliance with a legal obligation"}},"pageRequestUuid4":"a358e58e8-b93d-4903-90e2-82ec9fa288ee","pageByIdUrl":"https:\/\/www.comfyaicloud.com?page_id","pluginUrl":"https:\/\/devowl.io\/wordpress-real-cookie-banner\/"}}</script>
134<script data-skip-lazy-load="js-extra" data-skip-moving="true" data-no-defer nitro-exclude data-alt-type="application/ld+json" data-dont-merge data-wpmeteor-nooptimize="true" data-cfasync="false" id="ac9e0062d7262f1f111ce168d77613e682-js-extra">
135(()=>{var x=function (a,b){return-1<["codeOptIn","codeOptOut","codeOnPageLoad","contactEmail"].indexOf(a)&&"string"==typeof b&&b.startsWith("base64-encoded:")?window.atob(b.substr(15)):b},t=(e,t)=>new Proxy(e,{get:(e,n)=>{let r=Reflect.get(e,n);return n===t&&"string"==typeof r&&(r=JSON.parse(r,x),Reflect.set(e,n,r)),r}}),n=JSON.parse(document.getElementById("ac9e0062d7262f1f111ce168d77613e681-js-extra").innerHTML,x);window.Proxy?n.others.frontend=t(n.others.frontend,"groups"):n.others.frontend.groups=JSON.parse(n.others.frontend.groups,x);window.Proxy?n.others=t(n.others,"customizeValuesBanner"):n.others.customizeValuesBanner=JSON.parse(n.others.customizeValuesBanner,x);;window.realCookieBanner=n;window[Math.random().toString(36)]=n;
136})();
137</script>
137<script data-cfasync="false" id="real-cookie-banner-banner-js-before">
138((a,b)=>{a[b]||(a[b]={unblockSync:()=>undefined},["consentSync"].forEach(c=>a[b][c]=()=>({cookie:null,consentGiven:!1,cookieOptIn:!0})),["consent","consentAll","unblock"].forEach(c=>a[b][c]=(...d)=>new Promise(e=>a.addEventListener(b,()=>{a[b][c](...d).then(e)},{once:!0}))))})(window,"consentApi");
139//# sourceURL=real-cookie-banner-banner-js-before
140</script>
vendor: 1 bytes, line 140
140
141<script data-cfasync="false" id="real-cookie-banner-banner-js" defer src="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/105151384.js?ver=3beded15e3161a384bd6fee18bc701ed"></script>
141
142<style id="wp-img-auto-sizes-contain-inline-css">
143img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
144/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
145</style>
146
147<style id="global-styles-inline-css">
148:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);
148--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}:where(body) { margin: 0; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #32373c;border-width: 0;color: #fff;font-family: inherit;font-size: inherit;font-style: inherit;font-weight: inherit;letter-spacing: inherit;line-height: inherit;padding-top: calc(0.667em + 2px);padding-right: calc(1.333em + 2px);padding-bottom: calc(0.667em + 2px);padding-left: calc(1.333em + 2px);text-decoration: none;text-transform: inherit;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}
148.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
149/*# sourceURL=global-styles-inline-css */
150</style>
151
152<link rel='stylesheet' id='uag-style-3582-css' href='https://www.comfyaicloud.com/wp-content/uploads/uag-plugin/assets/4000/uag-css-3582.css?ver=69.9.10' media='all' />
153<script id="burst-timeme-js" async src="https://www.comfyaicloud.com/wp-content/plugins/burst-statistics/assets/js/timeme/timeme.min.js?ver=1790141310"></script>
153
154<link rel="https://api.w.org/" href="https://www.comfyaicloud.com/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://www.comfyaicloud.com/wp-json/wp/v2/pages/3582" />		
154<script type="text/javascript">
155			(function(c, l, a, r, i, t, y) {
156				c[a] = c[a] || function() {
157					(c[a].q = c[a].q || []).push(arguments)
158				};
159				t = l.createElement(r);
160				t.async = 1;
161				t.src = "https://www.clarity.ms/tag/" + i + "?ref=wordpress";
162				y = l.getElementsByTagName(r)[0];
163				y.parentNode.insertBefore(t, y);
164			})(window, document, "clarity", "script", "xdil04onpv");
165		</script>
165
166	<link rel="describedby" href="https://www.comfyaicloud.com/llms.txt" />
167<link rel="icon" href="https://www.comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040-32x32.png" sizes="32x32" />
168<link rel="icon" href="https://www.comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040-192x192.png" sizes="192x192" />
169<link rel="apple-touch-icon" href="https://www.comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040-180x180.png" />
170<meta name="msapplication-TileImage" content="https://www.comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040-270x270.png" />
171
172<!-- ── CRITICAL CSS v50: Truly critical — nav, hero, body, view system only.
173     All utility classes are in app.css (cached). Minimal = fastest FCP. ── -->
174<style>
175:root{--bg:#faf8f4;--ca-bg-custom:#faf8f4}
176/* ── Reset + Body: correct background before any stylesheet ── */
177*,*::before,*::after{box-sizing:border-box}
178html{
179  margin-top:0!important;
180  -webkit-text-size-adjust:100%;
181  height:auto!important;
182  min-height:100%;
183  overflow-x:hidden!important;
184  overflow-y:auto!important;
185  overscroll-behavior-y:auto!important;
186  touch-action:auto!important;
187}
188body{
189  font-family: var(--font-primary);
190  background:#faf8f4;color:#1c1917;
191  margin:0;padding:0;
192  -webkit-font-smoothing:antialiased;
193  height:auto!important;
194  min-height:100svh;
195  overflow-x:hidden!important;
196  overflow-y:auto!important;
197  overscroll-behavior-y:auto!important;
198  touch-action:auto!important;
199  contain:none!important;
200  content-visibility:visible!important;
201}
202/* Fallback font-size scale: system-ui is slightly larger than Inter.
203   size-adjust compensates so layout stays identical when swapping */
204
205
206/* ── Skeleton & Stability: Prevent shifts and fix 'broken UI' on load ── */
207@keyframes ca-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}
208.ca-skeleton{
209  background: linear-gradient(90deg, rgba(255,255,255,0.03) 25%, rgba(255,255,255,0.08) 50%, rgba(255,255,255,0.03) 75%);
210  background-size: 200% 100%;
211  animation: ca-shimmer 2s infinite linear;
212  border-radius: 12px;
213  color: transparent !important;
214}
215.ca-skeleton *{visibility: hidden !important;}
216
217/* Pre-size Lucide icons to prevent layout pop */
218[data-lucide]{width:1em;height:1em;display:inline-block;vertical-align:middle;flex-shrink:0;}
219.w-3{width:12px}.h-3{height:12px}.w-3\.5{width:14px}.h-3\.5{height:14px}
220.w-4{width:16px}.h-4{height:16px}.w-5{width:20px}.h-5{height:20px}
221.w-6{width:24px}.h-6{height:24px}.w-8{width:32px}.h-8{height:32px}
222.w-10{width:40px}.h-10{height:40px}.w-12{width:48px}.h-12{height:48px}
223
224/* Page entry animation: keep content visible even if a script fails. */
225.ca-body{opacity:1!important;transition:opacity 0.5s ease-out;contain:none!important;content-visibility:visible!important;}
226.ca-body.ca-ready{opacity:1!important;}
227body[class*="ca-anim-"],
228body[class*="pulse"],
229body[class*="glow"],
230body[class*="shimmer"] {
231  contain: none !important;
232  content-visibility: visible !important;
233}
234
235/* ── Admin bar: never show ── */
236#wpadminbar,#adminbar{display:none!important;height:0!important}
237body.admin-bar{margin-top:0!important;padding-top:0!important}
238
239/* ── Nav: positioned immediately — not waiting for app.css ──
240   CRITICAL: position:fixed must be inline, not in deferred stylesheet.
241   This is the fix for broken-header-on-load. ── */
242.ca-nav-mobile{
243  display:flex;position:fixed;
244  top:0;left:0;right:0;z-index:60;
245  padding-top:env(safe-area-inset-top);
246}
247/* Desktop-only: keeps action buttons docked to the right of the image */
248@media (min-width: 768px) {
249  #single-result-container .gen-result-wrapper {
250    display: flex !important;
251    flex-direction: row !important;
252    align-items: flex-end !important;
253    justify-content: center !important;
254    gap: 12px !important;
255    flex-wrap: nowrap !important;
256    margin-left: auto !important;
257    margin-right: auto !important;
258  }
259  #single-result-container .gen-result-wrapper .gen-atomic-wrap {
260    flex-shrink: 1 !important;
261    width: auto !important;
262  }
263  #single-result-container .gen-result-wrapper .gen-floating-actions {
264    display: flex !important;
265    flex-direction: column !important;
266    gap: 8px !important;
267    flex-shrink: 0 !important;
268    margin-bottom: 4px !important;
269    width: 44px !important;
270  }
271}
272.ca-nav-desktop{
273  display:none;position:fixed;
274  top:0;left:0;right:0;z-index:50;
275  pointer-events:none;
276  padding-top:env(safe-area-inset-top);
277}
278@media(min-width:768px){
279  .ca-nav-desktop{display:flex}
280  .ca-nav-mobile{display:none}
281}
282/* Hide main pill nav on home — replaced by .home-stitch-header */
283html.home-page .ca-nav-desktop,
284html.home-page .ca-nav-mobile,
285body.home-page .ca-nav-desktop,
286body.home-page .ca-nav-mobile,
287body.home .ca-nav-desktop,
288body.home .ca-nav-mobile{display:none!important;visibility:hidden!important;pointer-events:none!important}
289.glass-nav{
290  display:flex;align-items:center;
291  pointer-events:auto;
292  background:rgba(255,255,255,0.88);
293  backdrop-filter:blur(32px) saturate(1.8);
294  -webkit-backdrop-filter:blur(32px) saturate(1.8);
295  border-bottom:1px solid rgba(0,0,0,0.06);
296}
297
298/* ── Hero h1 LCP: gradient text visible before app.css loads ── */
299#view-home h1{
300  font-size:clamp(2.6rem,8vw,5.5rem);
301  font-weight:800;letter-spacing:-0.05em;line-height:1;
302  background:linear-gradient(180deg,#fff 0%,rgba(255,255,255,.5) 100%);
303  -webkit-background-clip:text;background-clip:text;color:transparent;
304  margin:0;
305}
306
307/* ── View system: sections hidden until .active ── */
308.view-section{
309  position:absolute;inset:0;opacity:0;visibility:hidden;
310  pointer-events:none;overflow-y:auto;background:transparent;
311  transition:opacity .5s ease,transform .5s ease,visibility 0s .5s;
312  transform:translateY(16px) scale(.99);
313}
314.view-section.active{
315  opacity:1;visibility:visible;pointer-events:auto;
316  transform:translateY(0) scale(1);
317  transition:opacity .5s ease,transform .5s ease,visibility 0s;
318  overflow-y:auto!important;
319  -webkit-overflow-scrolling:touch!important;
320}
321
322/* ── HOME PAGE: scrollable landing — overrides for stitch home ── */
323/* Use :has() to ensure these only apply when the home view is actually active (SPA-aware) */
324html:has(#view-home.active), 
325html:has(#view-home.active) body {
326  height: auto !important;
327  overflow-y: auto !important;
328  overflow-x: hidden !important;
329  position: relative !important;
330  touch-action: auto !important;
331}
332
333/* Hide global nav when home is active (to show the stitch home header instead) */
334html:has(#view-home.active) .ca-nav-desktop,
335html:has(#view-home.active) .ca-nav-mobile {
336  display: none !important;
337  visibility: hidden !important;
338}
339
340/* Hide support widget on home page only (clean landing) */
341html:has(#view-home.active) #ca-support-btn,
342html:has(#view-home.active) #ca-support-chat {
343  display: none !important;
344  visibility: hidden !important;
345}
346
347/* Hide history sheet and other views on home to prevent bleed-through */
348html:has(#view-home.active) #history-sheet,
349html:has(#view-home.active) #history-sheet-backdrop,
350html:has(#view-home.active) .view-section:not(#view-home) {
351  display: none !important;
352  visibility: hidden !important;
353  height: 0 !important;
354  overflow: hidden !important;
355  pointer-events: none !important;
356}
357
358#view-home.active{position:relative!important;display:block!important;height:auto!important;min-height:100svh!important;overflow:visible!important;inset:auto!important;background:#070a13!important;color:#f8fafc!important;z-index:1!important}
359
360/* ── App root: must expand on home ── */
361#app-root{position:relative;width:100%;height:auto!important;min-height:100svh;overflow:visible!important}
362html:has(#view-home.active) #app-root{height:auto!important;min-height:100svh!important;overflow:visible!important;display:block!important}
363#gen-lens-canvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0}
364
365/* ── Ambient bg ── */
366/* Ambient background base */
367.ambient-bg{position:fixed;inset:0;z-index:-2;overflow:hidden;pointer-events:none;background:#faf8f4}
368
369/* ── Sign-in button: only show immediately when logged OUT ── */
370/* When ?_ca_lo=1 is present (logout cache-bust), always render as logged-out
371   regardless of any WP session state — the cookie may still exist for a few
372   milliseconds during the redirect. This prevents a single-frame flash of the
373   signed-in header after logout. */
374#nav-signin-btn,#nav-signin-btn-m{
375  display:flex;align-items:center;gap:.4rem;border-radius:9999px;
376  background:#fff;color:#000;font-weight:700;border:none;cursor:pointer;white-space:nowrap;
377}
378#nav-signin-btn{padding:10px 20px;font-size:.875rem;min-height:40px}
379#nav-signin-btn-m{padding:8px 16px;font-size:0.75rem;min-height:36px}
380
381/* ── hidden class must be immediately available ── */
382.hidden{display:none!important}
383
384/* ═══════════════════════════════════════════════════════
385   COMFYAI CLOUD — APPLE-GRADE PAGE LOADER  v4
386   Smooth conic-gradient spinner in logo colours.
387   • Dark (home)  : adapts via .home-page class on <body data-rsssl=1 data-burst_id="3582" data-burst_type="page">
388   • Light (other): default cream/white bg
389   • Exit: silky blur-scale-fade (no jarring cut)
390   ═══════════════════════════════════════════════════════ */
391
392/* -- Base loader shell --------------------------------- */
393.ca-page-loader {
394  position: fixed;
395  inset: 0;
396  z-index: 9999;
397  display: flex;
398  align-items: center;
399  justify-content: center;
400  background: var(--loader-bg, #faf8f4);
401  opacity: 1;
402  visibility: visible;
403  transition:
404    opacity    0.55s cubic-bezier(0.4, 0, 0.15, 1),
405    filter     0.55s cubic-bezier(0.4, 0, 0.15, 1),
406    transform  0.55s cubic-bezier(0.4, 0, 0.15, 1),
407    visibility 0s   linear 0s;
408  will-change: opacity, filter, transform;
409}
410
411/* v60 blank-page guard: the loader must never be able to cover finished pages. */
412#ca-page-loader,
413body .ca-page-loader,
414html .ca-page-loader {
415  display: none !important;
416  opacity: 0 !important;
417  visibility: hidden !important;
418  pointer-events: none !important;
419}
420
421/* -- Exit state: blur-scale out ----------------------- */
422.ca-page-loader.ca-loader-hide {
423  opacity: 0;
424  filter: blur(12px);
425  transform: scale(1.04);
426  visibility: hidden;
427  transition:
428    opacity    0.55s cubic-bezier(0.4, 0, 0.15, 1),
429    filter     0.55s cubic-bezier(0.4, 0, 0.15, 1),
430    transform  0.55s cubic-bezier(0.4, 0, 0.15, 1),
431    visibility 0s   linear 0.55s;
432  pointer-events: none;
433}
434
435/* -- Spinner wrapper ----------------------------------- */
436.ca-loader-spinner-wrap {
437  position: relative;
438  z-index: 2;
439  display: flex;
440  align-items: center;
441  justify-content: center;
442  width: 64px;
443  height: 64px;
444}
445
446/* -- Outer conic ring ---------------------------------- */
447.ca-loader-ring {
448  position: absolute;
449  inset: 0;
450  border-radius: 50%;
451  background: conic-gradient(
452    from 0deg,
453    rgba(99,  102, 241, 0.0)   0%,
454    rgba(99,  102, 241, 1.0)  20%,
455    rgba(124,  58, 237, 1.0)  40%,
456    rgba(20,  184, 166, 1.0)  60%,
457    rgba(59,  130, 246, 1.0)  80%,
458    rgba(99,  102, 241, 0.0) 100%
459  );
460  animation: ca-spin 1.1s linear infinite;
461  will-change: transform;
462}
463
464/* -- Inner cutout (donut effect) ----------------------- */
465.ca-loader-ring::after {
466  content: '';
467  position: absolute;
468  inset: 7px;
469  border-radius: 50%;
470  background: var(--loader-bg, #faf8f4);
471}
472
473/* -- Soft glow bloom behind ring ----------------------- */
474.ca-loader-ring-glow {
475  position: absolute;
476  inset: -10px;
477  border-radius: 50%;
478  background: conic-gradient(
479    from 0deg,
480    rgba(99,  102, 241, 0.0)   0%,
481    rgba(99,  102, 241, 0.25) 25%,
482    rgba(20,  184, 166, 0.20) 55%,
483    rgba(124,  58, 237, 0.25) 80%,
484    rgba(99,  102, 241, 0.0) 100%
485  );
486  filter: blur(10px);
487  animation: ca-spin 1.1s linear infinite;
488  will-change: transform;
489  pointer-events: none;
490}
491
492@keyframes ca-spin {
493  to { transform: rotate(360deg); }
494}
495
496/* -- Full-page ambient radial — ultra-subtle ----------- */
497.ca-loader-ambient {
498  position: absolute;
499  inset: 0;
500  pointer-events: none;
501  background: radial-gradient(
502    ellipse 70% 55% at 50% 45%,
503    rgba(99,102,241,0.05) 0%,
504    transparent 70%
505  );
506  animation: ca-ambient-pulse 3.2s ease-in-out infinite alternate;
507}
508@keyframes ca-ambient-pulse {
509  0%   { opacity: 0.6; transform: scale(1); }
510  100% { opacity: 1;   transform: scale(1.06); }
511}
512
513/* ── HOME PAGE: dark loader ─────────────────────────── */
514html.home-page .ca-page-loader,
515body.home-page .ca-page-loader {
516  background: #0a0a0a !important;
517}
518/* Cutout matches dark bg on home */
519html.home-page .ca-loader-ring::after,
520body.home-page .ca-loader-ring::after {
521  background: #0a0a0a !important;
522}
523html.home-page .ca-loader-ambient,
524body.home-page .ca-loader-ambient {
525  background: radial-gradient(
526    ellipse 70% 55% at 50% 45%,
527    rgba(99,102,241,0.14) 0%,
528    rgba(124,58,237,0.07) 40%,
529    transparent 70%
530  ) !important;
531}
532
533/* ── Reduced motion fallback ─────────────────────────── */
534@media (prefers-reduced-motion: reduce) {
535  .ca-loader-ring         { animation: none !important; opacity: 0.6; }
536  .ca-loader-ring-glow    { animation: none !important; }
537  .ca-loader-ambient      { animation: none !important; }
538  .ca-page-loader.ca-loader-hide {
539    filter: none !important;
540    transform: none !important;
541    transition: opacity 0.3s ease, visibility 0s linear 0.3s !important;
542  }
543}
544
545/* Home page: override ambient bg on body */
546html.home-page .ambient-bg,body.home-page .ambient-bg{background:#0a0a0a !important;}
547html.home-page .ambient-orb,body.home-page .ambient-orb{opacity:0 !important;animation:none !important;}
548html.home-page,body.home-page{background:#0a0a0a !important;}
549
550/* ── Home header button defaults (desktop) ── */
551.home-stitch-ai-btn{padding:10px 20px;font-size:0.875rem;gap:6px;}
552.home-stitch-cta{padding:10px 22px;font-size:0.875rem;}
553.home-stitch-signin{padding:9px 18px;font-size:0.8125rem;gap:6px;}
554
555/* Mobile home: allow natural scrolling for the new scrollable landing page.
556   NOTE: body classes unreliable (plugin injects extra <body data-rsssl=1>), use html.home-page instead. */
557/* Mobile: Hide history sheet on home to prevent bleed-through.
558   The main scroll logic is now handled globally for html.home-page. */
559@media(max-width:767px){
560  #view-home.active~#history-sheet,
561	  #view-home.active~#history-sheet-backdrop {
562	    display:none!important;
563	}
564}
565	/* Worker Slider Styling */
566.ca-worker-slider { -webkit-appearance:none; width:80px; height:4px; background:#27272a; border-radius:2px; outline:none; cursor:pointer; }
567.ca-worker-slider::-webkit-slider-thumb { -webkit-appearance:none; width:12px; height:12px; background:#6366f1; border-radius:50%; cursor:pointer; box-shadow:0 0 8px rgba(99,102,241,0.4); transition:transform 0.2s ease; }
568.ca-worker-slider::-webkit-slider-thumb:hover { transform:scale(1.25); }
569</style>
570</head>
571<body data-rsssl=1 class="wp-singular page-template-default page page-id-3582 wp-theme-comfyaicloud antialiased ca-body">
572<div id="a358e58e8-b93d-4903-90e2-82ec9fa288ee" consent-skip-blocker="1" class="" data-bg="background-color: rgba(0, 0, 0, 0.500);" style="background-color: rgba(0, 0, 0, 0.500);  position:fixed;top:0;left:0;right:0;bottom:0;z-index:999999;pointer-events:all;display:none;filter:none;max-width:100vw;max-height:100vh;transform:translateZ(0);" ></div>
573<!-- ─────────────────────────────────────────────────────
574     COMFYAI PAGE LOADER — simplified lightweight spinner.
575     The original loader used complex conic‑gradient animations which
576     consumed significant CPU/GPU resources and extended Total Blocking
577     Time (TBT).  To improve perceived performance we remove the
578     animated conic rings and ambient glow, and instead render a
579     single minimal spinner.  This spinner uses only simple border
580     animations and does not rely on heavy gradients or drop shadows.
581     ───────────────────────────────────────────────────── -->
582<div id="ca-page-loader" class="ca-page-loader" aria-label="Loading" role="status">
583  <!-- Minimal spinner: border animates to indicate loading -->
584  <div class="ca-simple-spinner" aria-hidden="true"></div>
585</div>
586
587<script>
588/* ── Loader hide: run TWO rAF frames so CSS is fully parsed before hiding ── */
589(function(){
590  var HIDE_DELAY = 150; /* ms — was 580ms; cut to 150ms for faster FCP/LCP */
591
592  function hideLoader() {
593    var el = document.getElementById('ca-page-loader');
594    if (!el) return;
595    el.classList.add('ca-loader-hide');
596    setTimeout(function(){
597      if (el.parentNode) el.style.display = 'none';
598    }, HIDE_DELAY);
599  }
600
601  /* Fire as soon as DOM is ready; double-rAF ensures layout + paint are done */
602  function scheduleHide() {
603    requestAnimationFrame(function(){
604      requestAnimationFrame(hideLoader);
605    });
606  }
607
608  if (document.readyState === 'loading') {
609    document.addEventListener('DOMContentLoaded', scheduleHide);
610  } else {
611    scheduleHide();
612  }
613
614  /* Re-show on page navigation so the loader always covers new content */
615  window.addEventListener('beforeunload', function(){
616    var el = document.getElementById('ca-page-loader');
617    if (el) { el.style.display = ''; el.classList.remove('ca-loader-hide'); }
618  });
619})();
620</script>
620
621
622<!--
623  Override styles for the simplified loader and hide the original loader
624  elements.  The heavy conic gradient spinner and ambient glow are no
625  longer rendered, so we explicitly hide those classes.  The new
626  `.ca-simple-spinner` uses a single border animation which is far
627  less taxing on the main thread and GPU.
628-->
629<style id="ca-simple-loader-style">
630  /* Hide old loader elements to prevent off‑screen rendering */
631  .ca-loader-ambient,
632  .ca-loader-ring,
633  .ca-loader-ring-glow,
634  .ca-loader-spinner-wrap {
635    display: none !important;
636  }
637
638  /* Minimal spinner: simple border animation */
639  .ca-simple-spinner {
640    border: 4px solid rgba(99, 102, 241, 0.1);
641    border-top-color: #f43f5e; /* Match theme red/pink accent */
642    border-radius: 50%;
643    width: 54px;
644    height: 54px;
645    animation: ca-simple-spin 0.8s linear infinite;
646    position: relative;
647    z-index: 5;
648  }
649
650  /* Force loader to cover full viewport and be centered */
651  /* Force loader to cover full viewport and be centered */
652  .ca-page-loader {
653    position: fixed !important;
654    top: 0 !important;
655    left: 0 !important;
656    right: 0 !important;
657    bottom: 0 !important;
658    width: 100vw !important;
659    height: 100vh !important;
660    width: 100svw !important;
661    height: 100svh !important;
662    display: flex !important;
663    align-items: center !important;
664    justify-content: center !important;
665    z-index: 200000 !important;
666    background: #000000 !important; /* Force solid black for all dark views */
667    opacity: 1;
668    visibility: visible;
669  }
670
671	  /* Ensure the spinner is centered within the fixed loader */
672	  .ca-page-loader .ca-simple-spinner {
673	    margin: auto !important;
674	  }
675
676		  /* v60: never let the global loader black-screen live pages. */
677	  #ca-page-loader,
678	  body .ca-page-loader,
679	  html .ca-page-loader {
680	    display: none !important;
681	    opacity: 0 !important;
682	    visibility: hidden !important;
683	    pointer-events: none !important;
684	  }
685
686  /* COMPLETELY REMOVE LOADER ON HOME PAGE */
687  html:has(#view-home.active) .ca-page-loader,
688  html.home-page .ca-page-loader {
689    display: none !important;
690  }
691
692  .ca-page-loader.ca-loader-hide {
693    opacity: 0 !important;
694    visibility: hidden !important;
695    pointer-events: none !important;
696  }
697
698  @keyframes ca-simple-spin {
699    to {
700      transform: rotate(360deg);
701    }
702  }
703</style>
704
705<script>
706/*
707 * Prevent expensive cosmic particle animations from running on low‑end
708 * devices or when they are not needed.  The original app initialises
709 * a canvas animation via `app.setupCosmicParticles()`, which can
710 * consume CPU and extend TBT.  Here we override this method with a
711 * no‑op so that the canvas is never created.  This reduces total
712 * blocking time during load without affecting core functionality.
713 */
714document.addEventListener('DOMContentLoaded', function() {
715  if (window.app && typeof app.setupCosmicParticles === 'function') {
716    app.setupCosmicParticles = function() {};
717  }
718});
719</script>
719
720
721<style>:root{--ca-spd:1}</style>
722<script>
723/* ── View class on <html> for redesign.css to target without :has() reliance ── */
724(function(){
725  var v = "generate";
726  if (v) {
727    document.documentElement.classList.add('view-' + v);
728    document.documentElement.classList.add('rd-dark');
729    document.addEventListener('DOMContentLoaded', function(){
730      if (document.body) {
731        document.body.classList.add('view-' + v);
732        document.body.classList.add('rd-dark');
733      }
734    });
735  }
736})();
737</script>
737
738
739<!-- Global script: reposition AI Writer spinner on mobile for all views -->
740<script>
741(function() {
742  'use strict';
743  /**
744   * Determine if current viewport width qualifies as mobile.  Matches the
745   * breakpoint used throughout the theme (<768px).  Returns true on
746   * mobile and false on desktop/tablet.
747   */
748  function isMob() { return window.innerWidth < 768; }
749
750  /**
751   * Moves the AI writer spinner next to the generate button on mobile.  On
752   * desktop the spinner is restored to its original location within the
753   * writer row.  This ensures the three animated dots stay within the
754   * prompt bar and aligned with the generate button.
755   */
756  function repositionWriterSpinner() {
757    var spinner = document.getElementById('ca-writer-spinner');
758    var submitBtn = document.getElementById('gen-submit-btn');
759    var writerRow = document.getElementById('ca-writer-row');
760    if (!spinner || !submitBtn || !writerRow) return;
761    // Mobile layout: insert spinner before submit button within the same parent
762    if (isMob()) {
763      var parent = submitBtn.parentElement;
764      if (parent && !parent.contains(spinner)) {
765        parent.insertBefore(spinner, submitBtn);
766        // Provide some spacing so the spinner doesn't overlap the button
767        spinner.style.marginLeft = '0.5rem';
768      }
769    } else {
770      // Desktop/tablet: ensure spinner is back in the AI writer row
771      if (!writerRow.contains(spinner)) {
772        var btns = document.getElementById('ca-writer-btns');
773        // Append after writer buttons if available, otherwise append to row
774        if (btns) {
775          btns.parentNode.insertBefore(spinner, btns.nextSibling);
776        } else {
777          writerRow.appendChild(spinner);
778        }
779        spinner.style.marginLeft = '';
780      }
781    }
782  }
783  // Run reposition on DOM ready and window resize
784  document.addEventListener('DOMContentLoaded', repositionWriterSpinner);
785  window.addEventListener('resize', repositionWriterSpinner);
786})();
787</script>
787
788
789<!-- Removed ambient orbs per user request -->
790<div class="ambient-bg" aria-hidden="true" style="display:none"></div>
791
792<!-- ════════════════════════════════════════
793     DESKTOP NAVIGATION (≥768px)
794════════════════════════════════════════ -->
795<div class="ca-nav-desktop fixed top-0 left-0 right-0 z-50" style="padding-top:env(safe-area-inset-top);">    <nav class="glass-nav flex items-center justify-between pointer-events-auto w-full px-6 transition-all" style="height:64px; border-bottom:1px solid rgba(0,0,0,0.06);">
796        <!-- Logo — Admin-customizable + neon brand -->
797        <a href="https://www.comfyaicloud.com/" class="flex items-center gap-2.5 cursor-pointer group shrink-0 btn-spring" style="text-decoration:none">
798            <!-- Logo Mark — admin can change via Settings → Home Cards -->
799            <div class="relative shrink-0" style="width:32px;height:32px">
800                                                <img src="https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png"
801                     alt="ComfyAI Cloud" width="32" height="32" id="site-logo-img"
802                     fetchpriority="high" decoding="async"
803                     style="width:32px;height:32px;border-radius:50%;object-fit:cover;display:block;filter:drop-shadow(0 0 8px rgba(56,189,248,0.5))">
804                            </div>
805            <span class="ca-brand-name font-bold text-stone-800 tracking-tight" style="font-size:1.1rem">ComfyAI Cloud</span>
806        </a>
807
808        <!-- Nav links -->
809        <div class="flex items-center gap-1">
810        <a href="https://www.comfyaicloud.com/"           data-target="home"      class="nav-link  px-4 py-2.5 rounded-full text-sm font-semibold text-zinc-300 hover:text-stone-800 transition-all btn-spring" style="text-decoration:none">Home</a>
811        <a href="https://www.comfyaicloud.com/generate/"  data-target="generate"  class="nav-link active px-4 py-2.5 rounded-full text-sm font-semibold text-zinc-300 hover:text-stone-800 transition-all btn-spring" style="text-decoration:none">Generate</a>
812        <a href="https://www.comfyaicloud.com/pricing/"   data-target="plans"     class="nav-link  px-4 py-2.5 rounded-full text-sm font-semibold text-zinc-300 hover:text-stone-800 transition-all btn-spring" style="text-decoration:none">Credits</a>
813        <a href="https://www.comfyaicloud.com/ai/" data-target="ai" class="nav-link  px-4 py-2.5 rounded-full text-sm font-semibold text-zinc-300 hover:text-stone-800 transition-all btn-spring" style="text-decoration:none">AI</a>
814        <a href="https://www.comfyaicloud.com/comfyai-settings/" id="nav-admin-btn" data-target="admin" class="hidden nav-link px-4 py-2.5 rounded-full text-sm font-semibold text-indigo-500 hover:text-indigo-700 btn-spring" style="text-decoration:none">
815            <i data-lucide="shield" class="w-3.5 h-3.5 inline mr-1"></i>Admin
816        </a>
817        </div>
818
819        <div class="flex items-center gap-3">
820            <button id="nav-profile-btn" onclick="app.openModal('profile-modal')" class="hidden items-center gap-2 px-4 py-2 rounded-full bg-amber-600/10 hover:bg-amber-600/15 text-sm font-bold text-amber-700 border border-amber-600/20 transition-colors btn-spring" style="min-height:40px">
821                <img id="nav-avatar" src="https://ui-avatars.com/api/?name=U&#038;background=0D8B93&#038;color=fff" class="w-5 h-5 rounded-full border border-amber-600/40 object-cover" loading="lazy" width="20" height="20">
822                <span id="nav-credit-text" class="whitespace-nowrap font-black text-xs">…</span>
823            </button>
824            <button id="nav-signin-btn" onclick="app.openModal('auth-modal')" class="flex items-center gap-2 px-5 py-2.5 rounded-full bg-white text-black text-sm font-bold hover:bg-zinc-100 transition-colors btn-spring" style="min-height:40px">
825                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg> Sign In / Register
826            </button>
827        </div>
828    </nav>
829</div>
830
831<!-- ════════════════════════════════════════
832     MOBILE NAVIGATION — v8.0 (≤767px)
833════════════════════════════════════════ -->
834<div class="ca-nav-mobile fixed top-0 left-0 right-0 z-[60]" style="padding-top:env(safe-area-inset-top);">
835    <nav class="glass-nav flex items-center justify-between pointer-events-auto w-full px-3" style="height:56px; border-bottom:1px solid rgba(0,0,0,0.06);">
836
837        <!-- Logo -->
838        <a href="https://www.comfyaicloud.com/" class="flex items-center shrink-0 btn-spring" style="text-decoration:none">
839                                            <img src="https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7
839df4-4f94-8a09-1c33983ce040.png"
840                     alt="ComfyAI Cloud" width="26" height="26" id="site-logo-img-mobile"
841                     decoding="async" fetchpriority="high"
842                     style="width:26px;height:26px;border-radius:50%;object-fit:cover;display:block;filter:drop-shadow(0 0 5px rgba(168,85,247,0.45))">
843                        </a>
844
845        <!-- Nav Links — shrink to fit -->
846        <div class="mob-nav-links flex items-center gap-1 flex-1 justify-center min-w-0" style="overflow-x:auto; scrollbar-width:none;">
847            <a href="https://www.comfyaicloud.com/"           data-target="home"      class="nav-link mobile-nav-icon  mob-nav-lnk btn-spring">Home</a>
848            <a href="https://www.comfyaicloud.com/generate/"  data-target="generate"  class="nav-link mobile-nav-icon active mob-nav-lnk btn-spring">Gen</a>
849            <a href="https://www.comfyaicloud.com/pricing/"   data-target="plans"     class="nav-link mobile-nav-icon  mob-nav-lnk btn-spring">Plans</a>
850            <a href="https://www.comfyaicloud.com/ai/" data-target="ai" class="nav-link mobile-nav-icon  mob-nav-lnk btn-spring">AI</a>
851        </div>
852
853        <!-- Right side — always visible, never overflow -->
854        <div style="display:flex;align-items:center;gap:4px;flex-shrink:0;margin-left:3px">
855
856            <!-- Credits badge (logged-in only) -->
857            <a href="https://www.comfyaicloud.com/pricing/" id="mob-credit-pill" style="display:none;align-items:center;gap:3px;flex-shrink:0;padding:3px 7px 3px 6px;border-radius:9999px;background:rgba(201,106,0,0.12);border:1px solid rgba(201,106,0,0.28);text-decoration:none;line-height:1;white-space:nowrap">
858                <span style="width:5px;height:5px;border-radius:50%;background:#c96a00;flex-shrink:0;display:block"></span>
859                <span id="mob-credit-text" style="font-size:9px;font-weight:800;color:#c96a00;max-width:48px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block">…</span>
860            </a>
861
862            </a>
863
864            <!-- Avatar (logged-in) — perfectly inside pill -->
865            <button id="nav-profile-btn-m" onclick="app.openModal('profile-modal')" class="btn-spring" style="display:none;padding:0;border:none;background:none;cursor:pointer;flex-shrink:0;width:30px;height:30px;border-radius:50%;align-items:center;justify-content:center;position:relative;overflow:hidden">
866                <div style="position:absolute;inset:0;border-radius:50%;background:rgba(201,106,0,0.15);z-index:0"></div>
867                <img id="nav-avatar-m" src="https://ui-avatars.com/api/?name=U&#038;background=0D8B93&#038;color=fff" alt="Me"
868                     loading="lazy" width="27" height="27"
869                     style="position:absolute;inset:1.5px;width:calc(100% - 3px);height:calc(100% - 3px);border-radius:50%;object-fit:cover;z-index:2;display:block;border:1.5px solid rgba(201,106,0,0.55)">
870            </button>
871
872            <!-- Sign In (logged-out) -->
873            <button id="nav-signin-btn-m" onclick="app.openModal('auth-modal')" class="flex items-center gap-1 shrink-0 btn-spring" style="display:flex;padding:6px 12px;border-radius:9999px;background:#1c1917;color:white;font-size:11px;font-weight:700;border:none;cursor:pointer;white-space:nowrap">
874                <span>Sign In</span>
875            </button>
876
877        </div>
878    </nav>
879</div>
880
881<!-- ════════════════════════════════════════
882     MAIN SPA VIEWS
883════════════════════════════════════════ -->
884<main id="app-root" class="relative w-full" style="height:100svh">
885
886    <!-- ═══ HOME ═══ -->
887    <section id="view-home" class="view-section custom-scrollbar ">
888
889        <!-- ── Stitch-style Minimal Home Header (home-only, replaces glass nav on home) ── -->
890        <header class="home-stitch-header" role="banner">
891            <a href="https://www.comfyaicloud.com/" class="home-stitch-logo-link btn-spring" style="text-decoration:none;display:flex;align-items:center;gap:10px">
892                                                <img src="https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7
892df4-4f94-8a09-1c33983ce040.png"
893                     alt="Comfy AI image generation workflow screenshot" width="32" height="32"
894                     style="width:32px;height:32px;border-radius:50%;object-fit:cover;display:block;filter:drop-shadow(0 0 10px rgba(100,150,255,0.6))">
895                                <span class="home-stitch-brand">ComfyAI Cloud</span>
896            </a>
897            <div class="home-stitch-actions">
898                <a href="https://www.comfyaicloud.com/ai/" class="home-stitch-ai-btn btn-spring" style="text-decoration:none;display:inline-flex;align-items:center;border-radius:9999px;background:rgba(99,102,241,0.15);color:rgba(200,210,255,0.92);font-weight:700;border:1px solid rgba(99,102,241,0.35);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);white-space:nowrap;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z"/></svg>AI</a><a href="https://www.comfyaicloud.com/generate/" class="home-stitch-cta btn-spring js-auth-tool" data-auth-url="https://www.comfyaicloud.com/generate/" style="text-decoration:none">Generate</a>
899                <button id="hs-profile-btn" onclick="app.openModal('profile-modal')"
900                        class="home-stitch-avatar-btn btn-spring hidden">
901                    <img id="hs-avatar-img"
902                         src="https://ui-avatars.com/api/?name=U&#038;background=3B82F6&#038;color=fff"
903                         width="32" height="32" alt="Comfy AI User Profile"
904                         style="width:32px;height:32px;border-radius:50%;object-fit:cover;display:block">
905                </button>
906                <button id="hs-signin-btn" onclick="app.openModal('auth-modal')"
907                        class="home-stitch-signin btn-spring ">
908                    <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
909                    Sign In
910                </button>
911            </div>
912        </header>
913
914
915
916        <!-- ── Stitch-style Glow Background — arc blobs ── -->
917        <div id="home-glow-bg" aria-hidden="true">
918            <div class="home-arc-ring"></div>
919            <div class="home-arc-left"></div>
920            <div class="home-arc-right"></div>
921        </div>
922
923        <section class="home-seo-hero" aria-labelledby="home-main-heading">
924            <div class="home-seo-hero-inner">
925                <span class="home-seo-eyebrow"><i data-lucide="sparkles" class="w-4 h-4"></i> AI creator platform for images, video and social content</span>
926                <h1 id="home-main-heading">Create AI Images, Talking Videos &amp; Social Media Content</h1>
927                <p class="home-seo-lead">Generate high-quality AI images, turn portraits into lip-sync videos, and create ready-to-post social media content from one simple cloud platform.</p>
928                <div class="home-seo-actions">
929                    <a href="https://www.comfyaicloud.com/generate/" class="home-seo-primary btn-spring js-auth-tool" data-auth-url="https://www.comfyaicloud.com/generate/">
930                        Start Creating <i data-lucide="arrow-right" class="w-4 h-4"></i>
931                    </a>
932                    <a href="#popular-ai-tools" class="home-seo-secondary btn-spring">
933                        Explore AI Tools <i data-lucide="chevron-down" class="w-4 h-4"></i>
934                    </a>
935                </div>
936                <div class="home-seo-benefits" aria-label="Platform benefits">
937                    <span><i data-lucide="gift" class="w-4 h-4"></i> Free credits for new users</span>
938                    <span><i data-lucide="cloud" class="w-4 h-4"></i> No local setup required</span>
939                    <span><i data-lucide="badge-dollar-sign" class="w-4 h-4"></i> Pay only for the credits you use</span>
940                </div>
941            </div>
942        </section>
943
944                <section class="home-challenge-teaser" aria-labelledby="home-challenge-title">
945            <a class="home-challenge-card btn-spring" href="https://www.comfyaicloud.com/challenge/" aria-label="View the C
945omfyAICloud AI Art Challenge">
946                <div class="home-challenge-icon" aria-hidden="true">🏆</div>
947                <div class="home-challenge-copy">
948                    <div class="home-challenge-kicker">COMMUNITY AI ART CHALLENGE <span>LIVE</span></div>
949                    <h2 id="home-challenge-title">CYBERPUNK GODDESS</h2>
950                    <p>Create AI art, submit your work, collect community votes and compete for ComfyAICloud credits.</p>
951                </div>
952                                <div class="home-challenge-prizes" aria-label="Challenge prizes">
953                    <span><b>5,000</b> 1st</span>
954                    <span><b>2,500</b> 2nd</span>
955                    <span><b>1,000</b> 3rd</span>
956                </div>
957                                <span class="home-challenge-link">View Challenge <i data-lucide="arrow-right" class="w-4 h-4"></i></span>
958            </a>
959        </section>
960
961        <style>
962  .home-seo-hero{position:relative;z-index:2;padding:max(8.5rem,calc(7rem + env(safe-area-inset-top))) 1.25rem 4.75rem;overflow:hidden}
963  .home-seo-hero::before{content:"";position:absolute;inset:10% 8% auto;height:420px;background:radial-gradient(circle at 35% 45%,rgba(56,189,248,.18),transparent 42%),radial-gradient(circle at 70% 35%,rgba(217,70,239,.18),transparent 42%);filter:blur(20px);pointer-events:none}
964  .home-seo-hero-inner{position:relative;max-width:980px;margin:0 auto;text-align:center}
965  .home-seo-eyebrow{display:inline-flex;align-items:center;gap:.5rem;padding:.55rem .9rem;border:1px solid rgba(125,211,252,.22);border-radius:999px;background:rgba(15,23,42,.62);color:#c7d2fe;font-size:.78rem;font-weight:800;letter-spacing:.02em;box-shadow:0 16px 50px rgba(0,0,0,.2)}
966  .home-seo-hero h1{display:block;max-width:900px;margin:1.45rem auto 0;padding:.06em 0 .12em;color:#fff;font-family:var(--font-primary)!important;font-size:48px;line-height:1.2;letter-spacing:0;font-weight:900;text-wrap:balance;overflow:visible}
967  .home-seo-hero h1{background:linear-gradient(100deg,#fff 8%,#bfdbfe 48%,#f0abfc 92%);-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent}
968  .home-seo-lead{max-width:760px;margin:1.45rem auto 0;color:#aab5ca;font-size:clamp(1rem,2vw,1.2rem);line-height:1.75;text-wrap:balance}
969  .home-seo-actions{display:flex;justify-content:center;flex-wrap:wrap;gap:.85rem;margin-top:2rem}
970  .home-seo-primary,.home-seo-secondary{display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:50px;padding:.85rem 1.25rem;border-radius:14px;text-decoration:none!important;font-size:.94rem;font-weight:850}
971  .home-seo-primary{background:linear-gradient(135deg,#2563eb,#d946ef);color:#fff!important;box-shadow:0 16px 45px rgba(99,102,241,.28)}
972  .home-seo-secondary{border:1px solid rgba(255,255,255,.14);background:rgba(15,23,42,.72);color:#e2e8f0!important}
973  .home-seo-benefits{display:flex;justify-content:center;flex-wrap:wrap;gap:.75rem 1.35rem;margin-top:1.5rem;color:#8793aa;font-size:.78rem;font-weight:650}
974  .home-seo-benefits span{display:inline-flex;align-items:center;gap:.38rem}
975  .home-challenge-teaser{position:relative;z-index:3;width:min(1120px,calc(100% - 2.5rem));margin:-1.7rem auto 3rem}
976  .home-challenge-card{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:1.15rem;padding:1.05rem 1.2rem;border:1px solid rgba(167,139,250,.28);border-radius:18px;background:linear-gradient(110deg,rgba(17,24,39,.94),rgba(18,24,43,.92));box-shadow:0 18px 60px rgba(0,0,0,.22);text-decoration:none!important;overflow:hidden;position:relative}
977  .home-challenge-card:before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 10% 50%,rgba(217,70,239,.12),transparent 28%),radial-gradient(circle at 88% 50%,rgba(37,99,235,.12),transparent 30%);pointer-events:none}
978  .home-challenge-icon{position:relative;display:grid;place-items:center;width:48px;height:48px;border-radius:14px;background:rgba(245,158,11,.10);border:1px solid rgba(245,158,11,.22);font-size:25px}
979  .home-challenge-copy{position:relative;min-width:0}.home-challenge-kicker{color:#aab5ca;font-size:.68rem;font-weight:850;letter-spacing:.09em}
979.home-challenge-kicker span{display:inline-block;margin-left:.35rem;padding:.16rem .38rem;border-radius:999px;background:rgba(217,70,239,.15);color:#f0abfc;letter-spacing:.04em}.home-challenge-copy h2{margin:.25rem 0 .18rem;color:#fff;font-size:clamp(1.05rem,2vw,1.35rem);line-height:1.2;font-weight:850}.home-challenge-copy p{margin:0;color:#8f9bb0;font-size:.78rem;line-height:1.45}
980  .home-challenge-prizes{position:relative;display:flex;gap:.55rem}.home-challenge-prizes span{display:flex;flex-direction:column;min-width:58px;padding:.45rem .55rem;text-align:center;border-left:1px solid rgba(255,255,255,.08);color:#8f9bb0;font-size:.62rem}.home-challenge-prizes b{color:#e5e7eb;font-size:.78rem;line-height:1.2}.home-challenge-link{position:relative;display:inline-flex;align-items:center;gap:.35rem;white-space:nowrap;padding:.68rem .85rem;border-radius:11px;background:rgba(99,102,241,.14);border:1px solid rgba(129,140,248,.24);color:#dbeafe;font-size:.76rem;font-weight:800}.home-challenge-card:hover{border-color:rgba(167,139,250,.5);transform:translateY(-1px)}
981  @media(max-width:820px){.home-challenge-card{grid-template-columns:auto 1fr auto}.home-challenge-prizes{display:none}}
982  @media(max-width:600px){.home-challenge-teaser{width:calc(100% - 2rem);margin:-.8rem auto 2.4rem}.home-challenge-card{grid-template-columns:auto minmax(0,1fr);gap:.8rem;padding:.9rem}.home-challenge-icon{width:42px;height:42px;font-size:22px}.home-challenge-copy p{font-size:.72rem}.home-challenge-link{grid-column:1/-1;justify-content:center;width:100%;margin-top:.1rem}.home-challenge-kicker{font-size:.61rem}}
983  #popular-ai-tools{scroll-margin-top:86px}
984  @media(max-width:640px){.home-seo-hero{padding:7.25rem 1rem 3.25rem}.home-seo-eyebrow{font-size:.7rem}.home-seo-hero h1{font-size:48px;line-height:1.2;letter-spacing:0}.home-seo-lead{font-size:.97rem;line-height:1.65}.home-seo-actions{flex-direction:column}.home-seo-primary,.home-seo-secondary{width:100%}.home-seo-benefits{justify-content:flex-start;text-align:left}}
985  #view-home.active{background:#050914!important;color:#f8fafc;font-family:var(--font-primary)!important}
986  .home-stitch-header{position:sticky!important;top:0!important;z-index:100!important;background:rgba(5,9,20,.86)!important;backdrop-filter:blur(20px)!important;-webkit-backdrop-filter:blur(20px)!important;border-bottom:1px solid rgba(255,255,255,.08)!important}
987  .home-stitch-brand{color:#fff!important}.home-stitch-ai-btn{background:rgba(255,255,255,.08)!important;border-color:rgba(255,255,255,.16)!important;color:#fff!important}.home-stitch-cta{background:linear-gradient(135deg,#d946ef,#2563eb)!important;color:#fff!important;border:0!important}
988  .home-router-title{font-family:var(--font-primary)!important;font-size:clamp(2.5rem,7vw,5.35rem)!important;line-height:1.02!important;display:flex;flex-direction:column;align-items:center;letter-spacing:-.045em!important;margin:0!important}.home-router-subhead{font-family:var(--font-primary)!important;color:#aab5ca!important;font-size:clamp(.98rem,2vw,1.18rem)!important}.home-route-chips{display:flex;flex-wrap:wrap;justify-content:center;gap:.6rem;margin-top:1rem}.home-route-chips button{border:1px solid rgba(255,255,255,.12);background:rgba(15,23,42,.72);color:#cbd5e1;border-radius:999px;padding:.62rem .85rem;font-size:.78rem;font-weight:700;cursor:pointer;transition:.2s}.home-route-chips button:hover{color:#fff;border-color:rgba(125,211,252,.45);transform:translateY(-1px)}.home-router-note{text-align:center;color:#7f8ba3;font-size:.78rem;margin:.8rem 0 0}@media(max-width:600px){.home-router-title{font-size:clamp(2.15rem,12vw,3.2rem)!important}.home-route-chips{justify-content:flex-start}.home-route-chips button{font-size:.72rem}.home-router-note{text-align:left}}
989  #view-home #home-greeting-text{color:#aab5ca!important}.home-prompt-box{background:linear-gradient(135deg,rgba(21,35,55,.98),rgba(23,20,43,.98))!important;border:1px solid rgba(125,211,252,.25)!important}.home-prompt-box textarea{color:#f8fafc!important}.home-prompt-box textarea::placeholder{color:#8290aa!important}.home-prompt-tagline{color:#8490a5!important}.home-submit-arrow{background:linear-gradient(135deg,#38bdf8,#d946ef)!important;color:#fff!important}#home-glow-bg{display:none!important}
990  .hm-shell{max-width:1240px;margin:0 auto;padding:2.5rem 1.5rem 5rem}.hm-heading{text-align:center;max-width:780px;margin:0 auto 2rem}.hm-kicker{display:inline-flex;align-items:center;gap:.5rem;color:#7dd3fc;font-size:.76rem;font-weight:850;letter-spacing:.13em;text-transform:uppercase;margin-bottom:.75rem}.hm-heading h2{margin:0 0 .7rem;color:#fff;font-size:clamp(1.9rem,4vw,2.75rem);line-height:1.08;font-weight:850}.hm-heading p{margin:0;color:#9aa8bf;line-height:1.65}
991  .hm-popular{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}.hm-feature-card{position:relative;min-height:470px;overflow:hidden;border-radius:22px;border:1px solid rgba(255,255,255,.12);background:#0c1424;text-decoration:none;color:#fff;display:flex;flex-direction:column;transition:.28s ease;box-shadow:0 18px 45px rgba(0,0,0,.22)}.hm-feature-card:hover{transform:translateY(-5px);border-color:rgba(125,211,252,.48);box-shadow:0 22px 58px rgba(0,0,0,.38)}.hm-feature-visual{aspect-ratio:16/10;position:relative;overflow:hidden;background:#111827}.hm-feature-visual img,.hm-feature-visual video{width:100%;height:100%;object-fit:cover;object-position:center;display:block;transition:transform .45s ease}.hm-feature-visual video{pointer-events:none}.hm-image-card .hm-feature-visual img{object-position:center 38%}.hm-feature-card:not(.hm-image-card) .hm-feature-visual img{object-position:center}.hm-feature-card:hover .hm-feature-visual img,.hm-feature-card:hover .hm-feature-visual video{transform:scale(1.035)}.hm-feature-overlay{position:absolute;inset:0;background:linear-gradient(to top,rgba(5,9,20,.7),transparent 55%)}.hm-play{position:absolute;inset:50% auto auto 50%;transform:translate(-50%,-50%);width:52px;height:52px;border-radius:50%;display:grid;place-items:center;background:rgba(5,9,20,.72);border:1px solid rgba(255,255,255,.55);backdrop-filter:blur(8px)}.hm-feature-body{padding:1.25rem 1.3rem 1.35rem;display:flex;flex-direction:column;flex:1}.hm-feature-top{display:flex;align-items:center;justify-content:space-between;gap:.8rem;margin-bottom:.7rem}.hm-icon{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;color:#7dd3fc;background:rgba(56,189,248,.1);border:1px solid rgba(125,211,252,.28)}.hm-badge18{display:inline-flex;align-items:center;gap:.35rem;padding:.35rem .55rem;border-radius:999px;background:rgba(244,63,94,.11);border:1px solid rgba(251,113,133,.35);color:#fda4af;font-size:.7rem;font-weight:800}.hm-feature-card h3{font-size:1.3rem;line-height:1.15;margin:.15rem 0 .6rem;font-weight:850}.hm-feature-card p{color:#aab5c7;font-size:.9rem;line-height:1.58;margin:0 0 1rem;flex:1}.hm-card-cta{display:inline-flex;align-items:center;justify-content:space-between;gap:.6rem;padding:.75rem .9rem;border-radius:11px;border:1px solid rgba(125,211,252,.26);background:rgba(15,30,52,.85);font-weight:800;font-size:.84rem}.hm-feature-card:nth-child(1){border-color:rgba(217,70,239,.28)}.hm-feature-card:nth-child(2){border-color:rgba(59,130,246,.3)}.hm-feature-card:nth-child(3){border-color:rgba(45,212,191,.3)}
992  .hm-toggle-wrap{display:flex;justify-content:center;margin:1.35rem 0 0}.hm-toggle{display:inline-flex;align-items:center;gap:.6rem;min-height:48px;padding:.72rem 1.25rem;border-radius:14px;border:1px solid rgba(125,211,252,.28);background:#0d1729;color:#fff;font-weight:850;cursor:pointer}.hm-toggle i{transition:transform .25s}.hm-toggle[aria-expanded=true] i{transform:rotate(180deg)}.hm-more{margin-top:1rem}.hm-more-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;padding:14px;border-radius:20px;border:1px solid rgba(255,255,255,.1);background:rgba(10,18,33,.75)}.hm-small-card{display:flex;gap:1rem;align-items:flex-start;padding:1.1rem;border-radius:15px;border:1px solid rgba(255,255,255,.08);background:#0d1729;color:#fff;text-decoration:none;transition:.25s}.hm-small-card:hover{border-color:rgba(125,211,252,.35);transform:translateY(-2px)}.hm-small-card h3{font-size:1rem;margin:0 0 .35rem}.hm-small-card p{font-size:.82rem;line-height:1.5;color:#9aa8bd;margin:0}
993  .hm-process{padding:4.5rem 0 1rem}.hm-process-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px}.hm-step{display:flex;align-items:flex-start;gap:14px;position:relative}.hm-step-num{width:32px;height:32px;flex:0 0 32px;border-radius:50%;display:grid;place-items:center;border:1px solid rgba(125,211,252,.55);color:#fff;font-weight:800}.hm-step-icon{width:54px;height:54px;flex:0 0 54px;border-radius:15px;
993display:grid;place-items:center;background:rgba(56,189,248,.09);color:#7dd3fc;border:1px solid rgba(125,211,252,.2)}.hm-step h3{font-size:1rem;margin:0 0 .35rem;color:#fff}.hm-step p{font-size:.85rem;line-height:1.5;color:#9aa8bd;margin:0}
994  .hm-showcase{padding:4rem 0 1rem}.hm-showcase-grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:10px}.hm-showcase-item{aspect-ratio:4/5;border-radius:15px;overflow:hidden;border:1px solid rgba(255,255,255,.1);position:relative;background:#111827}.hm-showcase-item img{width:100%;height:100%;object-fit:cover;display:block}.hm-showcase-label{position:absolute;left:8px;bottom:8px;padding:.3rem .5rem;border-radius:999px;background:rgba(5,9,20,.72);backdrop-filter:blur(8px);color:#fff;font-size:.68rem;font-weight:750;border:1px solid rgba(255,255,255,.16)}
995  .hm-faq{max-width:1000px;margin:5rem auto 1rem}.hm-faq h2{text-align:center;color:#fff;font-size:2rem;font-weight:850;margin-bottom:1.6rem}.hm-faq-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px}.hm-faq-item h4{color:#7dd3fc;font-size:1rem;margin:0 0 .65rem}.hm-faq-item p{color:#94a3b8;font-size:.875rem;line-height:1.65;margin:0}
996  .hm-footer{text-align:center;padding:2rem;border-top:1px solid rgba(255,255,255,.05);color:#64748b;font-size:.85rem;margin-top:auto}.hm-footer a{color:#94a3b8;text-decoration:none;margin:0 10px}.hm-footer a:hover{color:#f8fafc}
997  @media(max-width:900px){.hm-popular{grid-template-columns:1fr}.hm-feature-card{min-height:0}.hm-feature-visual{aspect-ratio:16/9}.hm-more-grid,.hm-process-grid{grid-template-columns:1fr}.hm-showcase-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
998  @media(max-width:600px){.hm-shell{padding:1.5rem 1rem 4rem}.hm-feature-visual{aspect-ratio:16/10}.hm-showcase-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.hm-faq-grid{grid-template-columns:1fr}.hm-heading p{font-size:.92rem}}
999</style>
1000
1001<section class="hm-shell" id="popular-ai-tools">
1002  <div class="hm-heading">
1003    <span class="hm-kicker"><i data-lucide="sparkles" class="w-4 h-4"></i> Most Popular</span>
1004    <h2>Get started with our most popular tools</h2>
1005    <p>Create images, talking videos and ready-to-post social content without jumping between different platforms.</p>
1006  </div>
1007
1008  <div class="hm-popular">
1009    <a href="https://www.comfyaicloud.com/generate/" class="hm-feature-card hm-image-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/generate/">
1010      <div class="hm-feature-visual"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/popular-ai-image-generator.png" alt="AI-generated cyberpunk city portrait preview"><span class="hm-feature-overlay"></span></div>
1011      <div class="hm-feature-body">
1012        <div class="hm-feature-top"><span class="hm-icon"><i data-lucide="image"></i></span><span class="hm-badge18">18+ available</span></div>
1013        <h3>AI Image Generator</h3>
1014        <p>Create high-quality images for social media, ads, products and creative projects, with flexible content settings.</p>
1015        <span class="hm-card-cta">Create Image <i data-lucide="arrow-right" class="w-4 h-4"></i></span>
1016      </div>
1017    </a>
1018
1019    <a href="https://www.comfyaicloud.com/ugc-lip-sync/" class="hm-feature-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/ugc-lip-sync/">
1020      <div class="hm-feature-visual"><video autoplay muted loop playsinline preload="metadata" aria-label="Image-to-video preview"><source src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/popular-image-to-video.mp4" type="video/mp4"></video><span class="hm-feature-overlay"></span></div>
1021      <div class="hm-feature-body">
1022        <div class="hm-feature-top"><span class="hm-icon"><i data-lucide="video"></i></span></div>
1023        <h3>UGC with Lip Sync</h3>
1024        <p>Turn a portrait into a realistic talking video for TikTok, Reels and ads using the HeyGen-powered workflow.</p>
1025        <span class="hm-card-cta">Create Video <i data-lucide="arrow-right" class="w-4 h-4"></i></span>
1026      </div>
1027    </a>
1028
1029    <a href="https://www.comfyaicloud.com/social-media-content/" class="hm-feature-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/social-media-content/">
1030      <div class="hm-feature-visual"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/popular-social-media-content.jpeg" alt="Luxury perfume social media campaign preview"><span class="hm-feature-overlay"></span></div>
1031      <div class="hm-feature-body">
1032        <div class="hm-feature-top"><span class="hm-icon"><i data-lucide="pen-tool"></i></span></div>
1033        <h3>Social Media Content</h3>
1034        <p>Generate scroll-stopping graphics, thumbnails, posts and campaign creatives for every major platform.</p>
1035        <span class="hm-card-cta">Create Content <i data-lucide="arrow-right" class="w-4 h-4"></i></span>
1036      </div>
1037    </a>
1038  </div>
1039
1040  <div class="hm-toggle-wrap"><button type="button" id="hm-tools-toggle" class="hm-toggle" aria-expanded="false" aria-controls="hm-more-tools">More AI Tools <i data-lucide="chevron-down" class="w-4 h-4"></i></button></div>
1041  <div id="hm-more-tools" class="hm-more" hidden>
1042    <div class="hm-more-grid">
1043      <a href="https://www.comfyaicloud.com/deconstruct/" class="hm-small-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/replicate/"><span class="hm-icon"><i data-lucide="scan-search"></i></span><span><h3>Image Deconstruction</h3><p>Discover prompts, lighting, style and composition from any image.</p></span></a>
1044      <a href="https://www.comfyaicloud.com/chat/" class="hm-small-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/chat/"><span class="hm-icon"><i data-lucide="message-square-text"></i></span><span><h3>AI Chat Hub</h3><p>Get help with ideas, prompts, captions and creative tasks.</p></span></a>
1045      <a href="https://www.comfyaicloud.com/ai-friends/" class="hm-small-card js-auth-tool" data-auth-url="https://www.comfyaicloud.com/ai-friends/"><span class="hm-icon"><i data-lucide="users-round"></i></span><span><h3>AI Persona Hub</h3><p>Create reusable AI characters with unique personalities.</p></span></a>
1046    </div>
1047  </div>
1048
1049  <div class="hm-process">
1050    <div class="hm-heading"><h2>From idea to post in minutes</h2></div>
1051    <div class="hm-process-grid">
1052      <div class="hm-step"><span class="hm-step-num">1</span><span class="hm-step-icon"><i data-lucide="lightbulb"></i></span><span><h3>Choose what to create</h3><p>Select an image, talking video or social media workflow.</p></span></div>
1053      <div class="hm-step"><span class="hm-step-num">2</span><span class="hm-step-icon"><i data-lucide="upload-cloud"></i></span><span><h3>Upload or describe</h3><p>Add a portrait, reference image or prompt. No technical setup needed.</p></span></div>
1054      <div class="hm-step"><span class="hm-step-num">3</span><span class="hm-step-icon"><i data-lucide="send"></i></span><span><h3>Generate and share</h3><p>Download your result and publish it wherever your audience is.</p></span></div>
1055    </div>
1056  </div>
1057
1058  <div class="hm-showcase">
1059    <div class="hm-heading"><span class="hm-kicker">Made with ComfyAI Cloud</span><h2>See what you can create</h2><p>A quick look at the styles and content formats available inside the platform.</p></div>
1060    <div class="hm-showcase-grid">
1061            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_12.webp" alt="Fantasy AI image example" loading="lazy"><span class="hm-showcase-label">Fantasy</span></div>
1062            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_4.webp" alt="Influencer AI image example" loading="lazy"><span class="hm-showcase-label">Influencer</span></div>
1063            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_18.webp" alt="Product AI image example" loading="lazy"><span class="hm-showcase-label">Product</span></div>
1064            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_21.webp" alt="Anime AI image example" loading="lazy"><span class="hm-showcase-label">Anime</span></div>
1065            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_7.webp" alt="Realistic AI image example" loading="lazy"><span class="hm-showcase-label">Realistic</span></div>
1066            <div class="hm-showcase-item"><img src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/assets/models/model_26.webp" alt="Creative AI image example" loading="lazy"><span class="hm-showcase-label">Creative</span></div>
1067          </div>
1068  </div>
1069
1070  <div class="hm-faq">
1071    <h2>Comfy AI FAQ</h2>
1072    <div class="hm-faq-grid">
1073      <div class="hm-faq-item"><h4>What is Comfy AI?</h4><p>Comfy AI is a professional cloud-based image generation tool that brings ComfyUI workflows to the browser. It allows users to create, upscale, and deconstruct AI art without needing local hardware.</p></div>
1074      <div class="hm-faq-item"><h4>
1074How does the Comfy AI image generation tool work?</h4><p>Enter a prompt, choose your preferred settings and generate high-quality AI images through cloud-based workflows.</p></div>
1075      <div class="hm-faq-item"><h4>Can I use ComfyUI workflows online here?</h4><p>Yes. The platform supports cloud-based workflows that provide the flexibility of ComfyUI without a local installation.</p></div>
1076      <div class="hm-faq-item"><h4>Is there a free version of ComfyAI?</h4><p>New users receive free credits to explore the platform before purchasing additional credits. No subscription is required to start.</p></div>
1077    </div>
1078  </div>
1079
1080  
1080<script>
1081  (function(){
1082    var toggle=document.getElementById('hm-tools-toggle'),panel=document.getElementById('hm-more-tools');
1083    if(toggle&&panel)toggle.addEventListener('click',function(){var open=toggle.getAttribute('aria-expanded')==='true';toggle.setAttribute('aria-expanded',open?'false':'true');panel.hidden=open;});
1084    var loggedIn=false;
1085    var authParams=new URLSearchParams(window.location.search);
1086    var requestedLogin=authParams.get('login')==='1';
1087    var requestedNext=authParams.get('next')||'';
1088
1089    if(requestedNext){
1090      try{
1091        var parsedNext=new URL(requestedNext,window.location.origin);
1092        if(parsedNext.origin===window.location.origin){
1093          sessionStorage.setItem('ca_after_auth_url',parsedNext.href);
1094        }
1095      }catch(err){}
1096    }
1097
1098    if(loggedIn){
1099      try{
1100        var next=sessionStorage.getItem('ca_after_auth_url');
1101        if(next){
1102          sessionStorage.removeItem('ca_after_auth_url');
1103          if(next!==window.location.href)window.location.href=next;
1104        }
1105      }catch(e){}
1106      return;
1107    }
1108
1109    function openLandingAuthPopup(registerFirst){
1110      if(window.app&&typeof app.openModal==='function'){
1111        app.openModal('auth-modal');
1112      }else{
1113        var modal=document.getElementById('auth-modal');
1114        if(modal)modal.classList.remove('hidden');
1115      }
1116
1117      /* Paid-traffic/product CTAs should present Create Account first.
1118         Explicit Sign In links/buttons remain unchanged. */
1119      if(registerFirst){
1120        var attempts=0;
1121        var showRegister=function(){
1122          attempts++;
1123          if(window.app&&typeof app.switchAuthTab==='function'){
1124            app.switchAuthTab('email-register');
1125            return;
1126          }
1127          if(attempts<8)setTimeout(showRegister,60);
1128        };
1129        setTimeout(showRegister,30);
1130      }
1131    }
1132
1133    if(requestedLogin){
1134      setTimeout(function(){ openLandingAuthPopup(false); },180);
1135      try{
1136        var cleanUrl=new URL(window.location.href);
1137        cleanUrl.searchParams.delete('login');
1138        cleanUrl.searchParams.delete('next');
1139        window.history.replaceState({},'',cleanUrl.pathname+cleanUrl.search+cleanUrl.hash);
1140      }catch(err){}
1141    }
1142
1143    document.querySelectorAll('.js-auth-tool').forEach(function(link){
1144      link.addEventListener('click',function(e){
1145        e.preventDefault();
1146        var url=link.getAttribute('data-auth-url')||link.href;
1147        try{sessionStorage.setItem('ca_after_auth_url',url);}catch(err){}
1148        openLandingAuthPopup(true);
1149      });
1150    });
1151  })();
1152  </script>
1152
1153</section>
1154
1155
1156        <footer class="hm-footer">
1157            <p>&copy; 2026 ComfyAI Cloud. The ultimate Comfy AI image generation tool website.</p>
1158            <div style="margin-top: 15px; display: flex; flex-wrap: wrap; justify-content: center; gap: 15px; opacity: 0.8;">
1159                <a href="https://www.comfyaicloud.com/generate/">Comfy AI Image Generator</a>
1160                <a href="https://www.comfyaicloud.com/ugc-lip-sync/">UGC Lip Sync Video</a>
1161                <a href="https://www.comfyaicloud.com/social-media-content/">Social Media Content</a>
1162                <a href="https://www.comfyaicloud.com/ai-pricing/">Comfy AI Pricing</a>
1163            </div>
1164            <div style="margin-top: 10px; font-size: 0.75rem; opacity: 0.5;">
1165                <a href="https://www.comfyaicloud.com/terms/">Terms</a>
1166                <a href="https://www.comfyaicloud.com/privacy-policy/">Privacy</a>
1167            </div>
1168        </footer>
1169
1170    </section>
1171
1172    <!-- ═══ GENERATE ═══ -->
1173    <section id="view-generate" class="view-section active" >
1174        <!-- Mobile access enabled: responsive Generate Studio -->
1175        <canvas id="gen-lens-canvas" style="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;border-radius:inherit"></canvas>
1176
1177        <div class="flex h-full w-full relative z-10">
1178
1179            <!-- ── Claude-grade LEFT SIDEBAR (desktop only) ── -->
1180            <aside id="gen-sidebar" class="gen-sidebar open hidden md:flex flex-col shrink-0 h-full"
1181                   style="background:rgba(250,248,244,0.98);border-right:1px solid rgba(28,25,23,0.09);backdrop-filter:blur(30px)">
1182
1183                <!-- Sidebar Header -->
1184                <div class="gen-sidebar-header flex items-center justify-between px-4 py-4" style="padding-top:max(4.8rem,calc(3.8rem + env(safe-area-inset-top)))">
1185                    <span class="text-[11px] font-black text-zinc-500 uppercase tracking-widest whitespace-nowrap sidebar-text">Prompt History</span>
1186                    <button id="gen-sidebar-toggle" onclick="app.toggleGenSidebar()" class="btn-spring flex items-center justify-center w-8 h-8 rounded-lg hover:bg-white/5 text-zinc-500 hover:text-stone-800 transition-all" title="Toggle Sidebar">
1187                        <i data-lucide="panel-left-close" class="w-4 h-4 sidebar-icon-open"></i>
1188                        <i data-lucide="panel-left-open" class="w-4 h-4 sidebar-icon-closed" style="display:none"></i>
1189                    </button>
1190                </div>
1191
1192                <!-- Nav Items -->
1193                <div class="px-2 pb-2 sidebar-text space-y-0.5">
1194                    <a href="https://www.comfyaicloud.com/generate/" class="gen-sidebar-nav-btn w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-zinc-400 hover:text-stone-800 hover:bg-white/5 text-xs font-semibold transition-all btn-spring text-left" style="text-decoration:none">
1195                        <i data-lucide="image" class="w-4 h-4 text-amber-700 shrink-0"></i>
1196                        <span>Generate</span>
1197                    </a>
1198                    <a href="https://www.comfyaicloud.com/social-media-content/" class="gen-sidebar-nav-btn w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-zinc-400 hover:text-stone-800 hover:bg-white/5 text-xs font-semibold transition-all btn-spring text-left" style="text-decoration:none">
1199                        <i data-lucide="wrench" class="w-4 h-4 text-teal-400 shrink-0"></i>
1200                        <span>Enhance</span>
1201                    </a>
1202                    <a href="https://www.comfyaicloud.com/pricing/" class="gen-sidebar-nav-btn w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-zinc-400 hover:text-stone-800 hover:bg-white/5 text-xs font-semibold transition-all btn-spring text-left" style="text-decoration:none">
1203                        <i data-lucide="coins" class="w-4 h-4 text-yellow-400 shrink-0"></i>
1204                        <span>Credits</span>
1205                    </a>
1206                </div>
1207
1208                <div class="mx-3 my-1" style="height:1px;background:rgba(255,255,255,0.07)"></div>
1209
1210                <!-- Search — sits directly below divider with proper gap -->
1211                <div class="px-3 pt-3 pb-1 sidebar-text">
1212                    <div class="relative">
1213                        <i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-zinc-600 pointer-events-none"></i>
1214                        <input id="hist-search" type="text" placeholder="Search prompts…"
1215                               oninput="app.filterHistory(this.value)"
1216                               class="w-full bg-stone-100/80 border border-stone-300 rounded-xl text-xs text-stone-600 pl-8 pr-3 py-2.5 focus:outline-none focus:border-amber-600/35 placeholder-stone-400 transition-all"
1217                               style="min-height:36px;font-size:16px">
1218                    </div>
1219                </div>
1220
1221                <!-- History label -->
1222                <div class="px-4 pt-2 pb-1 sidebar-text">
1223                    <span class="text-[9px] font-black text-zinc-600 uppercase tracking-widest">Recent Prompts</span>
1224                </div>
1225
1226                <!-- History List -->
1227                <div id="history-list" class="flex-1 overflow-y-auto custom-scrollbar px-2 pb-4 space-y-0.5 sidebar-text"></div>
1228
1229                <!-- Bottom: Clear -->
1230                <div class="p-3 border-t border-white/5 sidebar-text">
1231                    <button onclick="app.clearHistory()" class="w-full flex items-center gap-2 px-3 py-2 rounded-xl text-zinc-600 hover:text-red-400 hover:bg-red-500/5 text-xs font-medium transition-all btn-spring">
1232                        <i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
1233                        <span>Clear History</span>
1234                    </button>
1235                </div>
1236            </aside>
1237
1238            <!-- ── Main generate area ── -->
1239            <main id="gen-main" class="flex-1 flex flex-col relative min-w-0 overflow-hidden ca-gen-main"
1240                  style="padding-top:max(5.5rem,calc(4.5rem + env(safe-area-inset-top)))">
1241
1242                <!-- Result area -->
1243                <div id="single-result-container" class="flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar flex items-center justify-center"
1244                     style="padding-bottom:13rem;padding-top:0.5rem;padding-left:1rem;padding-right:1rem;scroll-behavior:smooth">
1245                    <div id="generate-empty-state" class="flex flex-col items-center justify-center w-full h-full animate-scale-in" style="min-height:300px;position:relative">
1246                        <!-- chips canvas removed v26 -->
1247                        <div class="relative text-center px-4" style="opacity:0.6;z-index:2">
1248                            <i data-lucide="sparkles" class="w-10 h-10 md:w-12 md:h-12 mx-auto mb-4 text-amber-600/50"></i>
1249                            <p class="text-zinc-400 text-sm md:text-base">What will you create today?</p>
1250                        </div>
1251                    </div>
1252                </div>
1253
1254                <!-- Floating Prompt Bar -->
1255                <div class="ca-prompt-bar" style="padding-bottom:max(1rem,env(safe-area-inset-bottom))">
1256
1257                    <!-- ── MODEL ROW (engine toggle moved inside prompt box) ── -->
1258                    <div class="sidebar-model-row" style="display:flex;flex-direction:column;gap:6px">
1259
1260                        <!-- ComfyAI sub-row -->
1261                        <div id="comfy-model-row" class="gen-model-tabs" style="display:flex">
1262                            <div class="gen-model-choice-group" role="group" aria-label="Generation quality">
1263                                <button data-model="grok-imagine-image" onclick="app.selectGenModel(this,'grok-imagine-image',30)"
1264                                    class="gen-model-tab active flex items-center gap-1.5 btn-spring">
1265                                    <span>Fast</span>
1266                                    <span class="gen-tab-cost">30c</span>
1267                                </button>
1268                                <button data-model="grok-imagine-image-quality" onclick="app.selectGenModel(this,'grok-imagine-image-quality',70)"
1269                                    class="gen-model-tab flex items-center gap-1.5 btn-spring">
1270                                    <span>Quality</span>
1271                                    <span class="gen-tab-cost">70c</span>
1272                                </button>
1273                            </div>
1274                            <div class="gen-tab-divider" aria-hidden="true"></div>
1275                            <div class="gen-resolution-choice-group" role="group" aria-label="Image resolution">
1276                                <button data-res="1k" onclick="app.selectGenRes(this,'1k')" class="gen-res-tab active btn-spring">1K</button>
1277                                <button data-res="2k" onclick="app.selectGenRes(this,'2k')" class="gen-res-tab btn-spring">2K</button>
1278                            </div>
1279                        </div>
1280
1281                        <!-- ── NSFW Toggle ── -->
1282                        <!-- SD3 removed from site -->
1283                        <select id="sd3-aspect-select" style="display:none" aria-hidden="true">
1284                            <option value="16:9">16:9</option><option value="1:1">1:1</option><option value="9:16">9:16</option>
1285                            <option value="3:2">3:2</option><option value="2:3">2:3</option><option value="4:5">4:5</option>
1286                            <option value="5:4">5:4</option>
1287                        </select>
1288                    </div>
1289
1290                    <!-- Input Bar -->
1291                    <!-- Hidden file input for img-to-img
1292                         ★ sr-only hiding (NOT display:none) for iOS/Android compat
1293                         ★ accept="image/*" for max device compatibility
1294                         Handler attached via inline JS - zero dependency on app.init() or Lucide -->
1295                    <input type="file" id="gen-img-file-input" accept="image/*" multiple
1296 style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0">
1297                    
1297<script>
1298                    /* v53 — Bulletproof image-attach handler.
1299                       Attached inline so it works IMMEDIATELY — no wait for app.init() or Lucide.
1300                       The `app` object literal exists from the moment app.js is parsed (before init). */
1301                    document.getElementById('gen-img-file-input').addEventListener('change', function(e){
1302                        var files = Array.from(e.target.files || []);
1303                        if (!files.length) return;
1304                        /* Safety: if app.js hasn't loaded yet, bail with visible feedback */
1305                        if (typeof app === 'undefined' || !app._attachedImages) {
1306                            console.warn('[ComfyAI Cloud] app not ready — retrying in 500ms');
1307                            setTimeout(function(){ e.target.dispatchEvent(new Event('change')); }, 500);
1308                            return;
1309                        }
1310                        /*
1311                         * Clear existing attachments when entering edit mode.
1312                         * In edit mode only one image should be active; automatically
1313                         * remove previous attachments before adding new ones.  Uses
1314                         * available helper methods (_clearAllAttachedImgs or
1315                         * _removeAttachedImg) if present; otherwise resets the
1316                         * _attachedImages array and refreshes the UI.
1317                         */
1318                        try {
1319                            if (app._editMode && app._attachedImages && app._attachedImages.length > 0) {
1320                                // Clear any previously attached images
1321                                if (typeof app._clearAllAttachedImgs === 'function') {
1322                                    app._clearAllAttachedImgs();
1323                                } else if (typeof app._removeAttachedImg === 'function') {
1324                                    while (app._attachedImages.length) {
1325                                        var rem = app._attachedImages[0];
1326                                        if (rem && rem.id) {
1327                                            app._removeAttachedImg(rem.id);
1328                                        } else {
1329                                            app._attachedImages.shift();
1330                                        }
1331                                    }
1332                                } else {
1333                                    app._attachedImages = [];
1334                                }
1335                                // Update UI to reflect cleared attachments
1336                                if (typeof app._renderImgStrip === 'function') app._renderImgStrip();
1337                                if (typeof app._updateEditModeUI === 'function') app._updateEditModeUI();
1338                                /*
1339                                 * On mobile devices, also clear any existing result card.  When
1340                                 * switching to a new image in edit mode, the previous generation
1341                                 * result should disappear so only the new attached image is shown.
1342                                 */
1343                                if (window.innerWidth < 768) {
1344                                    var rc = document.getElementById('single-result-container');
1345                                    if (rc) rc.innerHTML = '';
1346                                    var es = document.getElementById('generate-empty-state');
1347                                    if (es) es.classList.remove('hidden');
1348                                }
1349                            }
1350                        } catch (err) {
1351                            console.error('[ComfyAI Cloud] Clear attachments error', err);
1352                        }
1353                        /* If the full method exists (app.js v53+), delegate to it */
1354                        if (typeof app.handleGenImgUpload === 'function') {
1355                            app.handleGenImgUpload(e);
1356                            return;
1357                        }
1358                        /* Fallback for older cached app.js — do the work directly */
1359                        var slots = 3 - app._attachedImages.length;
1360                        if (slots <= 0) {
1361                            if (typeof app.showToast === 'function') app.showToast('Maximum 3 images allowed.','warning');
1362                            e.target.value = '';
1363                            return;
1364                        }
1365                        files.slice(0, slots).forEach(function(file){
1366                            if (!file.type.startsWith('image/')) return;
1367                            if (file.size > 10*1024*1024) return;
1368                            var reader = new FileReader();
1369                            reader.onload = function(ev){
1370                                var id = 'ca-img-' + Date.now() + '-' + Math.random().toString(36).slice(2,6);
1371                                app._attachedImages.push({id:id, dataUri:ev.target.result, filename:file.name});
1372                                if (typeof app._renderImgStrip === 'function') app._renderImgStrip();
1373                                if (typeof app._updateEditModeUI === 'function') app._updateEditModeUI();
1374                            };
1375                            reader.readAsDataURL(file);
1376                        });
1377                        e.target.value = '';
1378                    });
1379                    </script>
1379
1380
1381                    <div class="glass-panel rounded-[2rem] p-2 flex flex-col shadow-2xl bg-[#faf8f4]/90 border border-white/10 transition-all duration-300 focus-within:border-amber-500/40 focus-within:shadow-[0_0_40px_rgba(201,106,0,0.12)] gen-prompt-card" id="gen-prompt-card"
1382                         style="margin:0 4px;max-width:860px;margin-left:auto;margin-right:auto;width:calc(100% - 8px)">
1383
1384                        <!-- Image strip — hidden until images attached -->
1385                        <div id="gen-img-strip" style="display:none;flex-wrap:nowrap;gap:8px;padding:8px 12px 6px;overflow-x:auto;border-bottom:1px solid rgba(0,0,0,0.06)"></div>
1386
1387                        <textarea id="gen-prompt" rows="3"
1388                            class="w-full bg-transparent text-stone-800 px-4 md:px-5 py-3 md:py-4 text-sm md:text-base resize-none focus:outline-none placeholder-stone-400 custom-scrollbar"
1389                            style="min-height:6.5rem;max-height:12rem"
1390                            placeholder="What image would you like to create?"></textarea>
1391                        <!-- ── AI Writer Brain Buttons ── -->
1392                        <div class="ca-writer-row" id="ca-writer-row">
1393                            <div class="ca-writer-label">
1394                                <i data-lucide="brain-circuit" class="w-3 h-3"></i>
1395                                <span>AI Writer</span>
1396                            </div>
1397                            <div class="ca-writer-btns" id="ca-writer-btns">
1398                                <button class="ca-writer-btn btn-spring" data-mode="rephrase" onclick="app.aiWriter('rephrase',this)" title="Rephrase — same intent, fresh words">
1399                                    <i data-lucide="refresh-cw" class="w-3 h-3"></i><span>Rephrase</span>
1400                                </button>
1401                                <button class="ca-writer-btn ca-writer-btn--improve btn-spring" data-mode="improve" onclick="app.aiWriter('improve',this)" title="Improve — add rich visual detail">
1402                                    <i data-lucide="sparkles" class="w-3 h-3"></i><span>Improve</span>
1403                                </button>
1404                                <button class="ca-writer-btn ca-writer-btn--creative btn-spring" data-mode="creative" onclick="app.aiWriter('creative',this)" title="Creative — bold unique reimagination">
1405                                    <i data-lucide="wand-2" class="w-3 h-3"></i><span>Creative</span>
1406                                </button>
1407                                <button class="ca-writer-btn ca-writer-btn--best btn-spring" data-mode="best" onclick="app.aiWriter('best',this)" title="Best — maximum quality output">
1408                                    <i data-lucide="zap" class="w-3 h-3"></i><span>Best</span>
1409                                </button>
1410                            </div>
1411                            <div class="ca-writer-spinner" id="ca-writer-spinner" style="display:none">
1412                                <div class="ca-writer-dot"></div><div class="ca-writer-dot"></div><div class="ca-writer-dot"></div>
1413                            </div>
1414                        </div>
1415
1416                        <div class="flex items-center justify-between px-2 md:px-3 pt-2 pb-1.5">
1417                            <div class="flex items-center gap-2 text-xs text-zinc-500 font-medium px-1">
1418                                <!-- Upload button -->
1419                                <label for="gen-img-file-input" id="gen-img-upload-btn"
1420                                    class="btn-spring flex items-center gap-1.5 px-2.5 py-1.5 rounded-xl text-xs font-semibold transition-all"
1421                                    style="background:rgba(99,102,241,0.08);border:1px solid rgba(99,102,241,0.2);color:#6366f1;min-height:32px;cursor:pointer"
1422                                    title="Attach reference image for editing">
1423                                    <i data-lucide="image-plus" class="w-3.5 h-3.5"></i>
1424                                    <span id="gen-img-upload-label">Add Image</span>
1425                                </label>
1426                                <!-- Resolution select is defined once beside the submit button. -->
1427                                <!-- AR Selector Button — visible for both engines -->
1428                                <button id="gen-ar-btn" onclick="app.openARPopup()"
1429                                    class="flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-semibold"
1430                                    style="min-height:32px"
1431                                    title="Select aspect ratio"
1432                                    aria-label="Select aspect ratio">
1433                                    <i data-lucide="ratio" class="w-3.5 h-3.5"></i>
1434                                    <span id="gen-ar-label">16:9</span>
1435                                </button>
1436
1437                                <!-- NSFW Toggle — enabled when fal.ai key is configured -->
1438                                <button id="ca-nsfw-switch" type="button" onclick="window.nsfwToggle && window.nsfwToggle()"
1439                                    class="btn-spring flex items-center gap-1.5 px-2.5 py-1.5 rounded-xl text-xs font-semibold transition-all"
1440                                    style="background:rgba(236,72,153,0.08);border:1px solid rgba(236,72,153,0.22);color:#ec4899;min-height:32px;cursor:pointer"
1441                                    title="Use fal.ai Flux LoRA mode" aria-pressed="false">
1442                                    <span class="ca-nsfw-track" aria-hidden="true"><span class="ca-nsfw-knob"></span></span>
1443                                    <span class="ca-nsfw-lbl">NSFW</span>
1444                                    <span id="ca-nsfw-cost" class="gen-tab-cost">30c</span>
1445                                </button>
1446
1447
1448                                <!-- Edit mode badge -->
1449                                <span id="gen-edit-mode-badge" style="display:none;align-items:center;gap:4px;padding:2px 8px;border-radius:9999px;font-size:11px;font-weight:700;background:linear-gradient(90deg,#6366f1,#8b5cf6);color:#fff">
1450                                    <i data-lucide="pencil" class="w-3 h-3"></i> Edit Mode
1451                                </span>
1452                            </div>
1453
1454                            <div class="flex items-center gap-2">
1455                                <!-- Hidden selects still used by backend -->
1456                                <select id="gen-model"  class="hidden" onchange="app.updateGenBtnCostUI()"><option value="grok-imagine-image">Fast</option><option value="grok-imagine-image-quality">Quality</option></select>
1457                                <select id="gen-aspect" class="hidden">
1458                                    <option value="auto">Auto</option>
1459                                    <option value="1:1">1:1</option>
1460                                    <option value="3:4">3:4</option>
1461                                    <option value="4:3">4:3</option>
1462                                    <option value="9:16">9:16</option>
1463                                    <option value="16:9" selected>16:9</option>
1464                                    <option value="2:3">2:3</option>
1465                                    <option value="3:2">3:2</option>
1466                                    <option value="9:19.5">9:19.5</option>
1467                                    <option value="19.5:9">19.5:9</option>
1468                                    <option value="9:20">9:20</option>
1469                                    <option value="20:9">20:9</option>
1470                                    <option value="1:2">1:2</option>
1471                                    <option value="2:1">2:1</option>
1472                                </select>
1473                                <select id="gen-res" class="hidden" onchange="app.updateGenBtnCostUI()">
1474                                  <option value="1k" selected>1K</option>
1475                                  <option value="2k">2K</option>
1476                                </select>
1477                                <button onclick="app.executeGenerationRouted()" id="gen-submit-btn"
1478                                    class="gen-submit-glass btn-spring relative overflow-hidden"
1479                                    style="min-height:44px">
1480
1481                                    <div class="gen-submit-glass-shine"></div>
1482                                    <!-- Mobile: shows only the up-arrow via CSS -->
1483                                    <i data-lucide="arrow-up" class="gen-submit-mob-icon" aria-hidden="true"></i>
1484                                    <span id="gen-submit-text" class="relative z-10 flex items-center gap-1.5">
1485                                        <span id="gen-submit-label">Generate</span>
1486                                        <span id="gen-btn-cost" class="gen-btn-cost-badge">-40c</span>
1487                                    </span>
1488                                </button>
1489                            </div>
1490                        </div>
1491                    </div>
1492
1493                    <!-- Dedicated mobile action: fixed to the visual viewport so short iPhone screens cannot crop it. -->
1494                    <button type="button" id="gen-submit-mobile"
1495                        onclick="var b=document.getElementById('gen-submit-btn'); if(b && !b.disabled){ b.click(); }"
1496                        aria-label="Generate image">
1497                        <i data-lucide="sparkles" aria-hidden="true"></i>
1498                        <span id="gen-submit-mobile-label">Generate</span>
1499                        <span id="gen-submit-mobile-cost"></span>
1500                    </button>
1501                    
1501<script>
1502                    (function(){
1503                      function syncMobileGenerate(){
1504                        var src=document.getElementById('gen-submit-btn');
1505                        var mob=document.getElementById('gen-submit-mobile');
1506                        var label=document.getElementById('gen-submit-label');
1507                        var cost=document.getElementById('gen-btn-cost');
1508                        var ml=document.getElementById('gen-submit-mobile-label');
1509                        var mc=document.getElementById('gen-submit-mobile-cost');
1510                        if(!src||!mob) return;
1511                        mob.disabled=!!src.disabled;
1512                        mob.setAttribute('aria-busy', src.getAttribute('aria-busy')||'false');
1513                        if(ml) ml.textContent=(label&&label.textContent.trim())||'Generate';
1514                        if(mc) mc.textContent=(cost&&cost.textContent.trim())||'';
1515                      }
1516                      document.addEventListener('DOMContentLoaded',function(){
1517                        syncMobileGenerate();
1518                        var src=document.getElementById('gen-submit-btn');
1519                        if(src && window.MutationObserver){
1520                          new MutationObserver(syncMobileGenerate).observe(src,{subtree:true,childList:true,characterData:true,attributes:true});
1521                        }
1522                      });
1523                      window.addEventListener('load',syncMobileGenerate);
1524                    })();
1525                    </script>
1525
1526
1527                    <!-- footer links removed — do not add back, they push prompt box off screen on mobile -->
1528                </div>
1529            </main>
1530        </div>
1531
1532<script>
1533/* ─────────────────────────────────────────────────────────
1534   caEngine — ComfyAI only. SD3 has been removed from the site.
1535   Kept as a compatibility shim so legacy call sites keep working.
1536   ───────────────────────────────────────────────────────── */
1537var caEngine = {
1538  _eng: 'comfy',
1539  _sd3Aspect: '16:9',
1540
1541  /* No-op — engine is permanently ComfyAI */
1542  switch: function() { this._cost(); },
1543
1544  _paint: function() {},
1545  _rows: function() {
1546    var cr    = document.getElementById('comfy-model-row');
1547    var arBtn = document.getElementById('gen-ar-btn');
1548    var imgUpload = document.getElementById('gen-img-upload-btn');
1549    if (cr)    cr.style.display    = '';
1550    if (arBtn && !(window.app && app._editMode)) arBtn.style.display = '';
1551    if (imgUpload) imgUpload.style.removeProperty('display');
1552  },
1553
1554  _cost: function() {
1555    var costs = (typeof CA !== 'undefined' && CA.costs) || {};
1556    var btn = document.getElementById('gen-btn-cost');
1557    if (!btn) return;
1558    var costs = (typeof CA !== 'undefined' && CA.costs) || {};
1559    var btn = document.getElementById('gen-btn-cost');
1560    if (!btn) return;
1561    
1562    /* NSFW mode has fixed cost from Settings */
1563    if (window.app && app._nsfwMode) {
1564        var isAdmin = window.app && app.isAdmin;
1565        var nsfwCost = costs.nsfw || 30;
1566        btn.textContent = isAdmin ? 'Free' : '-' + nsfwCost + 'c';
1567        return;
1568    }
1569
1570    var model = document.getElementById('gen-model');
1571    var res   = document.getElementById('gen-res');
1572    var m = model ? model.value : 'grok-imagine-image';
1573    var r = res   ? res.value   : '1k';
1574    var mc = (m === 'grok-imagine-image-quality') ? (costs.gen_2k || 40)
1575           :                                     (costs.gen_1k  || 15);
1576    var rc = (r === '2k') ? (costs.res_2k || 40) : (costs.res_1k || 15);
1577    var isAdmin = window.app && app.isAdmin;
1578    btn.textContent = isAdmin ? 'Free' : ('-' + (mc + rc) + 'c');
1579  },
1580
1581  setAspect: function(v)  { this._sd3Aspect = v; },
1582  getAspect: function()   { return this._sd3Aspect; },
1583  getEngine: function()   { return 'comfy'; },
1584
1585  init: function() {
1586    this._rows();
1587    var m = document.getElementById('gen-model');
1588    if (m && m.value === 'stable-diffusion-3-medium') m.value = 'grok-imagine-image';
1589    this._cost();
1590  }
1591};
1592
1593/* ── Generate-page patches: run at DOMContentLoaded ── */
1594document.addEventListener('DOMContentLoaded', function() {
1595
1596  /* 1. Init engine state (ComfyAI only) */
1597  caEngine.init();
1598
1599  /* 2. Patch app with safe overrides. */
1600  function patchApp(a) {
1601    if (!a || a._sd3Patched) return;
1602    a._sd3Patched = true;
1603
1604    /* Force UI updates */
1605    a.updateGenBtnCostUI = function() { caEngine._cost(); };
1606
1607    /* Store last result URL and fix download button */
1608    a._lastResultUrl = '';
1609    var _origRGR = a.renderGenerationResult.bind(a);
1610    a.renderGenerationResult = function(imgUrl, meta) {
1611      a._lastResultUrl = imgUrl; // Cache URL for subsequent actions
1612      _origRGR(imgUrl, meta);
1613      
1614      var wrap = document.getElementById('single-result-container');
1615      if (!wrap) return;
1616
1617      wrap.querySelectorAll('.gen-float-btn').forEach(function(btn) {
1618        var oc = btn.getAttribute('onclick') || '';
1619        if (oc.indexOf('downloadGeneratedImage') !== -1)
1620          btn.setAttribute('onclick', 'app.downloadGeneratedImage(app._lastResultUrl)');
1621        else if (oc.indexOf('expandGeneratedImage') !== -1)
1622          btn.setAttribute('onclick', 'app.expandGeneratedImage(app._lastResultUrl)');
1623        if (oc.indexOf('useResultAsReference') !== -1) {
1624          var label = btn.querySelector('span');
1625          if (label) label.textContent = 'Edit';
1626        }
1627      });
1628    };
1629
1630  }
1631
1632  /* app.js runs with defer — it executes before DOMContentLoaded fires.
1633     window.app is therefore set by the time this handler runs. */
1634  if (window.app) {
1635    patchApp(window.app);
1636  } else {
1637    /* Safety fallback — should not normally be needed */
1638    var _t = setInterval(function() {
1639      if (window.app) { clearInterval(_t); patchApp(window.app); }
1640    }, 50);
1641    setTimeout(function(){ clearInterval(_t); }, 3000);
1642  }
1643});
1644
1645</script>
1645
1646
1647<script>
1648/* Mobile generate prompt keyboard dock.
1649   Focus happens before some mobile browsers publish the final keyboard
1650   viewport. Measure through the keyboard animation and pin the composer above
1651   the keyboard even before the first typed character. */
1652document.addEventListener('DOMContentLoaded', function() {
1653  var prompt = document.getElementById('gen-prompt');
1654  if (!prompt || prompt._caKeyboardDockBound) return;
1655  prompt._caKeyboardDockBound = true;
1656
1657  var root = document.documentElement;
1658  var baseHeight = Math.max(window.innerHeight || 0, window.visualViewport ? window.visualViewport.height : 0);
1659
1660  function isMobile() {
1661    return window.innerWidth < 768 || (window.matchMedia && window.matchMedia('(hover: none) and (pointer: coarse)').matches);
1662  }
1663
1664  function refreshBaseHeight() {
1665    if (document.activeElement === prompt || document.body.classList.contains('ca-gen-prompt-keyboard')) return;
1666    var vv = window.visualViewport;
1667    baseHeight = Math.max(baseHeight || 0, window.innerHeight || 0, vv ? vv.height : 0);
1668  }
1669
1670  function measuredKeyboardOffset(useFallback) {
1671    var vv = window.visualViewport;
1672    var vvHeight = vv ? vv.height : window.innerHeight;
1673    var vvTop = vv ? vv.offsetTop : 0;
1674    var offset = Math.max(0, Math.round((baseHeight || window.innerHeight || vvHeight) - vvHeight - vvTop));
1675    if (useFallback && offset < 80) {
1676      offset = Math.max(260, Math.min(380, Math.round((baseHeight || window.innerHeight || 720) * 0.42)));
1677    }
1678    return offset;
1679  }
1680
1681  function applyDock(useFallback) {
1682    if (!isMobile() || document.activeElement !== prompt) return;
1683    var offset = measuredKeyboardOffset(useFallback);
1684    document.body.classList.add('ca-gen-prompt-keyboard');
1685    document.body.classList.add('ca-mobile-input-active');
1686    if (offset > 0) document.body.classList.add('ca-mobile-keyboard-open');
1687    root.style.setProperty('--ca-focus-keyboard-offset', offset + 'px');
1688    if (window.app && typeof app._syncResultPadding === 'function') app._syncResultPadding();
1689  }
1690
1691  function releaseDock() {
1692    setTimeout(function() {
1693      if (document.activeElement === prompt) return;
1694      document.body.classList.remove('ca-gen-prompt-keyboard');
1695      document.body.classList.remove('ca-mobile-input-active');
1696      root.style.setProperty('--ca-focus-keyboard-offset', '0px');
1697      refreshBaseHeight();
1698      if (window.app && typeof app._syncResultPadding === 'function') app._syncResultPadding();
1699    }, 180);
1700  }
1701
1702  function focusDock() {
1703    refreshBaseHeight();
1704    applyDock(false);
1705    [60, 120, 220, 360, 520].forEach(function(ms) {
1706      setTimeout(function() { applyDock(ms >= 220); }, ms);
1707    });
1708  }
1709
1710  prompt.addEventListener('focus', focusDock, { passive: true });
1711  prompt.addEventListener('click', focusDock, { passive: true });
1712  prompt.addEventListener('touchend', focusDock, { passive: true });
1713  prompt.addEventListener('input', function() { applyDock(false); }, { passive: true });
1714  prompt.addEventListener('blur', releaseDock, { passive: true });
1715  window.addEventListener('resize', function() { refreshBaseHeight(); applyDock(false); }, { passive: true });
1716  if (window.visualViewport) {
1717    window.visualViewport.addEventListener('resize', function() { applyDock(false); }, { passive: true });
1718    window.visualViewport.addEventListener('scroll', function() { applyDock(false); }, { passive: true });
1719  }
1720});
1721</script>
1721
1722
1723<!-- ══════════════════════════════════════════════════════════
1724     NSFW GENERATE ENGINE — isolated IIFE, zero coupling to patchApp.
1725     Intercepts generate button in capture phase — 100% reliable.
1726     ══════════════════════════════════════════════════════════ -->
1727<script>
1728(function(){
1729'use strict';
1730
1731/* ─── Toggle state ─── */
1732var _on = false;
1733
1734/* ─── Toggle UI: Generate-page NSFW switch ─── */
1735window.nsfwToggle = function() {
1736  var app = window.app;
1737  var sw = document.getElementById('ca-nsfw-switch');
1738
1739  if (typeof CA !== 'undefined' && !CA.has_fal_key) {
1740    if (app && app.showToast) app.showToast('NSFW generation unavailable — fal.ai API key not configured.', 'error');
1741    return;
1742  }
1743
1744  _on = !_on;
1745  if (app) app._nsfwMode = _on;
1746
1747  if (sw) {
1748    sw.classList.toggle('on', _on);
1749    sw.setAttribute('aria-pressed', _on ? 'true' : 'false');
1750  }
1751
1752  if (window.caEngine && caEngine._cost) caEngine._cost();
1753  if (app && app.showToast) {
1754    app.showToast(_on ? 'NSFW mode enabled — using fal.ai Flux LoRA.' : 'NSFW mode disabled — using Grok Imagine.', _on ? 'success' : 'info');
1755  }
1756};
1757
1758/* ─── Same AR size maps as app.js executeGeneration ─── */
1759/* Loading-state card sizes (matches the l-map in executeGeneration) */
1760var _cardMap = {
1761  '16:9':   {w:'760px', r:'16/9',   mh:'calc(100svh - 460px)'},
1762  '9:16':   {w:'280px', r:'9/16',   mh:'calc(100svh - 460px)'},
1763  '1:1':    {w:'480px', r:'1/1',    mh:'calc(100svh - 460px)'},
1764  '3:4':    {w:'360px', r:'3/4',    mh:'calc(100svh - 460px)'},
1765  '4:3':    {w:'640px', r:'4/3',    mh:'calc(100svh - 460px)'},
1766  '2:3':    {w:'320px', r:'2/3',    mh:'calc(100svh - 460px)'},
1767  '3:2':    {w:'600px', r:'3/2',    mh:'calc(100svh - 460px)'},
1768  '9:19.5': {w:'240px', r:'9/19.5', mh:'calc(100svh - 460px)'},
1769  '19.5:9': {w:'800px', r:'19.5/9', mh:'calc(100svh - 460px)'},
1770  '9:20':   {w:'230px', r:'9/20',   mh:'calc(100svh - 460px)'},
1771  '20:9':   {w:'840px', r:'20/9',   mh:'calc(100svh - 460px)'},
1772  '1:2':    {w:'280px', r:'1/2',    mh:'calc(100svh - 460px)'},
1773  '2:1':    {w:'720px', r:'2/1',    mh:'calc(100svh - 460px)'},
1774  '4:5':    {w:'380px', r:'4/5',    mh:'calc(100svh - 460px)'},
1775  '5:4':    {w:'500px', r:'5/4',    mh:'calc(100svh - 460px)'},
1776  'auto':   {w:'480px', r:'1/1',    mh:'calc(100svh - 460px)'},
1777};
1778/* Pixel dimensions sent to fal.ai (multiples of 32) */
1779var _pixMap = {
1780  '1:1':    {w:1024,h:1024}, '16:9':  {w:1344,h:768},
1781  '9:16':   {w:768, h:1344}, '4:3':   {w:1152,h:864},
1782  '3:4':    {w:864, h:1152}, '3:2':   {w:1152,h:768},
1783  '2:3':    {w:768, h:1152}, '2:1':   {w:1344,h:672},
1784  '1:2':    {w:672, h:1344}, '9:19.5':{w:736, h:1600},
1785  '19.5:9': {w:1600,h:736},  '9:20':  {w:720, h:1600},
1786  '20:9':   {w:1600,h:720},  '21:9':   {w:1600,h:688},
1787  '4:5':    {w:896, h:1120},  '5:4':    {w:1120,h:896},
1788  '9:21':   {w:688, h:1600},  'auto':  {w:1024,h:1024},
1789};
1790
1791/* ─── Build identical loading card HTML to executeGeneration ─── */
1792function _buildLoader(aspect) {
1793  var p   = _cardMap[aspect] || _cardMap['auto'];
1794  var mob = window.innerWidth < 768;
1795  var cardStyle;
1796  if (mob) {
1797    var ar = aspect !== 'auto' && aspect.indexOf(':') !== -1
1798           ? parseFloat(aspect.split(':')[0]) < parseFloat(aspect.split(':')[1])
1799           : false;
1800    cardStyle = 'width:min(' + (ar ? '85vw' : '90vw') + ',' + p.w + ');aspect-ratio:' + p.r + ';max-height:calc(100svh - 320px)';
1801  } else {
1802    cardStyle = 'width:min(' + p.w + ',90vw);aspect-ratio:' + p.r + ';max-height:' + p.mh;
1803  }
1804  return '<div class="relative rounded-3xl overflow-hidden flex items-center justify-center animate-scale-in mx-auto"'
1805    + ' style="' + cardStyle + ';background:linear-gradient(135deg,var(--indigo-bg,#eef2ff),var(--purple-bg,#f5f3ff));border:1px solid var(--border,rgba(0,0,0,0.08))">'
1806    + '<div class="absolute inset-0 overflow-hidden pointer-events-none">'
1807    + '<div class="absolute w-[50%] h-[50%] bg-indigo-400 rounded-full mix-blend-screen blur-[80px] opacity-50 animate-blob top-0 left-0"></div>'
1808    + '<div class="absolute w-[50%] h-[50%] bg-teal-400 rounded-full mix-blend-screen blur-[80px] opacity-50 animate-blob animation-delay-2000 top-0 right-0"></div>'
1809    + '<div class="absolute w-[50%] h-[50%] bg-purple-400 rounded-full mix-blend-screen blur-[80px] opacity-50 animate-blob animation-delay-4000 bottom-0 left-1/4"></div>'
1810    + '</div>'
1811    + '<div class="relative z-10 flex flex-col items-center gap-4">'
1812    + '<i data-lucide="loader-circle" class="w-10 h-10 text-indigo-500 animate-spin"></i>'
1813    + '<span class="text-[11px] font-bold tracking-[0.25em] uppercase text-indigo-400 animate-pulse">GENERATING</span>'
1814    + '</div></div>';
1815}
1816
1817/* ─── NSFW generation (text-to-image + img2img) ─── */
1818function executeGenerationNSFW() {
1819  var app = window.app;
1820  if (!app) { console.warn('[NSFW] app not ready'); return; }
1821  if (!app.isLoggedIn) { app.showToast('Please sign in first.'); app.openModal('auth-modal'); return; }
1822
1823  /* Guard: fal.ai key must be configured */
1824  if (typeof CA !== 'undefined' && !CA.has_fal_key) {
1825    app.showToast('NSFW generation unavailable — fal.ai API key not configured.', 'error');
1826    /* Turn toggle back off */
1827    _on = false;
1828    var sw = document.getElementById('ca-nsfw-switch');
1829    if (sw) { sw.classList.remove('on'); sw.setAttribute('aria-pressed', 'false'); }
1830    return;
1831  }
1832
1833  var promptEl = document.getElementById('gen-prompt');
1834  var prompt   = promptEl ? promptEl.value.trim() : '';
1835  if (!prompt) { app.showToast('Please enter a prompt.'); return; }
1836
1837  var isEdit  = !!(app._attachedImages && app._attachedImages.length > 0);
1838  var aspect  = (document.getElementById('gen-aspect') || {value:'1:1'}).value || '1:1';
1839  var pix     = _pixMap[aspect] || _pixMap['auto'];
1840
1841  /* Credit check — use CA.costs.nsfw (now correctly populated by PHP) */
1842  var costs    = (typeof CA !== 'undefined' && CA.costs) || {};
1843  var nsfwCost = costs.nsfw || ((costs.gen_1k || 15) + (costs.res_1k || 15));
1844  if (!app.isAdmin && app.credits < nsfwCost) {
1845    app.showToast('Need ' + nsfwCost + ' credits, have ' + app.credits + '.', 'error');
1846    setTimeout(function(){ window.location.href = (CA.urls && CA.urls.pricing) || '/pricing/'; }, 1200);
1847    return;
1848  }
1849
1850  /* Lock UI */
1851  var submitBtn = document.getElementById('gen-submit-btn');
1852  if (submitBtn) submitBtn.disabled = true;
1853  var es = document.getElementById('generate-empty-state');
1854  if (es) es.classList.add('hidden');
1855
1856  /* Show loading card — exact same style as normal generation */
1857  var rc = document.getElementById('single-result-container');
1858  if (rc) {
1859    rc.innerHTML = _buildLoader(aspect);
1860    if (typeof lucide !== 'undefined') lucide.createIcons();
1861  }
1862
1863  var resSel = document.getElementById('gen-res');
1864  var resolution = (resSel ? resSel.value : '1k');
1865
1866  /* Build FormData */
1867  var fd = new FormData();
1868  fd.append('action', 'ca_generate_nsfw');
1869  fd.append('nonce', CA.nonce);
1870  fd.append('prompt', prompt);
1871  fd.append('width',  pix.w);
1872  fd.append('height', pix.h);
1873  fd.append('res', resolution);
1874
1875  if (isEdit) {
1876    fd.append('img2img',  '1');
1877    fd.append('strength', '0.85'); /* Heavy strength required for robust Flux edits */
1878    var img = app._attachedImages[0];
1879
1880    if (img.isUrl) {
1881      /*
1882       * URL-based images (e.g. xAI CDN results) are auth-gated and NOT
1883       * publicly accessible by fal.ai. If useResultAsReference() already
1884       * proxied the image to a base64 previewUri, use that as image_data
1885       * so fal.ai receives the actual pixels. Fall back to the raw URL
1886       * only when no preview is available.
1887       */
1888      var b64src = (img.previewUri && img.previewUri.indexOf('data:') === 0)
1889                   ? img.previewUri : null;
1890      if (b64src) {
1891        app._compressImageForAPI(b64src, 1024, 0.85).then(function(compressed) {
1892          fd.append('image_data', compressed);
1893          _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1894        }).catch(function(err) {
1895          console.error('[NSFW img2img url-b64 compress]', err);
1896          fd.append('image_data', b64src);
1897          _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1898        });
1899        return; /* _doFetch called inside promise */
1900      } else {
1901        /* No proxied base64 yet — FIX: proxy-fetch the xAI CDN image to base64
1902         * BEFORE sending to fal.ai. Sending the raw URL directly caused fal.ai
1903         * to silently ignore img2img and generate a random unrelated image.    */
1904        var _rawUrl = img.dataUri;
1905        var _proxyFd = new FormData();
1906        _proxyFd.append('action', 'ca_proxy_image');
1907        _proxyFd.append('nonce', CA.nonce);
1908        _proxyFd.append('url', _rawUrl);
1909        _proxyFd.append('mode', 'base64');
1910        fetch(CA.ajax_url, {method:'POST', body:_proxyFd, credentials:'same-origin'})
1911          .then(function(r){ return r.json(); })
1912          .then(function(json) {
1913            if (json.success && json.data && json.data.data_uri) {
1914              img.previewUri = json.data.data_uri; /* cache for next time */
1915              app._compressImageForAPI(json.data.data_uri, 1024, 0.85).then(function(c) {
1916                fd.append('image_data', c);
1917                _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1918              }).catch(function() {
1919                fd.append('image_data', json.data.data_uri);
1920                _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1921              });
1922            } else {
1923              /* Proxy failed — fall back to URL (last resort) */
1924              fd.append('image_url', _rawUrl);
1925              _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1926            }
1927          })
1928          .catch(function() {
1929            fd.append('image_url', _rawUrl);
1930            _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1931          });
1932        return;
1932 /* async — _doFetch called inside promise */
1933      }
1934    } else {
1935      /* Local base64 image — compress then send */
1936      app._compressImageForAPI(img.dataUri, 1024, 0.85).then(function(compressed) {
1937        fd.append('image_data', compressed);
1938        _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1939      }).catch(function(err) {
1940        console.error('[NSFW img2img compress]', err);
1941        fd.append('image_data', img.dataUri);
1942        _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1943      });
1944      return; /* _doFetch called inside promise */
1945    }
1946  }
1947
1948  _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit);
1949}
1950
1951function _doFetch(fd, app, submitBtn, rc, prompt, aspect, isEdit) {
1952  fetch(CA.ajax_url, {method:'POST', body:fd, credentials:'same-origin'})
1953    .then(function(r){ return r.json(); })
1954    .then(function(json) {
1955      if (submitBtn) submitBtn.disabled = false;
1956
1957      if (json.success) {
1958        /* Update credits */
1959        if (json.data.credits !== undefined) {
1960          app.credits = parseInt(json.data.credits);
1961          app.updateCreditUI(true);
1962        }
1963        setTimeout(function(){ app._fetchLiveCredits(); }, 1000);
1964
1965        /* Render result immediately. Some fal.ai URLs do not reliably fire Image.onload
1966           in every browser/CORS situation, which left the black loader visible even
1967           though the API succeeded and credits were charged. */
1968        var imgUrl = (json.data && (json.data.url || json.data.image_url || json.data.image)) || '';
1969        if (!imgUrl) {
1970          app.showToast('Generation finished but no image URL was returned. Please contact support.', 'error');
1971          if (rc) rc.innerHTML = '';
1972          setTimeout(function(){ app._fetchLiveCredits && app._fetchLiveCredits(); }, 500);
1973          return;
1974        }
1975        try {
1976          app.renderGenerationResult(imgUrl, {
1977            model:        'fal-ai/flux-lora',
1978            prompt:       prompt,
1979            aspect_ratio: aspect,
1980            resolution:   (document.getElementById('gen-res') || {value:'1k'}).value || '1k'
1981          });
1982          app.saveToHistory(prompt, 'fal-ai/flux-lora', 'generate', 'success');
1983        } catch (renderErr) {
1984          console.error('[NSFW] render error:', renderErr);
1985          if (rc) {
1986            rc.innerHTML = '<div class="gen-result-wrapper animate-scale-in" data-aspect="'+aspect+'">'+
1987              '<div class="gen-atomic-wrap" style="position:relative;border-radius:1.25rem;overflow:hidden;line-height:0;background:#05070d">'+
1988              '<img src="'+String(imgUrl).replace(/&/g,'&amp;').replace(/"/g,'&quot;')+'" alt="Generated image" class="gen-result-image" style="width:100%;height:auto;display:block;border-radius:1.25rem;">'+
1989              '</div></div>';
1990          }
1991        }
1992        setTimeout(function(){ app._fetchLiveCredits && app._fetchLiveCredits(); }, 1000);
1993
1994      } else {
1995        /* Surface the real error to user */
1996        var falErr = (json.data && json.data.fal_error) ? json.data.fal_error : '';
1997        if (falErr) {
1998          console.error('[NSFW] fal error:', falErr, 'HTTP:', json.data.http_code);
1999        }
2000        var msg = (json.data && json.data.message) || 'Generation failed. Credits refunded.';
2001        /* Append fal.ai detail if short enough to be readable */
2002        if (falErr && falErr.length < 120 && msg.indexOf(falErr) === -1) {
2003          msg = msg + ' (' + falErr + ')';
2004        }
2005        app.showToast(msg, 'prompt-rejected');
2006        if (json.data && json.data.credits !== undefined) {
2007          app.credits = parseInt(json.data.credits);
2008          app.updateCreditUI(true);
2009        } else {
2010          setTimeout(function(){ app._fetchLiveCredits(); }, 500);
2011        }
2012        app.saveToHistory(prompt, 'generated', 'generate', 'fail');
2013        if (rc) rc.innerHTML = '';
2014      }
2015    })
2016    .catch(function(err) {
2017      console.error('[NSFW] fetch error:', err);
2018      if (submitBtn) submitBtn.disabled = false;
2019      if (window.app) app.showToast('Network error — please try again.', 'prompt-rejected');
2020      if (rc) rc.innerHTML = '';
2021    });
2022}
2023
2024/* ─── Intercept the generate button click (capture phase = before onclick) ─── */
2025/* Also wrap executeGenerationRouted for keyboard/programmatic triggers */
2026function _attachButton() {
2027  var btn = document.getElementById('gen-submit-btn');
2028  if (!btn || btn._nsfwCaptured) return;
2029  btn._nsfwCaptured = true;
2030
2031  btn.addEventListener('click', function(e) {
2032    if (!_on) return;              /* NSFW off → let normal onclick run */
2033    e.preventDefault();
2034    e.stopImmediatePropagation(); /* block onclick="app.executeGenerationRouted()" */
2035    executeGenerationNSFW();
2036  }, true); /* capture = true */
2037
2038  /* Also expose on app for programmatic callers (home page prompt → generate) */
2039  if (window.app && !window.app._nsfwRouted) {
2040    window.app._nsfwRouted = true;
2041    var _orig = window.app.executeGenerationRouted.bind(window.app);
2042    window.app.executeGenerationRouted = async function() {
2043      if (_on) { executeGenerationNSFW(); return; }
2044      return await _orig();
2045    };
2046  }
2047}
2048
2049/* ─── Boot ─── */
2050function _boot() {
2051  var sw = document.getElementById('ca-nsfw-switch');
2052  if (sw && typeof CA !== 'undefined' && !CA.has_fal_key) {
2053    sw.style.opacity = '0.45';
2054    sw.title = 'fal.ai API key not configured';
2055  }
2056  _attachButton();
2057  /* Retry in case generate section isn't rendered yet */
2058  if (!document.getElementById('gen-submit-btn')) {
2059    setTimeout(_boot, 100);
2060  }
2061}
2062
2063if (document.readyState === 'loading') {
2064  document.addEventListener('DOMContentLoaded', function(){ setTimeout(_boot, 200); });
2065} else {
2066  setTimeout(_boot, 200);
2067}
2068
2069})();
2070</script>
2070
2071
2072<!-- ══════════════════════════════════════════════════════════
2073     MOBILE IMAGE UPLOAD PATCH — v1.0
2074     On mobile: uploaded images go to result area as a clean preview card.
2075     AI Writer buttons stay visible in edit mode.
2076     Generate arrow stays circular in both modes.
2077     ══════════════════════════════════════════════════════════ -->
2078<script>
2079(function() {
2080  'use strict';
2081
2082  function isMob() { return window.innerWidth < 768; }
2083
2084  function showMobileImgCard(images) {
2085    var rc  = document.getElementById('single-result-container');
2086    var emp = document.getElementById('generate-empty-state');
2087    if (!rc) return;
2088    var old = document.getElementById('ca-mob-img-preview');
2089    if (old) old.remove();
2090    if (!images || images.length === 0) {
2091      if (emp && !rc.querySelector('.gen-result-wrapper:not(#ca-mob-img-preview)')) {
2092        emp.classList.remove('hidden');
2093      }
2094      return;
2095    }
2096    /* FIX: When entering edit mode on mobile, clear any previously generated
2097       image card so only the edit preview is shown (not both side-by-side). */
2098    var existingResult = rc.querySelector('.gen-result-wrapper:not(#ca-mob-img-preview)');
2099    if (existingResult) existingResult.remove();
2100    if (emp) emp.classList.add('hidden');
2101    var primary = images[0];
2102    var thumb   = primary.previewUri || primary.dataUri || '';
2103    if (!thumb) return;
2104    var extraInfo = images.length > 1
2105      ? '<div style="text-align:center;font-size:11px;font-weight:600;color:#a8a29e;padding:5px 0 2px">+' +
2106        (images.length - 1) + ' more image' + (images.length > 2 ? 's' : '') + '</div>'
2107      : '';
2108    var wrap = document.createElement('div');
2109    wrap.id        = 'ca-mob-img-preview';
2110    wrap.className = 'gen-result-wrapper animate-scale-in';
2111    wrap.setAttribute('data-aspect', (window.app && window.app._detectedEditAspect) || 'auto');
2112    wrap.style.cssText = 'width:min(90vw,380px);margin:0 auto;';
2113    wrap.innerHTML =
2114      '<div class="gen-atomic-wrap" style="position:relative;border-radius:1.25rem;overflow:hidden;line-height:0;">' +
2115        '<img src="' + thumb + '" alt="Reference image" draggable="false" oncontextmenu="return false"' +
2116             ' class="gen-result-image"' +
2117             ' style="width:100%;height:auto;max-height:52svh;object-fit:contain;display:block;border-radius:1.25rem;">' +
2118        /* Add delete (X) button in the top-right corner on mobile */
2119        '<button id="ca-mob-img-delete-btn" title="Remove image"' +
2120                ' style="position:absolute;top:10px;right:10px;z-index:10;' +
2121                        'width:28px;height:28px;border-radius:50%;' +
2122                        'background:rgba(239,68,68,0.90);border:2px solid rgba(255,255,255,0.35);' +
2123                        'color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;' +
2124                        'box-shadow:0 2px 10px rgba(239,68,68,0.45);' +
2125                        'backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);' +
2126                        '-webkit-tap-highlight-color:transparent;touch-action:manipulation;">' +
2127          '<i data-lucide="x" style="width:16px;height:16px;pointer-events:none;"></i>' +
2128        '</button>' +
2129        /* Existing edit button remains in bottom-right corner */
2130        '<button id="ca-mob-edit-btn" title="Write your prompt"' +
2131                ' style="position:absolute;bottom:10px;right:10px;z-index:10;' +
2132                        'width:40px;height:40px;border-radius:50%;' +
2133                        'background:rgba(99,102,241,0.90);border:2px solid rgba(255,255,255,0.35);' +
2134                        'color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;' +
2135                        'box-shadow:0 4px 18px rgba(99,102,241,0.45);' +
2136                        'backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);' +
2137                        '-webkit-tap-highlight-color:transparent;touch-action:manipulation;">' +
2138          '<i data-lucide="pencil" style="width:18px;height:18px;pointer-events:none;"></i>' +
2139        '</button>' +
2140      '</div>' + extraInfo;
2141    wrap.querySelector('#ca-mob-edit-btn').addEventListener('click', function() {
2142      if (window.app && typeof app.showToast === 'function') app.showToast('Write your prompt ✍️', 'success');
2143      setTimeout(function() { var p=document.getElementById('gen-prompt'); if(p) p.focus({preventScroll:true}); }, 200);
2144    });
2145    /* Delete button clears all attached images (edit mode) */
2146    var delBtn = wrap.querySelector('#ca-mob-img-delete-btn');
2147    if (delBtn) {
2148      delBtn.addEventListener('click', function(e) {
2149        e.stopPropagation();
2150        if (window.app) {
2151          if (typeof app._clearAllAttachedImgs === 'function') {
2152            app._clearAllAttachedImgs();
2153          } else if (typeof app._removeAttachedImg === 'function' && app._attachedImages && app._attachedImages.length) {
2154            var first = app._attachedImages[0];
2155            if (first && first.id) app._removeAttachedImg(first.id);
2156          }
2157          showMobileImgCard([]); /* re-render to clear preview */
2158        }
2159      });
2160    }
2161    rc.appendChild(wrap);
2162    if (typeof lucide !== 'undefined') lucide.createIcons();
2163    setTimeout(function() { rc.scrollTop = 0; }, 60);
2164  }
2165
2166  function patchApp(a) {
2167    if (a._mobImgPatchApplied) return;
2168    a._mobImgPatchApplied = true;
2169
2170    /* Keep the application's original toast messages intact.
2171       Do not redirect unrelated generation errors to the NSFW toggle. */
2172
2173    /* Patch _renderImgStrip */
2174    var _origStrip = a._renderImgStrip.bind(a);
2175    a._renderImgStrip = function() {
2176      if (isMob()) {
2177        showMobileImgCard(this._attachedImages);
2178        var s = document.getElementById('gen-img-strip');
2179        if (s) { s.style.display='none'; s.innerHTML=''; }
2180        return;
2181      }
2182      _origStrip();
2183    };
2184
2185    /* Patch _updateEditModeUI */
2186    var _origEditUI = a._updateEditModeUI.bind(a);
2187    a._updateEditModeUI = function() {
2188      _origEditUI();
2189      if (isMob()) {
2190        showMobileImgCard(this._attachedImages);
2191        var s = document.getElementById('gen-img-strip');
2192        if (s) s.style.display = 'none';
2193        /* AI Writer row: always keep visible */
2194        var wr = document.getElementById('ca-writer-row');
2195        if (wr && getComputedStyle(wr).display === 'none') wr.style.display = 'flex';
2196        /* Submit btn: always circular arrow */
2197        var st = document.getElementById('gen-submit-text');
2198        var mi = document.querySelector('.gen-submit-mob-icon');
2199        if (st) st.style.display = 'none';
2200        if (mi) { mi.style.display='block'; mi.style.width='20px'; mi.style.height='20px'; }
2201      }
2202    };
2203
2204    /* Patch _removeAttachedImg */
2205    var _origRem = a._removeAttachedImg.bind(a);
2206    a._removeAttachedImg = function(id) {
2207      _origRem(id);
2208      if (isMob()) showMobileImgCard(this._attachedImages);
2209    };
2210
2211    /* Patch _clearAllAttachedImgs */
2212    if (a._clearAllAttachedImgs) {
2213      var _origClr = a._clearAllAttachedImgs.bind(a);
2214      a._clearAllAttachedImgs = function() { _origClr(); if(isMob()) showMobileImgCard([]); };
2215    }
2216  }
2217
2218  document.addEventListener('DOMContentLoaded', function() {
2219    function tryPatch() {
2220      if (window.app && window.app._renderImgStrip) { patchApp(window.app); return; }
2221      setTimeout(tryPatch, 100);
2222    }
2223    tryPatch();
2224
2225    /* Ensure generate button stays circular on mobile in all modes */
2226    if (isMob()) {
2227      var btn = document.getElementById('gen-submit-btn');
2228      var obs = new MutationObserver(function() {
2229        var st = document.getElementById('gen-submit-text');
2230        var mi = document.querySelector('.gen-submit-mob-icon');
2231        if (st && st.style.display !== 'none') st.style.display = 'none';
2232        if (mi && mi.style.display === 'none') { mi.style.display='block'; }
2233      });
2234      if (btn) obs.observe(btn, {childList:true, subtree:true, attributes:true, attributeFilter:['style']});
2235    }
2236  });
2237})();
2238</script>
2238
2239
2240<!-- AR Selector Popup — Premium Bottom Sheet / Floating Card -->
2241        <div id="ar-popup" class="ar-popup" style="display:none;">
2242            <div class="ar-popup-backdrop" onclick="app.closeARPopup()"></div>
2243            <div class="ar-popup-content">
2244                <div class="ar-popup-header">
2245                    <span class="ar-popup-title">Aspect Ratio</span>
2246                    <button class="ar-popup-close" onclick="app.closeARPopup()" title="Close" aria-label="Close">
2247                        <i data-lucide="x" class="w-3.5 h-3.5"></i>
2248                    </button>
2249                </div>
2250                <div class="ar-popup-grid">
2251                    <button data-ar="auto" onclick="app.selectAR('auto', this)" class="ar-option">
2252                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-auto"><svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2.2" width="10" height="10"><path d="M6 1v10M1 6h10"/></svg></span></span>
2253                        <span class="ar-label">Auto</span>
2254                    </button>
2255                    <button data-ar="1:1" onclick="app.selectAR('1:1', this)" class="ar-option">
2256                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-1-1">1:1</span></span>
2257                        <span class="ar-label">Square</span>
2258                    </button>
2259                    <button data-ar="3:4" onclick="app.selectAR('3:4', this)" class="ar-option">
2260                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-3-4">3:4</span></span>
2261                        <span class="ar-label">Portrait</span>
2262                    </button>
2263                    <button data-ar="4:3" onclick="app.selectAR('4:3', this)" class="ar-option">
2264                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-4-3">4:3</span></span>
2265                        <span class="ar-label">Landscape</span>
2266                    </button>
2267                    <button data-ar="9:16" onclick="app.selectAR('9:16', this)" class="ar-option">
2268                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-9-16">9:16</span></span>
2269                        <span class="ar-label">Tall</span>
2270                    </button>
2271                    <button data-ar="16:9" onclick="app.selectAR('16:9', this)" class="ar-option active">
2272                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-16-9">16:9</span></span>
2273                        <span class="ar-label">Wide</span>
2274                    </button>
2275                    <button data-ar="2:3" onclick="app.selectAR('2:3', this)" class="ar-option">
2276                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-2-3">2:3</span></span>
2277                        <span class="ar-label">2:3</span>
2278                    </button>
2279                    <button data-ar="3:2" onclick="app.selectAR('3:2', this)" class="ar-option">
2280                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-3-2">3:2</span></span>
2281                        <span class="ar-label">3:2</span>
2282                    </button>
2283                    <button data-ar="9:19.5" onclick="app.selectAR('9:19.5', this)" class="ar-option">
2284                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-9-195">9:19.5</span></span>
2285                        <span class="ar-label">iPhone</span>
2286                    </button>
2287                    <button data-ar="19.5:9" onclick="app.selectAR('19.5:9', this)" class="ar-option">
2288                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-195-9">19.5:9</span></span>
2289                        <span class="ar-label">Cinema</span>
2290                    </button>
2291                    <button data-ar="9:20" onclick="app.selectAR('9:20', this)" class="ar-option">
2292                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-9-20">9:20</span></span>
2293                        <span class="ar-label">Story</span>
2294                    </button>
2295                    <button data-ar="20:9" onclick="app.selectAR('20:9', this)" class="ar-option">
2296                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-20-9">20:9</span></span>
2297                        <span class="ar-label">Ultra</span>
2298                    </button>
2299                    <button data-ar="1:2" onclick="app.selectAR('1:2', this)" class="ar-option">
2300                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-1-2">1:2</span></span>
2301                        <span class="ar-label">Vertical</span>
2302                    </button>
2303                    <button data-ar="2:1" onclick="app.selectAR('2:1', this)" class="ar-option">
2304                        <span class="ar-icon-wrap"><span class="ar-icon-inner ar-inner-2-1">2:1</span></span>
2305                        <span class="ar-label">Panorama</span>
2306                    </button>
2307                    <button data-ar="4:5" onclick="app.selectAR('4:5', this)" class="ar-option">
2308                        <span class="ar-icon-wrap"><span class="ar-icon-inner" style="width:40px;height:50px">4:5</span></span>
2309                        <span class="ar-label">Portrait+</span>
2310                    </button>
2311                    <button data-ar="5:4" onclick="app.selectAR('5:4', this)" class="ar-option">
2312                        <span class="ar-icon-wrap"><span class="ar-icon-inner" style="width:50px;height:40px">5:4</span></span>
2313                        <span class="ar-label">Landscape+</span>
2314                    </button>
2315                    <button data-ar="21:9" onclick="app.selectAR('21:9', this)" class="ar-option">
2316                        <span class="ar-icon-wrap"><span class="ar-icon-inner" style="width:70px;height:27px">21:9</span></span>
2317                        <span class="ar-label">Cinematic</span>
2318                    </button>
2319                    <button data-ar="9:21" onclick="app.selectAR('9:21', this)" class="ar-option">
2320                        <span class="ar-icon-wrap"><span class="ar-icon-inner" style="width:27px;height:70px">9:21</span></span>
2321                        <span class="ar-label">Tall</span>
2322                    </button>
2323                </div>
2324            </div>
2325        </div>
2326
2327        <!-- History Session Page (overlay) -->
2328        <div id="hist-session-page" class="hidden" style="position:absolute;inset:0;z-index:80;background:rgba(250,248,244,0.98);backdrop-filter:blur(20px);overflow-y:auto;padding:2rem">
2329            <div class="max-w-2xl mx-auto" style="padding-top:max(5rem,calc(4rem + env(safe-area-inset-top)))">
2330                <div class="flex items-center gap-3 mb-6">
2331                    <button onclick="app.closeHistorySession()" class="btn-spring flex items-center gap-2 text-zinc-400 hover:text-stone-800 text-sm font-semibold px-3 py-2 rounded-xl hover:bg-white/5 transition-all">
2332                        <i data-lucide="arrow-left" class="w-4 h-4"></i> Back to Generate
2333                    </button>
2334                </div>
2335                <h2 id="hist-session-title" class="text-xl font-bold text-stone-800 mb-1 truncate"></h2>
2336                <p id="hist-session-date" class="text-xs text-zinc-600 mb-6"></p>
2337                <div id="hist-session-list" class="space-y-3"></div>
2338            </div>
2339        </div>
2340    </section>
2341
2342    <!-- ═══ REPLICATE ═══ -->
2343    <section id="view-replicate" class="view-section custom-scrollbar " >
2344        <div class="max-w-7xl mx-auto w-full px-3 md:px-6 pb-6"
2345             style="padding-top:max(5.5rem,calc(4.5rem + env(safe-area-inset-top)))">
2346
2347            <!-- Header Row -->
2348            <div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 mb-6 animate-scale-in">
2349                <div>
2350                    <h2 class="text-2xl md:text-3xl font-bold tracking-tight mb-1 text-stone-800">Visual Deconstruction</h2>
2351                    <p class="text-zinc-400 text-xs md:text-sm flex flex-wrap items-center gap-2">
2352                        Reverse-engineer images into pixel-perfect prompts.
2353                        <span id="rep-cost-badge" class="inline-flex items-center gap-1 bg-cyan-500/10 text-cyan-400 px-2 py-0.5 rounded text-xs font-mono font-bold border border-cyan-500/20">
2354                            <i data-lucide="coins" class="w-3 h-3"></i> 5 Cr / Image
2355                        </span>
2356                    </p>
2357                </div>
2358
2359                <!-- Controls row -->
2360                <div class="flex flex-wrap items-center gap-2 w-full md:w-auto">
2361
2362                    <!-- Mode toggle — Fast / Brain — light blue / green -->
2363                    <div class="flex items-center gap-2 glass-panel border border-white/10 rounded-xl px-3 py-2 cursor-pointer select-none rep-toggle-wrap" onclick="app.toggleReplicateMode()" style="min-height:44px">
2364                        <span id="rep-toggle-label-fast" class="text-xs font-bold transition-colors duration-300" style="color:#38bdf8">Fast</span>
2365                        <button id="rep-pro-toggle" class="relative w-10 h-5 rounded-full transition-colors duration-300 pointer-events-none shrink-0" style="background:linear-gradient(135deg,#38bdf8,#818cf8)">
2366                            <div id="rep-pro-knob" class="absolute left-1 top-1 w-3 h-3 bg-white rounded-full shadow-sm transition-transform duration-300" style="box-shadow:0 1px 4px rgba(0,0,0,0.25)"></div>
2367                        </button>
2368                        <span id="rep-toggle-label-pro" class="text-xs font-bold transition-colors duration-300" style="color:rgba(100,180,220,0.45)">🧠 Brain</span>
2369                    </div>
2370
2371                    <!-- Parallel worker slider -->
2372                    <div class="rep-worker-slider-card" aria-label="Parallel worker control">
2373                        <div class="rep-worker-copy">
2374                            <span class="rep-worker-label">Workers</span>
2375                            <span id="rep-worker-meta" class="rep-worker-meta">Parallel queue</span>
2376                        </div>
2377                        <input id="rep-worker-range" type="range" min="1" max="10" value="1"
2378                               oninput="app.setReplicateWorkers(Number(this.value)||1)"
2379                               onchange="app.setReplicateWorkers(Number(this.value)||1)"
2380                               aria-label="Parallel workers">
2381                        <span id="rep-worker-count" class="rep-worker-count">1</span>
2382                    </div>
2383
2384                    <button onclick="app.downloadReplicatePrompts()" id="rep-download-btn" class="glass-panel px-3 md:px-4 py-2 rounded-xl text-xs md:text-sm font-medium hover:bg-white/10 flex items-center gap-2 btn-spring border border-white/10 hidden" style="min-height:44px">
2385                        <i data-lucide="file-text" class="w-4 h-4 text-amber-700"></i><span class="hidden sm:inline">Export TXT</span>
2386                    </button>
2387
2388                    <input type="file" id="rep-upload" multiple accept="image/*" class="hidden" onchange="app.handleReplicateUpload(event)">
2389
2390                    <button onclick="app.processReplicateQueue()" id="rep-process-btn"
2391                        class="rep-deconstruct-btn btn-spring flex items-center gap-2"
2392                        style="min-height:44px">
2393                        <i data-lucide="zap" class="w-4 h-4"></i> Deconstruct All
2394                    </button>
2395
2396                </div>
2397            </div>
2398
2399            <!-- Upload Drop Zone -->
2400            <div id="rep-drop-zone"
2401                 class="rep-drop-zone rep-drop-clean animate-scale-in"
2402                 onclick="document.getElementById('rep-upload').click()"
2403                 ondragover="event.preventDefault();this.classList.add('drag-over')"
2404                 ondragleave="this.classList.remove('drag-over')"
2405                 ondrop="event.preventDefault();this.classList.remove('drag-over');app._handleDropZoneDrop(event)">
2406                <div class="rep-drop-clean-core" aria-hidden="true">
2407                    <i data-lucide="image-plus" class="w-9 h-9"></i>
2408                </div>
2409                <span class="sr-only">Drop or click to upload images</span>
2410            </div>
2411
2412            <!-- Rep grid — cards appear here when images are added -->
2413            <div id="rep-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-5 pb-6">
2414                <div id="rep-empty" class="hidden"></div>
2415            </div>
2416        </div>
2417        <footer class="ca-footer">
2418            <a href="https://www.comfyaicloud.com/blog/" class="ca-footer-link" style="text-decoration:none;color:#c96a00;font-weight:700">Blog</a>
2419            <span class="text-zinc-700">&middot;</span>
2420            <a href="https://www.comfyaicloud.com/terms/" class="ca-footer-link" style="text-decoration:none">Terms of Service</a>
2421            <span class="text-zinc-700">·</span>
2422            <a href="https://www.comfyaicloud.com/privacy-policy/" class="ca-footer-link" style="text-decoration:none">Privacy Policy</a>
2423            <span class="text-zinc-700">·</span>
2424            <span class="text-zinc-600">© 2026 ComfyAI Cloud</span>
2425        </footer>
2426    </section>
2427
2428    <!-- ═══ PRICING / CREDITS ═══ -->
2429    <section id="view-plans" class="view-section custom-scrollbar " >
2430        <div class="w-full px-3 md:px-6 pb-6" style="padding-top:max(6rem,calc(5rem + env(safe-area-inset-top)))">
2431
2432            <!-- Header — Premium redesign -->
2433            <div class="text-center mb-8 md:mb-12 max-w-3xl mx-auto pricing-head">
2434                <div class="pricing-pill">
2435                    <i data-lucide="gem" class="w-3 h-3"></i> AI Pricing &amp; Credits
2436                </div>
2437                <h2 class="pricing-title mt-5 mb-4">
2438                    All AI Services,<br><em>One Credit System.</em>
2439                </h2>
2440                <p class="pricing-sub text-sm md:text-lg">Buy credits once and create whenever you want. No subscription — credits never expire.</p>
2441            </div>
2442
2443            <!-- Pricing cards -->
2444            <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 max-w-7xl mx-auto w-full" style="overflow:visible">
2445
2446                <!-- $10 Starter -->
2447                <div class="pricing-card pricing-card--starter p-6 md:p-7 rounded-[1.5rem] border flex flex-col items-center text-center">
2448                    <div class="mb-5">
2449                        <div class="pricing-card-icon starter">
2450                            <i data-lucide="rocket" class="w-6 h-6"></i>
2451                        </div>
2452                        <h3 class="pricing-plan-name pricing-plan-name--starter">Starter</h3>
2453                        <p class="text-xs text-zinc-500 mt-0.5">Perfect to explore</p>
2454                    </div>
2455                    <div class="mb-4">
2456                        <div class="flex items-center justify-center">
2457                            <span class="text-4xl font-bold text-stone-800">$10</span>
2458                        </div>
2459                        <div class="ca-credit-pill starter-pill" style="margin-top:12px">
2460                            <i data-lucide="coins" class="w-3.5 h-3.5"></i>
2461                            <span class="ca-pill-credits" data-plan="starter" data-credits="1500">1,500 Credits</span>
2462                        </div>
2463                    </div>
2464                    <ul class="ca-feat-list space-y-2.5 mb-5 flex-1">
2465                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>AI Image Generation</li>
2466                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>AI Friends (Voice)</li>
2467                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>Visual Deconstruction</li>
2468                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>Social Media Content</li>
2469                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>AI Chat Hub</li>
2470                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--starter shrink-0"></i>Credits never expire</li>
2471                    </ul>
2472                    <div id="paypal-btn-10" class="ca-paypal-btn"></div>
2473                </div>
2474
2475                <!-- $25 Most Popular -->
2476                <div class="pricing-card pricing-card--creator p-6 md:p-7 rounded-[1.5rem] border flex flex-col items-center text-center relative z-10">
2477                    <div class="mb-5">
2478                        <div class="pricing-card-icon creator">
2479                            <i data-lucide="brush" class="w-6 h-6"></i>
2480                        </div>
2481                        <h3 class="pricing-plan-name pricing-plan-name--creator">Creator</h3>
2482                        <p class="text-xs text-zinc-500 mt-0.5">For regular creators</p>
2483                    </div>
2484                    <div class="mb-4">
2485                        <div class="flex items-center justify-center">
2486                            <span class="text-4xl font-bold text-stone-800">$25</span>
2487                        </div>
2488                        <div class="ca-credit-pill creator-pill" style="margin-top:12px">
2489                            <i data-lucide="coins" class="w-3.5 h-3.5"></i>
2490                            <span class="ca-pill-credits" data-plan="creator" data-credits="5750">5,750 Credits</span>
2491                        </div>
2492                    </div>
2493                    <ul class="ca-feat-list space-y-2.5 mb-5 flex-1">
2494                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>AI Image Generation</li>
2495                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>AI Friends (Voice)</li>
2496                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>Visual Deconstruction</li>
2497                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>Social Media Content</li>
2498                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>AI Chat Hub</li>
2499                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--creator shrink-0"></i>Credits never expire</li>
2500                    </ul>
2501                    <div id="paypal-btn-25" class="ca-paypal-btn"></div>
2502                </div>
2503
2504                <!-- $50 Studio Pro -->
2505                <div class="pricing-card pricing-card--studio p-6 md:p-7 rounded-[1.5rem] border flex flex-col items-center text-center">
2506                    <div class="mb-5">
2507                        <div class="pricing-card-icon studio">
2508                            <i data-lucide="layers" class="w-6 h-6"></i>
2509                        </div>
2510                        <h3 class="pricing-plan-name pricing-plan-name--studio">Studio Pro</h3>
2511                        <p class="text-xs text-zinc-500 mt-0.5">For power users</p>
2512                    </div>
2513                    <div class="mb-4">
2514                        <div class="flex items-center justify-center">
2515                            <span class="text-4xl font-bold text-stone-800">$50</span>
2516                        </div>
2517                        <div class="ca-credit-pill studio-pill" style="margin-top:12px">
2518                            <i data-lucide="coins" class="w-3.5 h-3.5"></i>
2519                            <span class="ca-pill-credits" data-plan="studio" data-credits="14000">14,000 Credits</span>
2520                        </div>
2521                    </div>
2522                    <ul class="ca-feat-list space-y-2.5 mb-5 flex-1">
2523                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>AI Image Generation</li>
2524                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>AI Friends (Voice)</li>
2525                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>Visual Deconstruction</li>
2526                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>Social Media Content</li>
2527                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>AI Chat Hub</li>
2528                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--studio shrink-0"></i>Credits never expire</li>
2529                    </ul>
2530                    <div id="paypal-btn-50" class="ca-paypal-btn"></div>
2531                </div>
2532
2533                <!-- $150 Enterprise/Max -->
2534                <div class="pricing-card pricing-card--enterprise p-6 md:p-7 rounded-[1.5rem] border flex flex-col items-center text-center">
2535                    <div class="mb-5">
2536                        <div class="pricing-card-icon enterprise">
2537                            <i data-lucide="building-2" class="w-6 h-6"></i>
2538                        </div>
2539                        <h3 class="pricing-plan-name pricing-plan-name--enterprise">Max</h3>
2540                        <p class="text-xs text-zinc-500 mt-0.5">Maximum value</p>
2541                    </div>
2542                    <div class="mb-4">
2543                        <div class="flex items-center justify-center">
2544                            <span class="text-4xl font-bold text-stone-800">$150</span>
2545                        </div>
2546                        <div class="ca-credit-pill enterprise-pill" style="margin-top:12px">
2547                            <i data-lucide="coins" class="w-3.5 h-3.5"></i>
2548                            <span class="ca-pill-credits" data-plan="enterprise" data-credits="52500">52,500 Credits</span>
2549                        </div>
2550                    </div>
2551                    <ul class="ca-feat-list space-y-2.5 mb-5 flex-1">
2552                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>AI Image Generation</li>
2553                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>AI Friends (Voice)</li>
2554                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>Visual Deconstruction</li>
2555                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>Social Media Content</li>
2556                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>AI Chat Hub</li>
2557                        <li class="plans-feat-item flex items-center gap-2"><i data-lucide="check-circle" class="w-4 h-4 ca-check--enterprise shrink-0"></i>Credits never expire</li>
2558                    </ul>
2559                    <div id="paypal-btn-150" class="ca-paypal-btn"></div>
2560                </div>
2561            </div>
2562
2563            <!-- Trust badges -->
2564            <div class="trust-badges flex flex-wrap items-center justify-center gap-6 mt-10 mb-6 text-xs text-zinc-600">
2565                <span class="flex items-center gap-1.5"><i data-lucide="shield-check" class="w-3.5 h-3.5 text-emerald-600"></i> Secure Razorpay Card Payments</span>
2566                <span class="flex items-center gap-1.5"><i data-lucide="zap" class="w-3.5 h-3.5 text-emerald-600"></i> Instant Credit Delivery</span>
2567                <span class="flex items-center gap-1.5"><i data-lucide="infinity" class="w-3.5 h-3.5 text-emerald-600"></i> Credits Never Expire</span>
2568            </div>
2569        </div>
2570        <footer class="ca-footer">
2571            <a href="https://www.comfyaicloud.com/blog/" class="ca-footer-link" style="text-decoration:none;color:#c96a00;font-weight:700">Blog</a>
2572            <span class="text-zinc-700">&middot;</span>
2573            <a href="https://www.comfyaicloud.com/terms/" class="ca-footer-link" style="text-decoration:none">Terms of Service</a>
2574            <span class="text-zinc-700">·</span>
2575            <a href="https://www.comfyaicloud.com/privacy-policy/" class="ca-footer-link" style="text-decoration:none">Privacy Policy</a>
2576            <span class="text-zinc-700">·</span>
2577            <span class="text-zinc-600">© 2026 ComfyAI Cloud</span>
2578        </footer>
2579    </section>
2580
2581    <!-- ═══ ACCOUNT ═══ -->
2582    <section id="view-account" class="view-section custom-scrollbar " >
2583        <div class="w-full px-3 md:px-6 pb-16 animate-scale-in ca-acct-page-wrap">
2584
2585            <!-- ══ PROFILE HEADER CARD — matches auth image style ══ -->
2586            <div class="ca-acct-hero-card">
2587                <div class="ca-acct-hero-left">
2588                    <div class="ca-acct-avatar-ring">
2589                        <img id="account-avatar"
2590                             src="https://secure.gravatar.com/avatar/?s=128&#038;d=mm&#038;r=g"
2591                             class="ca-acct-avatar-img"
2592                             loading="lazy" width="56" height="56">
2593                        <span class="ca-acct-avatar-dot"></span>
2594                    </div>
2595                    <div class="ca-acct-hero-info">
2596                        <div class="ca-acct-hero-name" id="account-name">Loading…</div>
2597                        <div class="ca-acct-hero-email" id="account-email">—</div>
2598                    </div>
2599                </div>
2600                <div class="ca-acct-hero-credits">
2601                    <span class="ca-acct-cred-num" id="account-credits">0</span>
2602                    <span class="ca-acct-cred-label">CREDITS</span>
2603                </div>
2604            </div>
2605
2606            <!-- ══ CREDIT SPARKLINE ══ -->
2607            <div class="ca-acct-sparkline-row" id="acct-sparkline-wrap">
2608                <div class="ca-acct-sparkline-label">7-day usage</div>
2609                <canvas id="acct-sparkline" height="32" style="flex:1;min-width:0;max-width:200px"></canvas>
2610                <div class="ca-acct-sparkline-stats" id="acct-sparkline-stats"></div>
2611            </div>
2612
2613            <!-- ══ MAIN 2-COL LAYOUT ══ -->
2614            <div class="ca-account-grid ca-acct-layout">
2615
2616                <!-- LEFT: Activity & History Panel -->
2617                <div class="glass-panel rounded-2xl md:rounded-3xl border border-white/5 flex flex-col ca-acct-left-panel" style="min-height:520px">
2618
2619                    <!-- Tab Nav -->
2620                    <div class="ca-acct-tab-nav">
2621                        <button class="ca-acct-tab active" data-tab="rewards" onclick="app.switchAccountTab('rewards',this);caRewardsLoad()">
2622                            <i data-lucide="gift" class="w-3.5 h-3.5" style="color:#10b981"></i>
2623                            <span>Rewards</span>
2624                            <span id="acct-rewards-badge" class="ca-acct-tab-badge" style="background:rgba(16,185,129,.15);color:#059669;display:none"></span>
2625                        </button>
2626                        <button class="ca-acct-tab" data-tab="prompts" onclick="app.switchAccountTab('prompts',this)">
2627                            <i data-lucide="history" class="w-3.5 h-3.5"></i>
2628                            <span>Prompt History</span>
2629                            <span id="acct-hist-count" class="ca-acct-tab-badge"></span>
2630                        </button>
2631
2632                        <div class="ca-acct-tab-actions ml-auto flex items-center gap-2">
2633                            <select id="acct-hist-sort" class="ca-acct-sort-sel hidden" onchange="app.sortAccountHistory(this.value)" title="Sort prompts">
2634                                <option value="newest">Newest first</option>
2635                                <option value="oldest">Oldest first</option>
2636                                <option value="az">A → Z</option>
2637                            </select>
2638                            <button id="acct-batch-btn" class="ca-acct-batch-btn hidden" onclick="app.toggleBatchMode()" title="Select multiple">
2639                                <i data-lucide="check-square" style="width:13px;height:13px"></i>
2640                            </button>
2641                            <button id="acct-clear-all-btn" onclick="app.clearHistory()" class="ca-acct-clear-btn hidden">
2642                                <i data-lucide="trash-2" class="w-3 h-3"></i>
2643                                <span>Clear All</span>
2644                            </button>
2645                        </div>
2646                    </div>
2647
2648                    <!-- Batch action bar (hidden until batch mode on) -->
2649                    <div id="acct-batch-bar" class="ca-acct-batch-bar hidden">
2650                        <span id="acct-batch-count" class="ca-acct-batch-count">0 selected</span>
2651                        <button onclick="app.batchDeleteSelected()" class="ca-acct-batch-del-btn">
2652                            <i data-lucide="trash-2" style="width:12px;height:12px"></i> Delete selected
2653                        </button>
2654                        <button onclick="app.toggleBatchMode(false)" class="ca-acct-batch-cancel-btn">Cancel</button>
2655                    </div>
2656
2657                    <!-- Rewards Tab — FIRST, default active -->
2658                    <div id="acct-tab-rewards" class="ca-acct-tab-panel" style="display:flex;flex-direction:column;flex:1;overflow:hidden;min-height:0">
2659                        <!-- Header -->
2660                        <div class="rw-header">
2661                            <div class="rw-header-title">
2662                                <svg width="16" height="16" viewB
2662ox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2.5"><path d="M20 12V22H4V12"/><path d="M22 7H2v5h20V7z"/><path d="M12 22V7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg>
2663                                Earn Rewards
2664                            </div>
2665                            <button class="rw-refresh-btn" onclick="caRewardsLoad()" title="Refresh">
2666                                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
2667                            </button>
2668                        </div>
2669                        <!-- Stats -->
2670                        <div class="rw-stats-row" id="rw-stats-row">
2671                            <div class="rw-stat"><div class="rw-stat-val indigo" id="rw-stat-available">—</div><div class="rw-stat-lbl">Available</div></div>
2672                            <div class="rw-stat"><div class="rw-stat-val amber"  id="rw-stat-pending">—</div><div class="rw-stat-lbl">Pending</div></div>
2673                            <div class="rw-stat"><div class="rw-stat-val green"  id="rw-stat-earned">—</div><div class="rw-stat-lbl">Earned</div></div>
2674                        </div>
2675                        <!-- Task list -->
2676                        <div id="rw-task-list">
2677                            <div class="rw-empty">
2678                                <div class="rw-empty-icon">
2679                                    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2"><path d="M20 12V22H4V12"/><path d="M22 7H2v5h20V7z"/><path d="M12 22V7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg>
2680                                </div>
2681                                <p class="rw-empty-title">Loading tasks…</p>
2682                            </div>
2683                        </div>
2684                    </div>
2685
2686                    <!-- Prompt History Tab — hidden by default -->
2687                    <div id="acct-tab-prompts" class="ca-acct-tab-panel flex-1 flex-col" style="display:none;flex-direction:column">
2688                        <div class="px-4 pt-4 pb-2 shrink-0">
2689                            <div class="relative">
2690                                <i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-zinc-500 pointer-events-none"></i>
2691                                <input id="acct-hist-search" type="text" placeholder="Search prompts… (/ to focus)"
2692                                       oninput="app.filterAccountHistory(this.value)"
2693                                       class="w-full bg-stone-100/80 border border-stone-200 rounded-xl text-xs text-stone-700 pl-8 pr-3 py-2.5 focus:outline-none placeholder-stone-400 transition-all"
2694                                       style="min-height:36px;font-size:16px">
2695                            </div>
2696                        </div>
2697                        <div id="acct-prompt-skeleton" class="ca-skeleton-wrap px-4 pt-1">
2698                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2699                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2700                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2701                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2702                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2703                                                        <div class="ca-skeleton-row ca-skel-prompt"><div style="flex:1"><div class="ca-skel" style="width:90%;height:11px;margin-bottom:6px"></div><div class="ca-skel" style="width:55%;height:11px;margin-bottom:4px"></div><div class="ca-skel" style="width:30%;height:8px"></div></div></div>
2704                                                    </div>
2705                        <div id="acct-history-list" class="custom-scrollbar px-3 pb-4 space-y-1" style="flex:1;overflow-y:auto;display:none"></div>
2706                        <div id="acct-hist-empty" class="ca-acct-empty-state hidden">
2707                            <div class="ca-acct-empty-icon"><i data-lucide="image-off" style="width:32px;height:32px;color:#d4c8be"></i></div>
2708                            <p class="ca-acct-empty-title">No prompts yet</p>
2709                            <p class="ca-acct-empty-sub">Generate images to see your history here</p>
2710                            <a href="https://www.comfyaicloud.com/generate/" class="ca-acct-empty-cta">Start Creating</a>
2711                        </div>
2712                        <div class="px-4 py-3 shrink-0" id="acct-hist-hint" style="border-top:1px solid rgba(28,25,23,0.07);display:none">
2713                            <p class="text-[10px] text-zinc-500 flex items-center gap-1.5">
2714                                <i data-lucide="mouse-pointer-click" class="w-3 h-3 text-amber-700"></i>
2715                                Click any prompt to load it · Press <kbd class="ca-kbd">/ </kbd> to search
2716                            </p>
2717                        </div>
2718                    </div>
2719
2720
2721                </div><!-- /left panel -->
2722
2723                <!-- RIGHT: Sticky Quick Actions Sidebar -->
2724                <div class="ca-acct-sidebar">
2725                    <div class="ca-acct-sidebar-inner glass-panel roun
2725ded-2xl md:rounded-3xl p-5 border border-white/5 flex flex-col gap-3">
2726                        <h3 class="font-bold text-stone-800 mb-1 flex items-center gap-2 text-sm">
2727                            <i data-lucide="zap" class="w-4 h-4 text-cyan-400"></i> Quick Actions
2728                        </h3>
2729                        <a href="https://www.comfyaicloud.com/generate/"
2730                           class="ca-acct-action-btn"
2731                           style="text-decoration:none">
2732                            <i data-lucide="image" class="w-4 h-4 text-amber-700"></i> Generate Studio
2733                        </a>
2734                        <a href="https://www.comfyaicloud.com/replicate/"
2735                           class="ca-acct-action-btn"
2736                           style="text-decoration:none">
2737                            <i data-lucide="scan-line" class="w-4 h-4 text-cyan-400"></i> Replicate Engine
2738                        </a>
2739
2740                        
2741                        <div class="ca-acct-divider"><span>Account</span></div>
2742                        <a href="https://www.comfyaicloud.com/pricing/"
2743                           class="ca-acct-action-btn ca-acct-btn-primary"
2744                           style="text-decoration:none">
2745                            <i data-lucide="plus-circle" class="w-4 h-4"></i> Buy More Credits
2746                        </a>
2747                        <a href="https://www.comfyaicloud.com/early-access/"
2748                           class="ca-acct-action-btn ca-acct-btn-green"
2749                           style="text-decoration:none">
2750                            <i data-lucide="scan-eye" class="w-4 h-4"></i> Visual Deconstruction
2751                            <span class="ca-acct-beta-badge">BETA</span>
2752                        </a>
2753                        <button onclick="caUserResetPassword(this)"
2754                                class="ca-acct-action-btn ca-acct-btn-amber">
2755                            <i data-lucide="key-round" class="w-4 h-4"></i> Reset Password
2756                        </button>
2757                        <button onclick="app.openSupport()"
2758                                class="ca-acct-action-btn ca-acct-btn-cyan">
2759                            <i data-lucide="message-circle" class="w-4 h-4"></i> Contact Support
2760                        </button>
2761                        <button onclick="app.logout()"
2762                                class="ca-acct-action-btn ca-acct-btn-danger">
2763                            <i data-lucide="log-out" class="w-4 h-4"></i> Sign Out
2764                        </button>
2765                    </div><!-- /sidebar-inner -->
2766                </div><!-- /sidebar -->
2767
2768            </div><!-- /ca-account-grid -->
2769        </div>
2770        <footer class="ca-footer">
2771            <a href="https://www.comfyaicloud.com/blog/" class="ca-footer-link" style="text-decoration:none;color:#c96a00;font-weight:700">Blog</a>
2772            <span class="text-zinc-700">&middot;</span>
2773            <a href="https://www.comfyaicloud.com/terms/" class="ca-footer-link" style="text-decoration:none">Terms of Service</a>
2774            <span class="text-zinc-700">·</span>
2775            <a href="https://www.comfyaicloud.com/privacy-policy/" class="ca-footer-link" style="text-decoration:none">Privacy Policy</a>
2776            <span class="text-zinc-700">·</span>
2777            <span class="text-zinc-600">© 2026 ComfyAI Cloud</span>
2778        </footer>
2779    </section>
2780
2781
2782    <!-- ═══ SUPPORT CHAT WIDGET ═══ -->
2783    <!-- Floating button — desktop only (CSS hides on mobile) -->
2784    <button id="ca-support-btn" class="hidden" onclick="app.toggleSupportChat()" title="Support" aria-label="Open customer support chat">
2785        <span id="ca-support-unread" class="unread-badge"></span>
2786        <i data-lucide="message-circle-more" style="width:22px;height:22px;color:#fff"></i>
2787    </button>
2788
2789    <!-- Desktop chat box -->
2790    <div id="ca-support-chat">
2791        <div class="support-chat-header">
2792            <div class="support-chat-avatar" style="background:linear-gradient(135deg,#10b981,#059669);border-color:rgba(16,185,129,0.3)">
2793                <i data-lucide="message-circle-more" style="width:20px;height:20px;color:#fff"></i>
2794            </div>
2795            <div style="flex:1;min-width:0">
2796                <div style="font-weight:700;font-size:13px;color:#111">Customer Support</div>
2797                <div style="font-size:11px;color:#10b981;font-weight:600">● Online — Usually replies quickly</div>
2798            </div>
2799            <button onclick="app.toggleSupportChat()" style="background:none;border:none;color:rgba(161,161,170,0.7);
2799cursor:pointer;padding:4px;border-radius:8px;min-height:auto;display:flex;align-items:center" class="btn-spring hover:text-stone-800">
2800                <i data-lucide="x" style="width:16px;height:16px"></i>
2801            </button>
2802        </div>
2803        <div class="support-chat-messages custom-scrollbar" id="ca-chat-messages"></div>
2804
2805        <!-- Quick-help chips for desktop — hidden after first message -->
2806        <div id="ca-chat-chips" class="ca-support-chips-row" style="padding:8px 12px 4px">
2807            <p class="ca-support-chips-label">Common topics — tap to send</p>
2808            <div class="ca-support-chips-list">
2809                <button onclick="app.sendSupportChip(this,'💳 Billing &amp; Credits')"              class="ca-chip-btn">💳 Billing</button>
2810                <button onclick="app.sendSupportChip(this,'🖼 Image not generating')"               class="ca-chip-btn">🖼 Not generating</button>
2811                <button onclick="app.sendSupportChip(this,'🔄 Credits not added after payment')"    class="ca-chip-btn">🔄 Credits missing</button>
2812                <button onclick="app.sendSupportChip(this,'🔑 Can\'t sign in')"                    class="ca-chip-btn">🔑 Sign in issue</button>
2813                <button onclick="app.sendSupportChip(this,'📷 Replicate not working')"              class="ca-chip-btn">📷 Replicate issue</button>
2814            </div>
2815        </div>
2816
2817        <div class="support-chat-input-row">
2818            <textarea id="ca-chat-input" placeholder="Type your message…" rows="1"
2819                      oninput="this.style.height='auto';this.style.height=Math.min(this.scrollHeight,112)+'px'"
2820                      onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();app.sendSupportMessage();}"></textarea>
2821            <button class="support-chat-send btn-spring" onclick="app.sendSupportMessage()">
2822                <i data-lucide="send" style="width:15px;height:15px"></i>
2823            </button>
2824        </div>
2825    </div>
2826
2827    <!-- ═══ MOBILE FULL-PAGE SUPPORT CHAT ═══ -->
2828    <section id="view-support" class="view-section custom-scrollbar" style="background:var(--bg)">
2829        <!-- Back header bar -->
2830        <div class="ca-support-page-topbar">
2831            <button onclick="app.closeSupportPage()" class="ca-support-back-btn btn-spring">
2832                <i data-lucide="chevron-left" style="width:20px;height:20px"></i>
2833                <span>Back</span>
2834            </button>
2835            <div class="ca-support-page-title">
2836                <div class="ca-support-page-avatar" style="background:linear-gradient(135deg,#10b981,#059669);border-color:rgba(16,185,129,0.3)">
2837                    <i data-lucide="message-circle-more" style="width:20px;height:20px;color:#fff"></i>
2838                </div>
2839                <div>
2840                    <div style="font-weight:700;font-size:14px;color:#111;line-height:1.2">Customer Support</div>
2841                    <div style="font-size:11px;color:#10b981;font-weight:600">● Online · Replies quickly</div>
2842                </div>
2843            </div>
2844            <div style="width:60px"></div><!-- spacer for centering -->
2845        </div>
2846
2847        <!-- Chat area -->
2848        <div id="ca-support-page-messages" class="ca-support-page-messages custom-scrollbar"></div>
2849
2850        <!-- Quick-help chips (shown until first user message) -->
2851        <div id="ca-support-chips" class="ca-support-chips-row">
2852            <p class="ca-support-chips-label">Common topics — tap to send</p>
2853            <div class="ca-support-chips-list">
2854                <button onclick="app.sendSupportChip(this,'💳 Billing &amp; Credits')"    class="ca-chip-btn">💳 Billing &amp; Credits</button>
2855                <button onclick="app.sendSupportChip(this,'🖼 Image not generating')"     class="ca-chip-btn">🖼 Image not generating</button>
2856                <button onclick="app.sendSupportChip(this,'🔄 Credits not added after payment')" class="ca-chip-btn">🔄 Credits not added after payment</button>
2857                <button onclick="app.sendSupportChip(this,'🔑 Can\'t sign in')"           class="ca-chip-btn">🔑 Can't sign in</button>
2858                <button onclick="app.sendSupportChip(this,'📷 Replicate not working')"    class="ca-chip-btn">📷 Replicate not working</button>
2859                <button onclick="app.sendSupportChip(this,'🗑 Delete my account')"        class="ca-chip-btn">🗑 Delete my account</button>
2860            </div>
2861        </div>
2862
2863        <!-- Input bar — sticky bottom -->
2864        <div class="ca-support-page-input-bar">
2865            <div class="ca-support-page-input-wrap">
2866                <textarea id="ca-support-page-input"
2867                    placeholder="Message support…" rows="1"
2868                    oninput="this.style.height='auto';this.style.height=Math.min(this.scrollHeight,100)+'px'"
2869                    onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();app.sendSupportPageMessage();}"></textarea>
2870                <button onclick="app.sendSupportPageMessage()" class="ca-support-page-send btn-spring">
2871                    <i data-lucide="arrow-up" style="width:16px;height:16px"></i>
2872                </button>
2873            </div>
2874            <p class="ca-support-page-disclaimer">Usually replies within a few hours · <a href="https://www.comfyaicloud.com/terms/" style="color:rgba(113,113,122,0.6);font-size:10px;text-decoration:none">Terms</a></p>
2875        </div>
2876    </section>
2877
2878
2879
2880
2881    <!-- ═══ ADMIN ═══ -->
2882    <section id="view-admin" class="view-section custom-scrollbar" >
2883        <div class="max-w-3xl mx-auto w-full px-4 md:px-6 pb-16 animate-scale-in"
2884             style="padding-top:max(6rem,calc(5rem + env(safe-area-inset-top)))">
2885            <h2 class="text-2xl md:text-3xl font-bold text-stone-800 mb-6 flex items-center gap-3">
2886                <i data-lucide="shield" class="w-7 h-7 text-red-400"></i> Admin Area
2887            </h2>
2888            <div class="glass-panel rounded-2xl md:rounded-3xl border border-white/5 p-6 text-center">
2889                <p class="text-zinc-400 mb-4">All settings are managed in the WordPress Dashboard.</p>
2890                <a href="https://www.comfyaicloud.com/wp-admin/options-general.php?page=ca-settings" class="inline-block px-6 py-3 bg-white text-black font-bold rounded-xl hover:bg-zinc-100 btn-spring" style="min-height:48px">
2891                    Open ComfyAICloud Settings
2892                </a>
2893            </div>
2894        </div>
2895    </section>
2896
2897</main>
2898
2899<!-- ════════════════════════════════════════
2900     MOBILE HISTORY BOTTOM SHEET
2901════════════════════════════════════════ -->
2902<div id="history-sheet-backdrop" class="history-sheet-backdrop"></div>
2903<div id="history-sheet" class="history-sheet">
2904    <div class="p-4 border-b border-white/5 flex justify-between items-center shrink-0 relative">
2905        <div class="w-12 h-1 bg-stone-300 rounded-full mx-auto absolute left-1/2 -translate-x-1/2 top-2.5"></div>
2906        <h3 class="font-semibold text-sm flex items-center gap-2 text-stone-800 mt-2"><i data-lucide="history" class="w-4 h-4 text-amber-700"></i> Prompt History</h3>
2907        <div class="flex items-center gap-2">
2908            <button onclick="app.clearHistory()" class="text-zinc-500 hover:text-red-400 bg-stone-200/60 p-2 rounded-xl btn-spring" style="min-height:40px;min-width:40px"><i data-lucide="trash-2" class="w-4 h-4"></i></button>
2909            <button onclick="app.closeHistorySheet()" class="text-zinc-500 hover:text-stone-800 bg-white/5 p-2 rounded-xl btn-spring" style="min-height:40px;min-width:40px"><i data-lucide="x" class="w-4 h-4"></i></button>
2910        </div>
2911    </div>
2912    <div id="history-list-mobile" class="flex-1 overflow-y-auto custom-scrollbar p-4 space-y-4" style="scroll-behavior:smooth"></div>
2913</div>
2914
2915<!-- ════════════════════════════════════════
2916     PROFILE MODAL
2917════════════════════════════════════════ -->
2918<div id="profile-modal" class="modal-backdrop hidden" onclick="if(event.target===this)app.closeModal('profile-modal')">
2919    <div class="modal-sheet ca-profile-popup-sheet">
2920        <div class="modal-drag-handle md:hidden"></div>
2921
2922        <!-- Close -->
2923        <button onclick="app.closeModal('profile-modal')"
2924                class="ca-popup-close-btn" aria-label="Close">
2925            <i data-lucide="x" class="w-4 h-4"></i>
2926        </button>
2927
2928        <!-- Avatar + Identity -->
2929        <div class="ca-popup-identity">
2930            <div class="ca-popup-avatar-wrap">
2931                <img id="profile-dp"
2932                     src="https://secure.gravatar.com/avatar/?s=128&#038;d=mm&#038;r=g"
2933                     class="ca-popup-avatar"
2934                     loading="lazy" width="72" height="72">
2935                <span class="ca-popup-avatar-dot"></span>
2936            </div>
2937            <h3 id="profile-name" class="ca-popup-name">Guest</h3>
2938            <p id="profile-email-text" class="ca-popup-email">—</p>
2939            <div class="ca-popup-balance">
2940                Balance <span id="profile-credits-display" class="ca-popup-credits">0</span> Cr
2941            </div>
2942        </div>
2943
2944        <div class="ca-popup-divider"></div>
2945
2946        <!-- Navigation links -->
2947        <nav class="ca-popup-nav">
2948            <a href="https://www.comfyaicloud.com/account/"
2949               onclick="app.closeModal('profile-modal')"
2950               class="ca-popup-link">
2951                <i data-lucide="user" class="w-4 h-4"></i>
2952                <span>My Account</span>
2953                <i data-lucide="chevron-right" class="ca-popup-chevron"></i>
2954            </a>
2955                    </nav>
2956
2957        <!-- Sign out -->
2958        <button onclick="app.logout()" class="ca-popup-signout-btn">
2959            <i data-lucide="log-out" class="w-4 h-4"></i> Sign Out
2960        </button>
2961    </div>
2962</div>
2963
2964<!-- ════════════════════════════════════════
2965     AUTH MODAL — Google + Email Sign In/Register
2966════════════════════════════════════════ -->
2967<div id="auth-modal" class="modal-backdrop hidden">
2968    <div class="modal-sheet" style="max-width:420px">
2969        <div class="modal-drag-handle md:hidden"></div>
2970        <button onclick="app.closeModal('auth-modal')" class="absolute top-4 right-4 text-zinc-500 hover:text-stone-800 bg-stone-100 p-2 rounded-full" style="min-height:40px;min-width:40px;display:flex;align-items:center;justify-content:center">
2971            <i data-lucide="x" class="w-4 h-4"></i>
2972        </button>
2973
2974        <!-- Logo -->
2975        <div class="text-center mb-5">
2976            <div class="relative w-14 h-14 mx-auto mb-3">
2977                <img id="auth-modal-logo"
2978                     src="https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png"
2979                     alt="ComfyAI Cloud" width="56" height="56"
2980                     onerror="this.onerror=null;this.src='https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/logo.png';this.style.display='block';"
2981                     style="width:56px;height:56px;border-radius:50%;object-fit:cover;display:block;filter:drop-shadow(0 0 10px rgba(56,189,248,0.5));">
2982            </div>
2983            <h3 class="text-xl font-black text-stone-800 mb-1">Welcome to ComfyAI Cloud</h3>
2984            <p class="text-xs text-zinc-500"><span class="text-amber-700 font-bold">New accounts get 100 free credits 🎁</span></p>
2985        </div>
2986
2987        <!-- ── Panel: Social logins (default) ── -->
2988        <div id="auth-panel-social">
2989            <!-- Google -->
2990            <div id="google-signin-btn" class="flex justify-center" style="min-height:48px"></div>
2991
2992            <!-- Discord -->
2993            <button onclick="app.discordLogin()" id="discord-signin-btn"
2994                style="display:flex;align-items:center;justify-content:center;gap:10px;width:100%;margin-top:10px;padding:11px 16px;border-radius:8px;background:#5865F2;color:#fff;font-size:14px;font-weight:600;border:none;cursor:pointer;transition:background 0.2s"
2995                onmouseover="this.style.background='#4752c4'" onmouseout="this.style.background='#5865F2'">
2996                <svg width="20" height="20" viewBox="0 0 71 55" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M60.1 4.9A58.5 58.5 0 0 0 45.5.4a40.8 40.8 0 0 0-1.8 3.7 54 54 0 0 0-16.4 0A37.7 37.7 0 0 0 25.4.4 58.4 58.4 0 0 0 10.8 4.9C1.6 18.7-1 32.2.3 45.5a59.1 59.1 0 0 0 18 9.1 44.6 44.6 0 0 0 3.8-6.3 38.3 38.3 0 0 1-6-2.9l1.5-1.2a42 42 0 0 0 36 0l1.5 1.2a38.4 38.4 0 0 1-6 2.9 44.3 44.3 0 0 0 3.8 6.3 58.9 58.9 0 0 0 18-9 59 59 0 0 0-10.8-39ZM23.7 37.3c-3.5 0-6.4-3.3-6.4-7.3s2.8-7.3 6.4-7.3c3.5 0 6.4 3.2 6.3 7.3 0 4-2.8 7.3-6.3 7.3Zm23.5 0c-3.5 0-6.4-3.3-6.4-7.3s2.8-7.3 6.4-7.3c3.5 0 6.4 3.2 6.3 7.3 0 4-2.8 7.3-6.3 7.3Z" fill="currentColor"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h71v55H0z"/></clipPath></defs></svg>
2997                Continue with Discord
2998            </button>
2999
3000            <!-- Divider -->
3001            <div style="display:flex;align-items:center;gap:10px;margin:14px 0">
3002                <div style="flex:1;height:1px;background:#e4e4e7"></div>
3003                <span style="font-size:11px;color:#a1a1aa;white-space:nowrap">or use email</span>
3004                <div style="flex:1;height:1px;background:#e4e4e7"></div>
3005            </div>
3006
3007            <!-- Email tabs -->
3008            <div style="display:flex;border:1px solid #e4e4e7;border-radius:10px;overflow:hidden;margin-bottom:14px">
3009                <button class="ca-auth-tab-btn active" data-tab="email-login"
3010                    onclick="app.switchAuthTab('email-login')"
3011                    style="flex:1;padding:9px;font-size:13px;font-weight:600;border:none;background:#f4f4f5;color:#3f3f46;cursor:pointer;transition:all 0.2s">Sign In</button>
3012                <button class="ca-auth-tab-btn" data-tab="email-register"
3013                    onclick="app.switchAuthTab('email-register')"
3014                    style="flex:1;padding:9px;font-size:13px;font-weight:600;border:none;background:transparent;color:#71717a;cursor:pointer;transition:all 0.2s">Create Account</button>
3015            </div>
3016
3017            <!-- Email login form -->
3018            <div id="auth-email-login">
3019                <input id="auth-login-email" type="email" placeholder="Email address" autocomplete="email"
3020                    style="width:100%;padding:10px 12px;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;margin-bottom:8px;box-sizing:border-box;outline:none">
3021                <input id="auth-login-password" type="password" placeholder="Password" autocomplete="current-password"
3022                    style="width:100%;padding:10px 12px;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;margin-bottom:10px;box-sizing:border-box;outline:none">
3023                <button onclick="app.emailLogin()" class="ca-auth-submit-btn"
3024                    style="width:100%;padding:11px;background:#18181b;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:700;cursor:pointer;transition:opacity 0.2s">Sign In</button>
3025            </div>
3026
3027            <!-- Email register form -->
3028            <div id="auth-email-register" style="display:none">
3029                <input id="auth-reg-name" type="text" placeholder="Display name (optional)" autocomplete="name"
3030                    style="width:100%;padding:10px 12px;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;margin-bottom:8px;box-sizing:border-box;outline:none">
3031                <input id="auth-reg-email" type="email" placeholder="Email address" autocomplete="email"
3032                    style="width:100%;padding:10px 12px;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;margin-bottom:8px;box-sizing:border-box;outline:none">
3033                <input id="auth-reg-password" type="password" placeholder="Password (min 6 chars)" autocomplete="new-password"
3034                    style="width:100%;padding:10px 12px;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;margin-bottom:10px;box-sizing:border-box;outline:none">
3035                <button onclick="app.emailRegister()" class="ca-auth-submit-btn"
3036                    style="width:100%;padding:11px;background:#18181b;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:700;cursor:pointer;transition:opacity 0.2s">Create Account</button>
3037            </div>
3038
3039            <!-- Error message -->
3040            <p id="auth-error" class="text-red-400 text-xs text-center hidden mt-3 mb-1 px-2"></p>
3041        </div>
3042
3043        <!-- ── Panel: Verification pending ── -->
3044        <div id="auth-panel-verify" style="display:none;text-align:center;padding:10px 0">
3045            <div style="font-size:3rem;margin-bottom:10px">📧</div>
3046            <h4 style="font-size:16px;font-weight:800;color:#18181b;margin:0 0 8px">Check your inbox!</h4>
3047            <p style="font-size:13px;color:#71717a;margin:0 0 4px">We sent a verification link to</p>
3048            <p id="auth-verify-email-display" style="font-size:13px;font-weight:700;color:#18181b;margin:0 0 16px;word-break:break-all"></p>
3049            <p style="font-size:12px;color:#a1a1aa;margin:0 0 18px;line-height:1.5">Click the link in the email to activate your account and receive your free credits. Check spam if you don't see it.</p>
3050            <button onclick="app.resendVerification()" id="auth-resend-btn"
3051                style="padding:9px 20px;background:#f4f4f5;color:#3f3f46;border:1px solid #e4e4e7;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer">
3052                Resend Email
3053            </button>
3054            <p id="auth-resend-msg" style="font-size:11px;color:#16a34a;margin-top:8px;display:none"></p>
3055            <p style="margin-top:14px"><button onclick="app._showAuthPanel('social')" style="background:none;border:none;color:#a1a1aa;font-size:12px;cursor:pointer;text-decoration:underline">← Back to sign in</button></p>
3056        </div>
3057
3058        <!-- Terms -->
3059        <p class="text-center text-[10px] text-zinc-600 leading-relaxed mt-5">
3060            By continuing you agree to our
3061            <a href="https://www.comfyaicloud.com/terms/" class="text-zinc-500 hover:text-stone-800 underline" style="text-decoration:underline">Terms</a> and
3062            <a href="https://www.comfyaicloud.com/privacy-policy/" class="text-zinc-500 hover:text-stone-800 underline" style="text-decoration:underline">Privacy Policy</a>.
3063        </p>
3064    </div>
3065</div>
3066
3067<!-- ════════════════════════════════════════
3068     CODE MODAL (Admin only)
3069════════════════════════════════════════ -->
3070<div id="code-modal" class="modal-backdrop hidden">
3071    <div class="modal-sheet" style="max-width:640px">
3072        <div class="flex justify-between items-center mb-4">
3073            <h3 class="text-sm font-bold text-stone-800 flex items-center gap-2"><i data-lucide="terminal" class="w-4 h-4 text-amber-700"></i> API Payload</h3>
3074            <button onclick="app.closeModal('code-modal')" class="text-zinc-500 hover:text-stone-800 bg-stone-100 p-1.5 rounded-lg" style="min-height:36px;min-width:36px;display:flex;align-items:center;justify-content:center"><i data-lucide="x" class="w-4 h-4"></i></button>
3075        </div>
3076        <div class="bg-stone-800/90 rounded-xl p-4 overflow-auto" style="max-height:50vh">
3077            <pre id="code-block" class="text-xs font-mono text-amber-700/80 whitespace-pre-wrap"></pre>
3078        </div>
3079    </div>
3080</div>
3081
3082<script>
3083/* ═══════════════════════════════════════
3084   REWARDS — User JS v24 (clean rebuild)
3085═══════════════════════════════════════ */
3086var _rwLoaded = false;
3087var _rwTasks  = [];
3088
3089function rwEsc(s) {
3090    return String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
3091}
3092
3093function caRwToast(msg, type) {
3094    if (typeof app !== 'undefined' && app.showToast) { app.showToast(msg, type || ''); return; }
3095    var d = document.createElement('div');
3096    d.style.cssText = 'position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:rgba(9,9,13,.94);color:#fff7ed;padding:10px 20px;border-radius:999px;font-size:.78rem;font-weight:700;z-index:9999;border:1px solid ' + (type === 'error' ? 'rgba(251,113,133,.72)' : 'rgba(251,113,133,.58)') + ';box-shadow:0 18px 48px rgba(0,0,0,.38),0 0 34px rgba(244,63,94,.14)';
3097    d.textContent = msg;
3098    document.body.appendChild(d);
3099    setTimeout(function() { d.style.opacity = '0'; d.style.transition = 'opacity .3s'; setTimeout(function() { d.remove(); }, 300); }, 3000);
3100}
3101
3102function caRewardsSetList(html) {
3103    var el = document.getElementById('rw-task-list');
3104    if (el) el.innerHTML = html;
3105}
3106
3107function caRewardsSkeletonHTML() {
3108    var card = '<div class="rw-skeleton-card" style="margin-bottom:.75rem">' +
3109        '<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.75rem">' +
3110        '<div><div class="rw-skel" style="width:180px;height:13px;margin-bottom:8px"></div><div class="rw-skel" style="width:110px;height:9px"></div></div>' +
3111        '<div class="rw-skel" style="width:88px;height:26px;border-radius:999px"></div></div>' +
3112        '<div class="rw-skel" style="width:100%;height:9px;margin-bottom:6px"></div>' +
3113        '<div class="rw-skel" style="width:75%;height:9px;margin-bottom:14px"></div>' +
3114        '<div class="rw-skel" style="width:100%;height:68px;border-radius:10px"></div></div>';
3115    return card + card;
3116}
3117
3118async function caUserResetPassword(btn) {
3119    if (!confirm('Send a password reset email to your registered email address?')) return;
3120    if (btn) { btn.disabled = true; btn.innerHTML = '<i data-lucide="loader" class="w-4 h-4 animate-spin"></i> Sending…'; }
3121    try {
3122        var fd = new FormData();
3123        fd.append('action', 'ca_user_request_password_reset');
3124        fd.append('nonce', CA.nonce);
3125        var res = await fetch(CA.ajax_url, { method: 'POST', body: fd, credentials: 'same-origin' });
3126        var data = await res.json();
3127        if (data.success) {
3128            if (btn) { btn.innerHTML = '<i data-lucide="check" class="w-4 h-4"></i> Email Sent!'; btn.style.borderColor = 'rgba(16,185,129,.4)'; btn.style.color = '#059669'; }
3129            alert('✅ ' + data.data.message);
3130        } else {
3131            if (btn) { btn.innerHTML = '<i data-lucide="x" class="w-4 h-4"></i> Failed'; btn.style.color = '#dc2626'; }
3132            alert('❌ ' + (data.data?.message || 'Failed'));
3133        }
3134    } catch(e) {
3135        if (btn) { btn.innerHTML = '<i data-lucide="x" class="w-4 h-4"></i> Error'; }
3136        alert('Error: ' + e.message);
3137    }
3138    setTimeout(function() {
3139        if (btn) { btn.disabled = false; btn.innerHTML = '<i data-lucide="key-round" class="w-4 h-4"></i> Reset Password'; btn.style.borderColor = ''; btn.style.color = ''; }
3140        if (typeof lucide !== 'undefined') lucide.createIcons();
3141    }, 4000);
3142}
3143
3144async function caRewardsLoad() {
3145    _rwLoaded = true;
3146    caRewardsSetList(caRewardsSkeletonHTML());
3147    try {
3148        var fd = new FormData();
3149        fd.append('action', 'ca_get_reward_tasks');
3150        fd.append('nonce', CA.nonce);
3151        var res  = await fetch(CA.ajax_url, { method: 'POST', body: fd, credentials: 'same-origin' });
3152        var data = await res.json();
3153        if (!data.success) {
3154            caRewardsSetList('<div class="rw-empty"><div class="rw-empty-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/>
3154<line x1="12" y1="16" x2="12.01" y2="16"/></svg></div><p class="rw-empty-title">Unable to load tasks</p><p class="rw-empty-sub">Please try refreshing the page.</p></div>');
3155            return;
3156        }
3157        _rwTasks = data.data.tasks || [];
3158        caRewardsRender(_rwTasks);
3159    } catch(e) {
3160        caRewardsSetList('<div class="rw-empty"><div class="rw-empty-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div><p class="rw-empty-title">Connection error</p><p class="rw-empty-sub">Check your connection and try again.</p></div>');
3161    }
3162}
3163
3164function caRewardsRender(tasks) {
3165    var available = 0, pending = 0, earned = 0;
3166    for (var i = 0; i < tasks.length; i++) {
3167        var t = tasks[i];
3168        if (t.sub_status === 'approved') earned += parseInt(t.credits || 0);
3169        else if (t.sub_status === 'pending') pending++;
3170        else available++;
3171    }
3172    var sa = document.getElementById('rw-stat-available'); if (sa) sa.textContent = available;
3173    var sp = document.getElementById('rw-stat-pending');   if (sp) sp.textContent = pending;
3174    var se = document.getElementById('rw-stat-earned');    if (se) se.textContent = earned;
3175
3176    var badge = document.getElementById('acct-rewards-badge');
3177    if (badge) {
3178        var cnt = pending || available;
3179        badge.textContent = cnt || '';
3180        badge.style.display = cnt ? '' : 'none';
3181    }
3182
3183    if (!tasks.length) {
3184        caRewardsSetList(
3185            '<div class="rw-empty">' +
3186            '<div class="rw-empty-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2"><path d="M20 12V22H4V12"/><path d="M22 7H2v5h20V7z"/><path d="M12 22V7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg></div>' +
3187            '<p class="rw-empty-title">No tasks yet</p>' +
3188            '<p class="rw-empty-sub">The admin will post reward tasks soon. Come back to earn free credits!</p>' +
3189            '</div>'
3190        );
3191        return;
3192    }
3193    var html = '';
3194    for (var j = 0; j < tasks.length; j++) {
3195        html += caRewardsCardHTML(tasks[j]);
3196    }
3197    caRewardsSetList(html);
3198}
3199
3200function caRewardsCardHTML(t) {
3201    var sub = t.sub_status || '';
3202    var cardCls = sub === 'approved' ? 'status-approved' : sub === 'pending' ? 'status-pending' : sub === 'retry' ? 'status-retry' : '';
3203    var pillState = sub === 'approved' ? 'state-done' : (!sub || sub === 'retry') ? 'state-open' : 'state-locked';
3204    var pillIcon  = sub === 'approved' ? '&#10003;' : pillState === 'state-open' ? '&#10022;' : '&#9675;';
3205
3206    var statusMap = { '': ['s-open','Available'], 'pending': ['s-pending','Under Review'], 'approved': ['s-approved','Approved'], 'retry': ['s-retry','Revise &amp; Resubmit'] };
3207    var statusInfo = statusMap[sub] || statusMap[''];
3208    var statusCls = statusInfo[0], statusTxt = statusInfo[1];
3209
3210    // Parse steps robustly
3211    var stepsHTML = '';
3212    var rawSteps = t.steps || '';
3213    if (rawSteps) {
3214        var steps = [];
3215        try { steps = JSON.parse(rawSteps); } catch(e1) {
3216            try {
3217                // Try unescaping doubled backslashes before re-parsing
3218                var cleaned = rawSteps;
3219                cleaned = cleaned.replace(/\\"/g, '"');
3220                steps = JSON.parse(cleaned);
3221            } catch(e2) {
3222                // fallback: treat as single step
3223                steps = [rawSteps.replace(/^\["|"\]$/g, '').replace(/\\"/g, '"')];
3224            }
3225        }
3226        if (!Array.isArray(steps)) steps = [String(steps)];
3227        steps = steps.filter(function(s) { return String(s).trim(); });
3228
3229        if (steps.length) {
3230            var stepColors = ['#b45309','#4f46e5','#0e7490','#16a34a','#9333ea','#dc2626'];
3231            var stepBgs    = ['rgba(245,158,11,0.08)','rgba(99,102,241,0.07)','rgba(6,182,212,0.07)','rgba(22,163,74,0.07)','rgba(147,51,234,0.07)','rgba(239,68,68,0.07)'];
3232            var stepsInner = '';
3233            for (var k = 0; k < steps.length; k++) {
3234                var col = stepColors[k % stepColors.length];
3235                var bg  = stepBgs[k % stepBgs.length];
3236                stepsInner +=
3237                    '<div class="rw-step">' +
3238                    '<div class="rw-step-num" style="color:' + col + ';background:' + bg + '">' + (k + 1) + '</div>' +
3239                    '<div class="rw-step-text">' + rwEsc(String(steps[k])) + '</div>' +
3240                    '</div>';
3241            }
3242            stepsHTML = '<div class="rw-steps">' + stepsInner + '</div>';
3243        }
3244    }
3245
3246    // Bottom area
3247    var bottomHTML = '';
3248    var credits = parseInt(t.credits || 0).toLocaleString();
3249    if (sub === 'approved') {
3250        var note = t.admin_note ? '<br><span style="opacity:.75;font-size:.7rem">' + rwEsc(t.admin_note) + '</span>' : '';
3251        bottomHTML = '<div class="rw-feedback fb-approved"><div class="rw-feedback-icon"><span class="rw-check-anim">&#10003;</span></div><div><strong>Approved!</strong> ' + credits + ' credits added to your account.' + note + '</div></div>';
3252    } else if (sub === 'pending') {
3253        bottomHTML = '<div class="rw-feedback fb-pending"><div class="rw-feedback-icon">&#9203;</div><div><strong>Submitted — under review.</strong><br>You will receive <strong>' + credits + ' credits</strong> once approved.</div></div>';
3254    } else {
3255        var retryNote = '';
3256        if (sub === 'retry' && t.admin_note) {
3257            retryNote = '<div class="rw-feedback fb-retry" style="margin-bottom:.625rem"><div class="rw-feedback-icon">&#8617;</div><div><strong>Revision needed:</strong> ' + rwEsc(t.admin_note) + '</div></div>';
3258        }
3259        bottomHTML = retryNote +
3260            '<div class="rw-submit-area">' +
3261            '<div class="rw-submit-label"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>Submit Your Proof</div>' +
3262            '<textarea class="rw-submit-input" id="rw-proof-' + t.id + '" rows="2" placeholder="Paste your Reddit or DeviantArt post link here\u2026"></textarea>' +
3263            '<div class="rw-submit-footer"><span style="font-size:.67rem;color:var(--text-3);flex:1">Reviewed within 24 hours</span>' +
3264            '<button class="rw-submit-btn btn-spring" onclick="caRewardsSubmit(' + t.id + ',this)">' +
3265            '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>Submit</button></div>' +
3266            '</div>';
3267    }
3268
3269    return '<div class="rw-task-card ' + cardCls + '">' +
3270        '<div class="rw-task-stripe"></div>' +
3271        '<div class="rw-task-body">' +
3272        '<div class="rw-task-top">' +
3273        '<div style="flex:1;min-width:0"><div class="rw-task-title">' + rwEsc(t.title) + '</div>' +
3274        '<div style="margin-top:.3rem"><span class="rw-status ' + statusCls + '">' + statusTxt + '</span></div></div>' +
3275        '<div class="rw-credit-pill ' + pillState + '"><span class="rw-pill-icon">' + pillIcon + '</span><span>' + credits + ' credits</span></div>' +
3276        '</div>' +
3277        (t.description ? '<p class="rw-task-desc">' + rwEsc(t.description) + '</p>' : '') +
3278        stepsHTML + bottomHTML +
3279        '</div></div>';
3280}
3281
3282async function caRewardsSubmit(taskId, btn) {
3283    var proofEl = document.getElementById('rw-proof-' + taskId);
3284    var proof   = proofEl ? proofEl.value.trim() : '';
3285    if (!proof) { caRwToast('Please paste your post link before submitting', 'error'); if (proofEl) proofEl.focus(); return; }
3286
3287    btn.disabled = true;
3288    btn.textContent = 'Submitting\u2026';
3289
3290    try {
3291        var fd = new FormData();
3292        fd.append('action',  'ca_submit_reward_task');
3293        fd.append('nonce',   CA.nonce);
3294        fd.append('task_id', taskId);
3295        fd.append('proof',   proof);
3296        var res  = await fetch(CA.ajax_url, { method: 'POST', body: fd, credentials: 'same-origin' });
3297        var data = await res.json();
3298        if (data.success) {
3299            caRwToast('Submitted! Under review now.', 'success');
3300            setTimeout(function() { caRewardsLoad(); }, 500);
3301        } else {
3302            caRwToast(data.data && data.data.message ? data.data.message : 'Error submitting', 'error');
3303            btn.disabled = false;
3304            btn.innerHTML = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg> Submit';
3305        }
3306    } catch(e) {
3307        caRwToast('Network error — please try again', 'error');
3308        btn.disabled = false;
3309        btn.textContent = 'Submit';
3310    }
3311}
3312
3313// ── Android detection — UserAgent is the only reliable method ──
3314// CSS @supports / @media cannot override inline styles set by JS.
3315var _isAndroid = /Android/i.test(navigator.userAgent);
3316
3317// ── Android: remove Rewards from DOM entirely before anything renders ──
3318if (_isAndroid) {
3319    document.addEventListener('DOMContentLoaded', function() {
3320        // Remove the Rewards tab button
3321        var rewardsBtn = document.querySelector('.ca-acct-tab[data-tab="rewards"]');
3322        if (rewardsBtn) rewardsBtn.remove();
3323
3324        // Remove the Rewards tab panel
3325        var rewardsPanel = document.getElementById('acct-tab-rewards');
3326        if (rewardsPanel) rewardsPanel.remove();
3327
3328        // Remove the badge
3329        var rewardsBadge = document.getElementById('acct-rewards-badge');
3330        if (rewardsBadge) rewardsBadge.remove();
3331
3332        // Activate Prompt History tab as the new default
3333        var promptsBtn = document.querySelector('.ca-acct-tab[data-tab="prompts"]');
3334        var promptsPanel = document.getElementById('acct-tab-prompts');
3335        if (promptsBtn) {
3336            promptsBtn.classList.add('active');
3337            promptsBtn.style.borderBottomColor = '#f59e0b';
3338        }
3339        if (promptsPanel) {
3340            promptsPanel.style.display = 'flex';
3341            promptsPanel.style.flexDirection = 'column';
3342        }
3343        // Deactivate the (now removed) rewards tab's active class on any remaining sibling
3344        document.querySelectorAll('.ca-acct-tab').forEach(function(t) {
3345            if (t.dataset.tab !== 'prompts') t.classList.remove('active');
3346        });
3347    });
3348} else {
3349    // Non-Android: auto-load rewards when account page opens
3350    document.addEventListener('DOMContentLoaded', function() {
3351        setTimeout(function() {
3352            var p = document.getElementById('acct-tab-rewards');
3353            if (p && p.style.display !== 'none') {
3354                caRewardsLoad();
3355            }
3356        }, 200);
3357    });
3358}
3359</script>
3359
3360
3361
3362<script>
3363/* ════════════════════════════════════════════════════════════
3364   HOME-PAGE STITCH SYSTEM
3365   1. Keep body.home-page in sync when user navigates views
3366   2. Mirror nav-avatar into home stitch header
3367   3. After sign-in on home → redirect to /generate/
3368   ════════════════════════════════════════════════════════════ */
3369(function () {
3370    'use strict';
3371
3372    function _syncHomeClass(viewName) {
3373        var isHome = (viewName === 'home');
3374        document.documentElement.classList.toggle('home-page', isHome);
3375        document.body && document.body.classList.toggle('home-page', isHome);
3376        /* Toggle app-root between scrollable (home) and fixed (other views) */
3377        var appRoot = document.getElementById('app-root');
3378        if (appRoot) {
3379            appRoot.style.height = isHome ? 'auto' : '100svh';
3380            appRoot.style.minHeight = isHome ? '100svh' : '';
3381            appRoot.style.overflow = isHome ? 'visible' : '';
3382        }
3383        /* Hide/show all non-active views to prevent bleed-through */
3384        var allViews = document.querySelectorAll('.view-section');
3385        for (var i = 0; i < allViews.length; i++) {
3386            var v = allViews[i];
3387            if (isHome && !v.classList.contains('active')) {
3388                v.style.display = 'none';
3389            } else if (!isHome && v.style.display === 'none' && !v.classList.contains('active')) {
3390                v.style.display = '';
3391            }
3392        }
3393        /* When leaving home, restore active view display */
3394        if (!isHome) {
3395            var activeView = document.querySelector('.view-section.active');
3396            if (activeView) activeView.style.display = '';
3397        }
3398    }
3399
3400    document.addEventListener('DOMContentLoaded', function () {
3401        var homeSection = document.getElementById('view-home');
3402        if (!homeSection) return;
3403
3404        var observer = new MutationObserver(function (mutations) {
3405            mutations.forEach(function (m) {
3406                if (m.attributeName === 'class') {
3407                    var isActive = m.target.classList.contains('active');
3408                    _syncHomeClass(isActive ? 'home' : 'other');
3409                }
3410            });
3411        });
3412        observer.observe(homeSection, { attributes: true, attributeFilter: ['class'] });
3413
3414        /* ── Mirror main avatar into home stitch header ── */
3415        var mainAvatar = document.getElementById('nav-avatar');
3416        var hsAvatar   = document.getElementById('hs-avatar-img');
3417        var hsProfile  = document.getElementById('hs-profile-btn');
3418        var hsSignin   = document.getElementById('hs-signin-btn');
3419        var mobAvatar  = document.getElementById('nav-avatar-m');
3420        var mobProfile = document.getElementById('nav-profile-btn-m');
3421        var mobSignin  = document.getElementById('nav-signin-btn-m');
3422        var mobDivider = document.getElementById('mob-nav-divider');
3423        var mobCredit  = document.getElementById('mob-credit-pill');
3424
3425        function setAuthVisibility(el, visible, displayMode) {
3426            if (!el) return;
3427            el.classList.toggle('hidden', !visible);
3428            el.style.display = visible ? displayMode : 'none';
3429        }
3430
3431        function syncStitchHeader() {
3432            var isLoggedIn = (typeof app !== 'undefined' && app.isLoggedIn);
3433            if (!isLoggedIn) {
3434                var navProfile = document.getElementById('nav-profile-btn');
3435                isLoggedIn = navProfile && !navProfile.classList.contains('hidden') &&
3436                             navProfile.style.display !== 'none';
3437            }
3438            if (mainAvatar && mainAvatar.src && !mainAvatar.src.includes('ui-avatars')) {
3439                if (hsAvatar) {
3440                    hsAvatar.src = mainAvatar.src;
3441                }
3442                if (mobAvatar) {
3443                    mobAvatar.src = mainAvatar.src;
3444                }
3445            }
3446            setAuthVisibility(hsProfile, isLoggedIn, 'flex');
3447            setAuthVisibility(hsSignin, !isLoggedIn, 'inline-flex');
3448            setAuthVisibility(mobProfile, isLoggedIn, 'flex');
3449            setAuthVisibility(mobSignin, !isLoggedIn, 'flex');
3450            setAuthVisibility(mobDivider, isLoggedIn, 'block');
3451            setAuthVisibility(mobCredit, isLoggedIn, 'flex');
3452        }
3453
3454        setTimeout(syncStitchHeader, 150);
3455        setTimeout(syncStitchHeader, 800);
3456        setTimeout(syncStitchHeader, 2000);
3457        window.addEventListener('pageshow', syncStitchHeader);
3458
3459        /* ── Post-login redirect: home → /generate/ ── */
3460        function hookLoginRedirect() {
3461            if (typeof app === 'undefined' || !app._handleLoginSuccess) {
3462                setTimeout(hookLoginRedirect, 300);
3463                return;
3464            }
3465            if (app._loginSuccessHooked) return;
3466            app._loginSuccessHooked = true;
3467
3468            var originalHandleLogin = app._handleLoginSuccess.bind(app);
3469            app._handleLoginSuccess = function (d) {
3470                var onHome = document.documentElement.classList.contains('home-page');
3471                originalHandleLogin(d);
3472                if (onHome && (!d || !d.pendingView)) {
3473                    setTimeout(function () {
3474                        window.location.href = 'https://www.comfyaicloud.com/generate/';
3475                    }, 900);
3476                }
3477                setTimeout(syncStitchHeader, 400);
3478            };
3479        }
3480        setTimeout(hookLoginRedirect, 500);
3481    });
3482})();
3483</script>
3483
3484
3485
3486
3487<!-- ===================================================== -->
3488<!-- STRIPE LIVE - Subscriptions, then add-ons             -->
3489<!-- ===================================================== -->
3490<script>
3491(function() {
3492  function notify(message, type) {
3493    if (window.app && typeof app.showToast === 'function') app.showToast(message, type || '');
3494    else alert(message);
3495  }
3496
3497  function postPaymentForm(data) {
3498    const fd = new FormData();
3499    Object.keys(data).forEach(function(key) { fd.append(key, data[key]); });
3500    return fetch((window.CA || {}).ajax_url, { method: 'POST', body: fd, credentials: 'same-origin' })
3501      .then(function(res) { return res.json(); });
3502  }
3503
3504  function stripeButtonMarkup(label, loading) {
3505    return (loading ? '<span class="ca-btn-spinner" aria-hidden="true"></span>' : '') + '<span>' + label + '</span>';
3506  }
3507
3508  function setPaymentError(container, message) {
3509    clearPaymentError(container);
3510    const error = document.createElement('div');
3511    error.className = 'ca-stripe-error ca-rzp-error';
3512    error.textContent = message || 'Stripe Checkout could not start. Please try again.';
3513    container.appendChild(error);
3514  }
3515
3516  function clearPaymentError(container) {
3517    const old = container.querySelector('.ca-stripe-error, .ca-rzp-error');
3518    if (old) old.remove();
3519  }
3520
3521  function buttonTheme() {
3522    return {
3523      bg: 'linear-gradient(180deg,rgba(248,251,255,0.16) 0%,rgba(125,211,252,0.09) 46%,rgba(15,23,42,0.28) 100%)',
3524      border: 'rgba(125,211,252,0.26)',
3525      shadow: 'rgba(56,189,248,0.12)'
3526    };
3527  }
3528
3529  function initStripeCreditButtons() {
3530    const CA = window.CA || {};
3531    const stripeState = CA.stripe || {};
3532    const containers = [
3533      document.getElementById('paypal-btn-10'),
3534      document.getElementById('paypal-btn-25'),
3535      document.getElementById('paypal-btn-50'),
3536      document.getElementById('paypal-btn-150')
3537    ];
3538    const packages = (CA.packages && CA.packages.length) ? CA.packages : [];
3539
3540    containers.forEach((container, index) => {
3541      if (!container) return;
3542      const pkg = packages[index];
3543      if (!pkg) return;
3544
3545      container.innerHTML = '';
3546      container.classList.add('ca-stripe-button-shell', 'ca-rzp-button-shell');
3547      container.dataset.paymentMode = 'credit-pack';
3548
3549      const btn = document.createElement('button');
3550      btn.className = 'ca-stripe-pay-btn ca-rzp-pay-btn';
3551      const theme = buttonTheme();
3552      const baseShadow = '0 10px 22px ' + theme.shadow + ',inset 0 1px 0 rgba(255,255,255,0.24)';
3553      btn.style.cssText = 'width:100%;min-height:44px;padding:10px 14px;background:' + theme.bg + ';color:#f8fbff;border:1px solid ' + theme.border + ';border-radius:12px;font-size:14px;font-weight:700;line-height:1;letter-spacing:0;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;text-shadow:0 1px 1px rgba(0,0,0,0.14);box-shadow:' + baseShadow + ';backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);transition:none;';
3554      const label = 'Buy Credits';
3555      btn.innerHTML = stripeButtonMarkup(CA.is_logged_in ? label : 'Sign in to Purchase', false);
3556
3557      btn.onclick = async function() {
3558        if (!CA.ajax_url || !CA.nonce) {
3559          notify('Payment system loading. Please try again in a moment.', 'error');
3560          return;
3561        }
3562        if (!CA.is_logged_in) {
3563          if (window.app && typeof app.openModal === 'function') app.openModal('auth-modal');
3564          else window.location.href = (CA.urls && CA.urls.account) || '/account/';
3565          return;
3566        }
3567        if (!stripeState.configured) {
3568          notify('Stripe is not configured yet.', 'error');
3569          return;
3570        }
3571
3572        clearPaymentError(container);
3573        btn.disabled = true;
3574        btn.classList.add('is-loading');
3575        btn.innerHTML = stripeButtonMarkup('Opening Stripe Checkout...', true);
3576
3577        try {
3578          const data = await postPaymentForm({
3579            action: 'ca_create_stripe_credit_pack',
3580            nonce: CA.nonce,
3581            plan_key: pkg.key
3582          });
3583
3584          if (!data.success || !data.data || !data.data.checkout_url) {
3585            throw new Error((data.data && data.data.message) || 'Could not start Stripe Checkout.');
3586          }
3587
3588          window.location.href = data.data.checkout_url;
3589        } catch (err) {
3590          notify(err.message || 'Payment setup failed. Please try again.', 'error');
3591          btn.classList.remove('is-loading');
3592          btn.classList.add('is-error');
3593          setPaymentError(container, err.message || 'Stripe Checkout could not start. Please try again.');
3594          btn.disabled = false;
3595          btn.innerHTML = stripeButtonMarkup(label, false);
3596        }
3597      };
3598
3599      container.appendChild(btn);
3600      requestAnimationFrame(function() { container.classList.add('ca-rzp-ready'); });
3601    });
3602  }
3603
3604  if (window.app) window.app.paypalRendered = true;
3605  setTimeout(initStripeCreditButtons, 900);
3606  document.addEventListener('click', function(e) {
3607    if (e.target.closest('[data-target="plans"]')) {
3608      setTimeout(initStripeCreditButtons, 700);
3609    }
3610  });
3611})();
3612</script>
vendor: 1 bytes, line 3612
3612
3613<script type="speculationrules">
3614{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/comfyaicloud/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
3615</script>
vendor: 1 bytes, line 3615
3615
3616<script id="wp-consent-api-js-extra">
3617var consent_api = {"consent_type":"","waitfor_consent_hook":"","cookie_expiration":"30","cookie_prefix":"wp_consent","services":[]};
3618//# sourceURL=wp-consent-api-js-extra
3619</script>
vendor: 1 bytes, line 3619
3619
3620<script id="wp-consent-api-js" src="https://www.comfyaicloud.com/wp-content/plugins/wp-consent-api/assets/js/wp-consent-api.min.js?ver=2.1.0"></script>
vendor: 1 bytes, line 3620
3620
3621<script id="burst-js" defer src="https://www.comfyaicloud.com/wp-content/uploads/burst/js/burst.min.js?ver=1790873211"></script>
vendor: 1 bytes, line 3621
3621
3622<script data-cfasync="false" id="real-cookie-banner-blocker-js" defer src="https://www.comfyaicloud.com/wp-content/d38d8888893f702ea2b35cf6df393b10/dist/1825734372.js?ver=ad214e746d8dc6dc245f584439d27fff"></script>
vendor: 1 bytes, line 3622
3622
3623<script defer id="ca-lucide-js" src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/js/lucide.min.js?ver=69.9.7"></script>
vendor: 1 bytes, line 3623
3623
3624<script async id="ca-gis-js" src="https://accounts.google.com/gsi/client"></script>
vendor: 1 bytes, line 3624
3624
3625<script id="ca-app-js-extra">
3626var CA = {"ajax_url":"https://www.comfyaicloud.com/wp-admin/admin-ajax.php","nonce":"e6f2f63858","is_logged_in":"","is_admin":"","credits":"0","total_generations":"0","display_name":"","avatar_url":"","email":"","initial_view":"generate","free_credits_toast":"","free_credits":"100","google_client_id":"545822243259-cth8vj3tl1ossbf57dbijgrs7jehpv4r.apps.googleusercontent.com","paypal_client_id":"","razorpay":[],"stripe":{"configured":true,"mode":"live","currency":"USD"},"packages":[{"key":"starter","price":10,"label":"Starter","base":1000,"bonus_pct":50,"bonus_cr":500,"credits":1500,"bonus":"50%"},{"key":"creator","price":25,"label":"Creator","base":2500,"bonus_pct":130,"bonus_cr":3250,"credits":5750,"bonus":"130%"},{"key":"studio","price":50,"label":"Studio Pro","base":5000,"bonus_pct":180,"bonus_cr":9000,"credits":14000,"bonus":"180%"},{"key":"enterprise","price":150,"label":"Enterprise","base":15000,"bonus_pct":250,"bonus_cr":37500,"credits":52500,"bonus":"250%"}],"costs":{"gen_1k":30,"gen_mid":40,"gen_2k":70,"res_1k":10,"res_2k":15,"rep_fast":5,"rep_pro":10,"sd3":5,"playground":1000,"video_5s":100,"video_10s":200,"nsfw":30},"has_fal_key":"1","sd3_defaults":{"steps":28,"cfg":5,"neg_prompt":"blurry, low quality, watermark, text, bad anatomy, deformed, ugly, oversaturated"},"urls":{"home":"https://www.comfyaicloud.com/","generate":"https://www.comfyaicloud.com/generate/","replicate":"https://www.comfyaicloud.com/replicate/","pricing":"https://www.comfyaicloud.com/pricing/","account":"https://www.comfyaicloud.com/account/"},"theme_uri":"https://www.comfyaicloud.com/wp-content/themes/comfyaicloud","header_logo_url":"https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png","favicon_url":"https://comfyaicloud.com/wp-content/uploads/2026/02/cropped-06e69f10-7df4-4f94-8a09-1c33983ce040.png","site_tagline":"","footer_credit":"","settings_url":"https://www.comfyaicloud.com/comfyai-settings/","has_sd3_key":"1","has_xai_key":"1","cost_sd3":"5","bg_color":"#faf8f4","dot_opacity":"25","dot_brightness":"100","ui_mode":"dark","animations":["cursor_blink","cta_pulse","gen_wave","upload_breathe","grid_stagger","credits_tick","popular_ring","avatar_aura"],"anim_speed":"normal","dots_style":"classic","dots_color":"green","hero_text_anim":"0"};
3627//# sourceURL=ca-app-js-extra
3628</script>
vendor: 1 bytes, line 3628
3628
3629<script defer id="ca-app-js" src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/js/app.js?ver=69.9.7"></script>
vendor: 1 bytes, line 3629
3629
3630<script id="ca-challenge-integration-js-extra">
3631var CAChallengeGen = {"nonce":"33d1a138b6","challenge_url":"https://www.comfyaicloud.com/challenge/"};
3632//# sourceURL=ca-challenge-integration-js-extra
3633</script>
vendor: 1 bytes, line 3633
3633
3634<script id="ca-challenge-integration-js" src="https://www.comfyaicloud.com/wp-content/themes/comfyaicloud/js/challenge-integration.js?ver=69.9.7"></script>
3634
3635    
3635<script id="ca-google-ads-conversions">
3636    (function () {
3637      'use strict';
3638
3639      var ADS_SIGNUP_SEND_TO   = "AW-18226387043\/NEajCPO2xPocEOOwgvND";
3640      var ADS_PURCHASE_SEND_TO = "AW-18226387043\/1eeACKvAyfocEOOwgvND";
3641      var AJAX_URL             = "https:\/\/www.comfyaicloud.com\/wp-admin\/admin-ajax.php";
3642
3643      function postForm(data) {
3644        var fd = new FormData();
3645        Object.keys(data).forEach(function (key) { fd.append(key, data[key]); });
3646        return fetch(AJAX_URL, {
3647          method: 'POST',
3648          body: fd,
3649          credentials: 'same-origin',
3650          cache: 'no-store'
3651        }).then(function (r) { return r.json(); });
3652      }
3653
3654      function hasCookie(name) {
3655        return document.cookie.split(';').some(function (part) {
3656          return part.trim().indexOf(name + '=') === 0;
3657        });
3658      }
3659
3660      /* VERIFIED SIGNUP ONLY.
3661         The cookie/query string is just a hint; authenticated AJAX is the source
3662         of truth, so a visitor cannot create a lead by faking a URL parameter. */
3663      var qs = new URLSearchParams(window.location.search);
3664      var shouldCheckSignup = hasCookie('ca_gads_signup_pending') || qs.get('ca_verify_status') === 'ok';
3665
3666      if (shouldCheckSignup) {
3667        postForm({ action: 'ca_google_ads_signup_status' }).then(function (res) {
3668          if (!res || !res.success || !res.data || !res.data.pending) return;
3669          if (typeof window.gtag !== 'function') return;
3670
3671          var acked = false;
3672          var ackSignup = function () {
3673            if (acked) return;
3674            acked = true;
3675            postForm({
3676              action: 'ca_google_ads_signup_ack',
3677              nonce: String(res.data.ack_nonce || '')
3678            }).catch(function () {});
3679          };
3680
3681          window.gtag('event', 'conversion', {
3682            'send_to': ADS_SIGNUP_SEND_TO,
3683            'event_callback': ackSignup,
3684            'event_timeout': 2000
3685          });
3686        }).catch(function () {});
3687      }
3688
3689      /* COMPLETED STRIPE PURCHASE ONLY.
3690         The server endpoint retrieves the Checkout Session directly from Stripe,
3691         verifies ownership, paid status, currency and expected amount, then returns
3692         the exact value/currency/transaction ID for Google Ads. */
3693      if (qs.get('stripe_success') === '1') {
3694        var sessionId = qs.get('session_id') || '';
3695
3696        if (/^cs_/.test(sessionId)) {
3697          var storageKey = 'ca_gads_purchase_' + sessionId;
3698          var alreadySent = false;
3699          try { alreadySent = localStorage.getItem(storageKey) === '1'; } catch (e) {}
3700
3701          if (!alreadySent) {
3702            postForm({
3703              action: 'ca_stripe_check_session',
3704              nonce: (window.CA && CA.nonce) ? CA.nonce : '',
3705              session_id: sessionId
3706            }).then(function (res) {
3707              if (!res || !res.success || !res.data || !res.data.track_purchase) return;
3708              if (typeof window.gtag !== 'function') return;
3709
3710              var value = Number(res.data.value);
3711              var currency = String(res.data.currency || 'USD').toUpperCase();
3712              var transactionId = String(res.data.transaction_id || sessionId);
3713
3714              if (!isFinite(value) || value <= 0 || !transactionId) return;
3715
3716              window.gtag('event', 'conversion', {
3717                'send_to': ADS_PURCHASE_SEND_TO,
3718                'value': value,
3719                'currency': currency,
3720                'transaction_id': transactionId
3721              });
3722
3723              try { localStorage.setItem(storageKey, '1'); } catch (e) {}
3724            }).catch(function () {});
3725          }
3726        }
3727      }
3728    })();
3729    </script>
3729
3730    </body>
3731</html>
3732<!-- Cached by WP-Optimize (gzip) - https://teamupdraft.com/wp-optimize/ - Last modified: October 1, 2026 4:56 pm (UTC:0) -->

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.