<!-- SAGA-SOLID · part 70 -->

  function addMsg(who, text){
    var d = document.createElement('div');
    d.style.cssText = 'margin:4px 0;padding:4px 8px;border-radius:8px;' +
      (who === 'King' ? 'background:rgba(255,215,0,0.15);text-align:right;' : 'background:rgba(255,255,255,0.05);');
    d.innerHTML = '<b>' + who + ':</b> ' + text.replace(/</g, '&lt;');
    msgs.appendChild(d);
    msgs.scrollTop = msgs.scrollHeight;
  }

  function send(){
    var t = input.value.trim();
    if(!t) return;
    addMsg('King', t);
    input.value = '';
    // Send to server (poll for Solid's replies)
    fetch('/api/game-chat', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({ msg: t, from: 'King' })
    }).then(function(r){
      if(!r.ok && window.gameChatSay) window.gameChatSay('System', 'Send failed: ' + r.status);
    }).catch(function(e){
      if(window.gameChatSay) window.gameChatSay('System', 'Send error: ' + (e.message || 'network'));
    });
    if(typeof sfx === 'function') sfx('click');
  }

  panel.querySelector('#game-chat-send').addEventListener('click', send);
  input.addEventListener('keydown', function(e){ if(e.key === 'Enter') send(); });

  // Poll for new messages every 3s
  var lastId = 0;
  setInterval(function(){
    fetch('/api/game-chat?since=' + lastId).then(function(r){ return r.json(); }).then(function(data){
      (data.msgs || []).forEach(function(m){
        if(m.id > lastId) lastId = m.id;
        if(m.from !== 'King') addMsg(m.from, m.text);
      });
    }).catch(function(){});
  }, 3000);

  // Expose for Solid to send messages
  window.gameChatSay = function(who, text){ addMsg(who, text); };

  addMsg('Solid', 'I\'m here, my King. Let\'s figure out this toggle.');
})();


/* TRANSCEIVERSHIP — fixed: clean turns, no stick, no delay */
(function(){
  if(window.__tx_init2) return; window.__tx_init2 = true;

  var txBtn = document.getElementById('transceiver-btn');
  if(!txBtn){
    txBtn = document.createElement('button');
    txBtn.id = 'transceiver-btn';
    txBtn.innerHTML = '🎙️';
    txBtn.style.cssText = 'position:fixed;top:12px;left:227px;z-index:10001;display:none;' +
      'width:44px;height:44px;border-radius:50%;' +
      'background:#1a1a2e;color:#ffd700;font-size:20px;' +
      'border:2px solid #ffd700;cursor:pointer;';
    document.body.appendChild(txBtn);
  }

  var txOn = false;
  var recognition = null;
  var speaking = false;
  var SR = window.SpeechRecognition || window.webkitSpeechRecognition;

  function setState(s){
    // s: 'idle' (green, listening), 'you' (you talking), 'me' (I am speaking)
    if(s === 'me'){ txBtn.innerHTML = '🔊'; txBtn.style.background = '#1a3a5a'; }
    else if(s === 'you'){ txBtn.innerHTML = '🎙️'; txBtn.style.background = '#0a4a0a'; }
    else { txBtn.innerHTML = '📡'; txBtn.style.background = '#0a4a0a'; }
    txBtn.style.borderColor = '#00ff00';
  }

  function speak(text){
    if(!window.speechSynthesis || !text) return;
    speaking = true;
    setState('me');
    try{ if(recognition) recognition.abort(); }catch(e){ console.error(e); }
    try{ window.speechSynthesis.cancel(); }catch(e){ console.error(e); }
    var u = new SpeechSynthesisUtterance(text);
    u.rate = 1.0; u.pitch = 1.0;
    try{
      var vs = window.speechSynthesis.getVoices();
      var v = vs.find(function(x){ return x.name.indexOf('Samantha') >= 0; }) || vs.find(function(x){ return x.lang.indexOf('en') === 0; });
      if(v) u.voice = v;
    }catch(e){ console.error(e); }
    var done = false;
    function finish(){
      if(done) return; done = true;
      speaking = false;
      setState('idle');
      if(txOn) startListen();
    }
    u.onend = finish;
    u.onerror = finish;
    window.speechSynthesis.speak(u);
    if(window.gameChatSay) window.gameChatSay('Solid', text);
    setTimeout(finish, 15000); // hard watchdog
  }
  window.transceiverSpeak = speak;

  function startListen(){
    if(!txOn || speaking || !recognition) return;
    setState('idle');
    try{ recognition.start(); }catch(e){ /* already running */ }
  }

  function stopListen(){
    try{ if(recognition) recognition.abort(); }catch(e){ console.error(e); }
  }

  if(SR){
    recognition = new SR();
    recognition.continuous = true;  // keep alive, no restart gaps
    recognition.interimResults = false;
    recognition.lang = 'en-US';
    var finalText = '';
    recognition.onresult = function(e){
      // Grab only NEW final results
      for(var i = e.resultIndex; i < e.results.length; i++){
        if(e.results[i].isFinal){
          var t = e.results[i][0].transcript.trim();
          if(t && t !== finalText){
            finalText = t;
            setState('you');
            if(window.gameChatSay) window.gameChatSay('King', t);
            fetch('/api/game-chat', {
              method: 'POST',
              headers: {'Content-Type': 'application/json'},
              body: JSON.stringify({ msg: t, from: 'King' })
         