Код:
<script>
document.addEventListener('DOMContentLoaded', async () => {
  const chatWrapper = document.querySelector('.interactive-chat');
  if (!chatWrapper) return;

  const hostPost = chatWrapper.closest('.post');
  const hostPostId = hostPost ? hostPost.id : null;

  const punMain = document.getElementById('pun-main') || document.body;
  
  const style = document.createElement('style');
  style.innerHTML = `
    .chat-loading { text-align: center; font-size: 18px; padding: 50px; opacity: 1; animation: chatBlink 1.5s infinite; color: #888; }
    @keyframes chatBlink { 0% { opacity: 0.4; } 50% { opacity: 1; } 100% { opacity: 0.4; } }
    .chat-topic-title { text-align: center; font-weight: bold; font-size: 1.1em; padding: 10px 15px; border-bottom: 1px solid rgba(128,128,128,0.2); margin-bottom: 10px; }
    .post[data-user-id] { display: none !important; }
    body.show-original-posts .post[data-user-id] { display: block !important; }
    
    .chat-toggle-btn {
      font-size: 11px; padding: 4px 10px; cursor: pointer;
      border: 1px solid rgba(128,128,128,0.4); background: transparent; 
      border-radius: 4px; color: inherit; opacity: 0.7; transition: 0.2s;
    }
    .chat-toggle-btn:hover { opacity: 1; background: rgba(128,128,128,0.1); }
    .chat-controls-wrapper { text-align: right; margin-bottom: 10px; }

    /* Стили для кнопки плюса (репутации) в чате */
    .chat-like-btn {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 11px; padding: 2px 7px; margin-top: 6px;
      border-radius: 10px; background: rgba(128, 128, 128, 0.12);
      cursor: pointer; user-select: none; transition: 0.2s;
      opacity: 0.8; float: right; clear: both;
    }
    .chat-like-btn:hover { opacity: 1; background: rgba(220, 50, 50, 0.15); color: #e03131; }
    .chat-like-btn.liked { color: #e03131; background: rgba(220, 50, 50, 0.15); opacity: 1; }

    /* Стили нижней панели ввода (как в Telegram) */
    .write-msg {
      display: flex; align-items: flex-end; gap: 8px;
      padding: 10px 14px; border-top: 1px solid rgba(128,128,128,0.2);
      background: rgba(0, 0, 0, 0.03);
    }
    .chat-tg-input {
      flex: 1; resize: none; overflow-y: hidden;
      min-height: 20px; max-height: 140px;
      padding: 8px 14px; border-radius: 18px;
      border: 1px solid rgba(128,128,128,0.3);
      background: var(--bg-input, #fff); color: inherit;
      font-family: inherit; font-size: 14px; line-height: 1.4;
      outline: none; box-sizing: border-box; transition: border-color 0.2s;
    }
    .chat-tg-input:focus { border-color: rgba(128,128,128,0.6); }
    .chat-tg-send {
      width: 36px; height: 36px; border-radius: 50%;
      border: none; background: #3390ec; color: #fff;
      cursor: pointer; display: flex; align-items: center; justify-content: center;
      flex-shrink: 0; transition: transform 0.15s, background 0.2s;
    }
    .chat-tg-send:hover { background: #287ad1; }
    .chat-tg-send:active { transform: scale(0.92); }
    .chat-tg-send svg { width: 18px; height: 18px; fill: currentColor; margin-left: 2px; }
  `;
  document.head.appendChild(style);

  punMain.insertBefore(chatWrapper, punMain.firstChild);

  function createToggleBtn(targetContainer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'chat-controls-wrapper';
    
    const btn = document.createElement('button');
    btn.className = 'chat-toggle-btn';
    btn.textContent = 'Показать сообщения (для ред.)';
    
    btn.addEventListener('click', (e) => {
      e.preventDefault();
      const isVisible = document.body.classList.toggle('show-original-posts');
      btn.textContent = isVisible ? 'Скрыть сообщения' : 'Показать сообщения (для ред.)';
    });

    wrapper.appendChild(btn);
    targetContainer.parentNode.insertBefore(wrapper, targetContainer);
  }

  createToggleBtn(chatWrapper);
  chatWrapper.innerHTML = '<div class="chat-loading">Загрузка чата... собираем сообщения</div>';

  try {
    const pageLinksElements = Array.from(document.querySelectorAll('.pagelink a'));
    let allPageUrls = new Set();
    
    const currentUrl = window.location.href.split('#')[0];
    allPageUrls.add(currentUrl);

    pageLinksElements.forEach(a => {
      if (!a.classList.contains('next') && !a.classList.contains('prev')) {
        allPageUrls.add(a.href.split('#')[0]);
      }
    });

    const sortedUrls = Array.from(allPageUrls).sort((a, b) => {
      const pA = parseInt(new URL(a).searchParams.get('p')) || 1;
      const pB = parseInt(new URL(b).searchParams.get('p')) || 1;
      return pA - pB;
    });

    const postsData = [];
    const processedPostIds = new Set();
    const uniqueUserIds = new Set();
    let topicStarterId = null;

    for (const url of sortedUrls) {
      let doc;
      if (url === currentUrl) {
        doc = document;
      } else {
        const response = await fetch(url);
        const buffer = await response.arrayBuffer();
        const decoder = new TextDecoder('windows-1251');
        const html = decoder.decode(buffer);
        const parser = new DOMParser();
        doc = parser.parseFromString(html, 'text/html');
      }
      
      const postsOnPage = Array.from(doc.querySelectorAll('.post[data-user-id]'));
      
      for (const postEl of postsOnPage) {
        const userId = postEl.getAttribute('data-user-id');
        if (!userId) continue;

        if (!topicStarterId) topicStarterId = userId;
        
        const postId = postEl.id; 
        
        if (processedPostIds.has(postId) || (hostPostId && postId === hostPostId)) continue;
        
        processedPostIds.add(postId);
        uniqueUserIds.add(userId);

        const time = postEl.querySelector('.permalink')?.textContent || '';
        const avatarImg = postEl.querySelector('.pa-avatar img');
        const postAvatar = avatarImg ? avatarImg.src : null;
        const contentBox = postEl.querySelector('.post-content');
        
        const ratingLink = postEl.querySelector('.post-rating a');
        const ratingCount = ratingLink ? (ratingLink.textContent.trim() || '0') : null;
        
        if (contentBox) {
          const content = contentBox.innerHTML
            .replace(/\[icon\][\s\S]*?\[\/icon\]/gi, '')
            .replace(/<div class="post-sig".*?<\/div>/gi, '')
            .trim();

          if (content.replace(/<[^>]*>?/gm, '').trim() !== '' || content.includes('<img')) {
            postsData.push({ postId, userId, time, content, postAvatar, ratingCount });
          }
        }
      }
    }

    let userMap = {};
    if (uniqueUserIds.size > 0) {
      const userApiRes = await fetch(`/api.php?method=users.get&user_id=${Array.from(uniqueUserIds).join(',')}&fields=user_id,avatar,username,name`);
      const userApiData = await userApiRes.json();
      
      (userApiData.response?.users || []).forEach(u => {
        userMap[u.user_id] = {
          avatar: u.avatar || 'https://upforme.ru/uploads/001c/b7/5d/6/359207.png',
          name: u.username || u.name || 'Unknown'
        };
      });
    }

    let topicTitle = "Чат";
    const urlParams = new URLSearchParams(window.location.search);
    const topicId = urlParams.get('id');

    if (topicId) {
      try {
        const topicRes = await fetch(`/api.php?method=topic.get&topic_id=${topicId}&fields=id,subject`);
        const topicData = await topicRes.json();
        const topicsList = topicData.response?.topics || topicData.response || [];
        const currentTopic = Array.isArray(topicsList) ? topicsList.find(t => t.id == topicId) : null;
        if (currentTopic && currentTopic.subject) topicTitle = currentTopic.subject;
      } catch (e) {
        topicTitle = document.querySelector('h1')?.textContent || "Чат";
      }
    }

    const topicHeaderHTML = `<div class="chat-topic-title">💬 ${topicTitle}</div>`;
    let messagesHTML = '<div class="chwrap"><div class="soc-chat-wrapper">';

    postsData.forEach(post => {
      const isTopicStarter = post.userId === topicStarterId;
      const msgClass = isTopicStarter ? 'right-msg' : 'left-msg';
      const user = userMap[post.userId] || { avatar: '', name: 'Аноним' };
      const avatarToUse = post.postAvatar || user.avatar;

      const likeBtnHTML = post.ratingCount !== null 
        ? `<div class="chat-like-btn" data-post-id="${post.postId}" title="Поставить плюс">
             <span>❤</span> <span class="like-count">${post.ratingCount}</span>
           </div>`
        : '';

      messagesHTML += `
        <div class="${msgClass}" data-msgtime="${post.time}" data-post-id="${post.postId}">
          <img src="${avatarToUse}" class="msg-av" title="${user.name}">
          <div class="msg-body">
            ${post.content}
            ${likeBtnHTML}
          </div>
        </div>
      `;
    });

    const originalTextarea = document.getElementById('main-reply');
    const writeMsgHTML = originalTextarea ? `
      <div class="write-msg">
        <textarea class="chat-tg-input" rows="1" placeholder="Написать сообщение... (Enter — отправить, Shift+Enter — строка)"></textarea>
        <button type="button" class="chat-tg-send" title="Отправить">
          <svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
        </button>
      </div>
    ` : `<div class="write-msg" style="justify-content:center; opacity:0.6; font-size:12px;">Форма ответа недоступна</div>`;

    messagesHTML += `</div>${writeMsgHTML}</div>`;

    chatWrapper.innerHTML = topicHeaderHTML + messagesHTML;

    chatWrapper.addEventListener('click', (e) => {
      const likeBtn = e.target.closest('.chat-like-btn');
      if (!likeBtn) return;

      const postId = likeBtn.getAttribute('data-post-id');
      const countSpan = likeBtn.querySelector('.like-count');
      
      let realPost = document.getElementById(postId);
      let realRatingAnchor = realPost ? realPost.querySelector('.post-rating a') : null;

      if (realRatingAnchor) {
        realRatingAnchor.click();
        
        setTimeout(() => {
          countSpan.textContent = realRatingAnchor.textContent.trim();
          likeBtn.classList.add('liked');
        }, 500);
      } else if (typeof window.BR === 'function') {
        let phantomPost = document.createElement('div');
        phantomPost.id = postId;
        phantomPost.className = 'post';
        phantomPost.style.display = 'none';
        phantomPost.innerHTML = `<div class="post-rating"><p class="container"><a>${countSpan.textContent}</a></p></div>`;
        document.body.appendChild(phantomPost);

        const phantomAnchor = phantomPost.querySelector('a');
        window.BR(phantomAnchor);

        setTimeout(() => {
          countSpan.textContent = phantomAnchor.textContent.trim();
          likeBtn.classList.add('liked');
          phantomPost.remove();
        }, 600);
      }
    });

    const chatInput = chatWrapper.querySelector('.chat-tg-input');
    const chatSendBtn = chatWrapper.querySelector('.chat-tg-send');

    if (chatInput && originalTextarea) {
      chatInput.addEventListener('input', function() {
        this.style.height = 'auto';
        this.style.height = Math.min(this.scrollHeight, 140) + 'px';
        this.style.overflowY = this.scrollHeight > 140 ? 'auto' : 'hidden';
      });

      const submitChatMessage = () => {
        const text = chatInput.value.trim();
        if (!text) return;

        originalTextarea.value = text;

        const originalSubmitBtn = document.querySelector('.formsubmit input[name="submit"]') 
                               || document.querySelector('#post input[name="submit"]');

        if (originalSubmitBtn) {
          chatInput.disabled = true;
          chatSendBtn.style.opacity = '0.5';
          originalSubmitBtn.click();
        } else {
          const form = originalTextarea.closest('form');
          if (form) form.submit();
        }
      };

      chatSendBtn.addEventListener('click', submitChatMessage);

      chatInput.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
          e.preventDefault();
          submitChatMessage();
        }
      });
    }

    const socChatWrapper = chatWrapper.querySelector('.soc-chat-wrapper');
    if (socChatWrapper) {
      socChatWrapper.scrollTop = socChatWrapper.scrollHeight;
    }

  } catch (error) {
    console.error('Ошибка при генерации чата:', error);
    chatWrapper.innerHTML = '<div style="text-align:center; color:red; padding: 20px;">Произошла ошибка при загрузке чата.</div>';
  }
});
</script>