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&background=0D8B93&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&background=0D8B93&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&background=3B82F6&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 & 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>© 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,'&').replace(/"/g,'"')+'" 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">·</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 & 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">·</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&d=mm&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">·</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 & 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 & Credits')" class="ca-chip-btn">ð³ Billing & 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&d=mm&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,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); 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' ? '✓' : pillState === 'state-open' ? '✦' : '○'; 3205 3206 var statusMap = { '': ['s-open','Available'], 'pending': ['s-pending','Under Review'], 'approved': ['s-approved','Approved'], 'retry': ['s-retry','Revise & 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">✓</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">⏳</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">↩</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.