Your IP : 216.73.216.219


Current Path : /home/chauffn/vuzelia/2023/components/com_sppagebuilder/addons/comment/
Upload File :
Current File : /home/chauffn/vuzelia/2023/components/com_sppagebuilder/addons/comment/site.php

<?php

/**
 * @package SP Page Builder
 * @author JoomShaper http://www.joomshaper.com
 * @copyright Copyright (c) 2010 - 2025 JoomShaper
 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later
 */

require_once JPATH_ROOT . '/components/com_sppagebuilder/helpers/rate-limiter.php';
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Component\ComponentHelper;
use JoomShaper\SPPageBuilder\Comment\Services\CommentService;
use JoomShaper\SPPageBuilder\DynamicContent\Supports\Date;

//no direct access
defined('_JEXEC') or die('Restricted access');

class SppagebuilderAddonComment extends SppagebuilderAddons
{
	/**
	 * The addon frontend render method.
	 * The returned HTML string will render to the frontend page.
	 *
	 * @return  string  The HTML string.
	 * @since   1.0.0
	 */
	public function render()
	{
		$input = Factory::getApplication()->input;
		$collectionType = $input->get('collection_type', null, 'string');

		$viewType = $input->get('view', null, 'string');

		$articleId = $input->get('id', null, 'int');

		if ($collectionType === 'articles') {
			if (!\class_exists('SppagebuilderHelperArticles')) {
				require_once JPATH_ROOT . '/components/com_sppagebuilder/helpers/articles.php';
			}
			$articleId = Factory::getApplication()->input->get('collection_item_id', null, 'array');
			$articleId = $articleId ? (int) $articleId[0] : null;
			$authorised = \SppagebuilderHelperArticles::checkAuthorised($articleId);
	
			if (!$authorised) {
				return "";
			}
		}

		$commentService = new CommentService();
		if ($viewType == 'page') {
			$articleId = $commentService->getArticleId($articleId);
		}
		$itemId = $input->get('collection_item_id', null, 'array');
		$itemId = $itemId ? $itemId[0] : null;

		$itemId = $itemId ? $itemId : $articleId;

		if (($collectionType != 'articles' && $collectionType != 'normal-source') && empty($itemId)) {
			return "";
		}
		$collectionType = $collectionType ? $collectionType : 'articles';
		$comments = $commentService->getAllComments($itemId, $collectionType);
		$publishedCommentsCount = $commentService->getPublishedCommentsCount($itemId, $collectionType);
		$addonId = $this->addon->id;

		$settings = $this->addon->settings;
		$class = (isset($settings->class) && $settings->class) ? ' ' . $settings->class : '';

		$commentTitleText = (isset($settings->title_text) && $settings->title_text) ? $settings->title_text : 'Comments';
		$commentCountEnabled = (isset($settings->comment_count) && $settings->comment_count) ? $settings->comment_count : 0;
		$commentCountPosition = (isset($settings->comment_count_position) && $settings->comment_count_position) ? $settings->comment_count_position : 'left';
		$labelText = (isset($settings->label_text) && $settings->label_text) ? $settings->label_text : 'Leave a comment';
		$isLabelEnabled = (isset($settings->enable_label) && $settings->enable_label) ? $settings->enable_label : 0;
		$placeHolderText = (isset($settings->comment_field_placeholder) && $settings->comment_field_placeholder) ? $settings->comment_field_placeholder : Text::_('COM_SPPAGEBUILDER_SHARE_YOUR_THOUGHTS');
		$enableAnonymousComment = (isset($settings->enable_anonymous_comment) && $settings->enable_anonymous_comment) ? $settings->enable_anonymous_comment : 0;

		$likesIcon = (isset($settings->likes_icon) && $settings->likes_icon) ? $settings->likes_icon : 'fa fa-heart';
		$replyIcon = (isset($settings->reply_icon) && $settings->reply_icon) ? $settings->reply_icon : 'fa fa-reply';

		$postBtnText = (isset($settings->post_button_text) && $settings->post_button_text) ? $settings->post_button_text : 'Leave a comment';
		$postBtnAriaLabel = (isset($settings->post_button_aria_label) && $settings->post_button_aria_label) ? $settings->post_button_aria_label : '';
		$btnClass = 'sppb-btn ';
		$btnClass .= (isset($settings->post_button_type) && $settings->post_button_type) ? ' sppb-btn-' . $settings->post_button_type : '';
		$btnClass .= (isset($settings->post_button_block) && $settings->post_button_block) ? ' ' . $settings->post_button_block : '';
		$btnClass .= (isset($settings->post_button_shape) && $settings->post_button_shape) ? ' sppb-btn-' . $settings->post_button_shape : ' sppb-btn-rounded';
		$btnClass .= (isset($settings->post_button_appearance) && $settings->post_button_appearance) ? ' sppb-btn-' . $settings->post_button_appearance : '';
		$btnClass .= (isset($settings->post_button_size) && $settings->post_button_size) ? ' sppb-btn-' . $settings->post_button_size : ' sppb-btn-md';
		$postBtnIcon = (isset($settings->post_button_icon) && $settings->post_button_icon) ? $settings->post_button_icon : '';
		$postBtnIconPosition = (isset($settings->post_button_icon_position) && $settings->post_button_icon_position) ? $settings->post_button_icon_position : 'left';

		$ellipsisBtnClass = 'sppb-btn ';
		$ellipsisBtnClass .= (isset($settings->ellipsis_button_style) && $settings->ellipsis_button_style) ? ' sppb-btn-' . $settings->ellipsis_button_style : 'sppb-btn-custom';
		$ellipsisBtnClass .= (isset($settings->ellipsis_shape) && $settings->ellipsis_shape) ? ' sppb-btn-' . $settings->ellipsis_shape : ' sppb-btn-rounded';
		$ellipsisBtnClass .= (isset($settings->ellipsis_appearance) && $settings->ellipsis_appearance) ? ' sppb-btn-' . $settings->ellipsis_appearance : '';
		$ellipsisBtnClass .= (isset($settings->ellipsis_size) && $settings->ellipsis_size) ? ' sppb-btn-' . $settings->ellipsis_size : ' sppb-btn-md';
		$ellipsisBtnIcon = (isset($settings->ellipsis_icon) && $settings->ellipsis_icon) ? $settings->ellipsis_icon : 'fa fa-ellipsis-v';

		$currentUserId = Factory::getUser()->id;

		// The service reads this from the session; never trust the posted payload.
		Factory::getApplication()->getSession()->set('sppb_anon_comment_' . $collectionType . '_' . $itemId, (int) $enableAnonymousComment);

		$output = '';
		$output .= '<div class="sppb-addon sppb-addon-comment ' . $class . '">';

		$output .= '<div class="sppb-comment-title-wrapper">';
		if($commentCountEnabled && $commentCountPosition === 'left')
		{
			$output .= '<span class="sppb-comment-count">' . '(' . $publishedCommentsCount . ')' . '</span>';
		}
		$output .= '<span class="sppb-comment-title-text">' . $commentTitleText . '</span>';
		if($commentCountEnabled && $commentCountPosition === 'right')
		{
			$output .= '<span class="sppb-comment-count">' . '(' . $publishedCommentsCount . ')' . '</span>';
		}
		$output .= '</div>';

		if($isLabelEnabled)
		{
			$output .= '<div class="sppb-comment-label-wrapper">';
			$output .= '<span class="sppb-comment-label-text">' . $labelText . '</span>';
			$output .= '</div>';
		}

		$output .= '<form class="sppb-comment-form">';
		$output .= '<input hidden name="addon-id" value="' . $addonId . '">';
		$output .= '<textarea class="sppb-comment-field" name="comment" placeholder="' . $placeHolderText . '"></textarea>';
		$output .= '<div class="sppb-comment-btn-wrapper">';
		
		// Show normal comment submit button
		$output .= '<button aria-label="' . $postBtnAriaLabel . '" type="submit" class="comment-submit-btn ' . $btnClass . '" ' . (!$currentUserId && !$enableAnonymousComment ? 'disabled' : '') . ' style="cursor: ' . (!$currentUserId && !$enableAnonymousComment ? 'not-allowed' : 'pointer') . '; ' . (!$currentUserId && !$enableAnonymousComment ? 'opacity: 0.5' : '') . '" ' . (!$currentUserId && !$enableAnonymousComment ? 'title="' . Text::_("COM_SPPAGEBUILDER_PLEASE_SIGN_IN_TO_COMMENT") . '"' : '') . '>';
		if($postBtnIcon && $postBtnIconPosition === 'left')
		{
			$output .= '<i class="sppb-btn-icon ' . $postBtnIcon . '"></i>';
		}
		$output .= '<span>' . $postBtnText . '</span>';
		if($postBtnIcon && $postBtnIconPosition === 'right')
		{
			$output .= '<i class="sppb-btn-icon ' . $postBtnIcon . '"></i>';
		}
		$output .= '</button>';
		
		$output .= '</div>';
		$output .= '</form>';

		$output .= '<div class="sppb-comments-list" style="margin-top: 40px;">';
		$output .= $this->renderComments($comments, $ellipsisBtnClass, $ellipsisBtnIcon, $likesIcon, $replyIcon, $settings, $btnClass, $enableAnonymousComment, 0);
		$output .= '</div>';




		$output .= '</div>';
		$output .= $this->renderLoginModal();
		return $output;
	}

	private function getInitials($name) {
		$words = explode(' ', trim($name));
		$initials = '';
		if (count($words) > 1) {
			$initials .= mb_strtoupper(mb_substr($words[0], 0, 1, 'UTF-8'), 'UTF-8');
			$initials .= mb_strtoupper(mb_substr(end($words), 0, 1, 'UTF-8'), 'UTF-8');
		} else {
			$initials .= mb_strtoupper(mb_substr($name, 0, 1, 'UTF-8'), 'UTF-8');
		}
		return $initials;
	}

	private function getTextColor($color) {
		$r = hexdec(substr($color, 1, 2));
		$g = hexdec(substr($color, 3, 2));
		$b = hexdec(substr($color, 5, 2));

		$brightness = (($r * 299) + ($g * 587) + ($b * 114)) / 1000;

		return ($brightness > 128) ? '#000000' : '#FFFFFF';
	}

	private function getGravatarUrl($email, $size = 45, $default = '404') {
		if (empty($email)) {
			return false;
		}
		
		$hash = md5(strtolower(trim($email)));
		$url = "https://www.gravatar.com/avatar/{$hash}?s={$size}&d={$default}";
		
		return $url;
	}

	private function getRelativeTime($timestamp) {
		$time = strtotime($timestamp);
		$now = strtotime(Date::sqlSafeDate());
		$diff = $now - $time;
		
		if ($diff < 60) {
			return Text::_('COM_SPPAGEBUILDER_JUST_NOW');
		} elseif ($diff < 3600) {
			$minutes = floor($diff / 60);
			return ($minutes > 1 ? Text::sprintf('COM_SPPAGEBUILDER_MINUTES_AGO', $minutes) : Text::sprintf('COM_SPPAGEBUILDER_MINUTE_AGO', $minutes));
		} elseif ($diff < 86400) {
			$hours = floor($diff / 3600);
			return ($hours > 1 ? Text::sprintf('COM_SPPAGEBUILDER_HOURS_AGO', $hours) : Text::sprintf('COM_SPPAGEBUILDER_HOUR_AGO', $hours));
		} elseif ($diff < 2592000) {
			$days = floor($diff / 86400);
			return ($days > 1 ? Text::sprintf('COM_SPPAGEBUILDER_DAYS_AGO', $days) : Text::sprintf('COM_SPPAGEBUILDER_DAY_AGO', $days));
		} elseif ($diff < 31536000) {
			$months = floor($diff / 2592000);
			return ($months > 1 ? Text::sprintf('COM_SPPAGEBUILDER_MONTHS_AGO', $months) : Text::sprintf('COM_SPPAGEBUILDER_MONTH_AGO', $months));
		} else {
			$years = floor($diff / 31536000);
			return ($years > 1 ? Text::sprintf('COM_SPPAGEBUILDER_YEARS_AGO', $years) : Text::sprintf('COM_SPPAGEBUILDER_YEAR_AGO', $years));
		}
	}

	private function renderComments($comments, $ellipsisBtnClass, $ellipsisBtnIcon, $likesIcon, $replyIcon, $settings, $btnClass, $enableAnonymousComment, $level = 0) {
		$currentUserId = Factory::getUser()->id;

		$rootCommentClass = '';
		if($level === 0){
			$rootCommentClass = ' sppb-root-comment';
		} 

		$output = '';
		foreach ($comments as $comment) {
			$isOwnComment = false;
			// Check if this is the user's own comment (only for logged-in users)
			if ($currentUserId && $comment->created_by_id && $currentUserId === $comment->created_by_id) {
				$isOwnComment = true;
			}

			if(!$isOwnComment && $comment->published === 0){
				continue;
			}

			$profileImageUrl = null;

			if (!empty($comment->created_by_id)) {
				$profileImageUrl = !empty($comment->profile_image) ? $comment->profile_image : '';
			}

			$avatarColor = !empty($settings->commentator_avatar_color) ? $settings->commentator_avatar_color : "#4285F4";
			$textColor = $this->getTextColor($avatarColor);
			$initials = $this->getInitials($comment->created_by ?? Text::_('COM_SPPAGEBUILDER_ANONYMOUS_PERSON'));
			$gravatarUrl = null;
			$enableGravatar = ComponentHelper::getParams('com_sppagebuilder')->get('enable_gravatar', 1);
			if ($enableGravatar && !empty($comment->created_by_email)) {
				$gravatarUrl = $this->getGravatarUrl($comment->created_by_email, 45, '404');
			}
			
			$output .= '<div data-comment-id="' . $comment->id . '" data-parent-id="' . $comment->parent_id . '" class="sppb-comment-item sppb-comment-item ' . ((!isset($comment->parent_id) && !$comment->parent_id) ? ' sppb-parent-comment' : '') . ' ' . $rootCommentClass .'" style="margin-top: -4px; margin-left: ' . ($level > 0 ? (55) : 0) . 'px;">';
			$output .= '<div class="sppb-comment-thread-line" style="left:' . (-34) . 'px;"></div>';
			$output .= '<div class="sppb-comment-thread-connector" style="left:' . (-34) . 'px; width: ' . (55) . 'px;"></div>';
			$output .= '<div class="sppb-comment-content" ' . ($level > 0 ? 'style="margin-left: 0; margin-top: 11px;"' : "")  . '>';
			$output .= '<div class="sppb-comment-header sppb-comment-header">';

			if (!empty($profileImageUrl)) {
				$output .= '<div class="sppb-comment-avatar" style="border-radius: 50%; width: 45px; height: 45px; margin-right: 10px; overflow: hidden; flex-shrink: 0;">';
				$output .= '<img src="' . htmlspecialchars($profileImageUrl, ENT_QUOTES, 'UTF-8') . '" alt="' . htmlspecialchars($comment->created_by ?? Text::_('COM_SPPAGEBUILDER_ANONYMOUS_PERSON'), ENT_QUOTES, 'UTF-8') . '" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';" />';
				$output .= '<div class="sppb-comment-avatar-fallback" style="background-color: ' . $avatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: none; align-items: center; justify-content: center; font-size: 16px; font-weight: 600; color: ' . $textColor . '">';
				$output .= '<span>' . htmlspecialchars($initials, ENT_QUOTES, 'UTF-8') . '</span>';
				$output .= '</div>';
				$output .= '</div>';
			} elseif (!empty($gravatarUrl)) {
				$output .= '<div class="sppb-comment-avatar" style="border-radius: 50%; width: 45px; height: 45px; margin-right: 10px; overflow: hidden; flex-shrink: 0;">';
				$output .= '<img src="' . htmlspecialchars($gravatarUrl, ENT_QUOTES, 'UTF-8') . '" alt="' . htmlspecialchars($comment->created_by ?? Text::_('COM_SPPAGEBUILDER_ANONYMOUS_PERSON'), ENT_QUOTES, 'UTF-8') . '" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';" />';
				$output .= '<div class="sppb-comment-avatar-fallback" style="background-color: ' . $avatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: none; align-items: center; justify-content: center; font-size: 16px; font-weight: 600; color: ' . $textColor . '">';
				$output .= '<span>' . htmlspecialchars($initials, ENT_QUOTES, 'UTF-8') . '</span>';
				$output .= '</div>';
				$output .= '</div>';
			} else {
				$output .= '<div class="sppb-comment-avatar" style="background-color: ' . $avatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; font-weight: 600; margin-right: 10px; color: ' . $textColor . '">';
				$output .= '<span>' . htmlspecialchars($initials, ENT_QUOTES, 'UTF-8') . '</span>';
				$output .= '</div>';
			}
			$output .= '<div class="sppb-comment-header-left">';
			$output .= $this->getHeaderHtml($comment->created_by ?? Text::_('COM_SPPAGEBUILDER_ANONYMOUS_PERSON'), $comment, $settings);
			$output .= '</div>';

			if ($isOwnComment) {
				$output .= '<div class="sppb-comment-ellipsis-action ' . $ellipsisBtnClass . '">';
				$output .= '<i class="sppb-ellipsis-icon ' . $ellipsisBtnIcon . '"></i>';
				$output .= '<div class="sppb-ellipsis-dropdown" style="display: none;">';
				$output .= $this->renderEllipsisActionButtons($settings);
				$output .= '</div>';
				$output .= '</div>';
			}
				
			$output .= '</div>';

			$output .= '<div class="sppb-comment-content sppb-comment-body" data-comment-id="' . $comment->id . '" style="margin-left: 55px; padding-bottom: 29px;">';
			$output .= '<div class="sppb-comment-body-thread-line"></div>';

			$needsModeration = $isOwnComment && $comment->published === 0;

			if($needsModeration){
				$output .= '<div class="sppb-comment-unpublished-notice">' . Text::_('COM_SPPAGEBUILDER_COMMENT_UNAPPROVED_NOTICE') . '</div>';
			}

			$output .= '<span class="sppb-comment-content-text' . ($needsModeration ? ' sppb-comment-unpublished' : '') . '" style="margin-left: 10px; margin-top: 20px; display: inline-block;">';
			$output .= '<span>' . nl2br(htmlspecialchars($comment->content, ENT_QUOTES, 'UTF-8')) . '</span>';
			$output .= '</span>';
			$output .= '<div class="sppb-comment-edit-form sppb-comment-form" data-comment-id="' . $comment->id . '" style="display: none; ' . ($needsModeration ? 'margin-top: -45px;' : '') . '">';
			$output .= '<textarea type="text" class="sppb-comment-edit-input sppb-comment-field" data-comment-id="' . $comment->id . '">' . htmlspecialchars($comment->content, ENT_QUOTES, 'UTF-8') . '</textarea>';
			$output .= $this->renderEditCommentButtons($settings, $comment->id);
			$output .= '</div>';

			$isLikedClass = (isset($comment->user_liked) && $comment->user_liked) ? 'liked' : '';

			if(!$needsModeration){
				$output .= '<div class="sppb-comment-actions" style="margin-left: 10px">';
				$output .= '<div class="sppb-comment-likes ' . $isLikedClass . '">';
				$output .= '<i class="sppb-likes-icon ' . $likesIcon . '"></i>';
				$output .= '<span class="sppb-likes-text">' . ($comment->likes_count ?? 0) . ' ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '</span>';
				$output .= '</div>';
				$output .= '<div class="sppb-comment-reply-action" data-comment-id="' . $comment->id . '">';
				$output .= '<i class="sppb-reply-icon ' . $replyIcon . '"></i>';
				$output .= '<span class="sppb-reply-text">' . $comment->replies . ' ' . Text::_('COM_SPPAGEBUILDER_REPLY') . '</span>';
				$output .= '</div>';
				$output .= '</div>';
			}

			$output .= '<div class="sppb-comment-reply-form sppb-comment-form" data-comment-id="' . $comment->id . '" style="display: none;">';
			$output .= '<textarea type="text" class="sppb-comment-reply-input sppb-comment-field" data-comment-id="' . $comment->id . '" placeholder="' . Text::_('COM_SPPAGEBUILDER_WRITE_A_REPLY') . '"></textarea>';
			$output .= '<div class="sppb-comment-btn-wrapper">';
			$output .= '<button class="sppb-comment-reply-cancel-btn ' . $btnClass . '" data-comment-id="' . $comment->id . '">' . Text::_('COM_SPPAGEBUILDER_CANCEL') . '</button>';
			$output .= '<button class="sppb-comment-reply-submit-btn comment-submit-btn ' . $btnClass . '" data-comment-id="' . $comment->id . '" ' . (!$currentUserId && !$enableAnonymousComment ? 'disabled' : '') . ' style="cursor: ' . (!$currentUserId && !$enableAnonymousComment ? 'not-allowed' : 'pointer') . '; ' . (!$currentUserId && !$enableAnonymousComment ? 'opacity: 0.5' : '') . '" ' . (!$currentUserId && !$enableAnonymousComment ? 'title="' . Text::_('COM_SPPAGEBUILDER_PLEASE_SIGN_IN_TO_COMMENT') . '"' : '') . '>' . Text::_('COM_SPPAGEBUILDER_SUBMIT') . '</button>';
			$output .= '</div>';
			$output .= '</div>';
			$output .= '</div>';
			

			$output .= '</div>';
			if(isset($comment->children) && !empty($comment->children) && !$needsModeration){
				$output .= '<div class="sppb-comment-children-wrapper">';
				$output .= $this->renderComments($comment->children, $ellipsisBtnClass, $ellipsisBtnIcon, $likesIcon, $replyIcon, $settings, $btnClass, $enableAnonymousComment, $level + 1);
				$output .= '</div>';
			}
			$output .= '</div>';
		}
		return $output;
	}

	private function renderEditCommentButtons($settings, $commentId){
		$editCommentItems = $settings->edit_comment_button_item ?? [];
		$output = '';
		$output .= '<div class="sppb-comment-edit-buttons-wrapper sppb-comment-btn-wrapper">';
		foreach ($editCommentItems as $item_key => $item) {
			$uniqueId = 'sppb-comment-edit-button-' . $item_key;
			$btnClass = 'sppb-btn ';
			$btnClass .= (isset($item->edit_comment_button_appearance) && $item->edit_comment_button_appearance) ? ' sppb-btn-' . $item->edit_comment_button_appearance : '';
			$btnClass .= (isset($item->edit_comment_button_size) && $item->edit_comment_button_size) ? ' sppb-btn-' . $item->edit_comment_button_size : ' sppb-btn-md';
			$btnClass .= (isset($item->edit_comment_button_shape) && $item->edit_comment_button_shape) ? ' sppb-btn-' . $item->edit_comment_button_shape : ' sppb-btn-rounded';
			$output .= '<button class="sppb-comment-edit-button ' . ($item->title == 'Update' ? 'sppb-comment-edit-submit-btn' : 'sppb-comment-edit-cancel-btn') . ' ' . $btnClass . '" id="' . $uniqueId . '" data-comment-id="' . $commentId . '">'. ($item->title == 'Update' ? Text::_('COM_SPPAGEBUILDER_UPDATE') : Text::_('COM_SPPAGEBUILDER_CANCEL')) .'</button>';
		}
		$output .= '</div>';

		return $output;
	}

	private function renderEllipsisActionButtons($settings){
		$ellipsisActionItems = $settings->ellipsis_action_button_item ?? [];
		$output = '';
		$output .= '<div class="sppb-comment-ellipsis-action-buttons-wrapper">';
		foreach ($ellipsisActionItems as $item_key => $item) {
			$uniqueId = 'sppb-comment-ellipsis-action-button-' . $item_key;
			$btnClass = 'sppb-btn ';
			if ($item_key == 0) {
				$btnClass .= ' sppb-ellipsis-edit-btn ';
			} else {
				$btnClass .= ' sppb-ellipsis-delete-btn ';
			}
			$btnClass .= (isset($item->ellipsis_action_button_appearance) && $item->ellipsis_action_button_appearance) ? ' sppb-btn-' . $item->ellipsis_action_button_appearance : '';
			$btnClass .= (isset($item->ellipsis_action_button_size) && $item->ellipsis_action_button_size) ? ' sppb-btn-' . $item->ellipsis_action_button_size : ' sppb-btn-md';
			$btnClass .= (isset($item->ellipsis_action_button_shape) && $item->ellipsis_action_button_shape) ? ' sppb-btn-' . $item->ellipsis_action_button_shape : ' sppb-btn-rounded';
			$output .= '<button style="width: 100%; text-align: left;" class="sppb-comment-ellipsis-action-button ' . $btnClass . '" id="' . $uniqueId . '">'. ($item->title === 'Edit' ? Text::_('COM_SPPAGEBUILDER_EDIT') : Text::_('COM_SPPAGEBUILDER_DELETE')) .'</button>';
		}
		$output .= '</div>';

		return $output;
	}

	private function getHeaderHtml($commentatorName, $comment, $settings){
		$output = '';
		$output .= '<div class="commentator-name-wrapper">';
		$output .= '<span class="commentator-name">' . htmlspecialchars($commentatorName) . '</span>';
		$output .= '</div>';
		
		$enableTime = (isset($settings->enable_time) && $settings->enable_time) ? $settings->enable_time : 0;
		if ($enableTime) {
			$output .= '<div class="sppb-comment-time-wrapper">';
			$output .= '<span class="sppb-comment-time">' . $this->getRelativeTime($comment->created_on);
			
			$showEditedTime = (isset($settings->show_edited_time) && $settings->show_edited_time) ? $settings->show_edited_time : 0;
			if ($showEditedTime && $comment->modified && $comment->modified !== $comment->created_on) {
				$output .= '<span class="sppb-comment-edited-time"> • ' . Text::_('COM_SPPAGEBUILDER_COMMENT_EDITED') . ' ' . $this->getRelativeTime($comment->modified) . '</span>';
			}
			
			$output .= '</span>';
			$output .= '</div>';
		}
		
		return $output;
	}

	public static function getAjax(){
		$input  = Factory::getApplication()->input;
		$inputs = $input->get('data', [], 'ARRAY');
		$addonId = '';

		foreach ($inputs as $item) {
			if ($item['name'] === 'addon-id') {
				$addonId = $item['value'];
				break;
			}
		}

		$secureData        = Session::getInstance();
        $ipAddress         = Factory::getApplication()->input->server->get('REMOTE_ADDR');
        $maxRequests       = $secureData->get('max_requests_' . $addonId, 10);
        $timeWindow        = $secureData->get('time_window_' . $addonId, 60);
            
		if (SppagebuilderRateLimiterHelper::isRateLimited($ipAddress . $addonId, $maxRequests, $timeWindow)) {
			$timeUntilReset    = SppagebuilderRateLimiterHelper::getTimeUntilReset($ipAddress . $addonId, $timeWindow);
			$output['status']  = false;
			$output['content'] = '<span class="sppb-text-danger">' . Text::sprintf('COM_SPPAGEBUILDER_RATE_LIMIT_EXCEEDED', $timeUntilReset) . '</span>';
			return json_encode($output);
		}

		$output = [];
		$output['status']  = true;
		$output['content'] = 'success';

		return json_encode($output);
	}

	/**
	 * Generate the CSS string for the frontend page.
	 *
	 * @return 	string 	The CSS string for the page.
	 * @since 	1.0.0
	 */
	public function css()
	{
		$addon_id = '#sppb-addon-' . $this->addon->id;
		$settings = $this->addon->settings;
		$cssHelper = new CSSHelper($addon_id);
        $css = '';

		$css .= $cssHelper->generateStyle('.sppb-comment-title-wrapper', $settings,
				['title_alignment' => 'justify-content'], ['title_alignment' => false], [],[],[],
				'display: flex; align-items: center; gap: 16px; border-bottom: 1px solid #D3D7EB; margin-bottom: 40px; padding-bottom: 24px;');
		$css .= $cssHelper->typography('.sppb-comment-title-text', $settings, 'title_typography',
				['font'           => 'title_font_family',
				'size'           => 'title_fontsize',
				'line_height'    => 'title_lineheight',
				'letter_spacing' => 'title_letterspace',
				'uppercase'      => 'title_font_style.uppercase',
				'italic'         => 'title_font_style.italic',
				'underline'      => 'title_font_style.underline',
				'weight'         => 'title_font_style.weight',
				]);
		$css .= $cssHelper->generateStyle('.sppb-comment-title-text', $settings,
				['title_color' => 'color'], ['title_color' => false]);
		$settings->title_shadow = $cssHelper->parseBoxShadow($settings, 'title_shadow', true);
		$css .= $cssHelper->generateStyle('.sppb-comment-title-text', $settings,
				['title_shadow' => 'text-shadow'], ['title_shadow' => false]);
		$css .= $cssHelper->typography('.sppb-comment-count', $settings, 'comment_count_typography',
				['font'          => 'comment_count_font_family',
				'size'           => 'comment_count_fontsize',
				'line_height'    => 'comment_count_lineheight',
				'letter_spacing' => 'comment_count_letterspace',
				'uppercase'      => 'comment_count_font_style.uppercase',
				'italic'         => 'comment_count_font_style.italic',
				'underline'      => 'comment_count_font_style.underline',
				'weight'         => 'comment_count_font_style.weight',
				]);
		$css .= $cssHelper->generateStyle('.sppb-comment-count', $settings,
				['comment_count_color' => 'color'], ['comment_count_color' => false]);
		$settings->comment_count_shadow = $cssHelper->parseBoxShadow($settings, 'comment_count_shadow', true);
		$css .= $cssHelper->generateStyle('.sppb-comment-count', $settings,
				['comment_count_shadow' => 'text-shadow'], ['comment_count_shadow' => false]);

		$css .= $cssHelper->generateStyle('.sppb-comment-label-wrapper', $settings,
				['label_alignment' => 'justify-content'], ['label_alignment' => false], [],[],[],
				'display: flex; align-items: center; margin-bottom: 12px;');
		$css .= $cssHelper->generateStyle('.sppb-comment-label-text', $settings,
				['label_color' => 'color'], ['label_color' => false]);
		$settings->label_text_shadow = $cssHelper->parseBoxShadow($settings, 'label_text_shadow', true);
		$css .= $cssHelper->generateStyle('.sppb-comment-label-text', $settings,
				['label_text_shadow' => 'text-shadow'], ['label_text_shadow' => false]);

		$enableLikes = (isset($settings->enable_likes) && $settings->enable_likes) ? $settings->enable_likes : 0;
		if ($enableLikes) {
			$css .= $cssHelper->generateStyle('.sppb-comment-actions', $settings, [], [], [],[],[],
					'display: flex; align-items: center; gap: 20px; margin-top: 16px;');
			
			$css .= $cssHelper->generateStyle('.sppb-comment-likes', $settings, [], [], [],[],[],
					'display: flex; align-items: center; gap: 6px; cursor: pointer;');
			
			$css .= $cssHelper->typography('.sppb-likes-text', $settings, 'likes_typography',
					['font'           => 'likes_font_family',
					'size'           => 'likes_fontsize',
					'line_height'    => 'likes_lineheight',
					'letter_spacing' => 'likes_letterspace',
					'uppercase'      => 'likes_font_style.uppercase',
					'italic'         => 'likes_font_style.italic',
					'underline'      => 'likes_font_style.underline',
					'weight'         => 'likes_font_style.weight',
					]);
			
			$css .= $cssHelper->generateStyle('.sppb-likes-text', $settings,
					['likes_color' => 'color'], ['likes_color' => false]);

			$css .= $cssHelper->generateStyle('.sppb-comment-likes.liked > .sppb-likes-icon', $settings,
					['likes_focused_color' => 'color'], ['likes_focused_color' => false]);
			
			$settings->likes_text_shadow = $cssHelper->parseBoxShadow($settings, 'likes_text_shadow', true);
			$css .= $cssHelper->generateStyle('.sppb-likes-text', $settings,
					['likes_text_shadow' => 'text-shadow'], ['likes_text_shadow' => false]);
			
			$css .= $cssHelper->generateStyle('.sppb-likes-icon', $settings, [], [], [],[],[],
					'font-size: 16px; transition: color 0.3s ease;');
					$css .= $cssHelper->generateStyle('.sppb-likes-icon', $settings,
				['likes_color' => 'color'], ['likes_color' => false]);
		
			$css .= $cssHelper->generateStyle('.sppb-comment-avatar img', $settings, [], [], [],[],[],
					'transition: opacity 0.3s ease;');
			$css .= $cssHelper->generateStyle('.sppb-comment-avatar-fallback', $settings, [], [], [],[],[],
					'transition: opacity 0.3s ease;');
			
			$css .= $cssHelper->generateStyle('.sppb-comment-likes:hover .sppb-likes-text', $settings,
					['likes_hover_color' => 'color'], ['likes_hover_color' => false]);
			$css .= $cssHelper->generateStyle('.sppb-comment-likes:hover .sppb-likes-icon', $settings,
					['likes_hover_color' => 'color'], ['likes_hover_color' => false]);
			
			$css .= $cssHelper->generateStyle('.sppb-comment-likes:focus .sppb-likes-text', $settings,
					['likes_focused_color' => 'color'], ['likes_focused_color' => false]);
			$css .= $cssHelper->generateStyle('.sppb-comment-likes:focus .sppb-likes-icon', $settings,
					['likes_focused_color' => 'color'], ['likes_focused_color' => false]);
			
			$likesIconPosition = (isset($settings->likes_icon_position) && $settings->likes_icon_position) ? $settings->likes_icon_position : 'left';
			if ($likesIconPosition === 'right') {
				$css .= $cssHelper->generateStyle('.sppb-comment-likes', $settings, [], [], [],[],[],
						'flex-direction: row-reverse;');
			}
		}

		$enableReply = (isset($settings->enable_reply) && $settings->enable_reply) ? $settings->enable_reply : 0;
		if ($enableReply) {
			$css .= $cssHelper->generateStyle('.sppb-comment-reply-action', $settings, [], [], [],[],[],
					'display: flex; align-items: center; gap: 6px; cursor: pointer;');
			
			$css .= $cssHelper->typography('.sppb-reply-text', $settings, 'reply_typography',
					['font'           => 'reply_font_family',
					'size'           => 'reply_fontsize',
					'line_height'    => 'reply_lineheight',
					'letter_spacing' => 'reply_letterspace',
					'uppercase'      => 'reply_font_style.uppercase',
					'italic'         => 'reply_font_style.italic',
					'underline'      => 'reply_font_style.underline',
					'weight'         => 'reply_font_style.weight',
					]);
			
			$css .= $cssHelper->generateStyle('.sppb-reply-text', $settings,
					['reply_color' => 'color'], ['reply_color' => false]);
			
			$settings->reply_text_shadow = $cssHelper->parseBoxShadow($settings, 'reply_text_shadow', true);
			$css .= $cssHelper->generateStyle('.sppb-reply-text', $settings,
					['reply_text_shadow' => 'text-shadow'], ['reply_text_shadow' => false]);
			
			$css .= $cssHelper->generateStyle('.sppb-reply-icon', $settings, [], [], [],[],[],
					'font-size: 16px; transition: color 0.3s ease;');
			$css .= $cssHelper->generateStyle('.sppb-reply-icon', $settings,
					['reply_color' => 'color'], ['reply_color' => false]);
			
			$css .= $cssHelper->generateStyle('.sppb-comment-reply-action:hover .sppb-reply-text', $settings,
					['reply_hover_color' => 'color'], ['reply_hover_color' => false]);
			$css .= $cssHelper->generateStyle('.sppb-comment-reply-action:hover .sppb-reply-icon', $settings,
					['reply_hover_color' => 'color'], ['reply_hover_color' => false]);
			
			$replyIconPosition = (isset($settings->reply_icon_position) && $settings->reply_icon_position) ? $settings->reply_icon_position : 'left';
			if ($replyIconPosition === 'right') {
				$css .= $cssHelper->generateStyle('.sppb-comment-reply-action', $settings, [], [], [],[],[],
						'flex-direction: row-reverse;');
			}
		}

		$css .= $cssHelper->generateStyle('.sppb-comment-form',[], [], [], [],[],[],
				'display: flex; flex-direction: column;');
				
		$css .= $cssHelper->generateStyle('.sppb-comment-reply-form', $settings, [], [], [],[],[],
				'margin-top: 16px;');

		$css .= $cssHelper->generateStyle('.sppb-comment-field', $settings,
				['comment_field_height' => 'height',
				'comment_field_padding' => 'padding',
				'comment_field_typing_color' => 'color',
				'comment_field_background_color' => 'background-color',
				'comment_field_border_color' => 'border-color',
				'comment_field_border_width' => 'border-width'],
				['comment_field_padding' => false,
				'comment_field_typing_color' => false,
				'comment_field_background_color' => false,
				'comment_field_border_color' => false,
				'comment_field_border_width' => false],[],[],[], 'transition: all 0.05s ease-in-out; border-radius: 6px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; width: 100%; box-sizing: border-box;');
		$css .= $cssHelper->generateStyle('.sppb-comment-field::placeholder', $settings,
				['comment_field_placeholder_color' => 'color'], ['comment_field_placeholder_color' => false]);
		$css .= $cssHelper->generateStyle('.sppb-comment-field:hover', $settings,
				['comment_field_background_hover_color' => 'background-color'],
				['comment_field_background_hover_color' => false]);
		$css .= $cssHelper->generateStyle('.sppb-comment-field:hover::placeholder', $settings,
				['comment_field_placeholder_hover_color' => 'color'], ['comment_field_placeholder_hover_color' => false]);
		$css .= $cssHelper->generateStyle('.sppb-comment-field:focus', $settings,
				['comment_field_border_focus_color' => 'border-color',],
				['comment_field_border_focus_color' => false]);
		$css .= $cssHelper->typography('.sppb-comment-field', $settings, 'comment_field_typography',
				['font'           => 'comment_field_font_family',
				'size'           => 'comment_field_fontsize',
				'line_height'    => 'comment_field_lineheight',
				'letter_spacing' => 'comment_field_letterspace',
				'uppercase'      => 'comment_field_font_style.uppercase',
				'italic'         => 'comment_field_font_style.italic',
				'underline'      => 'comment_field_font_style.underline',
				'weight'         => 'comment_field_font_style.weight',
				]);

		$css .= $cssHelper->generateStyle('.sppb-comment-header', $settings, [], [], [],[],[],
				'display: flex; justify-content: space-between; align-items: center; position: relative;');
		
		$css .= $cssHelper->generateStyle('.sppb-comment-header-left', $settings, [], [], [],[],[],
				'display: flex; flex-direction: column; gap: 4px;');
		
		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action', $settings, [], [], [],[],[],
				'position: relative; cursor: inherit;');

		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action i', $settings, [], [], [],[],[],
				'cursor: pointer;');

		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action', $settings,
				['ellipsis_icon_bg_color' => 'background-color'], ['ellipsis_icon_bg_color' => false]);

		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action.sppb-btn-custom.sppb-btn-outline', $settings,
				[], [], [],[],[],
				'background-color: transparent; border-color: transparent;');
		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action.sppb-btn-custom.sppb-btn-outline i', $settings,
				[], [], [],[],[],
				'background-color: transparent; border-color: transparent;');
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-icon', $settings, [], [], [],[],[],
				'font-size: 16px; padding: 8px; border-radius: 50%; transition: all 0.3s ease;');
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-icon', $settings,
				['ellipsis_icon_color' => 'color'], ['ellipsis_icon_color' => false]);
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-icon', $settings,
				['ellipsis_icon_bg_color' => 'background-color'], ['ellipsis_icon_bg_color' => false]);
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-dropdown', $settings, [], [], [],[],[],
				'position: absolute; top: 100%; right: 0; background: white; border: 1px solid #ddd; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); z-index: 1000; min-width: 120px;');
		
		$css .= $cssHelper->typography('.sppb-ellipsis-edit-btn, .sppb-ellipsis-delete-btn', $settings, 'ellipsis_action_button_typography',
				['font'           => 'ellipsis_action_button_font_family',
				'size'           => 'ellipsis_action_button_fontsize',
				'line_height'    => 'ellipsis_action_button_lineheight',
				'letter_spacing' => 'ellipsis_action_button_letterspace',
				'uppercase'      => 'ellipsis_action_button_font_style.uppercase',
				'italic'         => 'ellipsis_action_button_font_style.italic',
				'underline'      => 'ellipsis_action_button_font_style.underline',
				'weight'         => 'ellipsis_action_button_font_style.weight',
				]);

				$ellipsisModes = ['.sppb-ellipsis-edit-btn', '.sppb-ellipsis-delete-btn'];

				for ($i = 0; $i < count($settings->ellipsis_action_button_item); $i++) {
					$css .= $cssHelper->generateStyle($ellipsisModes[$i], $settings->ellipsis_action_button_item[$i],
					['ellipsis_action_button_color' => 'color'], ['ellipsis_action_button_color' => false]);
			
					$css .= $cssHelper->generateStyle($ellipsisModes[$i], $settings->ellipsis_action_button_item[$i],
					['ellipsis_action_button_background_color' => 'background-color'], ['ellipsis_action_button_background_color' => false]);
			
					$css .= $cssHelper->generateStyle($ellipsisModes[$i] . ':hover', $settings->ellipsis_action_button_item[$i],
					['ellipsis_action_button_color_hover' => 'color'], ['ellipsis_action_button_color_hover' => false]);
			
					$css .= $cssHelper->generateStyle($ellipsisModes[$i] . ':hover', $settings->ellipsis_action_button_item[$i],
					['ellipsis_action_button_background_color_hover' => 'background-color'], ['ellipsis_action_button_background_color_hover' => false]);
				}
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-edit-btn:first-child', $settings, [], [], [],[],[],
				'border-radius: 6px 6px 0 0;');
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-delete-btn:last-child', $settings, [], [], [],[],[],
				'border-radius: 0 0 6px 6px;');
		
		$css .= $cssHelper->generateStyle('.sppb-ellipsis-edit-btn:only-child', $settings, [], [], [],[],[],
				'border-radius: 6px;');
		
		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action', $settings,
				['ellipsis_margin' => 'margin'], ['ellipsis_margin' => false]);

		$css .= $cssHelper->generateStyle('.sppb-comment-header-left', $settings, [], [], [],[],[], 'flex: 1;');

		$css .= $cssHelper->generateStyle('.sppb-comment-header-left', $settings, ['commentator_name_position' => 'display: flex; justify-content'], ['commentator_name_position' => false]);
		$css .= $cssHelper->generateStyle('.sppb-comment-ellipsis-action', $settings, ['ellipsis_position' => 'display: flex; justify-content'], ['ellipsis_position' => false]);
		
		$css .= $cssHelper->generateStyle('.comment-submit-btn',[],[],[],[],[],[], 'outline: none; cursor: pointer;');
		$css .= $cssHelper->typography('.comment-submit-btn', $settings, 'post_button_typography',
				['font'           => 'post_button_font_family',
				'size'           => 'post_button_fontsize',
				'line_height'    => 'post_button_lineheight',
				'letter_spacing' => 'post_button_letterspace',
				'uppercase'      => 'post_button_font_style.uppercase',
				'italic'         => 'post_button_font_style.italic',
				'underline'      => 'post_button_font_style.underline',
				'weight'         => 'post_button_font_style.weight',
				]);

		if(isset($settings->post_button_size) && $settings->post_button_size && $settings->post_button_size === 'custom'){
			$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom', $settings,
				['post_button_padding' => 'padding'], ['post_button_padding' => false]);
		}

		$css .= $cssHelper->generateStyle('.sppb-comment-form .sppb-comment-btn-wrapper',$settings,['comment_field_border_color' => 'border-color'],['comment_field_border_color' => false],[],[],[],
				'display: flex; padding: 16px; gap: 8px; align-items: center; border-width: 0px 1px 1px 1px; border-style: solid; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px;');
		$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom', $settings,
				['post_button_color' => 'color',
				'post_button_background_color' => 'background-color',],
				['post_button_color' => false,
				'post_button_background_color' => false]);

		$currentUserId = Factory::getUser()->id;

		if ($currentUserId) {
			$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom:hover', $settings,
			['post_button_color_hover' => 'color',
			'post_button_background_color_hover' => 'background-color',],
			['post_button_color_hover' => false,
			'post_button_background_color_hover' => false]);
		
			$settings->post_button_background_gradient = $cssHelper->parseColor($settings, 'post_button_background_gradient');
			$settings->post_button_background_gradient_hover = $cssHelper->parseColor($settings, 'post_button_background_gradient_hover');
	
			$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient', $settings,
					['post_button_background_gradient' => 'border:none; background-image',],
					['post_button_background_gradient' => false]);
			$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient:hover', $settings,
					['post_button_background_gradient_hover' => 'border:none; background-image',],
					['post_button_background_gradient_hover' => false]);
					$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom.sppb-btn-outline:hover', $settings,
					['post_button_background_color_hover' => 'background-color: transparent; border-color'],
					['post_button_background_color_hover' => false]);	
		}

		$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-custom.sppb-btn-outline', $settings,
				['post_button_background_color' => 'background-color: transparent; border-color'],
				['post_button_background_color' => false]);
		
		$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-link', $settings,
				['post_button_link_color' => 'color',
				'post_button_link_border_color' => 'border-color',
				'post_button_link_border_width' => 'border-width: 0 0 %spx 0',
				'post_button_link_padding_bottom' => 'padding: 0 0 %spx 0'],
				['post_button_link_color' => false,
				'post_button_link_border_color' => false,
				'post_button_link_border_width' => false,
				'post_button_link_padding_bottom' => false]);

		$css .= $cssHelper->generateStyle('.comment-submit-btn.sppb-btn-link:hover', $settings,
				['post_button_link_hover_color' => 'color',
				'post_button_link_border_hover_color' => 'border-color'],
				['post_button_link_hover_color' => false,
				'post_button_link_border_hover_color' => false]);

		$css .= $cssHelper->generateStyle('.sppb-comment-btn-wrapper', $settings,
				['post_button_alignment' => 'justify-content'],
				['post_button_alignment' => false],
				[], [], [],
				'display: flex; align-items: center;');
		$css .= $cssHelper->generateStyle('.sppb-btn-icon', $settings,
				['post_button_icon_margin' => 'margin'], ['post_button_icon_margin' => false]);

		foreach ($settings->edit_comment_button_item as $item_key => $item) {
			$css .= $cssHelper->typography('#sppb-comment-edit-button-' . $item_key, $item, 'edit_comment_button_typography',
					['font'           => 'edit_comment_button_font_family',
					'size'           => 'edit_comment_button_fontsize',
					'line_height'    => 'edit_comment_button_lineheight',
					'letter_spacing' => 'edit_comment_button_letterspace',
					'uppercase'      => 'edit_comment_button_font_style.uppercase',
					'italic'         => 'edit_comment_button_font_style.italic',
					'underline'      => 'edit_comment_button_font_style.underline',
					'weight'         => 'edit_comment_button_font_style.weight',
					]);
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key, $item,
					['edit_comment_button_color' => 'color',
					'edit_comment_button_background_color' => 'background-color'],
					['edit_comment_button_color' => false,
					'edit_comment_button_background_color' => false], [], [], [],
					'outline: none; cursor: pointer;');
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key . ':hover', $item,
					['edit_comment_button_color_hover' => 'color',
					'edit_comment_button_background_color_hover' => 'background-color'],
					['edit_comment_button_color_hover' => false,
					'edit_comment_button_background_color_hover' => false]);
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key . '.sppb-btn-outline', $item,
					['edit_comment_button_background_color' => 'background-color: transparent; border-color'],
					['edit_comment_button_background_color' => false]);
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key . '.sppb-btn-outline:hover', $item,
					['edit_comment_button_background_color_hover' => 'background-color: transparent; border-color'],
					['edit_comment_button_background_color_hover' => false]);
			$item->edit_comment_button_background_gradient = $cssHelper->parseColor($item, 'edit_comment_button_background_gradient');
			$item->edit_comment_button_background_gradient_hover = $cssHelper->parseColor($item, 'edit_comment_button_background_gradient_hover');
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key . '.sppb-btn-gradient', $item,
					['edit_comment_button_background_gradient' => 'border:none; background-image'],
					['edit_comment_button_background_gradient' => false]);
			$css .= $cssHelper->generateStyle('#sppb-comment-edit-button-' . $item_key . '.sppb-btn-gradient:hover', $item,
					['edit_comment_button_background_gradient_hover' => 'border:none; background-image'],
					['edit_comment_button_background_gradient_hover' => false]);
		}

	$css .= $cssHelper->generateStyle('.sppb-comment-edit-buttons-wrapper', $settings,
				['edit_comment_button_alignment' => 'justify-content',
				'edit_comment_button_gap' => 'gap'], ['edit_comment_button_alignment' => false, 'edit_comment_button_gap' => false],
				[], [], [],
				'display: flex; align-items: center;');

	$css .= $cssHelper->generateStyle('.commentator-name-wrapper', $settings,
				['commentator_name_alignment' => 'justify-content'], ['commentator_name_alignment' => false], [],[],[],
				'display: flex; align-items: center;');

	$css .= $cssHelper->typography('.commentator-name', $settings, 'commentator_name_typography',
				['font'           => 'commentator_name_font_family',
				'size'           => 'commentator_name_fontsize',
				'line_height'    => 'commentator_name_lineheight',
				'letter_spacing' => 'commentator_name_letterspace',
				'uppercase'      => 'commentator_name_font_style.uppercase',
				'italic'         => 'commentator_name_font_style.italic',
				'underline'      => 'commentator_name_font_style.underline',
				'weight'         => 'commentator_name_font_style.weight',
				]);
	$css .= $cssHelper->generateStyle('.commentator-name', $settings,
				['commentator_name_color' => 'color'], ['commentator_name_color' => false]);
	$settings->commentator_name_shadow = $cssHelper->parseBoxShadow($settings, 'commentator_name_text_shadow', true);
	$css .= $cssHelper->generateStyle('.commentator-name', $settings,
				['commentator_name_shadow' => 'text-shadow'], ['commentator_name_shadow' => false]);

		$css .= $cssHelper->typography('.sppb-comment-content-text', $settings, 'posted_comment_typography',
				['font'           => 'posted_comment_font_family',
				'size'           => 'posted_comment_fontsize',
				'line_height'    => 'posted_comment_lineheight',
				'letter_spacing' => 'posted_comment_letterspace',
				'uppercase'      => 'posted_comment_font_style.uppercase',
				'italic'         => 'posted_comment_font_style.italic',
				'underline'      => 'posted_comment_font_style.underline',
				'weight'         => 'posted_comment_font_style.weight',
				]);
		$css .= $cssHelper->generateStyle('.sppb-comment-content-text', $settings,
				['posted_comment_color' => 'color'], ['posted_comment_color' => false]);
		$settings->posted_comment_shadow = $cssHelper->parseBoxShadow($settings, 'posted_comment_text_shadow', true);
		$css .= $cssHelper->generateStyle('.sppb-comment-content-text', $settings,
				['posted_comment_shadow' => 'text-shadow'], ['posted_comment_shadow' => false]);


		// Time Styles
		$enableTime = (isset($settings->enable_time) && $settings->enable_time) ? $settings->enable_time : 0;
		if ($enableTime) {
			$css .= $cssHelper->typography('.sppb-comment-time', $settings, 'time_typography',
					['font'           => 'time_font_family',
					'size'           => 'time_fontsize',
					'line_height'    => 'time_lineheight',
					'letter_spacing' => 'time_letterspace',
					'uppercase'      => 'time_font_style.uppercase',
					'italic'         => 'time_font_style.italic',
					'underline'      => 'time_font_style.underline',
					'weight'         => 'time_font_style.weight',
					]);
			$css .= $cssHelper->generateStyle('.sppb-comment-time', $settings,
					['time_color' => 'color'], ['time_color' => false]);
			$settings->time_shadow = $cssHelper->parseBoxShadow($settings, 'time_text_shadow', true);
			$css .= $cssHelper->generateStyle('.sppb-comment-time', $settings,
					['time_shadow' => 'text-shadow'], ['time_shadow' => false]);
			$css .= $cssHelper->generateStyle('.sppb-comment-time-wrapper', $settings,
					['time_alignment' => 'text-align'], ['time_alignment' => false]);

			$showEditedTime = (isset($settings->show_edited_time) && $settings->show_edited_time) ? $settings->show_edited_time : 0;
			if ($showEditedTime) {
				$css .= $cssHelper->typography('.sppb-comment-edited-time', $settings, 'edited_time_typography',
						['font'           => 'edited_time_font_family',
						'size'           => 'edited_time_fontsize',
						'line_height'    => 'edited_time_lineheight',
						'letter_spacing' => 'edited_time_letterspace',
						'uppercase'      => 'edited_time_font_style.uppercase',
						'italic'         => 'edited_time_font_style.italic',
						'underline'      => 'edited_time_font_style.underline',
						'weight'         => 'edited_time_font_style.weight',
						]);
				$css .= $cssHelper->generateStyle('.sppb-comment-edited-time', $settings,
						['edited_time_color' => 'color'], ['edited_time_color' => false]);
				$settings->edited_time_shadow = $cssHelper->parseBoxShadow($settings, 'edited_time_text_shadow', true);
				$css .= $cssHelper->generateStyle('.sppb-comment-edited-time', $settings,
						['edited_time_shadow' => 'text-shadow'], ['edited_time_shadow' => false]);
				$css .= $cssHelper->generateStyle('.sppb-comment-edited-time-wrapper', $settings,
						['edited_time_alignment' => 'text-align'], ['edited_time_alignment' => false]);
			}
		}

		return $css;
	}

	public function js(){
		$js = '';
		$input = Factory::getApplication()->input;
		$collectionType = $input->get('collection_type', null, 'string');
		$viewType = $input->get('view', null, 'string');
		$articleId = $input->get('id', null, 'int');
		$commentService = new CommentService();
		if ($viewType == 'page') {
			$articleId = $commentService->getArticleId($articleId);
		}
		$itemId = $input->get('collection_item_id', null, 'array');
		$itemId = $itemId ? $itemId[0] : null;
		$itemId = $itemId ? $itemId : $articleId;
		if (($collectionType != 'articles' && $collectionType != 'normal-source') && empty($itemId)) {
			return "";
		}
		$collectionType = $collectionType ? $collectionType : 'articles';
		$avatarColor = !empty($this->addon->settings->commentator_avatar_color) ? $this->addon->settings->commentator_avatar_color : "#4285F4";
		$currentUserId = Factory::getUser()->id;
		$anonymousPerson = Text::_('COM_SPPAGEBUILDER_ANONYMOUS_PERSON');

		// Load language strings for JavaScript
		Text::script('COM_SPPAGEBUILDER_JUST_NOW');
		Text::script('COM_SPPAGEBUILDER_MINUTE_AGO');
		Text::script('COM_SPPAGEBUILDER_MINUTES_AGO');
		Text::script('COM_SPPAGEBUILDER_HOUR_AGO');
		Text::script('COM_SPPAGEBUILDER_HOURS_AGO');
		Text::script('COM_SPPAGEBUILDER_DAY_AGO');
		Text::script('COM_SPPAGEBUILDER_DAYS_AGO');
		Text::script('COM_SPPAGEBUILDER_MONTH_AGO');
		Text::script('COM_SPPAGEBUILDER_MONTHS_AGO');
		Text::script('COM_SPPAGEBUILDER_YEAR_AGO');
		Text::script('COM_SPPAGEBUILDER_YEARS_AGO');

		$js .= '
		
		const escapeHtml = (text) => {
			const div = document.createElement(\'div\');
			div.textContent = text;
			return div.innerHTML;
		};

		document.addEventListener("DOMContentLoaded", function() {
			// Handle Gravatar image loading and fallback
			const handleGravatarImages = () => {
				const gravatarImages = document.querySelectorAll(\'.sppb-comment-avatar img[src*="gravatar.com"]\');
				gravatarImages.forEach(img => {
					img.addEventListener(\'error\', function() {
						// Hide the image and show the fallback
						this.style.display = \'none\';
						const fallback = this.nextElementSibling;
						if (fallback && fallback.classList.contains(\'sppb-comment-avatar-fallback\')) {
							fallback.style.display = \'flex\';
						}
					});
					
					img.addEventListener(\'load\', function() {
						// Ensure fallback is hidden when image loads successfully
						const fallback = this.nextElementSibling;
						if (fallback && fallback.classList.contains(\'sppb-comment-avatar-fallback\')) {
							fallback.style.display = \'none\';
						}
					});
				});
			};
			
			// Initialize Gravatar handling
			handleGravatarImages();
			// Function to update comment count
			const updateCommentCount = () => {
				const commentItems = document.querySelectorAll(\'.sppb-comment-item[data-parent-id=""]\');
				const count = commentItems.length;
				const countElements = document.querySelectorAll(\'.sppb-comment-count\');
				countElements.forEach(element => {
					element.textContent = \'(\' + count + \')\';
				});
			};

			// Function to count all comments (including replies)
			const updateTotalCommentCount = () => {
				const allCommentItems = document.querySelectorAll(\'.sppb-comment-item\');
				const count = allCommentItems.length;
				const countElements = document.querySelectorAll(\'.sppb-comment-count\');
				countElements.forEach(element => {
					element.textContent = \'(\' + count + \')\';
				});
			};

			// Function to update reply count for a specific comment
			const updateReplyCount = (commentId) => {
				const $commentItem = document.querySelector(`[data-comment-id="${commentId}"]`);
				if (!$commentItem) return;
				
				const $childrenWrapper = $commentItem.querySelector(\'.sppb-comment-children-wrapper\');
				const $replyText = $commentItem.querySelector(\'.sppb-reply-text\');
				
				if ($childrenWrapper && $replyText) {
					const replyCount = $childrenWrapper.querySelectorAll(`.sppb-comment-item[data-parent-id="${commentId}"]`).length;
					$replyText.textContent = replyCount + \' reply\';
				}
			};

			document.addEventListener("submit", function(event) {
				if (event.target.classList.contains("sppb-comment-form")) {
					event.preventDefault();
					
					const form = event.target;
					const formData = new FormData(form);
					const commentContent = formData.get("comment");
					const ajaxData = $(form).serializeArray();

					const apiUrl = "'.Uri::root().'index.php?option=com_sppagebuilder&task=comment.comments";

					const requestData = {
						_method: "POST",
						comment: {
							content: commentContent,
							item_id: ' . $itemId . ',
							source_type: "'. $collectionType .'",
							parent_id: null
						}
					};

					const ajaxRequestData = {
						option: "com_sppagebuilder",
						task: "ajax",
						addon: "comment",
						data: ajaxData,
					};

					$.ajax({
						type: "POST",
						
						data: ajaxRequestData,
						success: function (response) {
							const parsedResponse = JSON.parse(response);
							const data = JSON.parse(parsedResponse.data);
							if (data?.status === true) {
								hasRateLimit = false;
								createComment(apiUrl, requestData);
							}
							return;
						},
					});

					return false;
				}
			});

			function createComment(apiUrl, requestData) {
				fetch(apiUrl, {
					method: "POST",
					headers: {
						"Content-Type": "application/json",
						 "X-CSRF-Token": Joomla.getOptions("csrf.token")
					},
					body: JSON.stringify(requestData)
				})
				.then(response => response.json())
				.then(data => {
					if (data?.success && !data?.data?.error) {
						const newComment = data.data?.data || "";

						if (!newComment) {
							return;
						}

						// Check if comment needs moderation (user\'s own comment that is unpublished)
						const needsModeration = (!newComment.created_by_id || (newComment.created_by_id && newComment.created_by_id === ' . $currentUserId . ')) && newComment.published === 0;

						const parentId = newComment.parent_id || null;
						const commentEntry = renderComment(newComment, needsModeration);

						if (parentId) {
							const parentComment = document.querySelector(`.sppb-comment-item [data-comment-id="${parentId}"]`);
							if (parentComment) {
								const repliesContainer = parentComment.querySelector(".sppb-comment-children-wrapper");
								if (repliesContainer) {
									repliesContainer.insertAdjacentHTML("afterbegin", commentEntry);
								}
							} else {
								alert("Parent comment not found.");
							}
						} else {
							const commentsList = document.querySelector(".sppb-comments-list");
							if (commentsList) {
								commentsList.insertAdjacentHTML("afterbegin", commentEntry);
							}
						}

						const commentInput = document.querySelector(".sppb-comment-field");
						if (commentInput) {
							commentInput.value = "";
						}

						// Update total comment count
						updateCommentCount();
						
						// Handle Gravatar for new comment
						handleGravatarImages();

					} else {
						alert("Error: " + data?.data?.error);
					}
				})
				.catch(error => {
					alert("An error occurred while submitting the comment: " + error.message);
				});
			}

			$(document).on("click", ".sppb-comment-reply-action", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.data("comment-id");

				$(".sppb-comment-reply-form").hide();

				const $replyForm = $self.closest(".sppb-comment-item").find(`.sppb-comment-reply-form[data-comment-id="${commentId}"]`);
				$replyForm.show();

				$replyForm.find(".sppb-comment-reply-input").focus();
			});

			// Handle reply form submission
			$(document).on("click", ".sppb-comment-reply-submit-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.data("comment-id");
				let replyContent = $self.closest(".sppb-comment-item").find(".sppb-comment-reply-input").val();
				
				if (!replyContent.trim()) {
					alert("Please enter a reply.");
					return;
				}

				const apiUrl = "'.Uri::root().'index.php?option=com_sppagebuilder&task=comment.comments";

				const requestData = {
					_method: "POST",
					comment: {
						content: replyContent,
						item_id: ' . $itemId . ',
						parent_id: commentId,
						source_type: "'. $collectionType .'"
					}
				};

				fetch(apiUrl, {
					method: "POST",
					headers: {
						"Content-Type": "application/json",
						 "X-CSRF-Token": Joomla.getOptions("csrf.token")
					},
					body: JSON.stringify(requestData)
				})
				.then(response => response.json())
				.then(data => {
					if (data?.success && !data?.data?.error) {
						const newReply = data.data?.data || "";

						if (!newReply) {
							return;
						}

						// Check if reply needs moderation (user\'s own reply that is unpublished)
						const needsModeration = (!newReply.created_by_id || (newReply.created_by_id && newReply.created_by_id === ' . $currentUserId . ')) && newReply.published === 0;

						const replyEntry = renderComment(newReply, needsModeration);
						const $parentComment = $self.closest(".sppb-comment-item");

						let $repliesContainer = $parentComment.find(".sppb-comment-children-wrapper");
						if ($repliesContainer?.length === 0) {
							$repliesContainer = $("<div class=\"sppb-comment-children-wrapper\"></div>");
							$parentComment.append($repliesContainer);
						}
						
						$($repliesContainer?.[0])?.prepend(replyEntry);

						$self.closest(".sppb-comment-item").find(".sppb-comment-reply-input").val("");
						$self.closest(".sppb-comment-item").find(".sppb-comment-reply-form").hide();

						// Update reply count for the parent comment
						updateReplyCount(newReply.parent_id);

						// Update total comment count
						updateTotalCommentCount();
						
						// Handle Gravatar for new reply
						handleGravatarImages();

					} else {
						alert("Error: " + data?.data?.error);
					}
				})
				.catch(error => {
					alert("An error occurred while submitting the reply: " + error.message);
				});
			});

			$(document).on("click", ".sppb-comment-reply-cancel-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.data("comment-id");
				$self.closest(".sppb-comment-item").find(".sppb-comment-reply-form").hide();
			});

			$(document).on("click", ".sppb-ellipsis-edit-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.closest(".sppb-comment-item").data("comment-id");

				$self.closest(".sppb-ellipsis-dropdown").hide();

				const $commentItem = $self.closest(".sppb-comment-item");
				const $editForm = $commentItem.find(`.sppb-comment-edit-form[data-comment-id=${commentId}]`);
				const $contentText = $commentItem.find(`.sppb-comment-content[data-comment-id=${commentId}] .sppb-comment-content-text`);
				
				$editForm.show();
				$self.closest(".sppb-comment-header").find(".sppb-comment-header-left").hide();
				$self.closest(".sppb-comment-header").find(".sppb-comment-ellipsis-action").hide();
				$contentText.hide();

				$commentItem.find(`.sppb-comment-edit-input[data-comment-id=${commentId}]`).focus();
			});

			$(document).on("click", ".sppb-comment-edit-submit-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.data("comment-id");
				let commentContent = $self.closest(".sppb-comment-item").find(".sppb-comment-edit-input").val();
				
				if (!commentContent.trim()) {
					alert("Please enter comment content.");
					return;
				}

				const apiUrl = "'.Uri::root().'index.php?option=com_sppagebuilder&task=comment.comments";

				$.ajax({
					url: apiUrl,
					headers: {
						"X-CSRF-Token": Joomla.getOptions("csrf.token"),
					},
					data: {
						_method: "POST",
						comment: {
							id: commentId,
							content: commentContent
						}
					},
					success: function (response) {
						if (response.success) {
							const $commentItem = $self.closest(".sppb-comment-item[data-comment-id=\'" + commentId + "\']");
							const $editForm = $commentItem.find(".sppb-comment-edit-form");
							const $contentText = $commentItem.find(".sppb-comment-content[data-comment-id=\'" + commentId + "\'] .sppb-comment-content-text span");

							const $contentTextWrapper = $commentItem.find(`.sppb-comment-content[data-comment-id=${commentId}] .sppb-comment-content-text`);

							$editForm.hide();
							$commentItem.find(".sppb-comment-header .sppb-comment-header-left").show();
							$commentItem.find(".sppb-comment-header .sppb-comment-ellipsis-action").show();
							$commentItem.find(".sppb-comment-content").show();
							
							const formattedContent = escapeHtml(commentContent).replace(/\\n/g, \'<br>\');
							$contentTextWrapper.show();
							$contentText.html(formattedContent);
						} else {
							alert("An error occurred while editing the comment: " + response.message);
						}
					},
					error: function (xhr, status, error) {
						alert("An error occurred while editing the comment: " + error);
					}
				});
			});

			$(document).on("click", ".sppb-comment-edit-cancel-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.data("comment-id");
				const $commentItem = $self.closest(".sppb-comment-item");
				const $editForm = $commentItem.find(".sppb-comment-edit-form");
				const $contentText = $commentItem.find(".sppb-comment-content .sppb-comment-content-text");
				
				$editForm.hide();
				$commentItem.find(".sppb-comment-header .sppb-comment-header-left").show();
				$commentItem.find(".sppb-comment-header .sppb-comment-ellipsis-action").show();
				$contentText.show();
			});

			$(document).on("click", ".sppb-ellipsis-delete-btn", function (event) {
				event.preventDefault();
				let $self = $(this);
				let $commentItem = $self.closest(".sppb-comment-item");
				let commentId = $commentItem.data("comment-id");
				let parentId = $commentItem.data("parent-id");

				if (!confirm("Are you sure you want to delete this comment?")) {
					return;
				}

				$self.closest(".sppb-ellipsis-dropdown").hide();

				const apiUrl = "'.Uri::root().'index.php?option=com_sppagebuilder&task=comment.comments";

				$.ajax({
					url: apiUrl,
					headers: {
						"X-CSRF-Token": Joomla.getOptions("csrf.token"),
					},
					data: {
						_method: "DELETE",
						comment: {
							id: commentId
						}
					},
					success: function (response) {
						if (response.success) {
							// Remove the comment item
							$commentItem.remove();
							
							// Update reply count for parent comment if this was a reply
							if (parentId) {
								updateReplyCount(parentId);
							}
							
							// Update total comment count
							updateCommentCount();
						} else {
							alert("An error occurred while deleting the comment: " + response.message);
						}
					},
					error: function (xhr, status, error) {
						alert("An error occurred while deleting the comment: " + error);
					}
				});
			});

			$(document).on("click", ".sppb-ellipsis-icon", function (event) {
				event.preventDefault();
				event.stopPropagation();
				let $self = $(this);
				let $dropdown = $self.siblings(".sppb-ellipsis-dropdown");

				$(".sppb-ellipsis-dropdown").not($dropdown).hide();

				$dropdown.toggle();
			});

			$(document).on("click", function (event) {
				if (!$(event.target).closest(".sppb-comment-ellipsis-action").length) {
					$(".sppb-ellipsis-dropdown").hide();
				}
			});

			$(document).on("click", ".sppb-comment-likes", function (event) {
				event.preventDefault();
				let $self = $(this);
				let commentId = $self.closest(".sppb-comment-item").data("comment-id");
				let $likesText = $self.find(".sppb-likes-text");
				let currentLikes = parseInt($likesText.text().match(/\d+/)[0]) || 0;
				
				const apiUrl = "'.Uri::root().'index.php?option=com_sppagebuilder&task=comment.comments";

				$.ajax({
					url: apiUrl,
					headers: {
						"X-CSRF-Token": Joomla.getOptions("csrf.token"),
					},
					data: {
						_method: "POST",
						comment: {
							id: commentId,
							action: "like"
						}
					},
					success: function (response) {
						if (response.success) {
							if ($self.hasClass("liked")) {
								$likesText.text((currentLikes - 1) + " ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '");
								$self.removeClass("liked");
							} else {
								$likesText.text((currentLikes + 1) + " ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '");
								$self.addClass("liked");
							}
						} else {
							alert(response?.data?.error || "An error occurred while liking the comment");
						}
					},
					error: function (xhr, status, error) {
						alert(xhr?.responseJSON?.data?.error || "An error occurred while liking the comment: " + error);
					}
				});
			});

			const renderComment = (commentRecord, needsModeration = false) => {
				// Helper functions to match PHP implementation
				// MD5 function for Gravatar generation
				const md5 = (string) => {
					function md5_RotateLeft(lValue, iShiftBits) {
						return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
					}
					function md5_AddUnsigned(lX, lY) {
						var lX4, lY4, lX8, lY8, lResult;
						lX8 = (lX & 0x80000000);
						lY8 = (lY & 0x80000000);
						lX4 = (lX & 0x40000000);
						lY4 = (lY & 0x40000000);
						lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
						if (lX4 & lY4) {
							return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
						}
						if (lX4 | lY4) {
							if (lResult & 0x40000000) {
								return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
							} else {
								return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
							}
						} else {
							return (lResult ^ lX8 ^ lY8);
						}
					}
					function md5_F(x, y, z) {
						return (x & y) | ((~x) & z);
					}
					function md5_G(x, y, z) {
						return (x & z) | (y & (~z));
					}
					function md5_H(x, y, z) {
						return (x ^ y ^ z);
					}
					function md5_I(x, y, z) {
						return (y ^ (x | (~z)));
					}
					function md5_FF(a, b, c, d, x, s, ac) {
						a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
						return md5_AddUnsigned(md5_RotateLeft(a, s), b);
					}
					function md5_GG(a, b, c, d, x, s, ac) {
						a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
						return md5_AddUnsigned(md5_RotateLeft(a, s), b);
					}
					function md5_HH(a, b, c, d, x, s, ac) {
						a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
						return md5_AddUnsigned(md5_RotateLeft(a, s), b);
					}
					function md5_II(a, b, c, d, x, s, ac) {
						a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
						return md5_AddUnsigned(md5_RotateLeft(a, s), b);
					}
					function md5_ConvertToWordArray(string) {
						var lWordCount;
						var lMessageLength = string.length;
						var lNumberOfWords_temp1 = lMessageLength + 8;
						var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
						var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
						var lWordArray = Array(lNumberOfWords - 1);
						var lBytePosition = 0;
						var lByteCount = 0;
						while (lByteCount < lMessageLength) {
							lWordCount = (lByteCount - (lByteCount % 4)) / 4;
							lBytePosition = (lByteCount % 4) * 8;
							lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
							lByteCount++;
						}
						lWordCount = (lByteCount - (lByteCount % 4)) / 4;
						lBytePosition = (lByteCount % 4) * 8;
						lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
						lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
						lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
						return lWordArray;
					}
					function md5_WordToHex(lValue) {
						var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
						for (lCount = 0; lCount <= 3; lCount++) {
							lByte = (lValue >>> (lCount * 8)) & 255;
							WordToHexValue_temp = "0" + lByte.toString(16);
							WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
						}
						return WordToHexValue;
					}
					function md5_Utf8Encode(string) {
						string = string.replace(/\\r\\n/g, "\\n");
						var utftext = "";
						for (var n = 0; n < string.length; n++) {
							var c = string.charCodeAt(n);
							if (c < 128) {
								utftext += String.fromCharCode(c);
							} else if ((c > 127) && (c < 2048)) {
								utftext += String.fromCharCode((c >> 6) | 192);
								utftext += String.fromCharCode((c & 63) | 128);
							} else {
								utftext += String.fromCharCode((c >> 12) | 224);
								utftext += String.fromCharCode(((c >> 6) & 63) | 128);
								utftext += String.fromCharCode((c & 63) | 128);
							}
						}
						return utftext;
					}
					var x = Array();
					var k, AA, BB, CC, DD, a, b, c, d;
					var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
					var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
					var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
					var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
					string = md5_Utf8Encode(string);
					x = md5_ConvertToWordArray(string);
					a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
					for (k = 0; k < x.length; k += 16) {
						AA = a; BB = b; CC = c; DD = d;
						a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
						d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
						c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
						b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
						a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
						d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
						c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
						b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
						a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
						d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
						c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
						b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
						a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
						d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
						c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
						b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
						a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
						d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
						c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
						b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
						a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
						d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
						c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
						b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
						a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
						d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
						c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
						b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
						a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
						d = md5_GG(d, a, b, c, x[k + 20], S22, 0xFCEFA3F8);
						c = md5_GG(c, d, a, b, x[k + 20], S23, 0x676F02D9);
						b = md5_GG(b, c, d, d, x[k + 5], S24, 0x8D2A4C8A);
						a = md5_HH(a, b, c, d, x[k + 8], S21, 0xFFFA3942);
						d = md5_HH(d, a, b, c, x[k + 11], S22, 0x8771F681);
						c = md5_HH(c, d, a, b, x[k + 14], S23, 0x6D9D6122);
						b = md5_HH(b, c, d, a, x[k + 1], S24, 0xFDE5380C);
						a = md5_HH(a, b, c, d, x[k + 4], S21, 0xA4BEEA44);
						d = md5_HH(d, a, b, c, x[k + 7], S22, 0x4BDECFA9);
						c = md5_HH(c, d, a, b, x[k + 10], S23, 0xF6BB4B60);
						b = md5_HH(b, c, d, a, x[k + 13], S24, 0xBEBFBC70);
						a = md5_HH(a, b, c, d, x[k + 0], S21, 0x289B7EC6);
						d = md5_HH(d, a, b, c, x[k + 3], S22, 0xEAA127FA);
						c = md5_HH(c, d, a, b, x[k + 6], S23, 0xD4EF3085);
						b = md5_HH(b, c, d, a, x[k + 9], S24, 0x4881D05);
						a = md5_HH(a, b, c, d, x[k + 12], S21, 0xD9D4D039);
						d = md5_HH(d, a, b, c, x[k + 15], S22, 0xE6DB99E5);
						a = md5_HH(a, b, c, d, x[k + 2], S23, 0x1FA27CF8);
						b = md5_HH(b, c, d, a, x[k + 5], S24, 0xC4AC5665);
						a = md5_II(a, b, c, d, x[k + 0], S21, 0xF4292244);
						d = md5_II(d, a, b, c, x[k + 6], S22, 0x432AFF97);
						c = md5_II(c, d, a, b, x[k + 13], S23, 0xAB9423A7);
						b = md5_II(b, c, d, a, x[k + 4], S24, 0xFC93A039);
						a = md5_II(a, b, c, d, x[k + 1], S21, 0x655B59C3);
						d = md5_II(d, a, b, c, x[k + 8], S22, 0x8F0CCC92);
						c = md5_II(c, d, a, b, x[k + 11], S23, 0xFFEFF47D);
						b = md5_II(b, c, d, a, x[k + 2], S24, 0x85845DD1);
						a = md5_II(a, b, c, d, x[k + 7], S21, 0x6FA87E4F);
						d = md5_II(d, a, b, c, x[k + 14], S22, 0xFE2CE6E0);
						c = md5_II(c, d, a, b, x[k + 5], S23, 0xA3014314);
						b = md5_II(b, c, d, a, x[k + 12], S24, 0x4E0811A1);
						a = md5_II(a, b, c, d, x[k + 9], S21, 0xF7537E82);
						d = md5_II(d, a, b, c, x[k + 15], S22, 0xBD3AF235);
						c = md5_II(c, d, a, b, x[k + 2], S23, 0x2AD7D2BB);
						b = md5_II(b, c, d, a, x[k + 0], S24, 0xEB86D391);
						a = md5_AddUnsigned(a, AA);
						b = md5_AddUnsigned(b, BB);
						c = md5_AddUnsigned(c, CC);
						d = md5_AddUnsigned(d, DD);
					}
					var temp = md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d);
					return temp.toLowerCase();
				};
				
				const getInitials = (name) => {
					if (typeof name !== "string") {
						return name;
					}
					const words = name.split(\' \');
					if (words.length > 1) {
						return words[0].charAt(0).toUpperCase() + words[words.length - 1].charAt(0).toUpperCase();
					}
					return name.charAt(0).toUpperCase();
				};
				
				const getRandomColor = () => {
					const colors = [\'#3B82F6\', \'#10B981\', \'#F59E0B\', \'#EF4444\', \'#8B5CF6\', \'#06B6D4\', \'#84CC16\', \'#F97316\'];
					return colors[Math.floor(Math.random() * colors.length)];
				};
				
				const getTextColor = (bgColor) => {
					const hex = bgColor.replace(\'#\', \'\');
					const r = parseInt(hex.substr(0, 2), 16);
					const g = parseInt(hex.substr(2, 2), 16);
					const b = parseInt(hex.substr(4, 2), 16);
					const brightness = (r * 299 + g * 587 + b * 114) / 1000;
					return brightness > 128 ? \'#000000\' : \'#FFFFFF\';
				};
				
				const getRelativeTime = (dateString) => {
					const date = new Date(dateString);
					const now = new Date(dateString);
					const diff = now - date;
					const diffInSeconds = Math.floor(diff / 1000);
					
					if (diffInSeconds < 60) {
						return Joomla.Text._(\'COM_SPPAGEBUILDER_JUST_NOW\');
					} else if (diffInSeconds < 3600) {
						const minutes = Math.floor(diffInSeconds / 60);
						const key = minutes > 1 ? \'COM_SPPAGEBUILDER_MINUTES_AGO\' : \'COM_SPPAGEBUILDER_MINUTE_AGO\';
						return Joomla.Text._(key).replace(\'%s\', minutes);
					} else if (diffInSeconds < 86400) {
						const hours = Math.floor(diffInSeconds / 3600);
						const key = hours > 1 ? \'COM_SPPAGEBUILDER_HOURS_AGO\' : \'COM_SPPAGEBUILDER_HOUR_AGO\';
						return Joomla.Text._(key).replace(\'%s\', hours);
					} else if (diffInSeconds < 2592000) {
						const days = Math.floor(diffInSeconds / 86400);
						const key = days > 1 ? \'COM_SPPAGEBUILDER_DAYS_AGO\' : \'COM_SPPAGEBUILDER_DAY_AGO\';
						return Joomla.Text._(key).replace(\'%s\', days);
					} else if (diffInSeconds < 31536000) {
						const months = Math.floor(diffInSeconds / 2592000);
						const key = months > 1 ? \'COM_SPPAGEBUILDER_MONTHS_AGO\' : \'COM_SPPAGEBUILDER_MONTH_AGO\';
						return Joomla.Text._(key).replace(\'%s\', months);
					} else {
						const years = Math.floor(diffInSeconds / 31536000);
						const key = years > 1 ? \'COM_SPPAGEBUILDER_YEARS_AGO\' : \'COM_SPPAGEBUILDER_YEAR_AGO\';
						return Joomla.Text._(key).replace(\'%s\', years);
					}
				};
				
				// Generate avatar and colors
				const avatarColor = "' . $avatarColor . '";
				const textColor = getTextColor(avatarColor);
				const commentatorName = commentRecord.created_by || \'' . $anonymousPerson . '\';
				const initials = getInitials(commentatorName);
				
				// Generate time display
				const createdTime = getRelativeTime(commentRecord.created_on);
				const editedTime = commentRecord.modified && commentRecord.modified !== commentRecord.created_on ? 
					\' • <span class="sppb-comment-edited-time">Edited \' + getRelativeTime(commentRecord.modified) + \'<\/span>\' : \'\';
				
				// Get settings from the page (we\'ll need to make these available)
				const settings = window.sppbCommentSettings || {};
				const ellipsisBtnClass = \'sppb-btn sppb-btn-custom sppb-btn-rounded sppb-btn-md\';
				const ellipsisBtnIcon = \'fa fa-ellipsis-v\';
				const likesIcon = \'fa fa-heart\';
				const replyIcon = \'fa fa-reply\';
				const btnClass = \'sppb-btn sppb-btn-default sppb-btn-rounded sppb-btn-md\';
				
				// Generate ellipsis action buttons HTML
				const generateEllipsisActionButtons = () => {
					return \'<div class="sppb-comment-ellipsis-action-buttons-wrapper">\' +
						\'<button style="width: 100%; text-align: left;" class="sppb-comment-ellipsis-action-button sppb-btn sppb-btn-md sppb-btn-rounded sppb-ellipsis-edit-btn" id="sppb-comment-ellipsis-action-button-0" data-comment-id="\' + commentRecord.id + \'">Edit<\/button>\' +
						\'<button style="width: 100%; text-align: left;" class="sppb-comment-ellipsis-action-button sppb-btn sppb-btn-md sppb-btn-rounded sppb-ellipsis-delete-btn" id="sppb-comment-ellipsis-action-button-1" data-comment-id="\' + commentRecord.id + \'">Delete<\/button>\' +
						\'<\/div>\';
				};
				
				// Generate edit comment buttons HTML
				const generateEditCommentButtons = () => {
					return \'<div class="sppb-comment-edit-buttons-wrapper sppb-comment-btn-wrapper">\' +
						\'<button class="sppb-comment-edit-button sppb-comment-edit-cancel-btn sppb-btn sppb-btn-md sppb-btn-rounded" id="sppb-comment-edit-button-0" data-comment-id="\' + commentRecord.id + \'">' . Text::_('COM_SPPAGEBUILDER_CANCEL') . '<\/button>\' +
						\'<button class="sppb-comment-edit-button sppb-comment-edit-submit-btn sppb-btn sppb-btn-md sppb-btn-rounded" id="sppb-comment-edit-button-1" data-comment-id="\' + commentRecord.id + \'">' . Text::_('COM_SPPAGEBUILDER_UPDATE') . '<\/button>\' +
						\'<\/div>\';
				};
				
				// Calculate margin and level based on parent
				const level = commentRecord.parent_id ? 1 : 0;
				const rootCommentClass = level === 0 ? \' sppb-root-comment\' : \'\';
				const parentCommentClass = (!commentRecord.parent_id) ? \' sppb-parent-comment\' : \'\';
				const marginLeft = level > 0 ? \'55px\' : \'0px\';
				const marginTop = \'-4px\';
				const contentMarginLeft = level > 0 ? \'style="margin-left: 0; margin-top: 11px;"\' : \'\';
				
				const formattedContent = escapeHtml(commentRecord.content).replace(/\\n/g, \'<br>\');

				// Build HTML in parts to avoid string concatenation issues
				const htmlParts = [];
				
				// Main container
				htmlParts.push(\'<div data-comment-id="\' + commentRecord.id + \'" data-parent-id="\' + (commentRecord.parent_id || "") + \'" class="sppb-comment-item sppb-comment-item \' + parentCommentClass + rootCommentClass + \'" style="margin-top: \' + marginTop + \'; margin-left: \' + marginLeft + \';">\');
				htmlParts.push(\'<div class="sppb-comment-thread-line" style="left:-34px;"><\/div>\');
				htmlParts.push(\'<div class="sppb-comment-thread-connector" style="left:-34px; width: 55px;"><\/div>\');
				htmlParts.push(\'<div class="sppb-comment-content" \' + contentMarginLeft + \'>\');
				
				// Header section
				htmlParts.push(\'<div class="sppb-comment-header sppb-comment-header">\');
				
				// Avatar section with profile image, Gravatar, and fallback logic
				if (commentRecord.profile_image) {
					htmlParts.push(\'<div class="sppb-comment-avatar" style="border-radius: 50%; width: 45px; height: 45px; margin-right: 10px; overflow: hidden; flex-shrink: 0;">\');
					htmlParts.push(\'<img src="\' + escapeHtml(commentRecord.profile_image) + \'" alt="\' + escapeHtml(commentatorName) + \'" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display=\\\'none\\\'; this.nextElementSibling.style.display=\\\'flex\\\';" />\');
					htmlParts.push(\'<div class="sppb-comment-avatar-fallback" style="background-color: \' + avatarColor + \'; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: none; align-items: center; justify-content: center; font-size: 16px; font-weight: 600; color: \' + textColor + \'">\');
					htmlParts.push(\'<span>\' + escapeHtml(initials) + \'<\/span>\');
					htmlParts.push(\'<\/div>\');
					htmlParts.push(\'<\/div>\');
				} else if (' . (!empty($this->addon->settings->enable_gravatar) ? 'true' : 'false') . ' && commentRecord.created_by_email) {
					// Generate Gravatar URL
					const gravatarHash = md5(commentRecord.created_by_email.toLowerCase().trim());
					const gravatarUrl = \'https://www.gravatar.com/avatar/\' + gravatarHash + \'?s=90&d=404\';
					htmlParts.push(\'<div class="sppb-comment-avatar" style="border-radius: 50%; width: 45px; height: 45px; margin-right: 10px; overflow: hidden; flex-shrink: 0;">\');
					htmlParts.push(\'<img src="\' + gravatarUrl + \'" alt="\' + escapeHtml(commentatorName) + \'" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display=\\\'none\\\'; this.nextElementSibling.style.display=\\\'flex\\\';" />\');
					htmlParts.push(\'<div class="sppb-comment-avatar-fallback" style="background-color: \' + avatarColor + \'; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: none; align-items: center; justify-content: center; font-size: 16px; font-weight: 600; color: \' + textColor + \'">\');
					htmlParts.push(\'<span>\' + escapeHtml(initials) + \'<\/span>\');
					htmlParts.push(\'<\/div>\');
					htmlParts.push(\'<\/div>\');
				} else {
					// Fallback to initials only
					htmlParts.push(\'<div class="sppb-comment-avatar" style="background-color: \' + avatarColor + \'; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; font-weight: 600; margin-right: 10px; color: \' + textColor + \'">\');
					htmlParts.push(\'<span>\' + escapeHtml(initials) + \'<\/span>\');
					htmlParts.push(\'<\/div>\');
				}
				
				// Header left content
				htmlParts.push(\'<div class="sppb-comment-header-left">\');
				htmlParts.push(\'<div class="commentator-name-wrapper">\');
				htmlParts.push(\'<span class="commentator-name">\' + escapeHtml(commentatorName) + \'<\/span>\');
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<div class="sppb-comment-time-wrapper">\');
				htmlParts.push(\'<span class="sppb-comment-time">\' + createdTime + editedTime + \'<\/span>\');
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				
				// Ellipsis action
				htmlParts.push(\'<div class="sppb-comment-ellipsis-action \' + ellipsisBtnClass + \'">\');
				htmlParts.push(\'<i class="sppb-ellipsis-icon \' + ellipsisBtnIcon + \'"><\/i>\');
				htmlParts.push(\'<div class="sppb-ellipsis-dropdown" style="display: none;">\');
				htmlParts.push(generateEllipsisActionButtons());
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				
				// Content section
				htmlParts.push(\'<div class="sppb-comment-content sppb-comment-body" data-comment-id="\' + commentRecord.id + \'" style="margin-left: 55px; padding-bottom: 29px;">\');
				htmlParts.push(\'<div class="sppb-comment-body-thread-line"><\/div>\');
				
				// Add moderation notice if needed
				if (needsModeration) {
					htmlParts.push(\'<div class="sppb-comment-unpublished-notice">' . Text::_('COM_SPPAGEBUILDER_COMMENT_UNAPPROVED_NOTICE') . '<\/div>\');
				}
				
				htmlParts.push(\'<span class="sppb-comment-content-text\' + (needsModeration ? \' sppb-comment-unpublished\' : \'\') + \'" style="margin-left: 10px; margin-top: 20px; display: inline-block;">\');
				htmlParts.push(\'<span>\' + formattedContent + \'<\/span>\');
				htmlParts.push(\'<\/span>\');
				
				// Edit form
				htmlParts.push(\'<div class="sppb-comment-edit-form sppb-comment-form" data-comment-id="\' + commentRecord.id + \'" style="display: none; \' + (needsModeration ? \'margin-top: -45px;\' : \'\') + \'">\');
				htmlParts.push(\'<textarea type="text" class="sppb-comment-edit-input sppb-comment-field" data-comment-id="\' + commentRecord.id + \'">\' + escapeHtml(commentRecord.content) + \'<\/textarea>\');
				htmlParts.push(generateEditCommentButtons());
				htmlParts.push(\'<\/div>\');
				
				// Actions section - only show if not needing moderation
				if (!needsModeration) {
					htmlParts.push(\'<div class="sppb-comment-actions" style="margin-left: 10px">\');
					htmlParts.push(\'<div class="sppb-comment-likes\' + (commentRecord.user_liked ? \' liked\' : \'\') + \'">\');
					htmlParts.push(\'<i class="sppb-likes-icon \' + likesIcon + \'"><\/i>\');
					htmlParts.push(\'<span class="sppb-likes-text">\' + (commentRecord.likes_count || 0) + \' ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '<\/span>\');
					htmlParts.push(\'<\/div>\');
					htmlParts.push(\'<div class="sppb-comment-reply-action" data-comment-id="\' + commentRecord.id + \'">\');
					htmlParts.push(\'<i class="sppb-reply-icon \' + replyIcon + \'"><\/i>\');
					htmlParts.push(\'<span class="sppb-reply-text">\' + (commentRecord.replies || 0) + \' ' . Text::_('COM_SPPAGEBUILDER_REPLY') . '<\/span>\');
					htmlParts.push(\'<\/div>\');
					htmlParts.push(\'<\/div>\');
				}
				
				// Reply form
				htmlParts.push(\'<div class="sppb-comment-reply-form sppb-comment-form" data-comment-id="\' + commentRecord.id + \'" style="display: none;">\');
				htmlParts.push(\'<textarea type="text" class="sppb-comment-reply-input sppb-comment-field" data-comment-id="\' + commentRecord.id + \'" placeholder="' . Text::_('COM_SPPAGEBUILDER_WRITE_A_REPLY') . '"><\/textarea>\');
				htmlParts.push(\'<div class="sppb-comment-btn-wrapper">\');
				htmlParts.push(\'<button class="sppb-comment-reply-cancel-btn \' + btnClass + \'" data-comment-id="\' + commentRecord.id + \'">' . Text::_('COM_SPPAGEBUILDER_CANCEL') . '<\/button>\');
				htmlParts.push(\'<button class="sppb-comment-reply-submit-btn comment-submit-btn \' + btnClass + \'" data-comment-id="\' + commentRecord.id + \'">' . Text::_('COM_SPPAGEBUILDER_SUBMIT') . '<\/button>\');
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				
				// Close content section
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				htmlParts.push(\'<\/div>\');
				
				const html = htmlParts.join(\'\');
				return html;
			};
		});';

		return $js;
	}

	/**
	 * Generate the lodash template string for the frontend editor.
	 *
	 * @return 	string 	The lodash template string.
	 * @since 	1.0.0
	 */
	public static function getTemplate()
	{
		$lodash = new Lodash('#sppb-addon-{{ data.id }}');
		$enableGravatar = ComponentHelper::getParams('com_sppagebuilder')->get('enable_gravatar', 1);
		$output = '<style type="text/css">';
		
		// Title wrapper styles
		$output .= '.sppb-comment-title-wrapper {display: flex; align-items: center; gap: 16px; border-bottom: 1px solid #D3D7EB; margin-bottom: 40px; padding-bottom: 24px;}';
		$output .= $lodash->alignment('justify-content', '.sppb-comment-title-wrapper', 'data.title_alignment');
		
		// Title text typography and styles
		$typographyFallbacks = [
			'font'           => 'data.title_font_family',
			'size'           => 'data.title_fontsize',
			'line_height'    => 'data.title_lineheight',
			'letter_spacing' => 'data.title_letterspace',
			'uppercase'      => 'data.title_font_style?.uppercase',
			'italic'         => 'data.title_font_style?.italic',
			'underline'      => 'data.title_font_style?.underline',
			'weight'         => 'data.title_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-title-text', 'data.title_typography', $typographyFallbacks);
		$output .= $lodash->color('color', '.sppb-comment-title-text', 'data.title_color');
		$output .= $lodash->textShadow('.sppb-comment-title-text', 'data.title_shadow');
		
		// Comment count styles
		$countTypographyFallbacks = [
			'font'           => 'data.comment_count_font_family',
			'size'           => 'data.comment_count_fontsize',
			'line_height'    => 'data.comment_count_lineheight',
			'letter_spacing' => 'data.comment_count_letterspace',
			'uppercase'      => 'data.comment_count_font_style?.uppercase',
			'italic'         => 'data.comment_count_font_style?.italic',
			'underline'      => 'data.comment_count_font_style?.underline',
			'weight'         => 'data.comment_count_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-count', 'data.comment_count_typography', $countTypographyFallbacks);
		$output .= $lodash->color('color', '.sppb-comment-count', 'data.comment_count_color');
		$output .= $lodash->textShadow('.sppb-comment-count', 'data.comment_count_shadow');

		// Label wrapper styles
		$output .= '.sppb-comment-label-wrapper {display: flex; align-items: center; margin-bottom: 12px;}';
		$output .= $lodash->alignment('justify-content', '.sppb-comment-label-wrapper', 'data.label_alignment');
		$output .= $lodash->color('color', '.sppb-comment-label-text', 'data.label_color');
		$output .= $lodash->textShadow('.sppb-comment-label-text', 'data.label_text_shadow');

		// Comment form styles
		$output .= '.sppb-comment-form {display: flex; flex-direction: column;}';
		$output .= '.sppb-comment-reply-form {margin-top: 16px;}';

		// Comment field styles
		$output .= '.sppb-comment-field {transition: all 0.05s ease-in-out; border-radius: 6px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; width: 100%; box-sizing: border-box;}';
		$output .= $lodash->unit('height', '.sppb-comment-field', 'data.comment_field_height');
		$output .= $lodash->spacing('padding', '.sppb-comment-field', 'data.comment_field_padding');
		$output .= $lodash->color('color', '.sppb-comment-field', 'data.comment_field_typing_color');
		$output .= $lodash->color('background-color', '.sppb-comment-field', 'data.comment_field_background_color');
		$output .= $lodash->unit('border-color', '.sppb-comment-field', 'data.comment_field_border_color');
		$output .= $lodash->unit('border-width', '.sppb-comment-field', 'data.comment_field_border_width');
		$output .= $lodash->color('color', '.sppb-comment-field::placeholder', 'data.comment_field_placeholder_color');
		$output .= $lodash->color('background-color', '.sppb-comment-field:hover', 'data.comment_field_background_hover_color');
		$output .= $lodash->color('color', '.sppb-comment-field:hover::placeholder', 'data.comment_field_placeholder_hover_color');
		$output .= $lodash->unit('border-color', '.sppb-comment-field:focus', 'data.comment_field_border_focus_color');
		
		$fieldTypographyFallbacks = [
			'font'           => 'data.comment_field_font_family',
			'size'           => 'data.comment_field_fontsize',
			'line_height'    => 'data.comment_field_lineheight',
			'letter_spacing' => 'data.comment_field_letterspace',
			'uppercase'      => 'data.comment_field_font_style?.uppercase',
			'italic'         => 'data.comment_field_font_style?.italic',
			'underline'      => 'data.comment_field_font_style?.underline',
			'weight'         => 'data.comment_field_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-field', 'data.comment_field_typography', $fieldTypographyFallbacks);

		// Comment header styles
		$output .= '.sppb-comment-header {display: flex; justify-content: space-between; align-items: center; position: relative;}';
		$output .= '.sppb-comment-header-left {display: flex; flex-direction: column; gap: 4px; flex: 1;}';

		// Ellipsis action styles
		$output .= '.sppb-comment-ellipsis-action {position: relative; cursor: inherit;}';
		$output .= '.sppb-comment-ellipsis-action i {cursor: pointer;}';
		$output .= $lodash->color('background-color', '.sppb-comment-ellipsis-action', 'data.ellipsis_icon_bg_color');
		$output .= '.sppb-ellipsis-icon {font-size: 16px; padding: 8px; border-radius: 50%; transition: all 0.3s ease;}';
		$output .= $lodash->color('color', '.sppb-ellipsis-icon', 'data.ellipsis_icon_color');
		$output .= $lodash->color('background-color', '.sppb-ellipsis-icon', 'data.ellipsis_icon_bg_color');
		$output .= '.sppb-ellipsis-dropdown {position: absolute; top: 100%; right: 0; background: white; border: 1px solid #ddd; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); z-index: 1000; min-width: 120px;}';

		// Comment actions styles
		$output .= '.sppb-comment-actions {display: flex; align-items: center; gap: 20px; margin-top: 16px;}';
		$output .= '.sppb-comment-likes {display: flex; align-items: center; gap: 6px; cursor: pointer;}';
		$output .= '.sppb-comment-reply-action {display: flex; align-items: center; gap: 6px; cursor: pointer;}';

		// Likes functionality styles
		$output .= $lodash->typography('.sppb-likes-text', 'data.likes_typography', [
			'font'           => 'data.likes_font_family',
			'size'           => 'data.likes_fontsize',
			'line_height'    => 'data.likes_lineheight',
			'letter_spacing' => 'data.likes_letterspace',
			'uppercase'      => 'data.likes_font_style?.uppercase',
			'italic'         => 'data.likes_font_style?.italic',
			'underline'      => 'data.likes_font_style?.underline',
			'weight'         => 'data.likes_font_style?.weight'
		]);
		$output .= $lodash->color('color', '.sppb-likes-text', 'data.likes_color');
		$output .= $lodash->color('color', '.sppb-comment-likes.liked > .sppb-likes-icon', 'data.likes_focused_color');
		$output .= $lodash->color('color', '.sppb-likes-icon', 'data.likes_color');
		$output .= '.sppb-likes-icon {font-size: 16px; transition: color 0.3s ease;}';
		$output .= $lodash->color('color', '.sppb-comment-likes:hover .sppb-likes-text', 'data.likes_hover_color');
		$output .= $lodash->color('color', '.sppb-comment-likes:hover .sppb-likes-icon', 'data.likes_hover_color');
		$output .= $lodash->color('color', '.sppb-comment-likes:focus .sppb-likes-text', 'data.likes_focused_color');
		$output .= $lodash->color('color', '.sppb-comment-likes:focus .sppb-likes-icon', 'data.likes_focused_color');
		$output .= $lodash->textShadow('.sppb-likes-text', 'data.likes_text_shadow');

		// Reply functionality styles
		$output .= $lodash->typography('.sppb-reply-text', 'data.reply_typography', [
			'font'           => 'data.reply_font_family',
			'size'           => 'data.reply_fontsize',
			'line_height'    => 'data.reply_lineheight',
			'letter_spacing' => 'data.reply_letterspace',
			'uppercase'      => 'data.reply_font_style?.uppercase',
			'italic'         => 'data.reply_font_style?.italic',
			'underline'      => 'data.reply_font_style?.underline',
			'weight'         => 'data.reply_font_style?.weight'
		]);
		$output .= $lodash->color('color', '.sppb-reply-text', 'data.reply_color');
		$output .= $lodash->color('color', '.sppb-reply-icon', 'data.reply_color');
		$output .= '.sppb-reply-icon {font-size: 16px; transition: color 0.3s ease;}';
		$output .= $lodash->color('color', '.sppb-comment-reply-action:hover .sppb-reply-text', 'data.reply_hover_color');
		$output .= $lodash->color('color', '.sppb-comment-reply-action:hover .sppb-reply-icon', 'data.reply_hover_color');
		$output .= $lodash->textShadow('.sppb-reply-text', 'data.reply_text_shadow');

		// Icon position handling
		$output .= '<# if (data.likes_icon_position === "right") { #>';
		$output .= '.sppb-comment-likes {flex-direction: row-reverse;}';
		$output .= '<# } #>';
		$output .= '<# if (data.reply_icon_position === "right") { #>';
		$output .= '.sppb-comment-reply-action {flex-direction: row-reverse;}';
		$output .= '<# } #>';

		// Commentator name styles
		$output .= '.commentator-name-wrapper {display: flex; align-items: center;}';
		$output .= $lodash->alignment('justify-content', '.commentator-name-wrapper', 'data.commentator_name_alignment');
		
		$nameTypographyFallbacks = [
			'font'           => 'data.commentator_name_font_family',
			'size'           => 'data.commentator_name_fontsize',
			'line_height'    => 'data.commentator_name_lineheight',
			'letter_spacing' => 'data.commentator_name_letterspace',
			'uppercase'      => 'data.commentator_name_font_style?.uppercase',
			'italic'         => 'data.commentator_name_font_style?.italic',
			'underline'      => 'data.commentator_name_font_style?.underline',
			'weight'         => 'data.commentator_name_font_style?.weight'
		];
		$output .= $lodash->typography('.commentator-name', 'data.commentator_name_typography', $nameTypographyFallbacks);
		$output .= $lodash->color('color', '.commentator-name', 'data.commentator_name_color');
		$output .= $lodash->textShadow('.commentator-name', 'data.commentator_name_text_shadow');
		
		// Gravatar avatar styles
		$output .= '.sppb-comment-avatar img {transition: opacity 0.3s ease;}';
		$output .= '.sppb-comment-avatar-fallback {transition: opacity 0.3s ease;}';

		// Comment content styles
		$contentTypographyFallbacks = [
			'font'           => 'data.posted_comment_font_family',
			'size'           => 'data.posted_comment_fontsize',
			'line_height'    => 'data.posted_comment_lineheight',
			'letter_spacing' => 'data.posted_comment_letterspace',
			'uppercase'      => 'data.posted_comment_font_style?.uppercase',
			'italic'         => 'data.posted_comment_font_style?.italic',
			'underline'      => 'data.posted_comment_font_style?.underline',
			'weight'         => 'data.posted_comment_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-content-text', 'data.posted_comment_typography', $contentTypographyFallbacks);
		$output .= $lodash->color('color', '.sppb-comment-content-text', 'data.posted_comment_color');
		$output .= $lodash->textShadow('.sppb-comment-content-text', 'data.posted_comment_text_shadow');

		// Time styles
		$timeTypographyFallbacks = [
			'font'           => 'data.time_font_family',
			'size'           => 'data.time_fontsize',
			'line_height'    => 'data.time_lineheight',
			'letter_spacing' => 'data.time_letterspace',
			'uppercase'      => 'data.time_font_style?.uppercase',
			'italic'         => 'data.time_font_style?.italic',
			'underline'      => 'data.time_font_style?.underline',
			'weight'         => 'data.time_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-time', 'data.time_typography', $timeTypographyFallbacks);
		$output .= $lodash->color('color', '.sppb-comment-time', 'data.time_color');
		$output .= $lodash->textShadow('.sppb-comment-time', 'data.time_text_shadow');
		$output .= $lodash->alignment('text-align', '.sppb-comment-time-wrapper', 'data.time_alignment');

		// Edited time styles
		$editedTimeTypographyFallbacks = [
			'font'           => 'data.edited_time_font_family',
			'size'           => 'data.edited_time_fontsize',
			'line_height'    => 'data.edited_time_lineheight',
			'letter_spacing' => 'data.edited_time_letterspace',
			'uppercase'      => 'data.edited_time_font_style?.uppercase',
			'italic'         => 'data.edited_time_font_style?.italic',
			'underline'      => 'data.edited_time_font_style?.underline',
			'weight'         => 'data.edited_time_font_style?.weight'
		];
		$output .= $lodash->typography('.sppb-comment-edited-time', 'data.edited_time_typography', $editedTimeTypographyFallbacks);
		$output .= $lodash->color('color', '.sppb-comment-edited-time', 'data.edited_time_color');
		$output .= $lodash->textShadow('.sppb-comment-edited-time', 'data.edited_time_text_shadow');
		$output .= $lodash->alignment('text-align', '.sppb-comment-edited-time-wrapper', 'data.edited_time_alignment');

		// Button styles
		$output .= '.comment-submit-btn {outline: none; cursor: pointer;}';
		$buttonTypographyFallbacks = [
			'font'           => 'data.post_button_font_family',
			'size'           => 'data.post_button_fontsize',
			'line_height'    => 'data.post_button_lineheight',
			'letter_spacing' => 'data.post_button_letterspace',
			'uppercase'      => 'data.post_button_font_style?.uppercase',
			'italic'         => 'data.post_button_font_style?.italic',
			'underline'      => 'data.post_button_font_style?.underline',
			'weight'         => 'data.post_button_font_style?.weight'
		];
		$output .= $lodash->typography('.comment-submit-btn', 'data.post_button_typography', $buttonTypographyFallbacks);
		$output .= '.sppb-comment-form .sppb-comment-btn-wrapper {display: flex; padding: 16px; gap: 8px; align-items: center; border-width: 0px 1px 1px 1px; border-style: solid; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px;}';
		$output .= $lodash->unit('border-color', '.sppb-comment-form .sppb-comment-btn-wrapper', 'data.comment_field_border_color');
		$output .= '.sppb-comment-btn-wrapper {display: flex; align-items: center;}';
		$output .= $lodash->alignment('justify-content', '.sppb-comment-btn-wrapper', 'data.post_button_alignment');

		// Edit comment buttons styles
		$output .= '.sppb-comment-edit-buttons-wrapper {display: flex; align-items: center;}';
		$output .= $lodash->alignment('justify-content', '.sppb-comment-edit-buttons-wrapper', 'data.edit_comment_button_alignment');
		$output .= $lodash->spacing('gap', '.sppb-comment-edit-buttons-wrapper', 'data.edit_comment_button_gap');

		// Edit comment button typography
		$output .= '<# if (data.edit_comment_button_item && data.edit_comment_button_item.length > 0) { #>';
		$output .= '<# data.edit_comment_button_item.forEach(function(item, index) { #>';
		$output .= $lodash->typography('#sppb-comment-edit-button-{{index}}', 'item.edit_comment_button_typography', [
			'font'           => 'item.edit_comment_button_font_family',
			'size'           => 'item.edit_comment_button_fontsize',
			'line_height'    => 'item.edit_comment_button_lineheight',
			'letter_spacing' => 'item.edit_comment_button_letterspace',
			'uppercase'      => 'item.edit_comment_button_font_style?.uppercase',
			'italic'         => 'item.edit_comment_button_font_style?.italic',
			'underline'      => 'item.edit_comment_button_font_style?.underline',
			'weight'         => 'item.edit_comment_button_font_style?.weight'
		]);
		$output .= '<# }); #>';
		$output .= '<# } #>';

		// Post button custom size handling - ONLY apply to custom button type
		$output .= '<# if (data.post_button_size === "custom") { #>';
		$output .= $lodash->spacing('padding', '.comment-submit-btn.sppb-btn-custom', 'data.post_button_padding');
		$output .= '<# } #>';

		// Post button custom styles - ONLY apply to custom button type
		$output .= $lodash->color('color', '.comment-submit-btn.sppb-btn-custom', 'data.post_button_color');
		$output .= $lodash->color('background-color', '.comment-submit-btn.sppb-btn-custom', 'data.post_button_background_color');
		$output .= $lodash->color('color', '.comment-submit-btn.sppb-btn-custom:hover', 'data.post_button_color_hover');
		$output .= $lodash->color('background-color', '.comment-submit-btn.sppb-btn-custom:hover', 'data.post_button_background_color_hover');

		// Post button outline styles - ONLY apply to custom button type
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-outline {background-color: transparent;}';
		$output .= $lodash->unit('border-color', '.comment-submit-btn.sppb-btn-custom.sppb-btn-outline', 'data.post_button_background_color');
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-outline:hover {background-color: transparent;}';
		$output .= $lodash->unit('border-color', '.comment-submit-btn.sppb-btn-custom.sppb-btn-outline:hover', 'data.post_button_background_color_hover');

		// Post button link styles
		$output .= $lodash->color('color', '.comment-submit-btn.sppb-btn-link', 'data.post_button_link_color');
		$output .= $lodash->unit('border-color', '.comment-submit-btn.sppb-btn-link', 'data.post_button_link_border_color');
		$output .= $lodash->unit('border-width', '.comment-submit-btn.sppb-btn-link', 'data.post_button_link_border_width', '0 0 %spx 0');
		$output .= $lodash->unit('padding', '.comment-submit-btn.sppb-btn-link', 'data.post_button_link_padding_bottom', '0 0 %spx 0');
		$output .= $lodash->color('color', '.comment-submit-btn.sppb-btn-link:hover', 'data.post_button_link_hover_color');
		$output .= $lodash->unit('border-color', '.comment-submit-btn.sppb-btn-link:hover', 'data.post_button_link_border_hover_color');

		// Post button gradient styles - ONLY apply to custom button type
		$output .= '<# if (data.post_button_background_gradient) { #>';
		$output .= '<# if (typeof data.post_button_background_gradient === "string") { #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient {border: none; background-image: {{data.post_button_background_gradient}};}';
		$output .= '<# } else if (data.post_button_background_gradient.type) { #>';
		$output .= '<# let color1 = data.post_button_background_gradient.color || "#398AF1"; #>';
		$output .= '<# let color2 = data.post_button_background_gradient.color2 || "#5EDCED"; #>';
		$output .= '<# if (data.post_button_background_gradient.type === "linear") { #>';
		$output .= '<# let start = data.post_button_background_gradient.pos || 0; #>';
		$output .= '<# let end = data.post_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let deg = data.post_button_background_gradient.deg || 0; #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient {border: none; background-image: linear-gradient({{deg}}deg, {{color1}} {{start}}%, {{color2}} {{end}}%);}';
		$output .= '<# } else if (data.post_button_background_gradient.type === "radial") { #>';
		$output .= '<# let start = data.post_button_background_gradient.pos || 0; #>';
		$output .= '<# let end = data.post_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let position = data.post_button_background_gradient.radialPos || "center center"; #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient {border: none; background-image: radial-gradient(at {{position}}, {{color1}} {{start}}%, {{color2}} {{end}}%);}';
		$output .= '<# } else { #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient {border: none; background-image: {{color1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# if (data.post_button_background_gradient_hover) { #>';
		$output .= '<# if (typeof data.post_button_background_gradient_hover === "string") { #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient:hover {border: none; background-image: {{data.post_button_background_gradient_hover}};}';
		$output .= '<# } else if (data.post_button_background_gradient_hover.type) { #>';
		$output .= '<# let hoverColor1 = data.post_button_background_gradient_hover.color || "#398AF1"; #>';
		$output .= '<# let hoverColor2 = data.post_button_background_gradient_hover.color2 || "#5EDCED"; #>';
		$output .= '<# if (data.post_button_background_gradient_hover.type === "linear") { #>';
		$output .= '<# let hoverStart = data.post_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let hoverEnd = data.post_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let hoverDeg = data.post_button_background_gradient_hover.deg || 0; #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient:hover {border: none; background-image: linear-gradient({{hoverDeg}}deg, {{hoverColor1}} {{hoverStart}}%, {{hoverColor2}} {{hoverEnd}}%);}';
		$output .= '<# } else if (data.post_button_background_gradient_hover.type === "radial") { #>';
		$output .= '<# let hoverStart = data.post_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let hoverEnd = data.post_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let hoverPosition = data.post_button_background_gradient_hover.radialPos || "center center"; #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient:hover {border: none; background-image: radial-gradient(at {{hoverPosition}}, {{hoverColor1}} {{hoverStart}}%, {{hoverColor2}} {{hoverEnd}}%);}';
		$output .= '<# } else { #>';
		$output .= '.comment-submit-btn.sppb-btn-custom.sppb-btn-gradient:hover {border: none; background-image: {{hoverColor1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';

		// Button icon margin
		$output .= $lodash->spacing('margin', '.sppb-btn-icon', 'data.post_button_icon_margin');

		// Ellipsis action button styles with proper fallbacks
		$output .= $lodash->typography('.sppb-ellipsis-edit-btn, .sppb-ellipsis-delete-btn', 'data.ellipsis_action_button_typography', [
			'font'           => 'data.ellipsis_action_button_font_family',
			'size'           => 'data.ellipsis_action_button_fontsize',
			'line_height'    => 'data.ellipsis_action_button_lineheight',
			'letter_spacing' => 'data.ellipsis_action_button_letterspace',
			'uppercase'      => 'data.ellipsis_action_button_font_style?.uppercase',
			'italic'         => 'data.ellipsis_action_button_font_style?.italic',
			'underline'      => 'data.ellipsis_action_button_font_style?.underline',
			'weight'         => 'data.ellipsis_action_button_font_style?.weight'
		]);

		// Ellipsis button specific styles
		$output .= '.sppb-ellipsis-edit-btn:first-child {border-radius: 6px 6px 0 0;}';
		$output .= '.sppb-ellipsis-delete-btn:last-child {border-radius: 0 0 6px 6px;}';
		$output .= '.sppb-ellipsis-edit-btn:only-child {border-radius: 6px;}';

		// Ellipsis action button specific colors and backgrounds
		$output .= '<# if (data.ellipsis_action_button_item && data.ellipsis_action_button_item.length > 0) { #>';
		$output .= '<# data.ellipsis_action_button_item.forEach(function(item, index) { #>';
		$output .= $lodash->color('color', '.sppb-ellipsis-action-button:nth-child({{index + 1}})', 'item.ellipsis_action_button_color');
		$output .= $lodash->color('background-color', '.sppb-ellipsis-action-button:nth-child({{index + 1}})', 'item.ellipsis_action_button_background_color');
		$output .= $lodash->color('color', '.sppb-ellipsis-action-button:nth-child({{index + 1}}):hover', 'item.ellipsis_action_button_color_hover');
		$output .= $lodash->color('background-color', '.sppb-ellipsis-action-button:nth-child({{index + 1}}):hover', 'item.ellipsis_action_button_background_color_hover');
		$output .= '<# }); #>';
		$output .= '<# } #>';

		// Ellipsis action button gradient styles
		$output .= '<# if (data.ellipsis_action_button_item && data.ellipsis_action_button_item.length > 0) { #>';
		$output .= '<# data.ellipsis_action_button_item.forEach(function(item, index) { #>';
		$output .= '<# if (item.ellipsis_action_button_background_gradient) { #>';
		$output .= '<# if (typeof item.ellipsis_action_button_background_gradient === "string") { #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient {border: none; background-image: {{item.ellipsis_action_button_background_gradient}};}';
		$output .= '<# } else if (item.ellipsis_action_button_background_gradient.type) { #>';
		$output .= '<# let itemColor1 = item.ellipsis_action_button_background_gradient.color || "#398AF1"; #>';
		$output .= '<# let itemColor2 = item.ellipsis_action_button_background_gradient.color2 || "#5EDCED"; #>';
		$output .= '<# if (item.ellipsis_action_button_background_gradient.type === "linear") { #>';
		$output .= '<# let itemStart = item.ellipsis_action_button_background_gradient.pos || 0; #>';
		$output .= '<# let itemEnd = item.ellipsis_action_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let itemDeg = item.ellipsis_action_button_background_gradient.deg || 0; #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient {border: none; background-image: linear-gradient({{itemDeg}}deg, {{itemColor1}} {{itemStart}}%, {{itemColor2}} {{itemEnd}}%);}';
		$output .= '<# } else if (item.ellipsis_action_button_background_gradient.type === "radial") { #>';
		$output .= '<# let itemStart = item.ellipsis_action_button_background_gradient.pos || 0; #>';
		$output .= '<# let itemEnd = item.ellipsis_action_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let itemPosition = item.ellipsis_action_button_background_gradient.radialPos || "center center"; #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient {border: none; background-image: radial-gradient(at {{itemPosition}}, {{itemColor1}} {{itemStart}}%, {{itemColor2}} {{itemEnd}}%);}';
		$output .= '<# } else { #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient {border: none; background-image: {{itemColor1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# if (item.ellipsis_action_button_background_gradient_hover) { #>';
		$output .= '<# if (typeof item.ellipsis_action_button_background_gradient_hover === "string") { #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient:hover {border: none; background-image: {{item.ellipsis_action_button_background_gradient_hover}};}';
		$output .= '<# } else if (item.ellipsis_action_button_background_gradient_hover.type) { #>';
		$output .= '<# let itemHoverColor1 = item.ellipsis_action_button_background_gradient_hover.color || "#398AF1"; #>';
		$output .= '<# let itemHoverColor2 = item.ellipsis_action_button_background_gradient_hover.color2 || "#5EDCED"; #>';
		$output .= '<# if (item.ellipsis_action_button_background_gradient_hover.type === "linear") { #>';
		$output .= '<# let itemHoverStart = item.ellipsis_action_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let itemHoverEnd = item.ellipsis_action_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let itemHoverDeg = item.ellipsis_action_button_background_gradient_hover.deg || 0; #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient:hover {border: none; background-image: linear-gradient({{itemHoverDeg}}deg, {{itemHoverColor1}} {{itemHoverStart}}%, {{itemHoverColor2}} {{itemHoverEnd}}%);}';
		$output .= '<# } else if (item.ellipsis_action_button_background_gradient_hover.type === "radial") { #>';
		$output .= '<# let itemHoverStart = item.ellipsis_action_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let itemHoverEnd = item.ellipsis_action_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let itemHoverPosition = item.ellipsis_action_button_background_gradient_hover.radialPos || "center center"; #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient:hover {border: none; background-image: radial-gradient(at {{itemHoverPosition}}, {{itemHoverColor1}} {{itemHoverStart}}%, {{itemHoverColor2}} {{itemHoverEnd}}%);}';
		$output .= '<# } else { #>';
		$output .= '.sppb-ellipsis-action-button:nth-child({{index + 1}}).sppb-btn-gradient:hover {border: none; background-image: {{itemHoverColor1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# }); #>';
		$output .= '<# } #>';

		// Edit comment button specific colors and backgrounds
		$output .= '<# if (data.edit_comment_button_item && data.edit_comment_button_item.length > 0) { #>';
		$output .= '<# data.edit_comment_button_item.forEach(function(item, index) { #>';
		$output .= $lodash->color('color', '#sppb-comment-edit-button-{{index}}', 'item.edit_comment_button_color');
		$output .= $lodash->color('background-color', '#sppb-comment-edit-button-{{index}}', 'item.edit_comment_button_background_color');
		$output .= $lodash->color('color', '#sppb-comment-edit-button-{{index}}:hover', 'item.edit_comment_button_color_hover');
		$output .= $lodash->color('background-color', '#sppb-comment-edit-button-{{index}}:hover', 'item.edit_comment_button_background_color_hover');
		$output .= $lodash->color('background-color', '#sppb-comment-edit-button-{{index}}.sppb-btn-outline', 'item.edit_comment_button_background_color');
		$output .= $lodash->unit('border-color', '#sppb-comment-edit-button-{{index}}.sppb-btn-outline', 'item.edit_comment_button_background_color');
		$output .= $lodash->color('background-color', '#sppb-comment-edit-button-{{index}}.sppb-btn-outline:hover', 'item.edit_comment_button_background_color_hover');
		$output .= $lodash->unit('border-color', '#sppb-comment-edit-button-{{index}}.sppb-btn-outline:hover', 'item.edit_comment_button_background_color_hover');
		$output .= '<# }); #>';
		$output .= '<# } #>';

		// Edit comment button gradient styles
		$output .= '<# if (data.edit_comment_button_item && data.edit_comment_button_item.length > 0) { #>';
		$output .= '<# data.edit_comment_button_item.forEach(function(item, index) { #>';
		$output .= '<# if (item.edit_comment_button_background_gradient) { #>';
		$output .= '<# if (typeof item.edit_comment_button_background_gradient === "string") { #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient {border: none; background-image: {{item.edit_comment_button_background_gradient}};}';
		$output .= '<# } else if (item.edit_comment_button_background_gradient.type) { #>';
		$output .= '<# let editColor1 = item.edit_comment_button_background_gradient.color || "#398AF1"; #>';
		$output .= '<# let editColor2 = item.edit_comment_button_background_gradient.color2 || "#5EDCED"; #>';
		$output .= '<# if (item.edit_comment_button_background_gradient.type === "linear") { #>';
		$output .= '<# let editStart = item.edit_comment_button_background_gradient.pos || 0; #>';
		$output .= '<# let editEnd = item.edit_comment_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let editDeg = item.edit_comment_button_background_gradient.deg || 0; #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient {border: none; background-image: linear-gradient({{editDeg}}deg, {{editColor1}} {{editStart}}%, {{editColor2}} {{editEnd}}%);}';
		$output .= '<# } else if (item.edit_comment_button_background_gradient.type === "radial") { #>';
		$output .= '<# let editStart = item.edit_comment_button_background_gradient.pos || 0; #>';
		$output .= '<# let editEnd = item.edit_comment_button_background_gradient.pos2 || 100; #>';
		$output .= '<# let editPosition = item.edit_comment_button_background_gradient.radialPos || "center center"; #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient {border: none; background-image: radial-gradient(at {{editPosition}}, {{editColor1}} {{editStart}}%, {{editColor2}} {{editEnd}}%);}';
		$output .= '<# } else { #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient {border: none; background-image: {{editColor1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# if (item.edit_comment_button_background_gradient_hover) { #>';
		$output .= '<# if (typeof item.edit_comment_button_background_gradient_hover === "string") { #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient:hover {border: none; background-image: {{item.edit_comment_button_background_gradient_hover}};}';
		$output .= '<# } else if (item.edit_comment_button_background_gradient_hover.type) { #>';
		$output .= '<# let editHoverColor1 = item.edit_comment_button_background_gradient_hover.color || "#398AF1"; #>';
		$output .= '<# let editHoverColor2 = item.edit_comment_button_background_gradient_hover.color2 || "#5EDCED"; #>';
		$output .= '<# if (item.edit_comment_button_background_gradient_hover.type === "linear") { #>';
		$output .= '<# let editHoverStart = item.edit_comment_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let editHoverEnd = item.edit_comment_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let editHoverDeg = item.edit_comment_button_background_gradient_hover.deg || 0; #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient:hover {border: none; background-image: linear-gradient({{editHoverDeg}}deg, {{editHoverColor1}} {{editHoverStart}}%, {{editHoverColor2}} {{editHoverEnd}}%);}';
		$output .= '<# } else if (item.edit_comment_button_background_gradient_hover.type === "radial") { #>';
		$output .= '<# let editHoverStart = item.edit_comment_button_background_gradient_hover.pos || 0; #>';
		$output .= '<# let editHoverEnd = item.edit_comment_button_background_gradient_hover.pos2 || 100; #>';
		$output .= '<# let editHoverPosition = item.edit_comment_button_background_gradient_hover.radialPos || "center center"; #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient:hover {border: none; background-image: radial-gradient(at {{editHoverPosition}}, {{editHoverColor1}} {{editHoverStart}}%, {{editHoverColor2}} {{editHoverEnd}}%);}';
		$output .= '<# } else { #>';
		$output .= '#sppb-comment-edit-button-{{index}}.sppb-btn-gradient:hover {border: none; background-image: {{editHoverColor1}};}';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# } #>';
		$output .= '<# }); #>';
		$output .= '<# } #>';

		// Ellipsis action positioning and margins
		$output .= $lodash->spacing('margin', '.sppb-comment-ellipsis-action', 'data.ellipsis_margin');
		$output .= $lodash->alignment('justify-content', '.sppb-comment-ellipsis-action', 'data.ellipsis_position');

		// Ellipsis action outline button styles
		$output .= '.sppb-comment-ellipsis-action.sppb-btn-custom.sppb-btn-outline {background-color: transparent; border-color: transparent;}';
		$output .= '.sppb-comment-ellipsis-action.sppb-btn-custom.sppb-btn-outline i {background-color: transparent; border-color: transparent;}';

		// Comment header left positioning
		$output .= $lodash->alignment('justify-content', '.sppb-comment-header-left', 'data.commentator_name_position');
		$output .= '.sppb-comment-header-left {flex: 1;}';

		$output .= $lodash->unit('height', '.sppb-comment-field', 'data.comment_field_height', 'px');

		// Comment field hover and focus states
		$output .= $lodash->color('background-color', '.sppb-comment-field:hover', 'data.comment_field_background_hover_color');
		$output .= $lodash->color('color', '.sppb-comment-field:hover::placeholder', 'data.comment_field_placeholder_hover_color');
		$output .= $lodash->unit('border-color', '.sppb-comment-field:focus', 'data.comment_field_border_focus_color');

		// Comment form button wrapper border styles
		$output .= $lodash->unit('border-color', '.sppb-comment-form .sppb-comment-btn-wrapper', 'data.comment_field_border_color');

		$output .= '</style>';
		
		// HTML Structure
		$output .= '<div class="sppb-addon sppb-addon-comment {{ data.class }}">';
		
		// Title wrapper
		$output .= '<div class="sppb-comment-title-wrapper">';
		$output .= '<# if (data.comment_count && data.comment_count_position === "left") { #>';
		$output .= '<span class="sppb-comment-count">(5)</span>';
		$output .= '<# } #>';
		$output .= '<span class="sppb-comment-title-text">{{ data.title_text || "Comments" }}</span>';
		$output .= '<# if (data.comment_count && data.comment_count_position === "right") { #>';
		$output .= '<span class="sppb-comment-count">(5)</span>';
		$output .= '<# } #>';
		$output .= '</div>';

		// Label wrapper
		$output .= '<# if (data.enable_label) { #>';
		$output .= '<div class="sppb-comment-label-wrapper">';
		$output .= '<span class="sppb-comment-label-text">{{ data.label_text || "Leave a comment" }}</span>';
		$output .= '</div>';
		$output .= '<# } #>';

		// Comment form
		$output .= '<form class="sppb-comment-form">';
		$output .= '<textarea class="sppb-comment-field" name="comment" placeholder="{{ data.comment_field_placeholder || \'Share your thoughts...\' }}"></textarea>';
		$output .= '<div class="sppb-comment-btn-wrapper">';
		$output .= '<button type="submit" class="comment-submit-btn sppb-btn {{ data.post_button_type ? \'sppb-btn-\' + data.post_button_type : \'sppb-btn-default\' }} {{ data.post_button_block || \'\' }} {{ data.post_button_shape ? \'sppb-btn-\' + data.post_button_shape : \'sppb-btn-rounded\' }} {{ data.post_button_appearance ? \'sppb-btn-\' + data.post_button_appearance : \'\' }} {{ data.post_button_size ? \'sppb-btn-\' + data.post_button_size : \'sppb-btn-md\' }}">';
		$output .= '<# if (data.post_button_icon && data.post_button_icon_position === "left") { #>';
		$output .= '<i class="sppb-btn-icon {{ data.post_button_icon }}"></i>';
		$output .= '<# } #>';
		$output .= '<span>{{ data.post_button_text || "Leave a comment" }}</span>';
		$output .= '<# if (data.post_button_icon && data.post_button_icon_position === "right") { #>';
		$output .= '<i class="sppb-btn-icon {{ data.post_button_icon }}"></i>';
		$output .= '<# } #>';
		$output .= '</button>';
		$output .= '</div>';
		$output .= '</form>';

		// Comments list
		$output .= '<div class="sppb-comments-list" style="margin-top: 40px;">';

		$output .=  '<# function getTextColor(color) {
			const r = parseInt(color.substr(1, 2), 16);
			const g = parseInt(color.substr(3, 2), 16);
			const b = parseInt(color.substr(5, 2), 16);
		
			const brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000;
		
			return (brightness > 128) ? "#000000" : "#FFFFFF";
		} #>';
	
		$personAvatarColor = '{{data?.commentator_avatar_color || "#4285F4"}}';
		$personAvatarColorValue = 'data?.commentator_avatar_color || "#4285F4"';
		$output .= '<# let persontextColor = getTextColor(' . $personAvatarColorValue . ') #>';
		
		// Static comment 1
		$output .= '<div data-comment-id="1" data-parent-id="" class="sppb-comment-item sppb-comment-item sppb-parent-comment sppb-root-comment" style="margin-top: -4px; margin-left: 0px;">';
		$output .= '<div class="sppb-comment-thread-line" style="left:-34px;"></div>';
		$output .= '<div class="sppb-comment-thread-connector" style="left:-34px; width: 55px;"></div>';
		$output .= '<div class="sppb-comment-content">';
		$output .= '<div class="sppb-comment-header sppb-comment-header">';
		$output .= '<div class="sppb-comment-avatar" style="background-color: ' . $personAvatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; font-weight: 600; margin-right: 10px; color: {{persontextColor}}">';
		$output .= '<span>SL</span>';
		$output .= '</div>';
		$output .= '<div class="sppb-comment-header-left">';
		$output .= '<div class="commentator-name-wrapper">';
		$output .= '<span class="commentator-name">Sofia Lindstrom</span>';
		$output .= '</div>';
		$output .= '<# if (data.enable_time) { #>';
		$output .= '<div class="sppb-comment-time-wrapper">';
		$output .= '<span class="sppb-comment-time">' . Text::sprintf('COM_SPPAGEBUILDER_HOURS_AGO', 2) . '</span>';
		$output .= '<# if (data.show_edited_time) { #>';
		$output .= '<span class="sppb-comment-edited-time"> • Edited ' . Text::sprintf('COM_SPPAGEBUILDER_HOUR_AGO', 1) . '</span>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '<div class="sppb-comment-ellipsis-action sppb-btn sppb-btn-custom sppb-btn-rounded sppb-btn-md">';
		$output .= '<i class="sppb-ellipsis-icon fa fa-ellipsis-v"></i>';
		$output .= '<div class="sppb-ellipsis-dropdown" style="display: none;">';
		$output .= '<div class="sppb-comment-ellipsis-action-buttons-wrapper">';
		$output .= '<button style="width: 100%; text-align: left;" class="sppb-comment-ellipsis-action-button sppb-btn sppb-btn-md sppb-btn-rounded sppb-ellipsis-edit-btn" data-comment-id="1">Edit</button>';
		$output .= '<button style="width: 100%; text-align: left;" class="sppb-comment-ellipsis-action-button sppb-btn sppb-btn-md sppb-btn-rounded sppb-ellipsis-delete-btn" data-comment-id="1">Delete</button>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '<div class="sppb-comment-content sppb-comment-body" data-comment-id="1" style="margin-left: 55px; padding-bottom: 29px;">';
		$output .= '<div class="sppb-comment-body-thread-line"></div>';
		$output .= '<span class="sppb-comment-content-text" style="margin-left: 10px; margin-top: 20px; display: inline-block;">';
		$output .= '<span>This is a great article, Jane! I really enjoyed reading it. Expecting more insightful writings from you.</span>';
		$output .= '</span>';
		$output .= '<div class="sppb-comment-edit-form sppb-comment-form" data-comment-id="1" style="display: none;">';
		$output .= '<textarea type="text" class="sppb-comment-edit-input sppb-comment-field" data-comment-id="1">This is a great article, Jane! I really enjoyed reading it. Expecting more insightful writings from you.</textarea>';
		$output .= '<div class="sppb-comment-edit-buttons-wrapper sppb-comment-btn-wrapper">';
		$output .= '<button class="sppb-comment-edit-button sppb-comment-edit-cancel-btn sppb-btn sppb-btn-md sppb-btn-rounded" data-comment-id="1">' . Text::_('COM_SPPAGEBUILDER_CANCEL') . '</button>';
		$output .= '<button class="sppb-comment-edit-button sppb-comment-edit-submit-btn sppb-btn sppb-btn-md sppb-btn-rounded" data-comment-id="1">' . Text::_('COM_SPPAGEBUILDER_UPDATE') . '</button>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '<# if (data.enable_likes || data.enable_reply) { #>';
		$output .= '<div class="sppb-comment-actions" style="margin-left: 10px">';
		$output .= '<# if (data.enable_likes) { #>';
		$output .= '<div class="sppb-comment-likes">';
		$output .= '<i class="sppb-likes-icon fa fa-heart"></i>';
		$output .= '<span class="sppb-likes-text">3 ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '</span>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '<# if (data.enable_reply) { #>';
		$output .= '<div class="sppb-comment-reply-action" data-comment-id="1">';
		$output .= '<i class="sppb-reply-icon fa fa-reply"></i>';
		$output .= '<span class="sppb-reply-text">2 ' . Text::_('COM_SPPAGEBUILDER_REPLY') . '</span>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '<div class="sppb-comment-reply-form sppb-comment-form" data-comment-id="1" style="display: none;">';
		$output .= '<textarea type="text" class="sppb-comment-reply-input sppb-comment-field" data-comment-id="1" placeholder="' . Text::_('COM_SPPAGEBUILDER_WRITE_A_REPLY') . '"></textarea>';
		$output .= '<div class="sppb-comment-btn-wrapper">';
		
		$output .= '<button class="sppb-comment-reply-cancel-btn sppb-btn sppb-btn-default sppb-btn-rounded sppb-btn-md" data-comment-id="1">' . Text::_('COM_SPPAGEBUILDER_CANCEL') . '</button>';
		$output .= '<button class="sppb-comment-reply-submit-btn comment-submit-btn {{ data.post_button_type ? \'sppb-btn-\' + data.post_button_type : \'sppb-btn-default\' }} {{ data.post_button_block || \'\' }} {{ data.post_button_shape ? \'sppb-btn-\' + data.post_button_shape : \'sppb-btn-rounded\' }} {{ data.post_button_appearance ? \'sppb-btn-\' + data.post_button_appearance : \'\' }} {{ data.post_button_size ? \'sppb-btn-\' + data.post_button_size : \'sppb-btn-md\' }}" data-comment-id="1">' . Text::_('COM_SPPAGEBUILDER_SUBMIT') . '</button>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		
		// Reply to comment 1
		$output .= '<div class="sppb-comment-children-wrapper">';
		$output .= '<div data-comment-id="2" data-parent-id="1" class="sppb-comment-item sppb-comment-item" style="margin-top: -4px; margin-left: 55px;">';
		$output .= '<div class="sppb-comment-thread-line" style="left:-34px;"></div>';
		$output .= '<div class="sppb-comment-thread-connector" style="left:-34px; width: 55px;"></div>';
		$output .= '<div class="sppb-comment-content" style="margin-left: 0; margin-top: 11px;">';
		$output .= '<div class="sppb-comment-header sppb-comment-header">';
		
		// Static Gravatar implementation
		$replyPersonAvatarColor = '{{data?.commentator_avatar_color || "#4285F4"}}';
		$replyPersonAvatarColorValue = 'data?.commentator_avatar_color || "#4285F4"';
		$output .= '<# let replyPersonTextColor = getTextColor(' . $replyPersonAvatarColorValue . ') #>';
		$avatarUrl = Uri::root() . 'components/com_sppagebuilder/assets/images/user_comment_placeholder.jpg';
		
		$output .= '<# if (' . $enableGravatar . ') { #>';
		$output .= '<div class="sppb-comment-avatar" style="border-radius: 50%; width: 45px; height: 45px; margin-right: 10px; overflow: hidden; flex-shrink: 0;">';
		$output .= '<img src="' . $avatarUrl . '" alt="Jane Doe" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';" />';
		$output .= '<div class="sppb-comment-avatar-fallback" style="background-color: ' . $replyPersonAvatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: none; align-items: center; justify-content: center; font-size: 16px; font-weight: 600; color: {{replyPersonTextColor}}">';
		$output .= '<span>JD</span>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '<# } else { #>';
		$output .= '<div class="sppb-comment-avatar" style="background-color: ' . $replyPersonAvatarColor . '; padding: 10px; border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; font-weight: 600; margin-right: 10px; color: {{replyPersonTextColor}}">';
		$output .= '<span>JD</span>';
		$output .= '</div>';
		$output .= '<# } #>';
		
		$output .= '<div class="sppb-comment-header-left">';
		$output .= '<div class="commentator-name-wrapper">';
		$output .= '<span class="commentator-name">Jane Doe</span>';
		$output .= '</div>';
		$output .= '<# if (data.enable_time) { #>';
		$output .= '<div class="sppb-comment-time-wrapper">';
		$output .= '<span class="sppb-comment-time">' . Text::sprintf('COM_SPPAGEBUILDER_HOUR_AGO', 1) . '</span>';
		$output .= '<# if (data.show_edited_time) { #>';
		$output .= '<span class="sppb-comment-edited-time"> • Edited ' . Text::sprintf('COM_SPPAGEBUILDER_MINUTE_AGO', 30) . '</span>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '<div class="sppb-comment-content sppb-comment-body" data-comment-id="2" style="margin-left: 55px; padding-bottom: 29px;">';
		$output .= '<div class="sppb-comment-body-thread-line"></div>';
		$output .= '<span class="sppb-comment-content-text" style="margin-left: 10px; margin-top: 20px; display: inline-block;">';
		$output .= '<span>Thanks, Sofia! Stay tuned for more updates.</span>';
		$output .= '</span>';
		$output .= '<# if (data.enable_likes || data.enable_reply) { #>';
		$output .= '<div class="sppb-comment-actions" style="margin-left: 10px">';
		$output .= '<# if (data.enable_likes) { #>';
		$output .= '<div class="sppb-comment-likes">';
		$output .= '<i class="sppb-likes-icon fa fa-heart"></i>';
		$output .= '<span class="sppb-likes-text">1 ' . Text::_('COM_SPPAGEBUILDER_LIKES') . '</span>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '<# if (data.enable_reply) { #>';
		$output .= '<div class="sppb-comment-reply-action" data-comment-id="2">';
		$output .= '<i class="sppb-reply-icon fa fa-reply"></i>';
		$output .= '<span class="sppb-reply-text">0 ' . Text::_('COM_SPPAGEBUILDER_REPLY') . '</span>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '<# } #>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';

		
		$output .= '</div>';
		$output .= '</div>';

		// Add JavaScript for template functionality
		$js = '';
		$js .= 'jQuery(document).ready(function($) {';
		
		// Handle Gravatar image loading and fallback
		$js .= 'const handleGravatarImages = () => {';
		$js .= 'const gravatarImages = document.querySelectorAll(\'.sppb-comment-avatar img[src*="gravatar.com"]\');';
		$js .= 'gravatarImages.forEach(img => {';
		$js .= 'img.addEventListener(\'error\', function() {';
		$js .= 'this.style.display = \'none\';';
		$js .= 'const fallback = this.nextElementSibling;';
		$js .= 'if (fallback && fallback.classList.contains(\'sppb-comment-avatar-fallback\')) {';
		$js .= 'fallback.style.display = \'flex\';';
		$js .= '}';
		$js .= '});';
		$js .= 'img.addEventListener(\'load\', function() {';
		$js .= 'const fallback = this.nextElementSibling;';
		$js .= 'if (fallback && fallback.classList.contains(\'sppb-comment-avatar-fallback\')) {';
		$js .= 'fallback.style.display = \'none\';';
		$js .= '}';
		$js .= '});';
		$js .= '});';
		$js .= '};';
		$js .= 'handleGravatarImages();';

		// Ellipsis menu functionality
		$js .= '$(".sppb-comment-ellipsis-action").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'e.stopPropagation();';
		$js .= 'var dropdown = $(this).find(".sppb-ellipsis-dropdown");';
		$js .= '$(".sppb-ellipsis-dropdown").not(dropdown).hide();';
		$js .= 'dropdown.toggle();';
		$js .= '});';
		
		// Close dropdown when clicking outside
		$js .= '$(document).on("click", function(e) {';
		$js .= 'if (!$(e.target).closest(".sppb-comment-ellipsis-action").length) {';
		$js .= '$(".sppb-ellipsis-dropdown").hide();';
		$js .= '}';
		$js .= '});';
		
		// Edit button functionality
		$js .= '$(".sppb-ellipsis-edit-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'e.stopPropagation();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'var contentText = commentContent.find(".sppb-comment-content-text span").text();';
		$js .= 'var editForm = commentContent.find(".sppb-comment-edit-form");';
		$js .= 'var editInput = editForm.find(".sppb-comment-edit-input");';
		$js .= 'editInput.val(contentText);';
		$js .= 'commentContent.find(".sppb-comment-content-text").hide();';
		$js .= 'editForm.show();';
		$js .= '$(".sppb-ellipsis-dropdown").hide();';
		$js .= '});';
		
		// Delete button functionality (just close dropdown)
		$js .= '$(".sppb-ellipsis-delete-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'e.stopPropagation();';
		$js .= '$(".sppb-ellipsis-dropdown").hide();';
		$js .= '});';
		
		// Edit form cancel button
		$js .= '$(".sppb-comment-edit-cancel-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'commentContent.find(".sppb-comment-edit-form").hide();';
		$js .= 'commentContent.find(".sppb-comment-content-text").show();';
		$js .= '});';
		
		// Edit form update button (non-functional, just close form)
		$js .= '$(".sppb-comment-edit-submit-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'commentContent.find(".sppb-comment-edit-form").hide();';
		$js .= 'commentContent.find(".sppb-comment-content-text").show();';
		$js .= '});';
		
		// Reply action functionality
		$js .= '$(".sppb-comment-reply-action").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'var replyForm = commentContent.find(".sppb-comment-reply-form");';
		$js .= 'replyForm.toggle();';
		$js .= '});';
		
		// Reply form cancel button
		$js .= '$(".sppb-comment-reply-cancel-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'commentContent.find(".sppb-comment-reply-form").hide();';
		$js .= '});';
		
		// Reply form submit button (non-functional, just close form)
		$js .= '$(".sppb-comment-reply-submit-btn").on("click", function(e) {';
		$js .= 'e.preventDefault();';
		$js .= 'var commentId = $(this).data("comment-id");';
		$js .= 'var commentContent = $(".sppb-comment-content[data-comment-id=\'" + commentId + "\']");';
		$js .= 'commentContent.find(".sppb-comment-reply-form").hide();';
		$js .= 'commentContent.find(".sppb-comment-reply-input").val("");';
		$js .= '});';
		
		$js .= '});';
		$js .= '';

		Factory::getDocument()->addScriptDeclaration($js);

		return $output;
	}

	private function renderLoginModal() {
		$shouldShowLoginModal = empty(Factory::getUser()->id) && empty($this->addon->settings->enable_anonymous_comment);
		
		$output = '';
		$output .= '<div class="sppb-login-modal-overlay"></div>';
		$output .= '<div id="sppb-login-modal" class="sppb-login-modal" style="display: none;">';
		$output .= '<div class="sppb-login-modal-content">';
		$output .= '<div class="sppb-login-modal-header">';
		$output .= '<div style="display: flex; justify-content: end;">';
		$output .= '<button type="button" class="sppb-login-modal-close"><span>&times;</span></button>';
		$output .= '</div>';
		$output .= '<h3>' . Text::_('COM_SPPAGEBUILDER_LOGIN_REQUIRED') . '</h3>';
		$output .= '</div>';
		$output .= '<div class="sppb-login-modal-body">';
		$output .= '<div id="sppb-login-form-container">';
		$output .= '<p>' . Text::_('COM_SPPAGEBUILDER_LOADING_LOGIN_FORM') . '</p>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		$output .= '</div>';
		
		// Add JavaScript to fetch the login form
		$js = '
		document.addEventListener("DOMContentLoaded", function() {
			// Fetch login form when modal is opened
			$(document).on("keyup", ".sppb-comment-field", function(e) {
				' . ($shouldShowLoginModal ? '$("#sppb-login-modal").show();' : '') . '
				' . ($shouldShowLoginModal ? '$(".sppb-login-modal-overlay").show();' : '') . '
				' . ($shouldShowLoginModal ? '$("#sppb-login-modal input[name=\'username\']").focus();' : '') . '
			});
			// $(document).on("click", ".sppb-login-required", function(e) {
				// e.preventDefault();
				fetchLoginForm();
				$(".sppb-login-modal-overlay").hide();
			// });
			
			// Close modal
			$(document).on("click", ".sppb-login-modal-close", function() {
				$("#sppb-login-modal").hide();
				$(".sppb-login-modal-overlay").hide();
			});
			
			// Handle form submission
			// $(document).on("submit", "#sppb-login-form-container form", function(e) {
			// 	e.preventDefault();
			// 	const form = $(this);
			// 	const formData = new FormData(this);
				
			// 	// Add return URL for redirect after login
			// 	const returnUrl = "' . base64_encode(\Joomla\CMS\Uri\Uri::current()) . '";
			// 	formData.append("return", returnUrl);
				
			// 	// Submit form via AJAX
			// 	$.ajax({
			// 		url: form.attr("action"),
			// 		type: "POST",
			// 		data: formData,
			// 		processData: false,
			// 		contentType: false,
			// 		success: function(response) {
			// 			if (response.success) {
			// 				// Login successful, reload page
			// 				window.location.reload();
			// 			} else {
			// 				// Show error message
			// 				alert(response.message || "Login failed. Please try again.");
			// 			}
			// 		},
			// 		error: function() {
			// 			alert("Login failed. Please try again.");
			// 		}
			// 	});
			// });
		});
		
		function fetchLoginForm() {
			const container = document.getElementById("sppb-login-form-container");
			container.innerHTML = "<p>' . Text::_('COM_SPPAGEBUILDER_LOADING_LOGIN_FORM') . '</p>";
			
			// Fetch the login form from Joomla\'s default login view
			fetch("' . \Joomla\CMS\Uri\Uri::root() . 'index.php?option=com_users&view=login&tmpl=component&layout=default", {
				method: "GET",
				headers: {
					"X-Requested-With": "XMLHttpRequest"
				}
			})
			.then(response => response.text())
			.then(html => {
				// Extract the form from the response
				const parser = new DOMParser();
				const doc = parser.parseFromString(html, "text/html");
				const form = doc.querySelector("form");
				
				if (form) {
					// Update form action to use component template
					form.action = "' . \Joomla\CMS\Uri\Uri::root() . 'index.php?option=com_users&task=user.login&tmpl=component";
					
					// Add return URL
					const returnInput = form.querySelector("input[name=\'return\']");
					if (returnInput) {
						returnInput.value = "' . base64_encode(\Joomla\CMS\Uri\Uri::getInstance()->toString()) . '";
					}
					
					// Replace the container content with the actual form
					container.innerHTML = "";
					container.appendChild(form);
					
					// Initialize Joomla form validation if available
					if (typeof Joomla !== "undefined" && Joomla.formvalidator) {
						Joomla.formvalidator.init(form);
					}
				} else {
					container.innerHTML = "<p>' . Text::_('COM_SPPAGEBUILDER_ERROR_LOADING_LOGIN_FORM') . '</p>";
				}
			})
			.catch(error => {
				console.error("Error fetching login form:", error);
				container.innerHTML = "<p>' . Text::_('COM_SPPAGEBUILDER_ERROR_LOADING_LOGIN_FORM') . '</p>";
			});
		}';
		
		Factory::getDocument()->addScriptDeclaration($js);
		
		return $output;
	}
}