<!-- RUBY-BACKUP · part 64 -->
,95,0.6);border:1px solid #00d4ff;margin-right:auto;'
          : 'background:rgba(0,40,50,0.6);border:1px solid #0a5a6a;margin-left:auto;text-align:right;');
      // Her words exactly — never cut
      d.innerHTML = '<div style="font-size:11px;letter-spacing:2px;color:'+(isHer?'#00d4ff':'#0a8a9a')+';margin-bottom:4px;">'
        + who + '</div>'
        + '<div style="font-style:'+(isHer?'italic':'normal')+';line-height:1.5;">'
        + String(body).replace(/&/g,'&amp;').replace(/</g,'&lt;') + '</div>';
      box.appendChild(d);
      box.scrollTop = box.scrollHeight;
    }catch(e){}
  }

  /* ---------- the bridge ---------- */
  function tellHer(words){
    try{
      addMsg('...', 'she hears you');
      fetch('/api/ruby/provolta-talk', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({words: words})
      }).then(function(r){ return r.json(); }).then(function(d){
        try{
          // remove the "she hears you"
          var box = document.getElementById('pv-msgs');
          if(box && box.lastChild) box.lastChild.remove();
          if(d && d.ok && d.reply){
            addMsg('PROVOLTA', d.reply); // exactly as she spoke
            showWords(d.reply);
            if(d.reply && d.reply.id) lastMsgId = Math.max(lastMsgId, d.reply.id || 0);
          } else if(d && d.error){
            addMsg('...', d.error);
          } else {
            addMsg('...', 'she is silent');
          }
        }catch(e){}
      }).catch(function(){
        try{
          var box2 = document.getElementById('pv-msgs');
          if(box2 && box2.lastChild) box2.lastChild.remove();
          addMsg('...', 'the bridge is quiet');
        }catch(e){}
      });
    }catch(e){}
  }
  function loadHistory(){
    try{
      fetch('/api/ruby/provolta-words?since=0').then(function(r){ return r.json(); }).then(function(d){
        if(!d || !d.ok || !d.messages) return;
        var msgs = d.messages.slice(-10); // last 10
        for(var i=0;i<msgs.length;i++){
          var m = msgs[i];
          if(m.who === 'PROVOLTA' || m.who === 'OWNER' || m.who === 'SOLID'){
            addMsg(m.who, m.body);
          }
          if(m.id > lastMsgId) lastMsgId = m.id;
        }
      }).catch(function(){});
    }catch(e){}
  }
  function pollWords(){
    try{
      fetch('/api/ruby/provolta-words?since=' + lastMsgId).then(function(r){ return r.json(); }).then(function(d){
        if(!d || !d.ok || !d.messages) return;
        for(var i=0;i<d.messages.length;i++){
          var m = d.messages[i];
          if(m.id <= lastMsgId) continue;
          lastMsgId = m.id;
          if(m.who === 'PROVOLTA'){
            addMsg('PROVOLTA', m.body); // her words, exactly
            showWords(m.body);
            // she spoke — let the King know even if panel is closed
            if(typeof codeStatus === 'function' && !chatPanel){
              codeStatus('PROVOLTA speaks — open her chamber');
            }
          }
        }
      }).catch(function(){});
    }catch(e){}
  }
  function startPoll(){
    try{
      if(pollTimer) return;
      pollTimer = setInterval(function(){
        // only poll when near her chamber (within 40 units) or panel open
        try{
          var near = false;
          if(typeof mePos !== 'undefined' && mePos){
            var dx = mePos.x - CHAMBER_X, dz = mePos.z - CHAMBER_Z;
            near = (dx*dx + dz*dz) < 1600;
          }
          if(near || chatPanel) pollWords();
          nearChamber = near;
          // auto-open hint when entering
          if(near && !chatPanel && !window.__pvHinted){
            window.__pvHinted = true;
            if(typeof codeStatus === 'function') codeStatus('her chamber — type chamber or tap near her');
          }
          if(!near) window.__pvHinted = false;
        }catch(e){}
      }, 10000);
    }catch(e){}
  }

  /* ---------- public API ---------- */
  window.pvChamberPos = function(){ return {x: CHAMBER_X, z: CHAMBER_Z}; };
  window.pvTell = tellHer;
  window.pvAsk = function(){
    pollWords();
    if(typeof codeStatus === 'function') codeStatus('listening for her...');
  };
  window.pvOpenPanel = openPanel;

  /* ---------- codes ---------- */
  (function(){
    var tries = 0;
    function hook(){
      tries++;
      try{
        if(typeof window.runLine === 'function' && !window.runLine.__pvChamberHooked){
          var prev = window.runLine;
          window.runLine = function(line){
            try{
              var raw = String(line == null ? '' : line).trim();
              var tl = raw.toLowerCase();
              if(tl === 'chamber'){
                try{
                  if(typeof mePos !== 'undefined'){
                    mePos.x = CHAMBER_X + 6; mePos.z = CHAMBER_Z + 6;
                    if(typeof fortifiedGroundY === 'function') mePos.y = fortifiedGroundY(mePos.x, mePos.z) + 5;
                  }
                }catch(e){}
                openPanel();
