Repository: adobecom/unity
Pull request #440: [MWPW-172411] Firefly workflow
Author: login: Ruchika4
Labels: name: verified
name: firefly
Created: 2025-05-22T19:55:46Z | Merged: 2025-05-24T01:07:36Z

* Firefly Workflow

Resolves: [MWPW-172411](https://jira.corp.adobe.com/browse/MWPW-172411)
[MWPW-172411](https://jira.corp.adobe.com/browse/MWPW-173783)
[MWPW-173792](https://jira.corp.adobe.com/browse/MWPW-173792)
[MWPW-173423](https://jira.corp.adobe.com/browse/MWPW-173423)
[MWPW-172420](https://jira.corp.adobe.com/browse/MWPW-172420)

**Test URLs:**
Page with prompt suggestion dropdown
- Before: https://main--cc--adobecom.hlx.page/drafts/ruchika/unity/firefly/unity-firefly?unitylibs=stage
- After: https://main--cc--adobecom.hlx.page/drafts/ruchika/unity/firefly/unity-firefly?unitylibs=firefly-workflow

Page without prompt suggestion dropdown
- Before: https://main--cc--adobecom.hlx.page/drafts/ruchika/unity/firefly/unity-firefly1?unitylibs=stage
- After: https://main--cc--adobecom.hlx.page/drafts/ruchika/unity/firefly/unity-firefly1?unitylibs=firefly-workflow

Page without verb dropdown
- Before: https://main--cc--adobecom.hlx.page/drafts/rclayton/firefly/text-to-image-alt?unitylibs=stage
- After: https://main--cc--adobecom.hlx.page/drafts/rclayton/firefly/text-to-image-alt?unitylibs=firefly-workflow




Diff:
diff --git a/test/core/workflow/mocks/ff-body.html b/test/core/workflow/mocks/ff-body.html
new file mode 100644
index 000000000..66f6d9cf0
--- /dev/null
+++ b/test/core/workflow/mocks/ff-body.html
@@ -0,0 +1,59 @@
+<div>
+  <div class="hero-marquee center con-block has-bg unity-enabled" data-block-status="loaded" daa-lh="b1|hero-marquee">
+    <div class="copy"></div>
+    <div>
+      <div data-valign="middle">
+        <picture>
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=webply&amp;optimize=medium" media="(min-width: 600px)">
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=webply&amp;optimize=medium">
+          <source type="image/png" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=png&amp;optimize=medium" media="(min-width: 600px)">
+          <img loading="lazy" alt="Picture, Picture" src="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=png&amp;optimize=medium" width="1440" height="500">
+        </picture>
+      </div>
+      <div data-valign="middle">
+        <picture>
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=webply&amp;optimize=medium" media="(min-width: 600px)">
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=webply&amp;optimize=medium">
+          <source type="image/png" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=png&amp;optimize=medium" media="(min-width: 600px)">
+          <img loading="lazy" alt="Picture, Picture" src="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=png&amp;optimize=medium" width="1440" height="500">
+        </picture>
+      </div>
+      <div data-valign="middle">
+        <picture>
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=webply&amp;optimize=medium" media="(min-width: 600px)">
+          <source type="image/webp" srcset="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=webply&amp;optimize=medium">
+          <source type="image/png" srcset="http://localhost:2000/test/assets/media_.jpeg?width=2000&amp;format=png&amp;optimize=medium" media="(min-width: 600px)">
+          <img loading="lazy" alt="Picture, Picture" src="http://localhost:2000/test/assets/media_.jpeg?width=750&amp;format=png&amp;optimize=medium" width="1440" height="500">
+        </picture>
+      </div>
+    </div>
+    <div>
+      <div data-valign="middle">
+        <p><a href="http://localhost:2000/test/assets/img.svg">http://localhost:2000/test/assets/img.svg</a> Adobe Firefly</p>
+        <h1 id="the-ultimate-creative-ai-solution">The ultimate creative AI solution.</h1>
+      </div>
+    </div>
+    <div>
+      <div data-valign="middle">con-block-row-supplemental (xs-body, bold, static-links)</div>
+      <div data-valign="middle"><a href="https://adobe.com/">Adobe Generative AI Terms</a></div>
+    </div>
+  </div>
+  <div class="unity workflow-firefly dark">
+    <div>
+      <div>
+        <ul>
+          <li><span class="icon icon-verb-image"></span><a href="http://localhost:2000/test/assets/img.svg">image</a></li>
+          <li><span class="icon icon-verb-video"></span><a href="http://localhost:2000/test/assets/img.svg">video</a></li>
+          <li><span class="icon icon-tip"></span>Describe a subject, an action, a place, a mood, or a style.</li>
+          <li><span class="icon icon-legal"></span><a href="https://www.adobe.com/#_blank">Adobe Generative AI Terms</a></li>
+          <li><span class="icon icon-generate"></span><a href="http://localhost:2000/test/assets/img.svg">http://localhost:2000/test/assets/img.svg</a> Generate</li>
+          <li><span class="icon icon-placeholder-input"></span>Describe your image</li>
+          <li><span class="icon icon-placeholder-prompt"></span>Prompt</li>
+          <li><span class="icon icon-placeholder-suggestions"></span>Suggestions</li>
+          <li><span class="icon icon-placeholder-tip"></span>Tip</li>
+          <li><span class="icon icon-cgen"></span>promoid=abcd12&amp;mv=other</li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/test/core/workflow/workflow.firefly.test.js b/test/core/workflow/workflow.firefly.test.js
new file mode 100644
index 000000000..c0e38b664
--- /dev/null
+++ b/test/core/workflow/workflow.firefly.test.js
@@ -0,0 +1,207 @@
+/* eslint-disable max-len */
+import { expect } from '@esm-bundle/chai';
+import sinon from 'sinon';
+import { readFile } from '@web/test-runner-commands';
+import ActionBinder from '../../../unitylibs/core/workflow/workflow-firefly/action-binder.js';
+import UnityWidget from '../../../unitylibs/core/workflow/workflow-firefly/widget.js';
+
+describe('Firefly Workflow Tests', () => {
+  let actionBinder;
+  let unityElement;
+  let workflowCfg;
+  let block;
+  let canvasArea;
+  let actionMap;
+  let unityWidget;
+  let spriteContainer;
+
+  before(async () => {
+    document.body.innerHTML = await readFile({ path: './mocks/ff-body.html' });
+    unityElement = document.querySelector('.unity');
+    workflowCfg = {
+      name: 'workflow-firefly',
+      targetCfg: { renderWidget: true, insert: 'before', target: 'a:last-of-type' },
+    };
+    spriteContainer = '<svg></svg>';
+    block = document.querySelector('.unity-enabled');
+    canvasArea = document.createElement('div');
+    actionMap = {
+      '.gen-btn': [{ actionType: 'generate' }],
+      '.drop-item': [{ actionType: 'setPromptValue' }],
+      '.close-btn': [{ actionType: 'closeDropdown' }],
+      '.inp-field': [{ actionType: 'autocomplete' }],
+    };
+
+    sinon.stub(UnityWidget.prototype, 'loadPrompts').callsFake(function () {
+      const samplePrompts = [
+        { verb: 'image', prompt: 'A calm face blending into a forest landscape with birds flying from the silhouette. Soft lighting with color popping trees', assetid: '17669552-32bc-4216-82fe-8f7e72ffb4b0' },
+        { verb: 'image', prompt: 'Make a cheerful product image of a collectible jar with a tiny person tending to a miniature garden, complete with working watering can, tiny plants, and a little bench, the jar lid decorated with flower patterns and labeled Green Thumb Series', assetid: '69c64e7a-83cb-466b-a530-6b42b06a914a' },
+        { verb: 'image', prompt: 'high quality image  of a translucent studio background with light prisms created by light sunlight, the atmosphere is magical, ephemeral, modern, in the center there is a a flower made of clouds', assetid: 'f56dbb62-53ed-4745-874f-adc549e81ee5' },
+        { verb: 'video', prompt: 'photograph of a boy standing in tall grass, wearing a pig mask over his head. hazy halation filter. weird surreal dreamy look', assetid: '0a3b51b4-23e8-4f80-a955-c0b91fd67bf7' },
+        { verb: 'video', prompt: 'a bright yellow sun with a face in a very blue sky', assetid: 'af9b6097-1c3a-49d3-a0f8-e0b4fe288ee1' },
+        { verb: 'video', prompt: 'vehicle that constantly shifts between three states: solid chrome geometry with sharp angles, flowing mercury that maintains speed while changing shape, and an energy wireframe that leaves trails of light - all on a track that loops through different reality layers.', assetid: 'da5d3aa3-61e3-4492-8795-9b558b495402' },
+      ];
+      // Group by verb
+      this.prompts = samplePrompts.reduce((acc, item) => {
+        if (!acc[item.verb]) acc[item.verb] = [];
+        acc[item.verb].push({ prompt: item.prompt, assetid: item.assetid });
+        return acc;
+      }, {});
+      return Promise.resolve();
+    });
+
+    // Ensure .copy contains a target <a> for widget insertion
+    const copy = block.querySelector('.copy');
+    if (copy && !copy.querySelector('a')) {
+      copy.innerHTML = '<a href="#">Target Link</a>';
+    }
+
+    unityWidget = new UnityWidget(block, unityElement, workflowCfg, spriteContainer);
+    await unityWidget.initWidget();
+
+    // Ensure .ex-unity-wrap is present before constructing ActionBinder
+    if (!document.querySelector('.ex-unity-wrap')) {
+      throw new Error('.ex-unity-wrap not found in DOM after widget initialization');
+    }
+
+    actionBinder = new ActionBinder(unityElement, workflowCfg, block, canvasArea, actionMap);
+  });
+
+  it('should initialize ActionBinder correctly', () => {
+    expect(actionBinder).to.exist;
+    expect(actionBinder.inputField).to.exist;
+    expect(actionBinder.dropdown).to.exist;
+    expect(actionBinder.widget).to.exist;
+  });
+
+  it('should bind event listeners on init', async () => {
+    await actionBinder.initActionListeners();
+    Object.keys(actionMap).forEach((selector) => {
+      document.querySelectorAll(selector).forEach((el) => {
+        expect(el.getAttribute('data-event-bound')).to.equal('true');
+      });
+    });
+  });
+
+  it('should initialize UnityWidget correctly', () => {
+    expect(unityWidget).to.exist;
+    expect(unityWidget.target).to.equal(block);
+    expect(unityWidget.el).to.equal(unityElement);
+  });
+
+  it('should insert widget into DOM', () => {
+    expect(document.querySelector('.ex-unity-wrap')).to.exist;
+  });
+
+  it('should correctly populate placeholders', () => {
+    const placeholders = unityWidget.popPlaceholders();
+    expect(placeholders).to.be.an('object');
+    expect(Object.keys(placeholders).length).to.be.greaterThan(0);
+  });
+
+  it('should generate dropdown with correct placeholders', async () => {
+    const placeholder = {
+      'placeholder-prompt': 'Prompt',
+      'placeholder-suggestions': 'Suggestions',
+    };
+    const dropdown = await unityWidget.genDropdown(placeholder);
+    expect(dropdown).to.exist;
+    expect(dropdown.querySelector('.drop-title')).to.exist;
+    expect(dropdown.querySelector('.close-btn')).to.exist;
+  });
+
+  it('should handle keydown events correctly', () => {
+    const dropdown = document.querySelector('.drop');
+    actionBinder.dropdown = dropdown;
+    const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown' });
+    actionBinder.handleKeyDown(arrowDownEvent);
+    expect(actionBinder.activeIndex).to.not.equal(-1);
+    const arrowUpEvent = new KeyboardEvent('keydown', { key: 'ArrowUp' });
+    actionBinder.handleKeyDown(arrowUpEvent);
+    expect(actionBinder.activeIndex).to.not.equal(-1);
+    const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape' });
+    sinon.stub(actionBinder, 'hideDropdown');
+    actionBinder.handleKeyDown(escapeEvent);
+    expect(actionBinder.hideDropdown.calledOnce).to.be.true;
+    actionBinder.hideDropdown.restore();
+  });
+
+  it('should move focus correctly with Arrow keys', () => {
+    const dropItems = [...document.querySelectorAll('.drop-item')];
+    actionBinder.moveFocusWithArrow(dropItems, 'down');
+    expect(document.activeElement).to.equal(dropItems[0]);
+
+    actionBinder.moveFocusWithArrow(dropItems, 'down');
+    expect(document.activeElement).to.equal(dropItems[1]);
+
+    actionBinder.moveFocusWithArrow(dropItems, 'up');
+    expect(document.activeElement).to.equal(dropItems[0]);
+  });
+
+  it('should correctly process Enter key actions', () => {
+    const dropItem = document.querySelector('.drop-item');
+    dropItem.focus();
+    actionBinder.activeIndex = 0;
+    const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
+    sinon.stub(actionBinder, 'setPrompt');
+    actionBinder.handleEnter(enterEvent, [dropItem], [], 0);
+    expect(actionBinder.setPrompt.calledOnce).to.be.true;
+    actionBinder.setPrompt.restore();
+  });
+
+  it('should handle Tab key navigation in dropdown', () => {
+    const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true });
+    const shiftEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, shiftKey: true });
+    const focusableElements = Array.from(document.querySelectorAll('.inp-field, .gen-btn, .drop-item, .close-btn'));
+    const dropItems = [document.querySelector('.drop-item')];
+    focusableElements[0].focus();
+    const currentIndex = focusableElements.indexOf(document.activeElement);
+    actionBinder.handleTab(event, focusableElements, dropItems, currentIndex);
+    expect(document.activeElement).to.equal(focusableElements[1]);
+    actionBinder.handleTab(shiftEvent, focusableElements, dropItems, 1);
+    expect(document.activeElement).to.equal(focusableElements[0]);
+  });
+
+  it('should move focus to legal-text if tip-con is focused', () => {
+    const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true });
+    const tipCon = document.querySelector('.tip-con');
+    const legalText = document.querySelector('.legal-text');
+    tipCon.focus();
+    expect(document.activeElement).to.equal(tipCon);
+    const queryStub = sinon.stub(actionBinder.block, 'querySelector');
+    queryStub.withArgs('.legal-text').returns(legalText);
+    actionBinder.handleTab(event, [tipCon, legalText], [], 0);
+    expect(document.activeElement).to.equal(legalText);
+    queryStub.restore();
+  });
+
+  it('should update prompt suggestions when verb is changed', async () => {
+    const imagePrompts = [
+      'A calm face blending into a forest landscape with birds flying from the silhouette. Soft lighting with color popping trees',
+      'Make a cheerful product image of a collectible jar with a tiny person tending to a miniature garden, complete with working watering can, tiny plants, and a little bench, the jar lid decorated with flower patterns and labeled Green Thumb Series',
+      'high quality image  of a translucent studio background with light prisms created by light sunlight, the atmosphere is magical, ephemeral, modern, in the center there is a a flower made of clouds',
+    ];
+    const videoPrompts = [
+      'photograph of a boy standing in tall grass, wearing a pig mask over his head. hazy halation filter. weird surreal dreamy look',
+      'a bright yellow sun with a face in a very blue sky',
+      'vehicle that constantly shifts between three states: solid chrome geometry with sharp angles, flowing mercury that maintains speed while changing shape, and an energy wireframe that leaves trails of light - all on a track that loops through different reality layers.',
+    ];
+    // Initial verb is 'image' (default)
+    await unityWidget.updateDropdownForVerb('image');
+    let dropItems = Array.from(document.querySelectorAll('.drop-item'));
+    expect(dropItems.length).to.be.greaterThan(0);
+    expect(dropItems.some((item) => imagePrompts.some((prompt) => item.getAttribute('aria-label').includes(prompt)))).to.be.true;
+
+    // Change verb to 'video'
+    await unityWidget.updateDropdownForVerb('video');
+    dropItems = Array.from(document.querySelectorAll('.drop-item'));
+    expect(dropItems.length).to.be.greaterThan(0);
+    expect(dropItems.some((item) => videoPrompts.some((prompt) => item.getAttribute('aria-label').includes(prompt)))).to.be.true;
+
+    // Change back to 'image'
+    await unityWidget.updateDropdownForVerb('image');
+    dropItems = Array.from(document.querySelectorAll('.drop-item'));
+    expect(dropItems.length).to.be.greaterThan(0);
+    expect(dropItems.some((item) => imagePrompts.some((prompt) => item.getAttribute('aria-label').includes(prompt)))).to.be.true;
+  });
+});
diff --git a/unitylibs/core/workflow/workflow-firefly/action-binder.js b/unitylibs/core/workflow/workflow-firefly/action-binder.js
new file mode 100644
index 000000000..fc63151c6
--- /dev/null
+++ b/unitylibs/core/workflow/workflow-firefly/action-binder.js
@@ -0,0 +1,469 @@
+/* eslint-disable max-len */
+/* eslint-disable max-classes-per-file */
+/* eslint-disable no-await-in-loop */
+/* eslint-disable class-methods-use-this */
+/* eslint-disable no-restricted-syntax */
+
+import {
+  unityConfig,
+  getUnityLibs,
+  createTag,
+  defineDeviceByScreenSize,
+  getLibs,
+  getHeaders,
+  getLocale,
+  sendAnalyticsEvent,
+} from '../../../scripts/utils.js';
+
+class ServiceHandler {
+  constructor(renderWidget = false, canvasArea = null, unityEl = null) {
+    this.renderWidget = renderWidget;
+    this.canvasArea = canvasArea;
+    this.unityEl = unityEl;
+  }
+
+  async fetchFromService(url, options) {
+    try {
+      const response = await fetch(url, options);
+      const error = new Error();
+      if (response.status !== 200) {
+        error.status = response.status;
+        throw error;
+      }
+      return response.json();
+    } catch (error) {
+      if (error.name === 'TimeoutError' || error.name === 'AbortError') {
+        error.status = 504;
+      }
+      throw error;
+    }
+  }
+
+  async postCallToService(api, options) {
+    const postOpts = {
+      method: 'POST',
+      headers: await getHeaders(unityConfig.apiKey),
+      ...options,
+    };
+    return this.fetchFromService(api, postOpts);
+  }
+
+  showErrorToast(errorCallbackOptions, error, lanaOptions, errorType = 'server') {
+    sendAnalyticsEvent(new CustomEvent(`FF Generate prompt ${errorType} error|UnityWidget`));
+    if (!errorCallbackOptions?.errorToastEl) return;
+    const msg = this.unityEl.querySelector(errorCallbackOptions.errorType)?.nextSibling.textContent;
+    const promptBarEl = this.canvasArea.querySelector('.copy .ex-unity-wrap');
+    promptBarEl.style.pointerEvents = 'none';
+    const errorToast = promptBarEl.querySelector('.alert-holder');
+    if (!errorToast) return;
+    const closeBtn = errorToast.querySelector('.alert-close');
+    if (closeBtn) closeBtn.style.pointerEvents = 'auto';
+    const alertText = errorToast.querySelector('.alert-text p');
+    if (!alertText) return;
+    alertText.innerText = msg;
+    errorToast.classList.add('show');
+    window.lana?.log(`Message: ${msg}, Error: ${error || ''}`, lanaOptions);
+  }
+}
+
+export default class ActionBinder {
+  boundHandleKeyDown = this.handleKeyDown.bind(this);
+
+  boundOutsideClickHandler = this.handleOutsideClick.bind(this);
+
+  constructor(unityEl, workflowCfg, block, canvasArea, actionMap = {}) {
+    this.unityEl = unityEl;
+    this.workflowCfg = workflowCfg;
+    this.block = block;
+    this.canvasArea = canvasArea;
+    this.actions = actionMap;
+    this.query = '';
+    this.serviceHandler = null;
+    this.activeIndex = -1;
+    this.id = '';
+    this.apiConfig = { ...unityConfig };
+    this.inputField = this.getElement('.inp-field');
+    this.dropdown = this.getElement('.drop');
+    this.widget = this.getElement('.ex-unity-widget');
+    this.viewport = defineDeviceByScreenSize();
+    this.widgetWrap = this.getElement('.ex-unity-wrap');
+    this.widgetWrap.addEventListener('firefly-reinit-action-listeners', () => this.initActionListeners());
+    this.scrRead = createTag('div', { class: 'sr-only', 'aria-live': 'polite', 'aria-atomic': 'true' });
+    this.widgetWrap.append(this.scrRead);
+    this.errorToastEl = null;
+    this.lanaOptions = { sampleRate: 1, tags: 'Unity-FF' };
+    this.sendAnalyticsToSplunk = null;
+    this.addAccessibility();
+    this.initAction();
+  }
+
+  async initAction() {
+    if (!this.errorToastEl) this.errorToastEl = await this.createErrorToast();
+    const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent)
+      || (navigator.userAgent.includes('Mac') && navigator.maxTouchPoints > 1);
+    if (!isIos) return;
+    window.addEventListener('pageshow', ({ persisted }) => {
+      if (!persisted || document.visibilityState !== 'visible') return;
+      const handleClick = ({ target }) => {
+        if (target === this.inputField) {
+          this.inputField.focus();
+          this.initActionListeners();
+          this.showDropdown();
+        }
+      };
+      document.addEventListener('click', handleClick, { once: true });
+    });
+  }
+
+  async createErrorToast() {
+    try {
+      const [alertImg, closeImg] = await Promise.all([
+        fetch(`${getUnityLibs()}/img/icons/alert.svg`).then((res) => res.text()),
+        fetch(`${getUnityLibs()}/img/icons/close.svg`).then((res) => res.text()),
+      ]);
+      const { decorateDefaultLinkAnalytics } = await import(`${getLibs()}/martech/attributes.js`);
+      const promptBarEl = this.canvasArea.querySelector('.copy .ex-unity-wrap');
+      const alertText = createTag('div', { class: 'alert-text' }, createTag('p', {}, 'Alert Text'));
+      const alertIcon = createTag('div', { class: 'alert-icon' });
+      alertIcon.innerHTML = alertImg;
+      alertIcon.append(alertText);
+      const alertClose = createTag('a', { class: 'alert-close', href: '#' });
+      alertClose.innerHTML = closeImg;
+      alertClose.append(createTag('span', { class: 'alert-close-text' }, 'Close error toast'));
+      const alertContent = createTag('div', { class: 'alert-content' });
+      alertContent.append(alertIcon, alertClose);
+      const alertToast = createTag('div', { class: 'alert-toast' }, alertContent);
+      const errholder = createTag('div', { class: 'alert-holder' }, alertToast);
+      alertClose.addEventListener('click', (e) => {
+        e.preventDefault();
+        e.stopPropagation();
+        errholder.classList.remove('show');
+        promptBarEl.style.pointerEvents = 'auto';
+      });
+      decorateDefaultLinkAnalytics(errholder);
+      promptBarEl.prepend(errholder);
+      return promptBarEl?.querySelector('.alert-holder');
+    } catch (e) {
+      window.lana?.log(`Message: Error creating error toast, Error: ${e}`, this.lanaOptions);
+      return null;
+    }
+  }
+
+  initializeApiConfig() {
+    return { ...unityConfig };
+  }
+
+  getElement(selector) {
+    const element = this.block.querySelector(selector);
+    if (!element) console.warn(`Element with selector "${selector}" not found.`);
+    return element;
+  }
+
+  async initActionListeners() {
+    Object.entries(this.actions).forEach(([selector, actionsList]) => {
+      this.block.querySelectorAll(selector).forEach((el) => {
+        if (!el.hasAttribute('data-event-bound')) {
+          this.addEventListeners(el, actionsList);
+          el.setAttribute('data-event-bound', 'true');
+        }
+      });
+    });
+  }
+
+  async loadServiceHandler() {
+    this.serviceHandler = new ServiceHandler(
+      this.workflowCfg.targetCfg.renderWidget,
+      this.canvasArea,
+      this.unityEl,
+    );
+  }
+
+  addEventListeners(el, actionsList) {
+    const handleClick = async (event) => {
+      event.preventDefault();
+      await this.execActions(actionsList, el);
+    };
+    switch (el.nodeName) {
+      case 'A':
+      case 'BUTTON':
+        el.addEventListener('click', handleClick);
+        break;
+      case 'LI':
+        el.addEventListener('mousedown', (event) => event.preventDefault());
+        el.addEventListener('click', handleClick);
+        break;
+      case 'INPUT':
+        this.addInputEvents(el);
+        break;
+      default:
+        break;
+    }
+  }
+
+  addInputEvents(el) {
+    el.addEventListener('focus', () => this.showDropdown());
+    el.addEventListener('focusout', ({ relatedTarget, currentTarget }) => {
+      if (!relatedTarget && this.widget?.contains(currentTarget)) return;
+      if (!this.widget?.contains(relatedTarget)) this.hideDropdown();
+    });
+  }
+
+  async execActions(action, el = null) {
+    try {
+      await this.handleAction(action, el);
+    } catch (err) {
+      window.lana?.log(`Message: Actions failed, Error: ${err}`, this.lanaOptions);
+    }
+  }
+
+  async handleAction(action, el) {
+    const actionMap = {
+      generate: () => this.generateContent(),
+      setPromptValue: () => this.setPrompt(el),
+      closeDropdown: () => this.resetDropdown(),
+    };
+    const execute = actionMap[action.actionType];
+    if (execute) await execute();
+  }
+
+  getSelectedVerbType = () => this.widgetWrap.getAttribute('data-selected-verb');
+
+  validateInput() {
+    if (this.inputField.value.length === 0 && !this.id) {
+      this.serviceHandler.showErrorToast({ errorToastEl: this.errorToastEl, errorType: '.icon-error-empty-input' }, 'Empty input');
+      return { isValid: false, errorCode: 'empty-input' };
+    }
+    if (this.inputField.value.length > 750) {
+      this.serviceHandler.showErrorToast({ errorToastEl: this.errorToastEl, errorType: '.icon-error-max-length' }, 'Max prompt characters exceeded');
+      return { isValid: false, errorCode: 'max-prompt-characters-exceeded' };
+    }
+    return { isValid: true };
+  }
+
+  async initAnalytics() {
+    if (!this.sendAnalyticsToSplunk && this.workflowCfg.targetCfg.sendSplunkAnalytics) {
+      this.sendAnalyticsToSplunk = (await import(`${getUnityLibs()}/scripts/splunk-analytics.js`)).default;
+    }
+  }
+
+  logAnalytics(eventName, data, { workflowStep, statusCode } = {}) {
+    const logData = {
+      ...data,
+      ...(workflowStep && { workflowStep }),
+      ...(typeof statusCode !== 'undefined' && { statusCode }),
+    };
+    this.sendAnalyticsToSplunk?.( eventName, this.workflowCfg.productName, logData, `${unityConfig.apiEndPoint}/log`, true);
+  }
+
+  async generateContent() {
+    await this.initAnalytics();
+    if (!this.serviceHandler) await this.loadServiceHandler();
+    const cgen = this.unityEl.querySelector('.icon-cgen')?.nextSibling?.textContent?.trim();
+    const queryParams = {};
+    if (cgen) {
+      cgen.split('&').forEach((param) => {
+        const [key, value] = param.split('=');
+        if (key && value) queryParams[key] = value;
+      });
+    }
+    if (!this.query) this.query = this.inputField.value.trim();
+    const selectedVerbType = `text-to-${this.getSelectedVerbType()}`;
+    const action = (this.id ? 'prompt-suggestion' : 'generate');
+    const eventData = { assetId: this.id, verb: selectedVerbType, action };
+    this.logAnalytics('generate', eventData, { workflowStep: 'start' });
+    const validation = this.validateInput();
+    if (!validation.isValid) {
+      this.logAnalytics('generate', { ...eventData, errorData: { code: validation.errorCode } }, { workflowStep: 'complete', statusCode: -1 });
+      return;
+    }
+    try {
+      const payload = {
+        targetProduct: this.workflowCfg.productName,
+        additionalQueryParams: queryParams,
+        payload: { workflow: selectedVerbType, locale: getLocale(), action },
+        ...(this.id ? { assetId: this.id } : { query: this.query }),
+      };
+      const { url } = await this.serviceHandler.postCallToService(
+        this.apiConfig.connectorApiEndPoint,
+        { body: JSON.stringify(payload) },
+      );
+      this.logAnalytics('generate', eventData, { workflowStep: 'complete', statusCode: 0 });
+      this.query = '';
+      this.id = '';
+      this.resetDropdown();
+      if (url) window.location.href = url;
+    } catch (err) {
+      this.serviceHandler.showErrorToast({ errorToastEl: this.errorToastEl, errorType: '.icon-error-request' }, err);
+      this.logAnalytics('generate', { ...eventData,
+        errorData: { code: 'request-failed', subCode: err.status, desc: err.message },
+      }, { workflowStep: 'complete', statusCode: -1 });
+      window.lana?.log(`Content generation failed:, Error: ${err}`, this.lanaOptions);
+    }
+  }
+
+  setPrompt(el) {
+    this.query = el.getAttribute('aria-label')?.trim();
+    this.id = el.getAttribute('id')?.trim();
+    this.generateContent();
+    this.hideDropdown();
+  }
+
+  addAccessibility() {
+    this.addKeyDown();
+  }
+
+  addKeyDown() {
+    this.rmvKeyDown();
+    this.block.addEventListener('keydown', this.boundHandleKeyDown);
+  }
+
+  rmvKeyDown() {
+    this.block.removeEventListener('keydown', this.boundHandleKeyDown);
+  }
+
+  handleKeyDown(ev) {
+    const validKeys = ['Tab', 'ArrowDown', 'ArrowUp', 'Enter', 'Escape'];
+    if (!validKeys.includes(ev.key)) return;
+    const dropItems = this.getDropdownItems();
+    const focusElems = this.getFocusElems(dropItems.length > 0);
+    const currIdx = focusElems.indexOf(document.activeElement);
+    const isDropVisi = this.isDropdownVisible();
+    switch (ev.key) {
+      case 'Tab':
+        if (!isDropVisi) return;
+        this.handleTab(ev, focusElems, dropItems, currIdx);
+        break;
+      case 'ArrowDown':
+        ev.preventDefault();
+        this.moveFocusWithArrow(dropItems, 'down');
+        break;
+      case 'ArrowUp':
+        ev.preventDefault();
+        this.moveFocusWithArrow(dropItems, 'up');
+        break;
+      case 'Enter':
+        this.handleEnter(ev, dropItems, focusElems, currIdx);
+        break;
+      case 'Escape':
+        this.inputField.focus();
+        this.hideDropdown();
+        break;
+      default:
+        break;
+    }
+  }
+
+  getDropdownItems() {
+    if (!this.dropdown) return [];
+    const dynamicItems = Array.from(this.dropdown?.querySelectorAll('.drop-item.dynamic'));
+    let tipCon = null;
+    if (this.viewport !== 'MOBILE') tipCon = this.dropdown?.querySelector('.tip-con');
+    if (dynamicItems.length > 0) return tipCon ? [...dynamicItems, tipCon] : dynamicItems;
+    const allItems = Array.from(this.dropdown?.querySelectorAll('.drop-item'));
+    return tipCon ? [...allItems, tipCon] : allItems;
+  }
+
+  getFocusElems() {
+    let elmSelector = this.block.querySelector('.close-btn.dynamic') ? '.close-btn.dynamic,.drop-item.dynamic' : '.close-btn,.drop-item';
+    if (this.viewport !== 'MOBILE') elmSelector = `${elmSelector}, .legal-text`;
+    const selector = `.inp-field, .gen-btn, ${elmSelector}`;
+    return Array.from(this.block.querySelectorAll(selector));
+  }
+
+  isDropdownVisible = () => !this.dropdown?.classList.contains('hidden');
+
+  handleTab(event, focusableElements, dropItems, currentIndex) {
+    if (!focusableElements.length) return;
+    event.preventDefault();
+    const isShift = event.shiftKey;
+    const currentElement = document.activeElement;
+    if (currentElement.classList.contains('tip-con')) {
+      if (!isShift) {
+        const legalText = this.block.querySelector('.legal-text');
+        if (legalText) {
+          legalText.focus();
+          return;
+        }
+      }
+    }
+    const nextIndex = isShift
+      ? (currentIndex - 1 + focusableElements.length) % focusableElements.length
+      : (currentIndex + 1) % focusableElements.length;
+    focusableElements[nextIndex].focus();
+    const newActiveIndex = dropItems.indexOf(focusableElements[nextIndex]);
+    this.activeIndex = newActiveIndex !== -1 ? newActiveIndex : -1;
+  }
+
+  moveFocusWithArrow(dropItems, direction) {
+    if (this.activeIndex === -1 || !this.isDropdownItemFocused(dropItems)) this.activeIndex = direction === 'down' ? 0 : dropItems.length - 1;
+    else this.activeIndex = direction === 'down' ? (this.activeIndex + 1) % dropItems.length : (this.activeIndex - 1 + dropItems.length) % dropItems.length;
+    this.setActiveItem(dropItems, this.activeIndex, this.inputField);
+  }
+
+  isDropdownItemFocused = (dropItems) => dropItems.some((item) => item === document.activeElement);
+
+  handleEnter(ev, dropItems, focusElems, currIdx) {
+    ev.preventDefault();
+    const nonInteractiveRoles = ['note', 'presentation'];
+    const role = document.activeElement.getAttribute('role');
+    if (role && nonInteractiveRoles.includes(role)) return;
+    if (
+      this.activeIndex >= 0
+      && dropItems[this.activeIndex]
+      && dropItems[this.activeIndex] === document.activeElement
+    ) {
+      this.setPrompt(dropItems[this.activeIndex]);
+      this.activeIndex = -1;
+      return;
+    }
+    const tarElem = focusElems[currIdx] || ev.target;
+    const actions = { 'inp-field': () => this.inpRedirect() };
+    if (tarElem) {
+      const matchCls = Object.keys(actions).find((cls) => tarElem.classList.contains(cls));
+      if (matchCls) actions[matchCls]();
+      else if (currIdx !== -1) tarElem.click();
+    }
+  }
+
+  setActiveItem(items, index, input) {
+    items.forEach((item, i) => {
+      if (i === index) {
+        input.setAttribute('aria-activedescendant', item.id || 'tip-content');
+        item.focus();
+      }
+    });
+  }
+
+  async inpRedirect() {
+    if (!this.query) return;
+    await this.generateContent();
+  }
+
+  showDropdown() {
+    this.dropdown?.classList.remove('hidden');
+    this.dropdown?.removeAttribute('inert');
+    this.inputField.setAttribute('aria-expanded', 'true');
+    this.dropdown?.removeAttribute('aria-hidden');
+    document.addEventListener('click', this.boundOutsideClickHandler, true);
+  }
+
+  hideDropdown() {
+    if (this.isDropdownVisible()) {
+      this.dropdown?.classList.add('hidden');
+      this.dropdown?.setAttribute('inert', '');
+      this.dropdown?.setAttribute('aria-hidden', 'true');
+      this.inputField.setAttribute('aria-expanded', 'false');
+      document.removeEventListener('click', this.boundOutsideClickHandler, true);
+    }
+  }
+
+  handleOutsideClick(event) {
+    if (!this.widget?.contains(event.target)) this.hideDropdown();
+  }
+
+  resetDropdown() {
+    this.inputField.focus();
+    if (!this.query) this.inputField.value = '';
+    this.hideDropdown();
+  }
+}
diff --git a/unitylibs/core/workflow/workflow-firefly/sprite.svg b/unitylibs/core/workflow/workflow-firefly/sprite.svg
new file mode 100644
index 000000000..1424cbb6c
--- /dev/null
+++ b/unitylibs/core/workflow/workflow-firefly/sprite.svg
@@ -0,0 +1,27 @@
+<svg width="0" height="0" class="hidden">
+  <symbol xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 10" id="unity-close-icon">
+    <path d="M5.74243 4.86514L9.38696 1.2209C9.59204 1.01582 9.59204 0.683595 9.38696 0.478516C9.18188 0.273437 8.84966 0.273437 8.64458 0.478516L5 4.12275L1.35542 0.478516C1.15034 0.273437 0.818117 0.273437 0.613038 0.478516C0.407959 0.683595 0.407959 1.01582 0.613038 1.2209L4.25757 4.86514L0.613038 8.50937C0.407959 8.71445 0.407959 9.04668 0.613038 9.25176C0.715574 9.35429 0.849904 9.40557 0.984227 9.40557C1.11855 9.40557 1.25288 9.3543 1.35542 9.25176L4.99999 5.60752L8.64457 9.25176C8.74711 9.35429 8.88144 9.40557 9.01576 9.40557C9.15008 9.40557 9.28441 9.3543 9.38695 9.25176C9.59203 9.04668 9.59203 8.71445 9.38695 8.50937L5.74243 4.86514Z" fill="#292929"></path>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 21" id="unity-info-icon">
+    <path d="M10 19.5317C5.1748 19.5317 1.25 15.6069 1.25 10.7817C1.25 5.95654 5.1748 2.03174 10 2.03174C14.8252 2.03174 18.75 5.95654 18.75 10.7817C18.75 15.6069 14.8252 19.5317 10 19.5317ZM10 3.53174C6.00195 3.53174 2.75 6.78369 2.75 10.7817C2.75 14.7798 6.00195 18.0317 10 18.0317C13.998 18.0317 17.25 14.7798 17.25 10.7817C17.25 6.78369 13.998 3.53174 10 3.53174Z" fill="#292929"></path>
+    <path d="M10.0006 6.04219C10.2313 6.03406 10.456 6.11606 10.6273 6.27081C10.9576 6.63586 10.9576 7.19183 10.6273 7.55688C10.4579 7.71539 10.2324 7.79996 10.0006 7.79192C9.76426 7.8014 9.53472 7.71157 9.36759 7.54417C9.20552 7.37627 9.11843 7.14985 9.12622 6.91662C9.11384 6.68165 9.19581 6.45147 9.35392 6.27722C9.5275 6.11248 9.76179 6.02734 10.0006 6.04219Z" fill="#292929"></path>
+    <path d="M10 15.8442C9.58594 15.8442 9.25 15.5083 9.25 15.0942V10.2593C9.25 9.84522 9.58594 9.50928 10 9.50928C10.4141 9.50928 10.75 9.84522 10.75 10.2593V15.0942C10.75 15.5083 10.4141 15.8442 10 15.8442Z" fill="#292929"></path>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 19" id="unity-prompt-icon">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M15.5694 7.51298L14.1114 6.10478L14.253 4.0833C14.253 4.08037 14.254 4.07646 14.254 4.07353C14.2735 3.74345 14.1495 3.42119 13.9083 3.18486C13.4581 2.75029 12.7374 2.76201 12.297 3.21318L10.8917 4.67119L8.87314 4.52959C8.54013 4.50811 8.20419 4.63115 7.97568 4.86943C7.76279 5.0872 7.64756 5.37529 7.65146 5.68095C7.65537 5.98564 7.77939 6.27079 7.99912 6.48368L9.45713 7.89188L9.31553 9.90848C9.29014 10.2483 9.41709 10.5784 9.66026 10.8118C9.87413 11.0188 10.1534 11.1311 10.4503 11.1311H10.4737C10.7784 11.1253 11.0626 11.0003 11.2696 10.7835L12.6769 9.32547L14.6945 9.46707C15.0284 9.48367 15.3624 9.36551 15.5968 9.12234C16.0333 8.67117 16.0206 7.94951 15.5694 7.51298Z" fill="#292929"></path>
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M7.22908 13.4642L7.3326 11.9847C7.34676 11.7914 7.27449 11.6029 7.13485 11.4671C6.87557 11.2152 6.46053 11.222 6.2076 11.4837L5.17977 12.5511L3.69735 12.4466C3.5035 12.4359 3.31551 12.5062 3.18417 12.6449C3.06259 12.7699 2.99716 12.9359 3.00009 13.1107C3.00253 13.2855 3.07333 13.4486 3.19931 13.5707L4.26523 14.6029L4.16025 16.0843C4.14804 16.2718 4.21787 16.4574 4.35507 16.5941C4.48202 16.7191 4.64755 16.7816 4.81405 16.7816C4.98446 16.7816 5.15536 16.7162 5.28573 16.5834L6.316 15.5199L7.79549 15.6195C7.98641 15.638 8.17684 15.5599 8.30428 15.4261C8.42782 15.3011 8.4952 15.1351 8.49373 14.9593C8.49226 14.7836 8.42244 14.6185 8.295 14.4945L7.22908 13.4642Z" fill="#292929"></path>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 21" id="unity-refresh-icon">
+    <path d="M18.2065 3.89745C17.8013 3.80272 17.3984 4.04784 17.3013 4.45116L16.9208 6.02587C15.5231 3.59399 12.919 2.02148 10 2.02148C6.31544 2.02148 3.12452 4.52148 2.24073 8.10156C2.14112 8.5039 2.38673 8.91015 2.78907 9.00976C3.19044 9.10937 3.59766 8.86328 3.69678 8.46093C4.41504 5.55273 7.00684 3.52148 10 3.52148C12.5168 3.52148 14.735 4.96777 15.809 7.1538L13.7065 6.6455C13.3032 6.55175 12.8989 6.79589 12.8013 7.19921C12.7041 7.60155 12.9517 8.00683 13.354 8.10448L16.5992 8.88866C16.724 8.97728 16.8729 9.03124 17.0308 9.03124C17.0903 9.03124 17.1509 9.0244 17.2109 9.00976C17.2592 8.9978 17.2968 8.96874 17.3401 8.94872C17.4097 8.93017 17.4835 8.92919 17.5459 8.89061C17.7153 8.78709 17.8369 8.6201 17.8838 8.42674L18.7593 4.80272C18.8564 4.40038 18.6089 3.9951 18.2065 3.89745Z" fill="#292929"/>
+    <path d="M17.2109 11.0322C16.814 10.9355 16.4028 11.1787 16.3032 11.5811C15.585 14.4902 12.9932 16.5215 10 16.5215C7.48298 16.5215 5.26478 15.075 4.19087 12.8879L6.29347 13.3965C6.6963 13.4883 7.10158 13.2461 7.19874 12.8428C7.29591 12.4404 7.04835 12.0352 6.64601 11.9375L3.39107 11.1509C3.22005 11.0327 3.00576 10.9795 2.78908 11.0322C2.77388 11.0361 2.76308 11.0469 2.74837 11.0515C2.64516 11.0647 2.54445 11.0957 2.45412 11.1514C2.28469 11.2549 2.1631 11.4219 2.11623 11.6152L1.24074 15.2393C1.14357 15.6416 1.39113 16.0469 1.79347 16.1445C1.85304 16.1582 1.91212 16.165 1.97023 16.165C2.30861 16.165 2.61574 15.9346 2.69875 15.5908L3.07918 14.0161C4.47682 16.4482 7.08107 18.0215 10 18.0215C13.6846 18.0215 16.8755 15.5205 17.7593 11.9404C17.8589 11.5381 17.6133 11.1318 17.2109 11.0322Z" fill="#292929"/>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 19" id="unity-search-icon">
+    <path d="M17.5303 16.835L12.447 11.7517C13.4164 10.5503 14 9.02526 14 7.36523C14 3.50585 10.8594 0.365234 7 0.365234C3.14062 0.365234 0 3.50584 0 7.36522C0 11.2246 3.14062 14.3652 7 14.3652C8.66003 14.3652 10.1851 13.7816 11.3865 12.8122L16.4697 17.8955C16.6162 18.042 16.8076 18.1152 17 18.1152C17.1924 18.1152 17.3838 18.042 17.5303 17.8955C17.8232 17.6025 17.8232 17.1279 17.5303 16.835ZM7 12.8652C3.96777 12.8652 1.5 10.3975 1.5 7.36522C1.5 4.33299 3.96777 1.86522 7 1.86522C10.0322 1.86522 12.5 4.33299 12.5 7.36522C12.5 10.3975 10.0322 12.8652 7 12.8652Z" fill="#292929"></path>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" id="unity-chevron-icon">
+   <path d="M5.99805 9.3014C6.04688 9.3014 6.09326 9.28138 6.14148 9.27357C6.20874 9.26283 6.27734 9.26063 6.34119 9.23463C6.45093 9.19007 6.55371 9.12342 6.64258 9.03456L11.335 4.34314C11.6904 3.98767 11.6904 3.40955 11.335 3.05408C10.9795 2.69861 10.4023 2.69763 10.0459 3.05408L5.99805 7.10108L1.9502 3.05408C1.59375 2.69763 1.01661 2.69861 0.661139 3.05408C0.48341 3.23181 0.39454 3.46521 0.39454 3.69861C0.39454 3.93201 0.48341 4.16541 0.661139 4.34314L5.35352 9.03455C5.44239 9.12342 5.54517 9.19007 5.65491 9.23462C5.71875 9.26062 5.78736 9.26282 5.85462 9.27356C5.90284 9.28137 5.94922 9.3014 5.99805 9.3014Z" fill="#292929"></path>
+  </symbol>
+  <symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" id="unity-checkmark-icon">
+   <path d="M3.50115 9.50298C3.20135 9.50298 2.91717 9.36821 2.72674 9.13579L0.276542 6.13579C-0.0730679 5.70806 -0.00958785 5.07817 0.418142 4.72856C0.845872 4.37797 1.47673 4.44243 1.82537 4.87016L3.4826 6.89946L8.16228 0.888716C8.50115 0.453166 9.12908 0.372116 9.5656 0.713916C10.0012 1.05279 10.0793 1.68169 9.7404 2.11724L4.2902 9.11724C4.10368 9.35747 3.81754 9.49908 3.51286 9.50298H3.50115Z" fill="#3B63FB"></path>
+  </symbol>
+</svg>
\ No newline at end of file
diff --git a/unitylibs/core/workflow/workflow-firefly/target-config.json b/unitylibs/core/workflow/workflow-firefly/target-config.json
new file mode 100644
index 000000000..14510c952
--- /dev/null
+++ b/unitylibs/core/workflow/workflow-firefly/target-config.json
@@ -0,0 +1,18 @@
+{
+  "hero-marquee": {
+    "type": "text",
+    "selector": ".copy",
+    "handler": "render",
+    "renderWidget": true,
+    "source": ".copy .main-copy",
+    "target": "a:last-of-type",
+    "insert": "before",
+    "actionMap": {
+      ".inp-field": { "actionType": "autocomplete" },
+      ".gen-btn": { "actionType": "generate" },
+      ".close-btn": { "actionType": "closeDropdown" },
+      ".drop-item": { "actionType": "setPromptValue" }
+    },
+    "sendSplunkAnalytics": true
+  }
+}
diff --git a/unitylibs/core/workflow/workflow-firefly/widget.css b/unitylibs/core/workflow/workflow-firefly/widget.css
new file mode 100644
index 000000000..86415a4a2
--- /dev/null
+++ b/unitylibs/core/workflow/workflow-firefly/widget.css
@@ -0,0 +1,720 @@
+.hero-marquee.unity-enabled {
+  overflow: unset;
+}
+
+.hero-marquee.unity-enabled::before {
+  content: '';
+  position: absolute;
+  bottom: -5px;
+  left: 0;
+  right: 0;
+  height: 20px;
+  pointer-events: none;
+  background: linear-gradient(180deg, rgba(255 255 255 / 0%), rgba(255 255 255 / 50%));
+  filter: blur(5px);
+  backdrop-filter: blur(1px);
+  opacity: 0.8;
+}
+
+.hero-marquee.unity-enabled .interactive-area {
+  display: inherit;
+  justify-content: center;
+  background: none;
+}
+
+.hero-marquee.unity-enabled .interactive-area .text {
+  max-width: 800px;
+  margin: var(--spacing-xxl) 0 var(--spacing-m);
+}
+
+.hero-marquee.unity-enabled .icon-area {
+  height: 32px;
+  width: auto;
+  margin: 0 auto;
+}
+
+.hero-marquee.unity-enabled [class^="heading-"]:only-of-type,
+.hero-marquee [class^="heading-"]:last-of-type {
+  margin-bottom: var(--spacing-xxs);
+}
+
+.hero-marquee.unity-enabled .interactive-area .text .body-m {
+  font-weight: 400;
+}
+
+.hero-marquee.unity-enabled p:last-of-type {
+  font-size: var(--type-body-xs-size);
+  line-height: var(--type-body-xs-lh);
+  padding-top: var(--spacing-s);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap {
+  position: relative;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .alert-holder {
+  background: none;
+  transform: translateY(-100%);
+  bottom: 30%;
+  top: unset;
+}
+
+.unity-enabled .interactive-area .alert-holder .alert-toast {
+  width: auto;
+  max-width: 340px;
+}
+
+.unity-enabled .interactive-area .alert-holder .alert-toast .alert-content .alert-icon {
+  justify-content: space-between;
+  width: 100%;
+}
+
+.unity-enabled .interactive-area .alert-holder .alert-toast .alert-content .alert-text {
+  width: auto;
+}
+
+.unity-enabled .interactive-area .alert-holder .alert-toast .alert-content .alert-text p {
+  padding-top: 0;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap + a {
+  display: inline-block;
+  margin-top: var(--spacing-xs);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .unity-sprite-container {
+  display: none;
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  white-space: nowrap;
+  border: 0;
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .widget-bg {
+  opacity: 0;
+  visibility: hidden;
+  -webkit-backdrop-filter: blur(30px);
+  backdrop-filter: blur(30px);
+  height: 10rem;
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  display: flex;
+  transition: opacity 0.1s cubic-bezier(0, 0, 1, 1), visibility 0.1s cubic-bezier(0, 0, 1, 1);
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky .widget-bg {
+  opacity: 1;
+  visibility: visible;
+  transition: opacity 0.2s cubic-bezier(0, 0, 1, 1), visibility 0.2s cubic-bezier(0, 0, 1, 1);
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky.hidden .widget-bg {
+  visibility: hidden;
+  opacity: 0;
+  transform: translateY(-5px);
+  transition: opacity 0.2s cubic-bezier(0, 0, 1, 1), visibility 0.2s cubic-bezier(0, 0, 1, 1), translate 0.2s cubic-bezier(0, 0, 1, 1);
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .widget-bg.blur {
+  -webkit-mask: linear-gradient(#0000 0%, #000 95%);
+  mask: linear-gradient(#0000 0%, #000 95%);
+  filter: blur(40px);
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .widget-bg .bg-one {
+  background-image: linear-gradient(#b2dfff00, #b2dfffb3 48%, #b2dfff);
+  flex: 0 auto;
+  width: 60%;
+  height: 100%;
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .widget-bg .bg-two {
+  background-image: linear-gradient(#b0acfe00, #b0acfebf 43%, #b0acfe);
+  flex: 0 auto;
+  width: 60%;
+  height: 100%;
+  position: absolute;
+  right: 0;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap:not(.sticky) .ex-unity-widget {
+  padding: 0 var(--spacing-l);
+  animation: fade-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
+  position: relative;
+  z-index: 1;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget {
+  width: 720px;
+  animation: fade-out 0.9s cubic-bezier(0.34, 1.56, 0.64, 1);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky.hidden .ex-unity-widget {
+  animation: none;
+}
+
+@keyframes fade-in {
+  0% {
+    opacity: 0;
+  }
+
+  100% {
+    opacity: 1;
+  }
+}
+@keyframes fade-out {
+  0% {
+    opacity: 1;
+  }
+
+  100% {
+    transform: translateY(0);
+  }
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .autocomplete {
+  position: relative;
+  background: linear-gradient(88.83deg, rgba(255 255 255 / 80%) 1.96%, rgba(255 255 255 / 20%) 415.55%);
+  border-radius: var(--spacing-m);
+  box-shadow: 0 0 10px #0000001c;
+  border-top: 1px solid #FFFFFFA8;
+  width: 720px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap {
+  display: flex;
+  padding-right: var(--spacing-xxs);
+  align-items: center;
+  border-radius: var(--spacing-m);
+  gap: var(--spacing-s);
+  background: transparent;
+  transition: background 0.3s ease-in-out;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap:hover {
+  background: rgba(255 255 255 / 30%);
+  transition: background 0.2s ease-in-out;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap:focus-within {
+  background: rgba(255 255 255 / 60%);
+  transition: background 0.2s ease-in-out;
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky.hidden {
+  visibility: hidden;
+  opacity: 0;
+  transform: translateY(-3px);
+  transition: opacity 0.1s cubic-bezier(0, 0, 1, 1), visibility 0.5s cubic-bezier(0, 0, 1, 1), translate 0.1s cubic-bezier(0, 0, 1, 1);
+}
+
+.hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky {
+  position: fixed;
+  bottom: 30px;
+  left: 0;
+  z-index: 101;
+  width: 100%;
+  display: flex;
+  justify-content: center;
+  visibility: visible;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget .inp-wrap {
+  background: linear-gradient(rgba(255 255 255 / 80%), rgba(255 255 255 / 80%));
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget .inp-wrap:hover {
+  background: linear-gradient(rgba(255 255 255 / 90%), rgba(255 255 255 / 90%));
+  transition: background 0.2s ease-in-out;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget .inp-wrap:focus-within {
+  background: linear-gradient(rgba(255 255 255 / 100%), rgba(255 255 255 / 100%));
+  transition: background 0.2s ease-in-out;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap .inp-field {
+  padding: 9px 5px 10px;
+  flex: 1;
+  color: #222;
+  font-size: var(--type-body-s-size);
+  font-weight: 400;
+  line-height: 20.8px;
+  border: none;
+  width: 100%;
+  border-radius: 3px;
+  font-family: inherit;
+  outline: none;
+  background: linear-gradient(rgba(255 255 255 / 0%), rgba(55 255 255 / 0%));
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap .inp-field::placeholder {
+  font-style: italic;
+  color: #222;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap {
+  display: flex;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .unity-act-btn {
+  text-decoration: none;
+  display: flex;
+  align-items: center;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .unity-act-btn:focus {
+  outline: 2px solid #005FCC;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .unity-act-btn .btn-ico {
+  display: flex;
+  align-content: center;
+}
+
+.unity-enabled .interactive-area .selected-verb > img {
+  position: relative;
+  top: 1px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .unity-act-btn .btn-ico img {
+  width: 24px;
+  height: 24px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .unity-act-btn .btn-txt {
+  display: flex;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .surprise-btn {
+  border-radius: 16px;
+  border: 2px solid #292929;
+  color: #292929;
+  font-size: var(--type-body-xs-size);
+  font-weight: 700;
+  line-height: normal;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .surprise-btn.hidden {
+  display: none;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .gen-btn {
+  border-radius: 25px;
+  background: linear-gradient(90deg, #D73220 0%, #D92361 33%, #7155FA 100%);
+  border: none;
+  padding: 12px 24px 14px;
+  gap: 8px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap .gen-btn .btn-txt {
+  color: var(--color-white);
+  font-size: 19px;
+  font-weight: 700;
+  line-height: normal;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop {
+  background: linear-gradient(0deg, rgba(255 255 255 / 100%) 0%, rgba(255 255 255 / 100%) 100%), linear-gradient(89deg, rgba(255 255 255 / 80%) 1.01%, rgba(255 255 255 / 20%) 111.14%);
+  box-shadow: 0 2px 8px 0 rgba(0 0 0 / 16%);
+  list-style: none;
+  width: 100%;
+  border-radius: 16px;
+  padding: 8px 0;
+  margin: 8px 0 0;
+  position: absolute;
+  z-index: 1;
+  opacity: 1;
+  visibility: visible;
+  transform: translateY(0);
+  transition: opacity 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),visibility 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget .drop.open-upward {
+  bottom: 100%;
+  margin-bottom: 10px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop.hidden {
+  opacity: 0;
+  visibility: hidden;
+  transform: translateY(-10px);
+  transition: opacity 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), visibility 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: var(--spacing-xxs) var(--spacing-xs);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con .drop-title {
+  font-weight: 700;
+  font-size: var(--type-body-s-size);
+  color: #292929;
+  line-height: 20.8px;
+  padding: 0 var(--spacing-xxs);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con .close-btn {
+  background: transparent;
+  border: 0;
+  cursor: pointer;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con.dynamic .close-btn {
+  margin-left: auto;
+}
+
+.unity-enabled .interactive-area .selected-verb .menu-icon,
+.unity-enabled .interactive-area .verb-list .verb-link .selected-icon {
+  font-size: 0;
+}
+
+.unity-enabled .interactive-area .selected-verb .menu-icon,
+.unity-enabled .interactive-area .selected-verb .menu-icon svg,
+.unity-enabled .interactive-area .verb-list .verb-link .selected-icon,
+.unity-enabled .interactive-area .verb-list .verb-link .selected-icon svg {
+  width: 12px;
+  height: 12px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con .close-btn svg {
+  width: 10px;
+  height: 10px;
+  display: block;
+  padding: 5px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con.dynamic .title-text {
+  color: var(--color-gray-500);
+  font-weight: 900;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con.dynamic .refresh-btn {
+  margin-left: 5px;
+  background: transparent;
+  border: 0;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-item svg {
+  display: inline-block;
+  width: 20px;
+  height: 20px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con.dynamic .refresh-btn svg {
+  width: 15px;
+  height: 15px;
+  display: block;
+  cursor: pointer;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop-title-con.hidden {
+  display: none;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-item {
+  cursor: pointer;
+  color: #292929;
+  font-size: var(--type-body-s-size);
+  font-weight: 400;
+  line-height: var(--type-body-s-lh);
+  padding: var(--spacing-xxs) var(--spacing-xs);
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-xxs);
+  text-align: left;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-empty-msg {
+  min-height: 150px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-item.hidden {
+  display: none;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-item:hover {
+  background-color: #e6e6e6;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-sep {
+  border-top: 1px solid #E1E1E1;
+  margin: 0 16px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer {
+  padding: var(--spacing-xxs) var(--spacing-xs);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: var(--type-body-s-size);
+  color: #292929;
+  font-weight: 400;
+  line-height: var(--type-body-s-lh);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .tip-con {
+  display: flex;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .tip-con.active {
+  border: 1px solid #005FCC;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .tip-con svg {
+  width: 20px;
+  height: 20px;
+  padding-right: var(--spacing-xxs);
+  margin-top: 3px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .tip-con .tip-text {
+  font-weight: 700;
+  margin-right: 5px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .legal-con {
+  margin-left: auto;
+  display: flex;
+  align-items: center;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .legal-con::before {
+  content: "|";
+  color: #C6C6C6;
+  margin-right: var(--spacing-xxs);;
+  font-size: 12px;
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .legal-con .legal-text {
+  color: #5258E4;
+  text-decoration: none;
+  font-weight: 500;
+  font-size: 14px;
+  line-height: var(--type-detail-s-lh);
+}
+
+.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer .legal-con .legal-text:focus {
+  outline: 2px solid #005FCC;
+}
+
+.unity-enabled .interactive-area .verbs-container {
+  display: flex;
+  flex-wrap: wrap;
+  border-right: 1px solid rgb(0 0 0 / 9%);
+  width: 144px;
+  height: 70px;
+  justify-content: flex-start;
+}
+
+.unity-enabled .interactive-area .verbs-container .menu-icon {
+  position: relative;
+  top: 1px;
+  transition: transform 0.15s ease-in;
+}
+
+.unity-enabled .interactive-area .verbs-container.show-menu .menu-icon {
+  transform: rotate(-180deg);
+}
+
+.unity-enabled .interactive-area .selected-verb {
+  display: flex;
+  align-items: center;
+  gap: 7px;
+  justify-content: stretch;
+  padding: 0 32px;
+  border-right: 1px solid #000;
+  color: #333;
+  cursor: pointer;
+  border: none;
+  background: none;
+  font-size: 16px;
+  font-family: inherit;
+  text-transform: capitalize;
+  width: 100%;
+  height: 100%;
+}
+
+.unity-enabled .interactive-area .selected-verb[disabled="true"] {
+  cursor: auto;
+} 
+
+.unity-enabled .interactive-area .verb-list {
+  display: none;
+  padding: 18px;
+  list-style: none;
+  background: #fff;
+  box-shadow: 0 0 10px #0000001c;
+  border-radius: 10px;
+  color: #292929;
+  margin: 8px 0 0;
+}
+
+.unity-enabled .interactive-area .verbs-container.show-menu .verb-list {
+  display: block;
+}
+
+.unity-enabled .interactive-area .verb-list .verb-link {
+  color: inherit;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 10px 10px 10px 20px;
+  text-transform: capitalize;
+  text-decoration: none;
+  position: relative;
+}
+
+.unity-enabled .interactive-area .verb-list .verb-item .selected-icon {
+  display: none;
+}
+
+.unity-enabled .interactive-area .verb-list .verb-item.selected .selected-icon {
+  display: block;
+  position: absolute;
+  top: 50%;
+  left: 3px;
+  transform: translateY(-50%);
+}
+
+@media (max-width: 1024px) {
+  .unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .autocomplete {
+    width: auto;
+  }
+
+  .unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap {
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding: var(--spacing-m);
+  }
+
+  .unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap .inp-field {
+    order: 1;
+    flex: 1 1 100%;
+  }
+
+  .unity-enabled .interactive-area .verbs-container {
+    order: 2;
+    border-right: none;
+    height: auto;
+    position: relative;
+  }
+
+  .unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .act-wrap {
+    order: 3;
+  }
+
+  .unity-enabled .interactive-area .selected-verb {
+    padding: 0;
+  }
+
+  .unity-enabled .interactive-area .verb-list {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    transform: translateY(70px);
+  }
+
+  .unity-enabled .interactive-area .ex-unity-wrap .alert-holder {
+    transform: translateY(-80%);
+    bottom: 0;
+  }
+}
+
+@media (min-width: 768px) and (max-width: 1024px) {
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget {
+    padding: 0;
+    max-width: 720px;
+    margin: 0 auto;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky {
+    bottom: 16px;
+  }
+}
+
+@media (min-width: 600px) and (max-width: 767px) {
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget {
+    padding: 0;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky {
+    bottom: 16px;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget {
+    width: 95%;
+  }
+}
+
+@media screen and (max-width: 599px) {
+  .hero-marquee.unity-enabled h1,
+  .hero-marquee.unity-enabled h2,
+  .hero-marquee.unity-enabled h3,
+  .hero-marquee.unity-enabled h4,
+  .hero-marquee.unity-enabled h5 {
+    font-size: var(--type-heading-xl-size);
+    line-height: var(--type-heading-xl-lh);
+  }
+
+  .hero-marquee.unity-enabled p {
+    font-size: var(--type-body-s-size);
+    line-height: var(--type-body-s-lh);
+  }   
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky {
+    bottom: 16px;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap {
+    row-gap: var(--spacing-s);
+    column-gap: 0;
+    padding: var(--spacing-s);
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget {
+    padding: 0;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap.sticky .ex-unity-widget {
+    width: 95%;
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .inp-wrap .inp-field {
+    width: 100%;
+    padding: 2px 0;
+    line-height: var(--type-detail-xl-size);
+  }
+
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-sep,
+  .hero-marquee.unity-enabled .interactive-area .ex-unity-wrap .ex-unity-widget .drop .drop-footer {
+    display: none;
+  }
+
+  .unity-enabled .interactive-area .verbs-container {
+    width: auto;
+  }
+
+  .unity-enabled .interactive-area .verbs-container.show-menu .verb-list {
+    width: 140px;
+  }
+
+  .unity-enabled .interactive-area .ex-unity-wrap .alert-holder {
+    transform: translateY(-90%);
+  }
+}
diff --git a/unitylibs/core/workflow/workflow-firefly/widget.js b/unitylibs/core/workflow/workflow-firefly/widget.js
new file mode 100644
index 000000000..d7195d931
--- /dev/null
+++ b/unitylibs/core/workflow/workflow-firefly/widget.js
@@ -0,0 +1,356 @@
+/* eslint-disable class-methods-use-this */
+
+import { createTag, getConfig, unityConfig } from '../../../scripts/utils.js';
+
+export default class UnityWidget {
+  constructor(target, el, workflowCfg, spriteCon) {
+    this.el = el;
+    this.target = target;
+    this.workflowCfg = workflowCfg;
+    this.widget = null;
+    this.actionMap = {};
+    this.spriteCon = spriteCon;
+    this.prompts = null;
+    this.selectedVerbType = '';
+    this.closeBtn = null;
+    this.promptItems = [];
+    this.genBtn = null;
+    this.hasPromptSuggestions = false;
+    this.lanaOptions = { sampleRate: 100, tags: 'Unity-FF' };
+  }
+
+  async initWidget() {
+    const [widgetWrap, widget, unitySprite] = ['ex-unity-wrap', 'ex-unity-widget', 'unity-sprite-container']
+      .map((c) => createTag('div', { class: c }));
+    this.widgetWrap = widgetWrap;
+    this.widget = widget;
+    unitySprite.innerHTML = this.spriteCon;
+    this.widgetWrap.append(unitySprite);
+    this.workflowCfg.placeholder = this.popPlaceholders();
+    const hasPromptPlaceholder = !!this.el.querySelector('.icon-placeholder-prompt');
+    const hasSuggestionsPlaceholder = !!this.el.querySelector('.icon-placeholder-suggestions');
+    this.hasPromptSuggestions = hasPromptPlaceholder && hasSuggestionsPlaceholder;
+    const inputWrapper = this.createInpWrap(this.workflowCfg.placeholder);
+    let dropdown = null;
+    if (this.hasPromptSuggestions) dropdown = await this.genDropdown(this.workflowCfg.placeholder);
+    const comboboxContainer = createTag('div', { class: 'autocomplete', role: 'combobox' });
+    comboboxContainer.append(inputWrapper);
+    if (dropdown) comboboxContainer.append(dropdown);
+    this.widget.append(comboboxContainer);
+    this.addWidget();
+    if (this.workflowCfg.targetCfg.floatPrompt) this.initIO();
+    return this.workflowCfg.targetCfg.actionMap;
+  }
+
+  popPlaceholders() {
+    return Object.fromEntries(
+      [...this.el.querySelectorAll('[class*="placeholder"]')].map((element) => [
+        element.classList[1]?.replace('icon-', '') || '',
+        element.closest('li')?.innerText || '',
+      ]).filter(([key]) => key),
+    );
+  }
+
+  showVerbMenu(selectedElement) {
+    const menuContainer = selectedElement.parentElement;
+    document.querySelectorAll('.verbs-container').forEach((container) => {
+      if (container !== menuContainer) {
+        container.classList.remove('show-menu');
+        container.querySelector('.selected-verb')?.setAttribute('aria-expanded', 'false');
+      }
+    });
+    menuContainer.classList.toggle('show-menu');
+    selectedElement.setAttribute('aria-expanded', menuContainer.classList.contains('show-menu') ? 'true' : 'false');
+  }
+
+  hidePromptDropdown() {
+    const dropdown = this.widget.querySelector('#prompt-dropdown');
+    const inputField = this.widget.querySelector('.inp-field');
+    if (dropdown && !dropdown.classList.contains('hidden')) {
+      dropdown.classList.add('hidden');
+      dropdown.setAttribute('inert', '');
+      dropdown.setAttribute('aria-hidden', 'true');
+      if (inputField) inputField.setAttribute('aria-expanded', 'false');
+    }
+  }
+
+  updateAnalytics(verb) {
+    if (this.closeBtn) {
+      this.closeBtn.setAttribute('daa-ll', `X Close Prompt--${verb}--Prompt suggestions`);
+    }
+    if (this.promptItems && this.promptItems.length > 0) {
+      this.promptItems.forEach((item) => {
+        const ariaLabel = item.getAttribute('aria-label') || '';
+        item.setAttribute('daa-ll', `${ariaLabel.slice(0, 20)}--${verb}--Prompt suggestion`);
+      });
+    }
+    if (this.genBtn) {
+      this.genBtn.setAttribute('daa-ll', `Generate--${verb}`);
+    }
+  }
+
+  handleVerbLinkClick(link, verbList, selectedElement, menuIcon, inputPlaceHolder) {
+    return (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      verbList.querySelectorAll('.verb-link').forEach((listLink) => {
+        listLink.parentElement.classList.remove('selected');
+        listLink.parentElement.setAttribute('aria-label', `${listLink.getAttribute('data-verb-type')} prompt: ${inputPlaceHolder}`);
+      });
+      selectedElement.parentElement.classList.toggle('show-menu');
+      selectedElement.setAttribute('aria-expanded', selectedElement.parentElement.classList.contains('show-menu') ? 'true' : 'false');
+      link.parentElement.classList.add('selected');
+      const copiedNodes = link.cloneNode(true).childNodes;
+      copiedNodes[0].remove();
+      this.selectedVerbType = link.getAttribute('data-verb-type');
+      selectedElement.replaceChildren(...copiedNodes, menuIcon);
+      selectedElement.dataset.selectedVerb = this.selectedVerbType;
+      selectedElement.setAttribute('aria-label', `${this.selectedVerbType} prompt: ${inputPlaceHolder}`);
+      selectedElement.focus();
+      link.parentElement.setAttribute('aria-label', `${this.selectedVerbType} prompt selected:  ${inputPlaceHolder}`);
+      this.updateDropdownForVerb(this.selectedVerbType);
+      this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+      this.updateAnalytics(this.selectedVerbType);
+    };
+  }
+
+  verbDropdown() {
+    const verbs = this.el.querySelectorAll('[class*="icon-verb"]');
+    const inputPlaceHolder = this.el.querySelector('.icon-placeholder-input').parentElement.textContent;
+    const selectedVerbType = verbs[0]?.className.split('-')[2];
+    const selectedVerb = verbs[0]?.nextElementSibling;
+    const { href } = selectedVerb;
+    const selectedElement = createTag('button', {
+      class: 'selected-verb',
+      'aria-expanded': 'false',
+      'aria-controls': 'prompt-menu',
+      'aria-label': `${selectedVerbType} prompt: ${inputPlaceHolder}`,
+      'data-selected-verb': selectedVerbType,
+    }, `<img src="${href}" alt="" />${selectedVerbType}`);
+    this.selectedVerbType = selectedVerbType;
+    this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+    if (verbs.length <= 1) {
+      selectedElement.setAttribute('disabled', 'true');
+      return [selectedElement];
+    }
+    const menuIcon = createTag('span', { class: 'menu-icon' }, '<svg><use xlink:href="#unity-chevron-icon"></use></svg>');
+    const verbList = createTag('ul', { class: 'verb-list', id: 'prompt-menu' });
+    selectedElement.append(menuIcon);
+    const handleDocumentClick = (e) => {
+      const menuContainer = selectedElement.parentElement;
+      if (!menuContainer.contains(e.target)) {
+        document.removeEventListener('click', handleDocumentClick);
+        menuContainer.classList.remove('show-menu');
+        selectedElement.setAttribute('aria-expanded', 'false');
+      }
+    };
+    selectedElement.addEventListener('click', (e) => {
+      e.stopPropagation();
+      this.hidePromptDropdown();
+      this.showVerbMenu(selectedElement);
+      document.addEventListener('click', handleDocumentClick);
+    }, true);
+    selectedElement.addEventListener('keydown', (e) => {
+      if (e.key === 'Enter' || e.key === ' ') {
+        this.hidePromptDropdown();
+        this.showVerbMenu(selectedElement);
+      }
+      if (e.key === 'Escape' || e.code === 27) {
+        selectedElement.parentElement.classList?.remove('show-menu');
+        selectedElement.focus();
+      }
+    });
+    verbs.forEach((verb, idx) => {
+      const name = verb.nextElementSibling?.textContent.trim();
+      const verbType = verb.className.split('-')[2];
+      const icon = verb.nextElementSibling?.href;
+      const item = createTag('li', {
+        class: 'verb-item',
+        'aria-label': `${verbType} prompt: ${inputPlaceHolder}`,
+      });
+      const selectedIcon = createTag('span', { class: 'selected-icon' }, '<svg><use xlink:href="#unity-checkmark-icon"></use></svg>');
+      const link = createTag('a', {
+        href: '#',
+        class: 'verb-link',
+        'data-verb-type': verbType,
+      }, `<img src="${icon}" alt="" />${name}`);
+      if (idx === 0) {
+        item.classList.add('selected');
+        item.setAttribute('aria-label', `${verbType} prompt selected: ${inputPlaceHolder}`);
+      }
+      verbs[0].classList.add('selected');
+      link.prepend(selectedIcon);
+      item.append(link);
+      verbList.append(item);
+      link.addEventListener('click', this.handleVerbLinkClick(link, verbList, selectedElement, menuIcon, inputPlaceHolder));
+    });
+    return [selectedElement, verbList];
+  }
+
+  createInpWrap(ph) {
+    const inpWrap = createTag('div', { class: 'inp-wrap' });
+    const actWrap = createTag('div', { class: 'act-wrap' });
+    const verbBtn = createTag('div', { class: 'verbs-container', 'aria-label': 'Prompt options' });
+    const inpField = createTag('input', {
+      id: 'promptInput',
+      class: 'inp-field',
+      type: 'text',
+      placeholder: ph['placeholder-input'],
+      'aria-autocomplete': 'list',
+      'aria-haspopup': 'listbox',
+      'aria-controls': 'prompt-dropdown',
+      'aria-expanded': 'false',
+      'aria-owns': 'prompt-dropdown',
+      'aria-activedescendant': '',
+    });
+    const verbDropdown = this.verbDropdown();
+    const genBtn = this.createActBtn(this.el.querySelector('.icon-generate')?.closest('li'), 'gen-btn');
+    actWrap.append(genBtn);
+    verbBtn.append(...verbDropdown);
+    inpWrap.append(verbBtn, inpField, actWrap);
+    return inpWrap;
+  }
+
+  getLimitedDisplayPrompts(prompts) {
+    const shuffled = prompts.sort(() => 0.5 - Math.random());
+    return shuffled.slice(0, 3).map(({ prompt, assetid }) => ({
+      prompt,
+      assetid,
+      displayPrompt: prompt.length > 105 ? `${prompt.slice(0, 105)}…` : prompt,
+    }));
+  }
+
+  addPromptItemsToDropdown(dropdown, prompts, placeholder) {
+    this.promptItems = [];
+    prompts.forEach(({ prompt, assetid, displayPrompt }, idx) => {
+      const item = createTag('li', {
+        id: assetid,
+        class: 'drop-item',
+        role: 'option',
+        tabindex: '0',
+        'aria-label': prompt,
+        'aria-description': `${placeholder['placeholder-prompt']} ${placeholder['placeholder-suggestions']}`,
+        'daa-ll': `${prompt.slice(0, 20)}--${this.selectedVerbType}--Prompt suggestion`,
+      }, `<svg><use xlink:href="#unity-prompt-icon"></use></svg> ${displayPrompt}`);
+      dropdown.insertBefore(item, dropdown.children[2 + idx]);
+      this.promptItems.push(item);
+    });
+  }
+
+  async genDropdown(ph) {
+    if (!this.hasPromptSuggestions) return null;
+    const dd = createTag('ul', {
+      id: 'prompt-dropdown',
+      class: 'drop hidden',
+      'daa-lh': 'Marquee',
+      role: 'listbox',
+      'aria-labelledby': 'promptInput',
+      'aria-hidden': 'true',
+    });
+    const titleCon = createTag('li', { class: 'drop-title-con', 'aria-labelledby': 'prompt-suggestions' });
+    const title = createTag('span', { class: 'drop-title', id: 'prompt-suggestions' }, `${ph['placeholder-prompt']} ${ph['placeholder-suggestions']}`);
+    const closeBtn = createTag('button', { class: 'close-btn', 'daa-ll': `X Close Prompt--${this.selectedVerbType}--Prompt suggestions`, 'aria-label': 'Close dropdown' }, '<svg><use xlink:href="#unity-close-icon"></use></svg>');
+    closeBtn.addEventListener('click', () => {
+      dd.classList.add('hidden');
+      dd.setAttribute('aria-hidden', 'true');
+    });
+    this.closeBtn = closeBtn;
+    titleCon.append(title, closeBtn);
+    dd.append(titleCon);
+    const prompts = await this.getPrompt(this.selectedVerbType);
+    const limited = this.getLimitedDisplayPrompts(prompts);
+    this.addPromptItemsToDropdown(dd, limited, ph);
+    dd.append(createTag('li', { class: 'drop-sep', role: 'separator' }));
+    dd.append(this.createFooter(ph));
+    return dd;
+  }
+
+  createFooter(ph) {
+    const footer = createTag('li', { class: 'drop-footer' });
+    const tipEl = this.el.querySelector('.icon-tip')?.closest('li');
+    const tipCon = createTag('div', { id: 'tip-content', class: 'tip-con', tabindex: '-1', role: 'note', 'aria-label': `${ph['placeholder-tip']} ${tipEl?.innerText}` }, '<svg><use xlink:href="#unity-info-icon"></use></svg>');
+    const tipText = createTag('span', { class: 'tip-text', id: 'tip-text' }, `${ph['placeholder-tip']}:`);
+    const tipDesc = createTag('span', { class: 'tip-desc', id: 'tip-desc' }, tipEl?.innerText || '');
+    tipCon.append(tipText, tipDesc);
+    const legalEl = this.el.querySelector('.icon-legal')?.closest('li');
+    const legalCon = createTag('div', { class: 'legal-con' });
+    const legalLink = legalEl?.querySelector('a');
+    const legalText = createTag('a', { href: legalLink?.href || '#', class: 'legal-text' }, legalLink?.innerText || 'Legal');
+    legalCon.append(legalText);
+    footer.append(tipCon, legalCon);
+    return footer;
+  }
+
+  createActBtn(cfg, cls) {
+    if (!cfg) return null;
+    const txt = cfg.innerText?.trim();
+    const img = cfg.querySelector('img[src*=".svg"]');
+    const btn = createTag('a', { href: '#', class: `unity-act-btn ${cls}`, 'daa-ll': `Generate--${this.selectedVerbType}` });
+    if (img) btn.append(createTag('div', { class: 'btn-ico' }, img));
+    if (txt) btn.append(createTag('div', { class: 'btn-txt' }, txt.split('\n')[0]));
+    this.genBtn = btn;
+    return btn;
+  }
+
+  addWidget() {
+    const interactArea = this.target.querySelector('.copy');
+    const para = interactArea?.querySelector(this.workflowCfg.targetCfg.target);
+    this.widgetWrap.append(this.widget);
+    if (para && this.workflowCfg.targetCfg.insert === 'before') para.before(this.widgetWrap);
+    else if (para) para.after(this.widgetWrap);
+    else interactArea?.appendChild(this.widgetWrap);
+  }
+
+  async loadPrompts() {
+    const { locale } = getConfig();
+    const { origin } = window.location;
+    const baseUrl = (origin.includes('.aem.') || origin.includes('.hlx.'))
+      ? `https://main--unity--adobecom.${origin.includes('.hlx.') ? 'hlx' : 'aem'}.live`
+      : origin;
+    const promptFile = locale.prefix && locale.prefix !== '/'
+      ? `${baseUrl}${locale.prefix}/unity/configs/prompt/firefly-prompt.json`
+      : `${baseUrl}/unity/configs/prompt/firefly-prompt.json`;
+    const promptRes = await fetch(promptFile);
+    if (!promptRes.ok) {
+      throw new Error('Failed to fetch prompts.');
+    }
+    const promptJson = await promptRes.json();
+    this.prompts = this.createPromptMap(promptJson?.content?.data);
+  }
+
+  async getPrompt(verb) {
+    if (!this.hasPromptSuggestions) return [];
+    try {
+      if (!this.prompts || Object.keys(this.prompts).length === 0) await this.loadPrompts();
+      return (this.prompts?.[verb] || []).filter((item) => item.prompt && item.prompt.trim() !== '');
+    } catch (e) {
+      window.lana?.log(`Message: Error loading promts, Error: ${e}`, this.lanaOptions);
+      return [];
+    }
+  }
+
+  createPromptMap(data) {
+    const promptMap = {};
+    if (Array.isArray(data)) {
+      data.forEach((item) => {
+        const itemEnv = item.env || 'prod';
+        if (item.verb && item.prompt && item.assetid && itemEnv === unityConfig.env) {
+          if (!promptMap[item.verb]) promptMap[item.verb] = [];
+          promptMap[item.verb].push({ prompt: item.prompt, assetid: item.assetid });
+        }
+      });
+    }
+    return promptMap;
+  }
+
+  async updateDropdownForVerb(verb) {
+    if (!this.hasPromptSuggestions) return;
+    const dropdown = this.widget.querySelector('#prompt-dropdown');
+    if (!dropdown) return;
+    dropdown.querySelectorAll('.drop-item').forEach((item) => item.remove());
+    const prompts = await this.getPrompt(verb);
+    const limited = this.getLimitedDisplayPrompts(prompts);
+    this.addPromptItemsToDropdown(dropdown, limited, this.workflowCfg.placeholder);
+    this.widgetWrap.dispatchEvent(new CustomEvent('firefly-reinit-action-listeners'));
+  }
+}
diff --git a/unitylibs/core/workflow/workflow-upload/action-binder.js b/unitylibs/core/workflow/workflow-upload/action-binder.js
index 1e028d66d..c8b042a9e 100644
--- a/unitylibs/core/workflow/workflow-upload/action-binder.js
+++ b/unitylibs/core/workflow/workflow-upload/action-binder.js
@@ -306,18 +306,14 @@ export default class ActionBinder {
   }
 
   async initAnalytics() {
-    if (this.workflowCfg.targetCfg.sendSplunkAnalytics) {
+    if (!this.sendAnalyticsToSplunk && this.workflowCfg.targetCfg.sendSplunkAnalytics) {
       this.sendAnalyticsToSplunk = (await import(`${getUnityLibs()}/scripts/splunk-analytics.js`)).default;
     }
   }
 
   logAnalyticsinSplunk(eventName, data) {
     if (this.sendAnalyticsToSplunk) {
-      const category = this.workflowCfg.productName;
-      this.sendAnalyticsToSplunk(eventName, {
-        eventName,
-        ...data,
-      }, `${unityConfig.apiEndPoint}/log`, category);
+      this.sendAnalyticsToSplunk(eventName, this.workflowCfg.productName, data, `${unityConfig.apiEndPoint}/log`);
     }
   }
 
diff --git a/unitylibs/core/workflow/workflow.js b/unitylibs/core/workflow/workflow.js
index 90d8eaaee..db4fbfe2e 100644
--- a/unitylibs/core/workflow/workflow.js
+++ b/unitylibs/core/workflow/workflow.js
@@ -50,7 +50,7 @@ function createInteractiveArea(el, pic) {
 
 async function getTargetArea(el) {
   const metadataSec = el.closest('.section');
-  const intEnb = metadataSec.querySelector('.marquee, .aside');
+  const intEnb = metadataSec.querySelector('.marquee, .aside, .hero-marquee');
   try {
     intEnb.classList.add('unity-enabled');
     await intEnbReendered(intEnb);
@@ -134,6 +134,7 @@ class WfInitiator {
         `${getUnityLibs()}/core/features/progress-circle/progress-circle.css`,
       ],
       'workflow-ai': sharedWfRes,
+      'workflow-firefly': sharedWfRes,
     };
     const commonResources = [
       `${baseWfPath}/target-config.json`,
@@ -316,6 +317,11 @@ class WfInitiator {
         sfList: new Set([feature]),
         psw,
       },
+      'workflow-firefly': {
+        productName: 'Firefly',
+        sfList: new Set(['text-to-mage']),
+        stList: new Set(['prompt', 'tip', 'legal', 'generate']),
+      },
     };
     if (!wfName || !workflowCfg[wfName]) return [];
     return {
diff --git a/unitylibs/scripts/splunk-analytics.js b/unitylibs/scripts/splunk-analytics.js
index e05bd906d..528669a70 100644
--- a/unitylibs/scripts/splunk-analytics.js
+++ b/unitylibs/scripts/splunk-analytics.js
@@ -7,12 +7,16 @@ function getSessionID() {
   return tokenPayload.sub || tokenPayload.user_id;
 }
 
-function createPayloadForSplunk(metaData, category) {
-  const { eventName, errorData, redirectUrl, assetId } = metaData;
+function createPayloadForSplunk(metaData) {
+  const { eventName, product, errorData, redirectUrl, assetId, statusCode, verb, action, workflowStep } = metaData;
   return {
     event: {
       name: eventName,
-      category,
+      category: product,
+      ...(verb && { subcategory: verb }),
+      ...(action && { action }),
+      ...(statusCode!==undefined && { statusCode }),
+      ...(workflowStep && { workflowStep }),
     },
     content: { ...(assetId && { assetId }) },
     source: {
@@ -34,9 +38,10 @@ function createPayloadForSplunk(metaData, category) {
   };
 }
 
-export default function sendAnalyticsToSplunk(eventName, metaData, splunkEndpoint, category) {
+export default function sendAnalyticsToSplunk(eventName, product, metaData, splunkEndpoint, sendBeacon=false) {
   try {
-    const eventDataPayload = createPayloadForSplunk({ ...metaData, eventName }, category);
+    const eventDataPayload = createPayloadForSplunk({ ...metaData, eventName, product });
+    if (navigator.sendBeacon && navigator.sendBeacon(splunkEndpoint, JSON.stringify(eventDataPayload))) return;
     fetch(splunkEndpoint, {
       method: 'POST',
       headers: { 'Content-Type': 'application/json' },


Reviews:
user: login: sanjayms01
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T00:08:10Z
user: login: sanjayms01
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T00:13:15Z
user: login: sanjayms01
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T00:14:43Z
user: login: sanjayms01
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-23T00:15:14Z
user: login: rgclayton
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T01:00:23Z
user: login: rgclayton
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T01:45:26Z
user: login: rgclayton
body: @Ruchika4 I noticed `workflow-upload/action-binder.js` is included in this as a modified file. Is that expected?
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T03:39:56Z

Review comments:
diff_hunk: @@ -0,0 +1,18 @@
+{
+  "hero-marquee": {
+    "type": "text",
+    "selector": ".copy",
+    "handler": "render",
+    "renderWidget": true,
+    "source": ".copy .main-copy",
+    "target": "a:last-of-type",
+    "insert": "before",
+    "actionMap": {
+      ".inp-field": { "actionType": "autocomplete" },
+      ".gen-btn": { "actionType": "generate" },
+      ".close-btn": { "actionType": "closeDropdown" },
+      ".drop-item": { "actionType": "setPromptValue" }
+    },
+    "sendSplunkAnalytics": true
+  }
+}
path: unitylibs/core/workflow/workflow-firefly/target-config.json
user: login: sanjayms01
body: nit: Add new line to EOF.
created_at: 2025-05-23T00:08:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,349 @@
+/* eslint-disable class-methods-use-this */
+
+import { createTag, getConfig } from '../../../scripts/utils.js';
+
+export default class UnityWidget {
+  constructor(target, el, workflowCfg, spriteCon) {
+    this.el = el;
+    this.target = target;
+    this.workflowCfg = workflowCfg;
+    this.widget = null;
+    this.actionMap = {};
+    this.spriteCon = spriteCon;
+    this.prompts = null;
+    this.selectedVerbType = '';
+    this.closeBtn = null;
+    this.promptItems = [];
+    this.genBtn = null;
+    this.hasPromptSuggestions = false;
+  }
+
+  async initWidget() {
+    const [widgetWrap, widget, unitySprite] = ['ex-unity-wrap', 'ex-unity-widget', 'unity-sprite-container']
+      .map((c) => createTag('div', { class: c }));
+    this.widgetWrap = widgetWrap;
+    this.widget = widget;
+    unitySprite.innerHTML = this.spriteCon;
+    this.widgetWrap.append(unitySprite);
+    this.workflowCfg.placeholder = this.popPlaceholders();
+    const hasPromptPlaceholder = !!this.el.querySelector('.icon-placeholder-prompt');
+    const hasSuggestionsPlaceholder = !!this.el.querySelector('.icon-placeholder-suggestions');
+    this.hasPromptSuggestions = hasPromptPlaceholder && hasSuggestionsPlaceholder;
+    const inputWrapper = this.createInpWrap(this.workflowCfg.placeholder);
+    let dropdown = null;
+    if (this.hasPromptSuggestions) dropdown = await this.genDropdown(this.workflowCfg.placeholder);
+    const comboboxContainer = createTag('div', { class: 'autocomplete', role: 'combobox' });
+    comboboxContainer.append(inputWrapper);
+    if (dropdown) comboboxContainer.append(dropdown);
+    this.widget.append(comboboxContainer);
+    this.addWidget();
+    if (this.workflowCfg.targetCfg.floatPrompt) this.initIO();
+    return this.workflowCfg.targetCfg.actionMap;
+  }
+
+  popPlaceholders() {
+    return Object.fromEntries(
+      [...this.el.querySelectorAll('[class*="placeholder"]')].map((element) => [
+        element.classList[1]?.replace('icon-', '') || '',
+        element.closest('li')?.innerText || '',
+      ]).filter(([key]) => key),
+    );
+  }
+
+  showVerbMenu(selectedElement) {
+    const menuContainer = selectedElement.parentElement;
+    document.querySelectorAll('.verbs-container').forEach((container) => {
+      if (container !== menuContainer) {
+        container.classList.remove('show-menu');
+        container.querySelector('.selected-verb')?.setAttribute('aria-expanded', 'false');
+      }
+    });
+    menuContainer.classList.toggle('show-menu');
+    selectedElement.setAttribute('aria-expanded', menuContainer.classList.contains('show-menu') ? 'true' : 'false');
+  }
+
+  hidePromptDropdown() {
+    const dropdown = this.widget.querySelector('#prompt-dropdown');
+    const inputField = this.widget.querySelector('.inp-field');
+    if (dropdown && !dropdown.classList.contains('hidden')) {
+      dropdown.classList.add('hidden');
+      dropdown.setAttribute('inert', '');
+      dropdown.setAttribute('aria-hidden', 'true');
+      if (inputField) inputField.setAttribute('aria-expanded', 'false');
+    }
+  }
+
+  updateAnalytics(verb) {
+    if (this.closeBtn) {
+      this.closeBtn.setAttribute('daa-ll', `X Close Prompt--${verb}--Prompt suggestions`);
+    }
+    if (this.promptItems && this.promptItems.length > 0) {
+      this.promptItems.forEach((item) => {
+        const ariaLabel = item.getAttribute('aria-label') || '';
+        item.setAttribute('daa-ll', `${ariaLabel.slice(0, 20)}--${verb}--Prompt suggestion`);
+      });
+    }
+    if (this.genBtn) {
+      this.genBtn.setAttribute('daa-ll', `Generate--${verb}`);
+    }
+  }
+
+  handleVerbLinkClick(link, verbList, selectedElement, menuIcon) {
+    return (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      verbList.querySelectorAll('.verb-link').forEach((listLink) => {
+        listLink.parentElement.classList.remove('selected');
+        listLink.parentElement.removeAttribute('aria-label');
+      });
+      selectedElement.parentElement.classList.toggle('show-menu');
+      selectedElement.setAttribute('aria-expanded', selectedElement.parentElement.classList.contains('show-menu') ? 'true' : 'false');
+      link.parentElement.classList.add('selected');
+      const copiedNodes = link.cloneNode(true).childNodes;
+      copiedNodes[0].remove();
+      this.selectedVerbType = link.getAttribute('data-verb-type');
+      selectedElement.replaceChildren(...copiedNodes, menuIcon);
+      selectedElement.dataset.selectedVerb = this.selectedVerbType;
+      selectedElement.setAttribute('aria-label', `${this.selectedVerbType} prompt type selected`);
+      selectedElement.focus();
+      link.parentElement.setAttribute('aria-label', `${this.selectedVerbType} prompt type selected`);
+      this.updateDropdownForVerb(this.selectedVerbType);
+      this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+      this.updateAnalytics(this.selectedVerbType);
+    };
+  }
+
+  verbDropdown() {
+    const verbs = this.el.querySelectorAll('[class*="icon-verb"]');
+    const selectedVerbType = verbs[0]?.className.split('-')[2];
+    const selectedVerb = verbs[0]?.nextElementSibling;
+    const { href } = selectedVerb;
+    const selectedElement = createTag('button', {
+      class: 'selected-verb',
+      'aria-expanded': 'false',
+      'aria-controls': 'prompt-menu',
+      'aria-label': `${selectedVerbType} prompt type selected`,
+      'data-selected-verb': selectedVerbType,
+    }, `<img src="${href}" alt="" />${selectedVerbType}`);
+    this.selectedVerbType = selectedVerbType;
+    this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+    if (verbs.length <= 1) {
+      selectedElement.setAttribute('disabled', 'true');
+      return [selectedElement];
+    }
+    const menuIcon = createTag('span', { class: 'menu-icon' }, '<svg><use xlink:href="#unity-chevron-icon"></use></svg>');
+    const verbList = createTag('ul', { class: 'verb-list', id: 'prompt-menu' });
+    selectedElement.append(menuIcon);
+    const handleDocumentClick = (e) => {
+      const menuContainer = selectedElement.parentElement;
+      if (!menuContainer.contains(e.target)) {
+        document.removeEventListener('click', handleDocumentClick);
+        menuContainer.classList.remove('show-menu');
+        selectedElement.setAttribute('aria-expanded', 'false');
+      }
+    };
+    selectedElement.addEventListener('click', (e) => {
+      e.stopPropagation();
+      this.hidePromptDropdown();
+      this.showVerbMenu(selectedElement);
+      document.addEventListener('click', handleDocumentClick);
+    }, true);
+    selectedElement.addEventListener('keydown', (e) => {
+      if (e.key === 'Enter' || e.key === ' ') {
+        this.hidePromptDropdown();
+        this.showVerbMenu(selectedElement);
+      }
+      if (e.key === 'Escape' || e.code === 27) {
+        selectedElement.parentElement.classList?.remove('show-menu');
+        selectedElement.focus();
+      }
+    });
+    verbs.forEach((verb, idx) => {
+      const name = verb.nextElementSibling?.textContent.trim();
+      const verbType = verb.className.split('-')[2];
+      const icon = verb.nextElementSibling?.href;
+      const item = createTag('li', { class: 'verb-item' });
+      const selectedIcon = createTag('span', { class: 'selected-icon' }, '<svg><use xlink:href="#unity-checkmark-icon"></use></svg>');
+      const link = createTag('a', {
+        href: '#',
+        class: 'verb-link',
+        'data-verb-type': verbType,
+      }, `<img src="${icon}" alt="" />${name}`);
+      if (idx === 0) {
+        item.classList.add('selected');
+        item.setAttribute('aria-label', `${verbType} prompt type selected`);
+      }
+      verbs[0].classList.add('selected');
+      link.prepend(selectedIcon);
+      item.append(link);
+      verbList.append(item);
+      link.addEventListener('click', this.handleVerbLinkClick(link, verbList, selectedElement, menuIcon));
+    });
+    return [selectedElement, verbList];
+  }
+
+  createInpWrap(ph) {
+    const inpWrap = createTag('div', { class: 'inp-wrap' });
+    const actWrap = createTag('div', { class: 'act-wrap' });
+    const verbBtn = createTag('div', { class: 'verbs-container', 'aria-label': 'Prompt options' });
+    const inpField = createTag('input', {
+      id: 'promptInput',
+      class: 'inp-field',
+      type: 'text',
+      placeholder: ph['placeholder-input'],
+      'aria-autocomplete': 'list',
+      'aria-haspopup': 'listbox',
+      'aria-controls': 'prompt-dropdown',
+      'aria-expanded': 'false',
+      'aria-owns': 'prompt-dropdown',
+      'aria-activedescendant': '',
+    });
+    const verbDropdown = this.verbDropdown();
+    const genBtn = this.createActBtn(this.el.querySelector('.icon-generate')?.closest('li'), 'gen-btn');
+    actWrap.append(genBtn);
+    verbBtn.append(...verbDropdown);
+    inpWrap.append(verbBtn, inpField, actWrap);
+    return inpWrap;
+  }
+
+  getLimitedDisplayPrompts(prompts) {
+    const shuffled = prompts.sort(() => 0.5 - Math.random());
+    return shuffled.slice(0, 3).map(({ prompt, assetid }) => ({
+      prompt,
+      assetid,
+      displayPrompt: prompt.length > 105 ? `${prompt.slice(0, 105)}…` : prompt,
+    }));
+  }
+
+  addPromptItemsToDropdown(dropdown, prompts, placeholder) {
+    this.promptItems = [];
+    prompts.forEach(({ prompt, assetid, displayPrompt }, idx) => {
+      const item = createTag('li', {
+        id: assetid,
+        class: 'drop-item',
+        role: 'option',
+        tabindex: '0',
+        'aria-label': prompt,
+        'aria-description': `${placeholder['placeholder-prompt']} ${placeholder['placeholder-suggestions']}`,
+        'daa-ll': `${prompt.slice(0, 20)}--${this.selectedVerbType}--Prompt suggestion`,
+      }, `<svg><use xlink:href="#unity-prompt-icon"></use></svg> ${displayPrompt}`);
+      dropdown.insertBefore(item, dropdown.children[2 + idx]);
+      this.promptItems.push(item);
+    });
+  }
+
+  async genDropdown(ph) {
+    if (!this.hasPromptSuggestions) return null;
+    const dd = createTag('ul', {
+      id: 'prompt-dropdown',
+      class: 'drop hidden',
+      'daa-lh': 'Marquee',
+      role: 'listbox',
+      'aria-labelledby': 'promptInput',
+      'aria-hidden': 'true',
+    });
+    const titleCon = createTag('li', { class: 'drop-title-con', 'aria-labelledby': 'prompt-suggestions' });
+    const title = createTag('span', { class: 'drop-title', id: 'prompt-suggestions' }, `${ph['placeholder-prompt']} ${ph['placeholder-suggestions']}`);
+    const closeBtn = createTag('button', { class: 'close-btn', 'daa-ll': `X Close Prompt--${this.selectedVerbType}--Prompt suggestions`, 'aria-label': 'Close dropdown' }, '<svg><use xlink:href="#unity-close-icon"></use></svg>');
+    closeBtn.addEventListener('click', () => {
+      dd.classList.add('hidden');
+      dd.setAttribute('aria-hidden', 'true');
+    });
+    this.closeBtn = closeBtn;
+    titleCon.append(title, closeBtn);
+    dd.append(titleCon);
+    const prompts = await this.getPrompt(this.selectedVerbType);
+    const limited = this.getLimitedDisplayPrompts(prompts);
+    this.addPromptItemsToDropdown(dd, limited, ph);
+    dd.append(createTag('li', { class: 'drop-sep', role: 'separator' }));
+    dd.append(this.createFooter(ph));
+    return dd;
+  }
+
+  createFooter(ph) {
+    const footer = createTag('li', { class: 'drop-footer' });
+    const tipEl = this.el.querySelector('.icon-tip')?.closest('li');
+    const tipCon = createTag('div', { id: 'tip-content', class: 'tip-con', tabindex: '-1', role: 'note', 'aria-label': `${ph['placeholder-tip']} ${tipEl?.innerText}` }, '<svg><use xlink:href="#unity-info-icon"></use></svg>');
+    const tipText = createTag('span', { class: 'tip-text', id: 'tip-text' }, `${ph['placeholder-tip']}:`);
+    const tipDesc = createTag('span', { class: 'tip-desc', id: 'tip-desc' }, tipEl?.innerText || '');
+    tipCon.append(tipText, tipDesc);
+    const legalEl = this.el.querySelector('.icon-legal')?.closest('li');
+    const legalCon = createTag('div', { class: 'legal-con' });
+    const legalLink = legalEl?.querySelector('a');
+    const legalText = createTag('a', { href: legalLink?.href || '#', class: 'legal-text' }, legalLink?.innerText || 'Legal');
+    legalCon.append(legalText);
+    footer.append(tipCon, legalCon);
+    return footer;
+  }
+
+  createActBtn(cfg, cls) {
+    if (!cfg) return null;
+    const txt = cfg.innerText?.trim();
+    const img = cfg.querySelector('img[src*=".svg"]');
+    const btn = createTag('a', { href: '#', class: `unity-act-btn ${cls}`, 'daa-ll': `Generate--${this.selectedVerbType}` });
+    if (img) btn.append(createTag('div', { class: 'btn-ico' }, img));
+    if (txt) btn.append(createTag('div', { class: 'btn-txt' }, txt.split('\n')[0]));
+    this.genBtn = btn;
+    return btn;
+  }
+
+  addWidget() {
+    const interactArea = this.target.querySelector('.copy');
+    const para = interactArea?.querySelector(this.workflowCfg.targetCfg.target);
+    this.widgetWrap.append(this.widget);
+    if (para && this.workflowCfg.targetCfg.insert === 'before') para.before(this.widgetWrap);
+    else if (para) para.after(this.widgetWrap);
+    else interactArea?.appendChild(this.widgetWrap);
+  }
+
+  async loadPrompts() {
+    const { locale } = getConfig();
+    const { origin } = window.location;
+    const baseUrl = (origin.includes('.aem.') || origin.includes('.hlx.'))
+      ? `https://main--unity--adobecom.${origin.includes('.hlx.') ? 'hlx' : 'aem'}.live`
+      : origin;
+    const promptFile = locale.prefix && locale.prefix !== '/'
+      ? `${baseUrl}${locale.prefix}/unity/configs/prompt/firefly-prompt.json`
+      : `${baseUrl}/unity/configs/prompt/firefly-prompt.json`;
+    const promptRes = await fetch(promptFile);
+    if (!promptRes.ok) {
+      throw new Error('Failed to fetch prompts.');
+    }
+    const promptJson = await promptRes.json();
+    this.prompts = this.createPromptMap(promptJson?.content?.data);
+  }
+
+  async getPrompt(verb) {
+    if (!this.hasPromptSuggestions) return [];
+    try {
+      if (!this.prompts || Object.keys(this.prompts).length === 0) await this.loadPrompts();
+      return (this.prompts?.[verb] || []).filter((item) => item.prompt && item.prompt.trim() !== '');
+    } catch (e) {
+      return [];
path: unitylibs/core/workflow/workflow-firefly/widget.js
user: login: sanjayms01
body: Should we log to lana here if we catch an exception here?
created_at: 2025-05-23T00:13:15Z
author_association: COLLABORATOR
diff_hunk: @@ -316,6 +317,11 @@ class WfInitiator {
         sfList: new Set([feature]),
         psw,
       },
+      'workflow-firefly': {
+        productName: 'Firefly',
+        sfList: new Set(['text-to-mage']),
path: unitylibs/core/workflow/workflow.js
user: login: sanjayms01
body: Seems like a typo? Should be `text-to-image`
created_at: 2025-05-23T00:14:43Z
author_association: COLLABORATOR
diff_hunk: @@ -316,6 +317,11 @@ class WfInitiator {
         sfList: new Set([feature]),
         psw,
       },
+      'workflow-firefly': {
+        productName: 'Firefly',
+        sfList: new Set(['text-to-mage']),
path: unitylibs/core/workflow/workflow.js
user: login: rgclayton
body: Hmm. It's the same on line 312 for `workflow-ai`. Not sure why. @Ruchika4?
created_at: 2025-05-23T01:00:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,349 @@
+/* eslint-disable class-methods-use-this */
+
+import { createTag, getConfig } from '../../../scripts/utils.js';
+
+export default class UnityWidget {
+  constructor(target, el, workflowCfg, spriteCon) {
+    this.el = el;
+    this.target = target;
+    this.workflowCfg = workflowCfg;
+    this.widget = null;
+    this.actionMap = {};
+    this.spriteCon = spriteCon;
+    this.prompts = null;
+    this.selectedVerbType = '';
+    this.closeBtn = null;
+    this.promptItems = [];
+    this.genBtn = null;
+    this.hasPromptSuggestions = false;
+  }
+
+  async initWidget() {
+    const [widgetWrap, widget, unitySprite] = ['ex-unity-wrap', 'ex-unity-widget', 'unity-sprite-container']
+      .map((c) => createTag('div', { class: c }));
+    this.widgetWrap = widgetWrap;
+    this.widget = widget;
+    unitySprite.innerHTML = this.spriteCon;
+    this.widgetWrap.append(unitySprite);
+    this.workflowCfg.placeholder = this.popPlaceholders();
+    const hasPromptPlaceholder = !!this.el.querySelector('.icon-placeholder-prompt');
+    const hasSuggestionsPlaceholder = !!this.el.querySelector('.icon-placeholder-suggestions');
+    this.hasPromptSuggestions = hasPromptPlaceholder && hasSuggestionsPlaceholder;
+    const inputWrapper = this.createInpWrap(this.workflowCfg.placeholder);
+    let dropdown = null;
+    if (this.hasPromptSuggestions) dropdown = await this.genDropdown(this.workflowCfg.placeholder);
+    const comboboxContainer = createTag('div', { class: 'autocomplete', role: 'combobox' });
+    comboboxContainer.append(inputWrapper);
+    if (dropdown) comboboxContainer.append(dropdown);
+    this.widget.append(comboboxContainer);
+    this.addWidget();
+    if (this.workflowCfg.targetCfg.floatPrompt) this.initIO();
+    return this.workflowCfg.targetCfg.actionMap;
+  }
+
+  popPlaceholders() {
+    return Object.fromEntries(
+      [...this.el.querySelectorAll('[class*="placeholder"]')].map((element) => [
+        element.classList[1]?.replace('icon-', '') || '',
+        element.closest('li')?.innerText || '',
+      ]).filter(([key]) => key),
+    );
+  }
+
+  showVerbMenu(selectedElement) {
+    const menuContainer = selectedElement.parentElement;
+    document.querySelectorAll('.verbs-container').forEach((container) => {
+      if (container !== menuContainer) {
+        container.classList.remove('show-menu');
+        container.querySelector('.selected-verb')?.setAttribute('aria-expanded', 'false');
+      }
+    });
+    menuContainer.classList.toggle('show-menu');
+    selectedElement.setAttribute('aria-expanded', menuContainer.classList.contains('show-menu') ? 'true' : 'false');
+  }
+
+  hidePromptDropdown() {
+    const dropdown = this.widget.querySelector('#prompt-dropdown');
+    const inputField = this.widget.querySelector('.inp-field');
+    if (dropdown && !dropdown.classList.contains('hidden')) {
+      dropdown.classList.add('hidden');
+      dropdown.setAttribute('inert', '');
+      dropdown.setAttribute('aria-hidden', 'true');
+      if (inputField) inputField.setAttribute('aria-expanded', 'false');
+    }
+  }
+
+  updateAnalytics(verb) {
+    if (this.closeBtn) {
+      this.closeBtn.setAttribute('daa-ll', `X Close Prompt--${verb}--Prompt suggestions`);
+    }
+    if (this.promptItems && this.promptItems.length > 0) {
+      this.promptItems.forEach((item) => {
+        const ariaLabel = item.getAttribute('aria-label') || '';
+        item.setAttribute('daa-ll', `${ariaLabel.slice(0, 20)}--${verb}--Prompt suggestion`);
+      });
+    }
+    if (this.genBtn) {
+      this.genBtn.setAttribute('daa-ll', `Generate--${verb}`);
+    }
+  }
+
+  handleVerbLinkClick(link, verbList, selectedElement, menuIcon) {
+    return (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      verbList.querySelectorAll('.verb-link').forEach((listLink) => {
+        listLink.parentElement.classList.remove('selected');
+        listLink.parentElement.removeAttribute('aria-label');
+      });
+      selectedElement.parentElement.classList.toggle('show-menu');
+      selectedElement.setAttribute('aria-expanded', selectedElement.parentElement.classList.contains('show-menu') ? 'true' : 'false');
+      link.parentElement.classList.add('selected');
+      const copiedNodes = link.cloneNode(true).childNodes;
+      copiedNodes[0].remove();
+      this.selectedVerbType = link.getAttribute('data-verb-type');
+      selectedElement.replaceChildren(...copiedNodes, menuIcon);
+      selectedElement.dataset.selectedVerb = this.selectedVerbType;
+      selectedElement.setAttribute('aria-label', `${this.selectedVerbType} prompt type selected`);
+      selectedElement.focus();
+      link.parentElement.setAttribute('aria-label', `${this.selectedVerbType} prompt type selected`);
+      this.updateDropdownForVerb(this.selectedVerbType);
+      this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+      this.updateAnalytics(this.selectedVerbType);
+    };
+  }
+
+  verbDropdown() {
+    const verbs = this.el.querySelectorAll('[class*="icon-verb"]');
+    const selectedVerbType = verbs[0]?.className.split('-')[2];
+    const selectedVerb = verbs[0]?.nextElementSibling;
+    const { href } = selectedVerb;
+    const selectedElement = createTag('button', {
+      class: 'selected-verb',
+      'aria-expanded': 'false',
+      'aria-controls': 'prompt-menu',
+      'aria-label': `${selectedVerbType} prompt type selected`,
+      'data-selected-verb': selectedVerbType,
+    }, `<img src="${href}" alt="" />${selectedVerbType}`);
+    this.selectedVerbType = selectedVerbType;
+    this.widgetWrap.setAttribute('data-selected-verb', this.selectedVerbType);
+    if (verbs.length <= 1) {
+      selectedElement.setAttribute('disabled', 'true');
+      return [selectedElement];
+    }
+    const menuIcon = createTag('span', { class: 'menu-icon' }, '<svg><use xlink:href="#unity-chevron-icon"></use></svg>');
+    const verbList = createTag('ul', { class: 'verb-list', id: 'prompt-menu' });
+    selectedElement.append(menuIcon);
+    const handleDocumentClick = (e) => {
+      const menuContainer = selectedElement.parentElement;
+      if (!menuContainer.contains(e.target)) {
+        document.removeEventListener('click', handleDocumentClick);
+        menuContainer.classList.remove('show-menu');
+        selectedElement.setAttribute('aria-expanded', 'false');
+      }
+    };
+    selectedElement.addEventListener('click', (e) => {
+      e.stopPropagation();
+      this.hidePromptDropdown();
+      this.showVerbMenu(selectedElement);
+      document.addEventListener('click', handleDocumentClick);
+    }, true);
+    selectedElement.addEventListener('keydown', (e) => {
+      if (e.key === 'Enter' || e.key === ' ') {
+        this.hidePromptDropdown();
+        this.showVerbMenu(selectedElement);
+      }
+      if (e.key === 'Escape' || e.code === 27) {
+        selectedElement.parentElement.classList?.remove('show-menu');
+        selectedElement.focus();
+      }
+    });
+    verbs.forEach((verb, idx) => {
+      const name = verb.nextElementSibling?.textContent.trim();
+      const verbType = verb.className.split('-')[2];
+      const icon = verb.nextElementSibling?.href;
+      const item = createTag('li', { class: 'verb-item' });
+      const selectedIcon = createTag('span', { class: 'selected-icon' }, '<svg><use xlink:href="#unity-checkmark-icon"></use></svg>');
+      const link = createTag('a', {
+        href: '#',
+        class: 'verb-link',
+        'data-verb-type': verbType,
+      }, `<img src="${icon}" alt="" />${name}`);
+      if (idx === 0) {
+        item.classList.add('selected');
+        item.setAttribute('aria-label', `${verbType} prompt type selected`);
+      }
+      verbs[0].classList.add('selected');
+      link.prepend(selectedIcon);
+      item.append(link);
+      verbList.append(item);
+      link.addEventListener('click', this.handleVerbLinkClick(link, verbList, selectedElement, menuIcon));
+    });
+    return [selectedElement, verbList];
+  }
+
+  createInpWrap(ph) {
+    const inpWrap = createTag('div', { class: 'inp-wrap' });
+    const actWrap = createTag('div', { class: 'act-wrap' });
+    const verbBtn = createTag('div', { class: 'verbs-container', 'aria-label': 'Prompt options' });
+    const inpField = createTag('input', {
+      id: 'promptInput',
+      class: 'inp-field',
+      type: 'text',
+      placeholder: ph['placeholder-input'],
+      'aria-autocomplete': 'list',
+      'aria-haspopup': 'listbox',
+      'aria-controls': 'prompt-dropdown',
+      'aria-expanded': 'false',
+      'aria-owns': 'prompt-dropdown',
+      'aria-activedescendant': '',
+    });
+    const verbDropdown = this.verbDropdown();
+    const genBtn = this.createActBtn(this.el.querySelector('.icon-generate')?.closest('li'), 'gen-btn');
+    actWrap.append(genBtn);
+    verbBtn.append(...verbDropdown);
+    inpWrap.append(verbBtn, inpField, actWrap);
+    return inpWrap;
+  }
+
+  getLimitedDisplayPrompts(prompts) {
+    const shuffled = prompts.sort(() => 0.5 - Math.random());
+    return shuffled.slice(0, 3).map(({ prompt, assetid }) => ({
+      prompt,
+      assetid,
+      displayPrompt: prompt.length > 105 ? `${prompt.slice(0, 105)}…` : prompt,
+    }));
+  }
+
+  addPromptItemsToDropdown(dropdown, prompts, placeholder) {
+    this.promptItems = [];
+    prompts.forEach(({ prompt, assetid, displayPrompt }, idx) => {
+      const item = createTag('li', {
+        id: assetid,
+        class: 'drop-item',
+        role: 'option',
+        tabindex: '0',
+        'aria-label': prompt,
+        'aria-description': `${placeholder['placeholder-prompt']} ${placeholder['placeholder-suggestions']}`,
+        'daa-ll': `${prompt.slice(0, 20)}--${this.selectedVerbType}--Prompt suggestion`,
+      }, `<svg><use xlink:href="#unity-prompt-icon"></use></svg> ${displayPrompt}`);
+      dropdown.insertBefore(item, dropdown.children[2 + idx]);
+      this.promptItems.push(item);
+    });
+  }
+
+  async genDropdown(ph) {
+    if (!this.hasPromptSuggestions) return null;
+    const dd = createTag('ul', {
+      id: 'prompt-dropdown',
+      class: 'drop hidden',
+      'daa-lh': 'Marquee',
+      role: 'listbox',
+      'aria-labelledby': 'promptInput',
+      'aria-hidden': 'true',
+    });
+    const titleCon = createTag('li', { class: 'drop-title-con', 'aria-labelledby': 'prompt-suggestions' });
+    const title = createTag('span', { class: 'drop-title', id: 'prompt-suggestions' }, `${ph['placeholder-prompt']} ${ph['placeholder-suggestions']}`);
+    const closeBtn = createTag('button', { class: 'close-btn', 'daa-ll': `X Close Prompt--${this.selectedVerbType}--Prompt suggestions`, 'aria-label': 'Close dropdown' }, '<svg><use xlink:href="#unity-close-icon"></use></svg>');
+    closeBtn.addEventListener('click', () => {
+      dd.classList.add('hidden');
+      dd.setAttribute('aria-hidden', 'true');
+    });
+    this.closeBtn = closeBtn;
+    titleCon.append(title, closeBtn);
+    dd.append(titleCon);
+    const prompts = await this.getPrompt(this.selectedVerbType);
+    const limited = this.getLimitedDisplayPrompts(prompts);
+    this.addPromptItemsToDropdown(dd, limited, ph);
+    dd.append(createTag('li', { class: 'drop-sep', role: 'separator' }));
+    dd.append(this.createFooter(ph));
+    return dd;
+  }
+
+  createFooter(ph) {
+    const footer = createTag('li', { class: 'drop-footer' });
+    const tipEl = this.el.querySelector('.icon-tip')?.closest('li');
+    const tipCon = createTag('div', { id: 'tip-content', class: 'tip-con', tabindex: '-1', role: 'note', 'aria-label': `${ph['placeholder-tip']} ${tipEl?.innerText}` }, '<svg><use xlink:href="#unity-info-icon"></use></svg>');
+    const tipText = createTag('span', { class: 'tip-text', id: 'tip-text' }, `${ph['placeholder-tip']}:`);
+    const tipDesc = createTag('span', { class: 'tip-desc', id: 'tip-desc' }, tipEl?.innerText || '');
+    tipCon.append(tipText, tipDesc);
+    const legalEl = this.el.querySelector('.icon-legal')?.closest('li');
+    const legalCon = createTag('div', { class: 'legal-con' });
+    const legalLink = legalEl?.querySelector('a');
+    const legalText = createTag('a', { href: legalLink?.href || '#', class: 'legal-text' }, legalLink?.innerText || 'Legal');
+    legalCon.append(legalText);
+    footer.append(tipCon, legalCon);
+    return footer;
+  }
+
+  createActBtn(cfg, cls) {
+    if (!cfg) return null;
+    const txt = cfg.innerText?.trim();
+    const img = cfg.querySelector('img[src*=".svg"]');
+    const btn = createTag('a', { href: '#', class: `unity-act-btn ${cls}`, 'daa-ll': `Generate--${this.selectedVerbType}` });
+    if (img) btn.append(createTag('div', { class: 'btn-ico' }, img));
+    if (txt) btn.append(createTag('div', { class: 'btn-txt' }, txt.split('\n')[0]));
+    this.genBtn = btn;
+    return btn;
+  }
+
+  addWidget() {
+    const interactArea = this.target.querySelector('.copy');
+    const para = interactArea?.querySelector(this.workflowCfg.targetCfg.target);
+    this.widgetWrap.append(this.widget);
+    if (para && this.workflowCfg.targetCfg.insert === 'before') para.before(this.widgetWrap);
+    else if (para) para.after(this.widgetWrap);
+    else interactArea?.appendChild(this.widgetWrap);
+  }
+
+  async loadPrompts() {
+    const { locale } = getConfig();
+    const { origin } = window.location;
+    const baseUrl = (origin.includes('.aem.') || origin.includes('.hlx.'))
+      ? `https://main--unity--adobecom.${origin.includes('.hlx.') ? 'hlx' : 'aem'}.live`
+      : origin;
+    const promptFile = locale.prefix && locale.prefix !== '/'
+      ? `${baseUrl}${locale.prefix}/unity/configs/prompt/firefly-prompt.json`
+      : `${baseUrl}/unity/configs/prompt/firefly-prompt.json`;
+    const promptRes = await fetch(promptFile);
+    if (!promptRes.ok) {
+      throw new Error('Failed to fetch prompts.');
+    }
+    const promptJson = await promptRes.json();
+    this.prompts = this.createPromptMap(promptJson?.content?.data);
+  }
+
+  async getPrompt(verb) {
+    if (!this.hasPromptSuggestions) return [];
+    try {
+      if (!this.prompts || Object.keys(this.prompts).length === 0) await this.loadPrompts();
+      return (this.prompts?.[verb] || []).filter((item) => item.prompt && item.prompt.trim() !== '');
+    } catch (e) {
+      return [];
path: unitylibs/core/workflow/workflow-firefly/widget.js
user: login: rgclayton
body: Added lanalog
created_at: 2025-05-23T01:45:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: aem-code-sync[bot]
created_at: 2025-05-22T19:55:49Z
body: <!-- aem-bot-dash -->
Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch and validate page speed.
In case there are problems, just click a checkbox below to rerun the respective action.

- [ ] <!-- action-psi --> Re-run PSI checks
- [ ] <!-- action-sync --> Re-sync branch

<details>
<summary>Commits</summary>
<!-- commit-history -->

* [96357e3](https://github.com/adobecom/unity/commit/96357e34b5599fcbe48d4c02278bf89e0c18faa9) :white_check_mark: (latest)
* [68e3335](https://github.com/adobecom/unity/commit/68e3335139301fd0f7eafa6308f6c92d04f159b3) :white_check_mark:
* [fac0010](https://github.com/adobecom/unity/commit/fac001071e024be836bdb6a14843bdc345e86170) :white_check_mark:
* [bfeb44a](https://github.com/adobecom/unity/commit/bfeb44a04eaa8fbebe45303e796db326a763f254) :white_check_mark:
* [8e02d3f](https://github.com/adobecom/unity/commit/8e02d3fa5569adfc357cd8c347562c00628c4e04) :white_check_mark:
* [38708a1](https://github.com/adobecom/unity/commit/38708a10101b05b5c37c97dd2afc31de2946f6e8) :white_check_mark:
* [1492ac2](https://github.com/adobecom/unity/commit/1492ac2a9999db6b6f06ba037874427c75dbcbc6) :white_check_mark:
* [28fe24a](https://github.com/adobecom/unity/commit/28fe24a43b3f837d90ba2cc39739ed7131520b5d) :white_check_mark:
* [141033c](https://github.com/adobecom/unity/commit/141033ccf2dde0d8f99c87a9d979aa6ee6092e06) :white_check_mark:
* [fc683f4](https://github.com/adobecom/unity/commit/fc683f416a90c6b37f71bae5c28355774d7b3810) :white_check_mark:
* [8ae1d5a](https://github.com/adobecom/unity/commit/8ae1d5a5c2344eba224a4d394c1e23cb38a75f9b) :white_check_mark:
* [f411a40](https://github.com/adobecom/unity/commit/f411a409f9e97bc777930de9e060f8f9c3604855) :white_check_mark:
* [0e0bfd2](https://github.com/adobecom/unity/commit/0e0bfd2db539045f8b1615f01c371aa3a707fff5) :white_check_mark:
* [71afe28](https://github.com/adobecom/unity/commit/71afe28cfd96c5eb508266cf1e2635e64c8ac5fd) :white_check_mark:
* [5302dc4](https://github.com/adobecom/unity/commit/5302dc48616ad03aa1783ad0698f76d383bc2b8f) :white_check_mark:
* [c3415bd](https://github.com/adobecom/unity/commit/c3415bd6ca6cff03ac08e20bd190ec0c546f6538) :white_check_mark:
* [528e4cf](https://github.com/adobecom/unity/commit/528e4cfa83c3466672ffa607c11ced695389cd60) :arrows_counterclockwise:
* [56063e2](https://github.com/adobecom/unity/commit/56063e2160366756ac11f68f197932e575a626ee) :white_check_mark:
* [bed9f0c](https://github.com/adobecom/unity/commit/bed9f0c948eacce41294f7501ba69b12b3dcbd2a) :white_check_mark:
* [ebed61a](https://github.com/adobecom/unity/commit/ebed61ad6d541aaa8ccdca4e87e8b88e927aa212) :white_check_mark:
* [be1945d](https://github.com/adobecom/unity/commit/be1945de5108e21eba2f55eb9671bda0f3baa3b1) :white_check_mark:
* [6981b2a](https://github.com/adobecom/unity/commit/6981b2acc85457ebfaea57658148867adeb5a644) :white_check_mark:
* [7cefb11](https://github.com/adobecom/unity/commit/7cefb1138acb83e6210a00037b3f9990e8443742) :white_check_mark:
* [2bda7cd](https://github.com/adobecom/unity/commit/2bda7cd1593cb6b5e989bd23f37138426981930e) :white_check_mark:

<!-- commit-history-end -->
</details>
author_association: NONE
user: login: skumar09
created_at: 2025-05-24T00:41:40Z
body: Observing following product issues often,
- Issue: Blank Popup
       - Page with prompt suggestion dropdown
       - https://main--cc--adobecom.hlx.page/drafts/ruchika/unity/firefly/unity-firefly?unitylibs=firefly-workflow
       - Steps: 
           - Enter text in the prompt and click Generate button
           - Here getting blank pop-up ( Image-1)
           - work-around : I f user clicks outside the pop-up and click generate again, user is shown SUSI  pop-up ( expected)
- Image-1
       ![image](https://github.com/user-attachments/assets/99cc6129-a2bb-41a8-acc7-8db75e868ef2)
- Image-2
    ![image](https://github.com/user-attachments/assets/283b05d9-5a6b-477f-9980-9add371acf2e)



note: 
- As discussed in the call, the blank pop-up is a product issue, ( and not unity related), we can merge this pr to stage

cc: @rgclayton @Ruchika4 @sanjayms01 @sigadamvenkata 



Also performed quick sanity on following pages on pr-branch: `firefly-workflow` and looks good
```
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/compress-pdf?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/sign-pdf?unitylibs=
* [https://stage--dc--adobecom.hlx.page/acrobat/online/test/delete-pdf-pages?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/add-pages-to-pdf?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/rearrange-pdf?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/extract-pdf-pages?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/request-signature?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/pdf-editor?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/crop-pdf?unitylibs=
* https://stage--dc--adobecom.hlx.page/acrobat/online/test/split-pdf?unitylibs=
```
author_association: COLLABORATOR
user: login: Ruchika4
created_at: 2025-05-24T00:47:23Z
body: > @Ruchika4 I noticed `workflow-upload/action-binder.js` is included in this as a modified file. Is that expected?

That's expected. It was updated because code for logging analytics data to splunk was updated
author_association: COLLABORATOR