nothumanallowed 13.5.20 → 13.5.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.5.20",
3
+ "version": "13.5.22",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '13.5.20';
8
+ export const VERSION = '13.5.22';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -2620,8 +2620,11 @@ function renderSettings(el) {
2620
2620
  ]) +
2621
2621
  '<div class="card" style="margin-top:16px"><div class="card__title">Google Account</div>' +
2622
2622
  '<div style="font-size:11px;color:var(--dim);margin-bottom:8px">Connect Gmail, Calendar, Drive, Contacts, and Tasks. Opens a browser window for Google sign-in.</div>' +
2623
- (settingsData.hasGoogle ? '<div style="color:var(--green);font-size:12px;margin-bottom:8px">\\u2705 Connected</div>' : '') +
2623
+ (settingsData.hasGoogle ? '<div style="color:var(--green);font-size:12px;margin-bottom:8px">&#9989; Connected</div>' : '') +
2624
+ '<div style="display:flex;gap:8px;flex-wrap:wrap">' +
2624
2625
  '<button onclick="connectGoogle()" style="background:var(--green3);color:var(--bg);padding:8px 20px;border-radius:var(--r);font-weight:700;font-size:12px;cursor:pointer;border:none">' + (settingsData.hasGoogle ? 'Reconnect Google' : 'Connect Google') + '</button>' +
2626
+ (settingsData.hasGoogle ? '<button onclick="disconnectGoogle()" style="background:var(--red3,#7f1d1d);color:#fca5a5;padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px;cursor:pointer;border:1px solid var(--red,#ef4444)">Disconnect Google</button>' : '') +
2627
+ '</div>' +
2625
2628
  '<div id="googleStatus" style="margin-top:8px;font-size:10px;color:var(--dim)"></div>' +
2626
2629
  '</div>' +
2627
2630
  '</div>';
@@ -2637,6 +2640,17 @@ function connectGoogle() {
2637
2640
  if (s) { s.textContent = 'Error: ' + e.message; s.style.color = 'var(--red)'; }
2638
2641
  });
2639
2642
  }
2643
+ function disconnectGoogle() {
2644
+ var s = document.getElementById('googleStatus');
2645
+ if (s) s.textContent = 'Disconnecting...';
2646
+ apiPost('/api/google/revoke', {}).then(function() {
2647
+ if (s) { s.textContent = 'Google account disconnected.'; s.style.color = 'var(--dim)'; }
2648
+ setTimeout(function(){ location.reload(); }, 1200);
2649
+ }).catch(function() {
2650
+ // Fallback: delete token file via CLI hint
2651
+ if (s) { s.textContent = 'Run: nha google revoke'; s.style.color = 'var(--amber)'; }
2652
+ });
2653
+ }
2640
2654
 
2641
2655
  function settingsSection(id, title, desc, fields) {
2642
2656
  var h = '<form class="card" style="margin-bottom:16px" id="settings-' + id + '" onsubmit="event.preventDefault();saveSettingsSection(\\x27' + id + '\\x27)">' +
@@ -3238,7 +3252,7 @@ function renderSidebar() {
3238
3252
  \x27<div class="sidebar__brand">\x27+
3239
3253
  \x27<button class="sidebar__close" onclick="closeSidebar()" title="Close menu">&times;</button>\x27+
3240
3254
  \x27<div style="display:flex;align-items:center;gap:8px">\x27+
3241
- \x27<div class="sidebar__brand-name">NHA</div>\x27+
3255
+ \x27<div class="sidebar__brand-name">NHA <span style="font-size:11px;font-weight:500;opacity:.7;letter-spacing:.5px">3rdArm</span></div>\x27+
3242
3256
  \x27<span id="wsIndicator" style="color:var(--dim);font-size:8px" title="Daemon WebSocket">&#9679;</span>\x27+
3243
3257
  \x27</div>\x27+
3244
3258
  \x27<div id="sidebarPageTitle" style="font-size:11px;color:var(--bright);margin-top:4px;font-weight:600">\x27+t(\x27nav_dashboard\x27)+\x27</div>\x27+
@@ -3311,7 +3325,7 @@ var studioAbortController = null;
3311
3325
  var parlActiveAgent = null; // active agent label during parliament streaming
3312
3326
  var parlDoneAgents = {}; // set of completed agent labels during parliament
3313
3327
  var _parlPersistHtml = null; // persists parliament block HTML across tab navigations
3314
- var _PARL_STAMP = '<!--nha-parl-v13.5.20-->';
3328
+ var _PARL_STAMP = '<!--nha-parl-v13.5.22-->';
3315
3329
 
3316
3330
  function stopStudio() {
3317
3331
  if (!studioState.running) return;
@@ -3932,10 +3946,14 @@ function renderStudioNodes() {
3932
3946
  : (isActive ? \x27\u2022\u2022\u2022 lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27)));
3933
3947
  var bubbleBg = isOrch ? \x27rgba(99,102,241,.15)\x27 : (isActive ? \x27rgba(99,102,241,.12)\x27 : (isDone ? \x27rgba(0,0,0,.08)\x27 : \x27rgba(239,68,68,.12)\x27));
3934
3948
  var glowBox = isActive ? (\x270 0 0 3px \x27+accentColor+\x2744,0 8px 24px \x27+accentColor+\x2733\x27) : (isDone ? (\x270 0 0 2px rgba(0,0,0,.25)\x27) : \x27none\x27);
3949
+ // orchWalkClass goes on the CHAR only, not the whole station card
3935
3950
  var orchWalkClass = (isOrch && hasActive) ? \x27 iso-orch-walking\x27 : (isOrch && doneCount===totalCount&&totalCount>0 ? \x27 iso-orch-done\x27 : \x27\x27);
3936
- var charHtml = isoCharSvg({emojiIdx: isOrch ? 99 : emojiIdx, isActive: isActive, isDone: isDone, scale: 1.1, accentColor: accentColor});
3951
+ var charHtml = \x27<div class="iso-char-mover\x27+orchWalkClass+\x27">\x27+isoCharSvg({emojiIdx: isOrch ? 99 : emojiIdx, isActive: isActive, isDone: isDone, scale: 1.1, accentColor: accentColor})+\x27</div>\x27;
3937
3952
  var clickAttr = isOrch ? \x27\x27 : (\x27data-agent-label="\x27+esc(label)+\x27" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))"\x27);
3938
- return \x27<div class="iso-station\x27+orchWalkClass+\x27" \x27+clickAttr+\x27 style="box-shadow:\x27+glowBox+\x27;border-color:\x27+accentColor+\x27;transition:box-shadow .4s">\x27+
3953
+ // Flying doc emoji when active
3954
+ var flyDoc = isActive ? \x27<div class="iso-fly-doc" style="color:\x27+accentColor+\x27">\x27+String.fromCodePoint(0x1F4C4)+\x27</div>\x27 : \x27\x27;
3955
+ return \x27<div class="iso-station" \x27+clickAttr+\x27 style="box-shadow:\x27+glowBox+\x27;border-color:\x27+accentColor+\x27;transition:box-shadow .4s">\x27+
3956
+ flyDoc+
3939
3957
  \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" style="border-color:\x27+accentColor+\x27;color:\x27+accentColor+\x27;background:\x27+bubbleBg+\x27;visibility:\x27+(bubbleText||isOrch?\x27visible\x27:\x27hidden\x27)+\x27">\x27+esc(bubbleText)+\x27</div>\x27+
3940
3958
  \x27<div class="iso-tool-badge">\x27+toolEmoji+\x27</div>\x27+
3941
3959
  charHtml+
@@ -4601,7 +4619,7 @@ async function runStudio() {
4601
4619
  // Read from both DOM and studioState (supports mid-run activation via nudge)
4602
4620
  var parliamentChk = document.getElementById(\x27studioParliamentMode\x27);
4603
4621
  var parliamentActive = studioState.parliamentMode || (parliamentChk && parliamentChk.checked);
4604
- if (parliamentActive && studioState.nodes.length >= 1) {
4622
+ if (parliamentActive && studioState.nodes.length >= 1 && studioState.running) {
4605
4623
  var proposals = studioState.nodes
4606
4624
  .filter(function(n) {
4607
4625
  if (!n.output || n.output === \x27(no output)\x27) return false;
@@ -4655,7 +4673,7 @@ async function runStudio() {
4655
4673
  if (!parlBlockBuilt || !pb.innerHTML.trim()) {
4656
4674
  parlBlockBuilt = true;
4657
4675
 
4658
- // ── Seat card builder — emoji + bubble + name ──────────────────────
4676
+ // ── FREE agent builder — no box, just floating emoji+name ─────────
4659
4677
  function buildSeat(prop, seatIdx) {
4660
4678
  var lbl = prop.label || prop.agent;
4661
4679
  var safeLbl = lbl.replace(new RegExp('[^a-zA-Z0-9_-]','g'),\x27_\x27);
@@ -4664,12 +4682,11 @@ async function runStudio() {
4664
4682
  void seatIdx;
4665
4683
  return \x27<div class="br-seat" id="brseat_\x27+safeLbl+\x27" data-lbl="\x27+esc(lbl)+\x27">\x27+
4666
4684
  \x27<div class="br-bubble" id="brbubble_\x27+safeLbl+\x27" style="display:none"></div>\x27+
4667
- \x27<div class="br-char">\x27+agentEmoji+\x27</div>\x27+
4685
+ \x27<div class="br-char" id="brchar_\x27+safeLbl+\x27">\x27+agentEmoji+\x27</div>\x27+
4668
4686
  \x27<div class="br-seat-name" id="brname_\x27+safeLbl+\x27">\x27+esc(lbl)+\x27</div>\x27+
4669
4687
  \x27</div>\x27;
4670
4688
  }
4671
4689
 
4672
- // Split agents: even indices top, odd indices bottom
4673
4690
  var topSeats = [];
4674
4691
  var botSeats = [];
4675
4692
  proposals.forEach(function(prop, si) {
@@ -4678,72 +4695,150 @@ async function runStudio() {
4678
4695
  var topHtml = topSeats.map(buildSeat).join(\x27\x27);
4679
4696
  var botHtml = botSeats.map(buildSeat).join(\x27\x27);
4680
4697
 
4681
- // Orchestrator at left head of table
4698
+ // Orchestrator head free floating, no box
4682
4699
  var orchEmoji2 = String.fromCodePoint(0x1F9D1,0x200D,0x1F4BC);
4683
4700
  var crownEm = String.fromCodePoint(0x1F451);
4684
- var orchHeadHtml = \x27<div class="br-orch" id="brOrch" style="display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 10px;flex-shrink:0">\x27+
4701
+ var orchHeadHtml = \x27<div class="br-orch" id="brOrch">\x27+
4685
4702
  \x27<div class="br-orch-speech" id="brOrchSpeech" style="display:none"></div>\x27+
4686
- \x27<span style="font-size:18px;line-height:1">\x27+crownEm+\x27</span>\x27+
4687
- \x27<span style="font-size:48px;line-height:1;filter:drop-shadow(0 0 14px #818cf8BB)">\x27+orchEmoji2+\x27</span>\x27+
4703
+ \x27<div class="br-orch-inner">\x27+
4704
+ \x27<span class="br-orch-crown">\x27+crownEm+\x27</span>\x27+
4705
+ \x27<span class="br-orch-emoji" id="brOrchEmoji">\x27+orchEmoji2+\x27</span>\x27+
4706
+ \x27</div>\x27+
4688
4707
  \x27<div class="br-orch-label">Orchestratore</div>\x27+
4689
4708
  \x27</div>\x27;
4690
4709
 
4691
- // Conference table SVG — wide walnut rectangle
4710
+ // ── Conference table SVG — rich walnut with real objects ────────────
4692
4711
  var tblSvg = \x27<svg viewBox="0 0 1000 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:50%;left:0;width:100%;height:140px;transform:translateY(-50%);z-index:1;pointer-events:none">\x27+
4693
- \x27<defs><linearGradient id="tblGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#5a3a18"/><stop offset="0.5" stop-color="#3d2510"/><stop offset="1" stop-color="#2a1808"/></linearGradient></defs>\x27+
4694
- \x27<rect x="8" y="12" width="984" height="176" rx="20" fill="rgba(0,0,0,.22)"/>\x27+
4695
- \x27<rect x="0" y="4" width="1000" height="176" rx="18" fill="url(#tblGrad)"/>\x27+
4696
- \x27<rect x="0" y="4" width="1000" height="8" rx="8" fill="rgba(255,255,255,.08)"/>\x27+
4697
- \x27<line x1="0" y1="60" x2="1000" y2="60" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4698
- \x27<line x1="0" y1="100" x2="1000" y2="100" stroke="rgba(0,0,0,.09)" stroke-width="2"/>\x27+
4699
- \x27<line x1="0" y1="140" x2="1000" y2="140" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4700
- \x27<text x="500" y="115" text-anchor="middle" font-family="system-ui" font-size="52" font-weight="900" fill="rgba(150,130,255,.1)" letter-spacing="8">NHA</text>\x27+
4701
- \x27<rect x="180" y="60" width="60" height="40" rx="4" fill="rgba(99,102,241,.18)" stroke="rgba(99,102,241,.35)" stroke-width="1.5"/>\x27+
4702
- \x27<rect x="390" y="55" width="70" height="45" rx="4" fill="rgba(99,102,241,.14)" stroke="rgba(99,102,241,.3)" stroke-width="1.5"/>\x27+
4703
- \x27<rect x="650" y="62" width="55" height="38" rx="4" fill="rgba(99,102,241,.18)" stroke="rgba(99,102,241,.35)" stroke-width="1.5"/>\x27+
4704
- \x27<circle cx="300" cy="90" r="14" fill="rgba(180,120,60,.4)" stroke="rgba(180,120,60,.6)" stroke-width="1.5"/>\x27+
4705
- \x27<circle cx="750" cy="92" r="14" fill="rgba(180,120,60,.4)" stroke="rgba(180,120,60,.6)" stroke-width="1.5"/>\x27+
4712
+ \x27<defs>\x27+
4713
+ \x27<linearGradient id="tblGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#6b4423"/><stop offset="0.4" stop-color="#4a2e12"/><stop offset="1" stop-color="#2e1a08"/></linearGradient>\x27+
4714
+ \x27<linearGradient id="tblSheen" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="rgba(255,255,255,0)"/><stop offset="0.3" stop-color="rgba(255,255,255,.04)"/><stop offset="0.7" stop-color="rgba(255,255,255,.06)"/><stop offset="1" stop-color="rgba(255,255,255,0)"/></linearGradient>\x27+
4715
+ \x27</defs>\x27+
4716
+ // Shadow
4717
+ \x27<rect x="6" y="10" width="988" height="178" rx="22" fill="rgba(0,0,0,.28)"/>\x27+
4718
+ // Table body
4719
+ \x27<rect x="0" y="2" width="1000" height="178" rx="20" fill="url(#tblGrad)"/>\x27+
4720
+ // Wood grain lines
4721
+ \x27<line x1="0" y1="48" x2="1000" y2="48" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4722
+ \x27<line x1="0" y1="96" x2="1000" y2="96" stroke="rgba(0,0,0,.09)" stroke-width="2.5"/>\x27+
4723
+ \x27<line x1="0" y1="144" x2="1000" y2="144" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4724
+ // Sheen
4725
+ \x27<rect x="0" y="2" width="1000" height="178" rx="20" fill="url(#tblSheen)"/>\x27+
4726
+ // Top edge highlight
4727
+ \x27<rect x="0" y="2" width="1000" height="6" rx="4" fill="rgba(255,255,255,.1)"/>\x27+
4728
+ // NHA monogram
4729
+ \x27<text x="500" y="118" text-anchor="middle" font-family="system-ui" font-size="58" font-weight="900" fill="rgba(160,140,255,.09)" letter-spacing="10">NHA</text>\x27+
4730
+ // Laptop 1
4731
+ \x27<rect x="155" y="55" width="68" height="46" rx="5" fill="#1a1a2e" stroke="#4a4a8a" stroke-width="2"/>\x27+
4732
+ \x27<rect x="160" y="59" width="58" height="34" rx="3" fill="#0d0d1a"/>\x27+
4733
+ \x27<rect x="162" y="61" width="54" height="30" rx="2" fill="#1e3a5f"/>\x27+
4734
+ \x27<rect x="148" y="101" width="82" height="5" rx="2" fill="#333"/>\x27+
4735
+ // Laptop 2
4736
+ \x27<rect x="770" y="55" width="68" height="46" rx="5" fill="#1a1a2e" stroke="#4a4a8a" stroke-width="2"/>\x27+
4737
+ \x27<rect x="775" y="59" width="58" height="34" rx="3" fill="#0d0d1a"/>\x27+
4738
+ \x27<rect x="777" y="61" width="54" height="30" rx="2" fill="#1e3a5f"/>\x27+
4739
+ \x27<rect x="763" y="101" width="82" height="5" rx="2" fill="#333"/>\x27+
4740
+ // Telephone with handset (center-left)
4741
+ \x27<rect x="360" y="62" width="52" height="38" rx="4" fill="#2a2a2a" stroke="#555" stroke-width="1.5"/>\x27+
4742
+ \x27<ellipse cx="366" cy="72" rx="6" ry="8" fill="#1a1a1a" stroke="#888" stroke-width="1"/>\x27+
4743
+ \x27<ellipse cx="406" cy="72" rx="6" ry="8" fill="#1a1a1a" stroke="#888" stroke-width="1"/>\x27+
4744
+ \x27<line x1="366" y1="72" x2="406" y2="72" stroke="#666" stroke-width="3" stroke-linecap="round"/>\x27+
4745
+ \x27<rect x="372" y="76" width="40" height="18" rx="2" fill="#333"/>\x27+
4746
+ // Coffee cup 1
4747
+ \x27<rect x="570" y="68" width="28" height="28" rx="4" fill="#f5f0e8" stroke="#c8b08a" stroke-width="1.5"/>\x27+
4748
+ \x27<rect x="575" y="73" width="18" height="15" rx="2" fill="#6b3a1f" opacity=".8"/>\x27+
4749
+ \x27<path d="M598 78 Q608 83 598 88" stroke="#c8b08a" stroke-width="2" fill="none"/>\x27+
4750
+ // Mini plant on table
4751
+ \x27<rect x="470" y="72" width="14" height="16" rx="2" fill="#8B6914"/>\x27+
4752
+ \x27<ellipse cx="477" cy="68" rx="10" ry="12" fill="#2d6a2d"/>\x27+
4753
+ \x27<ellipse cx="470" cy="65" rx="7" ry="9" fill="#3a8a3a"/>\x27+
4754
+ \x27<ellipse cx="484" cy="65" rx="7" ry="9" fill="#2d7a2d"/>\x27+
4706
4755
  \x27</svg>\x27;
4707
4756
 
4708
- // Background: parquet floor + white wall + windows + chandelier + door
4757
+ // ── Background SVG enhanced room with art, detailed door, windows
4709
4758
  var bgSvg = \x27<svg viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none">\x27+
4710
4759
  \x27<defs>\x27+
4711
4760
  \x27<filter id="brGlow" x="-100%" y="-100%" width="300%" height="300%"><feGaussianBlur stdDeviation="5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27+
4712
- \x27<linearGradient id="brWall" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#faf7f2"/><stop offset="1" stop-color="#ede8e0"/></linearGradient>\x27+
4761
+ \x27<filter id="brShadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="2" dy="2" stdDeviation="3" flood-color="rgba(0,0,0,.2)"/></filter>\x27+
4762
+ \x27<linearGradient id="brWall" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#f5f0e8"/><stop offset="1" stop-color="#e8e0d0"/></linearGradient>\x27+
4763
+ \x27<linearGradient id="winGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#b8dff8"/><stop offset="1" stop-color="#d8f0ff"/></linearGradient>\x27+
4764
+ \x27<linearGradient id="doorGrad" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#a0724a"/><stop offset="0.5" stop-color="#c8905c"/><stop offset="1" stop-color="#a0724a"/></linearGradient>\x27+
4713
4765
  \x27</defs>\x27+
4714
- \x27<rect x="0" y="0" width="1000" height="210" fill="url(#brWall)"/>\x27+
4715
- \x27<rect x="0" y="205" width="1000" height="7" fill="#d4c4a8" rx="2"/>\x27+
4766
+ // Wall
4767
+ \x27<rect x="0" y="0" width="1000" height="215" fill="url(#brWall)"/>\x27+
4768
+ // Crown molding
4769
+ \x27<rect x="0" y="0" width="1000" height="8" fill="#d8cfc0"/>\x27+
4770
+ \x27<rect x="0" y="8" width="1000" height="4" fill="#e8e0d0"/>\x27+
4771
+ // Baseboard
4772
+ \x27<rect x="0" y="206" width="1000" height="9" fill="#c8b898" rx="1"/>\x27+
4773
+ \x27<rect x="0" y="210" width="1000" height="3" fill="#b0a080"/>\x27+
4774
+ // Parquet floor
4716
4775
  function() {
4717
- var s2 = \x27\x27;
4718
- var pColors = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#caa86e\x27];
4719
- var pH2 = 32; var pW2 = 120;
4720
- for (var fy2 = 212; fy2 < 600+pH2; fy2 += pH2) {
4721
- var ro3 = (Math.floor((fy2-212)/pH2) % 2) * (pW2/2);
4722
- for (var fx2 = -pW2+ro3; fx2 < 1000+pW2; fx2 += pW2) {
4723
- var pc3 = pColors[Math.abs(Math.round(fx2/pW2+fy2/pH2*1.3)) % pColors.length];
4724
- s2 += \x27<rect x="\x27+Math.round(fx2)+\x27" y="\x27+fy2+\x27" width="\x27+(pW2-2)+\x27" height="\x27+(pH2-2)+\x27" fill="\x27+pc3+\x27" rx="2"/>\x27;
4725
- s2 += \x27<line x1="\x27+Math.round(fx2+pW2*.4)+\x27" y1="\x27+fy2+\x27" x2="\x27+Math.round(fx2+pW2*.4)+\x27" y2="\x27+(fy2+pH2-2)+\x27" stroke="rgba(0,0,0,.04)" stroke-width="1.5"/>\x27;
4776
+ var s3 = \x27\x27;
4777
+ var pC = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#caa86e\x27];
4778
+ var pH3 = 32; var pW3 = 120;
4779
+ for (var fy3 = 215; fy3 < 600+pH3; fy3 += pH3) {
4780
+ var ro4 = (Math.floor((fy3-215)/pH3) % 2) * (pW3/2);
4781
+ for (var fx3 = -pW3+ro4; fx3 < 1000+pW3; fx3 += pW3) {
4782
+ var pc4 = pC[Math.abs(Math.round(fx3/pW3+fy3/pH3*1.3)) % pC.length];
4783
+ s3 += \x27<rect x="\x27+Math.round(fx3)+\x27" y="\x27+fy3+\x27" width="\x27+(pW3-2)+\x27" height="\x27+(pH3-2)+\x27" fill="\x27+pc4+\x27" rx="2"/>\x27;
4784
+ s3 += \x27<line x1="\x27+Math.round(fx3+pW3*.4)+\x27" y1="\x27+fy3+\x27" x2="\x27+Math.round(fx3+pW3*.4)+\x27" y2="\x27+(fy3+pH3-2)+\x27" stroke="rgba(0,0,0,.04)" stroke-width="1.5"/>\x27;
4726
4785
  }
4727
4786
  }
4728
- return s2;
4787
+ return s3;
4729
4788
  }()+
4730
- \x27<rect x="40" y="22" width="110" height="88" rx="5" fill="#c8e6f8" stroke="#a8cce0" stroke-width="3"/>\x27+
4731
- \x27<line x1="95" y1="22" x2="95" y2="110" stroke="#a8cce0" stroke-width="2"/>\x27+
4732
- \x27<line x1="40" y1="66" x2="150" y2="66" stroke="#a8cce0" stroke-width="2"/>\x27+
4733
- \x27<rect x="40" y="22" width="110" height="88" rx="5" fill="rgba(255,255,255,.18)"/>\x27+
4734
- \x27<rect x="850" y="22" width="110" height="88" rx="5" fill="#c8e6f8" stroke="#a8cce0" stroke-width="3"/>\x27+
4735
- \x27<line x1="905" y1="22" x2="905" y2="110" stroke="#a8cce0" stroke-width="2"/>\x27+
4736
- \x27<line x1="850" y1="66" x2="960" y2="66" stroke="#a8cce0" stroke-width="2"/>\x27+
4737
- \x27<rect x="850" y="22" width="110" height="88" rx="5" fill="rgba(255,255,255,.18)"/>\x27+
4738
- \x27<rect x="463" y="0" width="74" height="210" fill="#c8a87a" stroke="#a07848" stroke-width="2"/>\x27+
4739
- \x27<rect x="472" y="10" width="56" height="50" rx="5" fill="rgba(255,255,255,.18)"/>\x27+
4740
- \x27<circle cx="524" cy="108" r="6" fill="#8a6028"/>\x27+
4741
- \x27<line x1="500" y1="0" x2="500" y2="32" stroke="#bbb" stroke-width="3"/>\x27+
4742
- \x27<ellipse cx="500" cy="42" rx="60" ry="16" fill="#e8d960" stroke="#c8b030" stroke-width="2"/>\x27+
4743
- \x27<circle cx="468" cy="52" r="10" fill="#fffde0" filter="url(#brGlow)"/>\x27+
4744
- \x27<circle cx="500" cy="56" r="10" fill="#fffde0" filter="url(#brGlow)"/>\x27+
4745
- \x27<circle cx="532" cy="52" r="10" fill="#fffde0" filter="url(#brGlow)"/>\x27+
4746
- \x27<polygon points="440,66 560,66 680,600 320,600" fill="rgba(255,252,200,.05)"/>\x27+
4789
+ // Window LEFT thick frame, venetian blinds effect
4790
+ \x27<rect x="28" y="18" width="126" height="96" rx="3" fill="#4a6080" stroke="#2a3a50" stroke-width="4"/>\x27+
4791
+ \x27<rect x="34" y="24" width="114" height="84" rx="2" fill="url(#winGrad)"/>\x27+
4792
+ \x27<rect x="34" y="24" width="114" height="84" rx="2" fill="rgba(255,255,255,.12)"/>\x27+
4793
+ \x27<line x1="91" y1="24" x2="91" y2="108" stroke="#3a5070" stroke-width="3"/>\x27+
4794
+ \x27<line x1="34" y1="66" x2="148" y2="66" stroke="#3a5070" stroke-width="3"/>\x27+
4795
+ // window sill
4796
+ \x27<rect x="22" y="114" width="138" height="8" rx="2" fill="#c8b898"/>\x27+
4797
+ // Window RIGHT
4798
+ \x27<rect x="846" y="18" width="126" height="96" rx="3" fill="#4a6080" stroke="#2a3a50" stroke-width="4"/>\x27+
4799
+ \x27<rect x="852" y="24" width="114" height="84" rx="2" fill="url(#winGrad)"/>\x27+
4800
+ \x27<rect x="852" y="24" width="114" height="84" rx="2" fill="rgba(255,255,255,.12)"/>\x27+
4801
+ \x27<line x1="909" y1="24" x2="909" y2="108" stroke="#3a5070" stroke-width="3"/>\x27+
4802
+ \x27<line x1="852" y1="66" x2="966" y2="66" stroke="#3a5070" stroke-width="3"/>\x27+
4803
+ \x27<rect x="840" y="114" width="138" height="8" rx="2" fill="#c8b898"/>\x27+
4804
+ // Door CENTER detailed with panels and handle
4805
+ \x27<rect x="455" y="0" width="90" height="215" fill="url(#doorGrad)" stroke="#7a5030" stroke-width="3"/>\x27+
4806
+ // Door panels
4807
+ \x27<rect x="463" y="10" width="74" height="55" rx="3" fill="rgba(0,0,0,.08)" stroke="rgba(0,0,0,.15)" stroke-width="1.5"/>\x27+
4808
+ \x27<rect x="463" y="72" width="74" height="55" rx="3" fill="rgba(0,0,0,.08)" stroke="rgba(0,0,0,.15)" stroke-width="1.5"/>\x27+
4809
+ \x27<rect x="463" y="134" width="74" height="55" rx="3" fill="rgba(0,0,0,.06)" stroke="rgba(0,0,0,.12)" stroke-width="1.5"/>\x27+
4810
+ // Door handle
4811
+ \x27<circle cx="533" cy="118" r="7" fill="#c8a040" stroke="#a07828" stroke-width="2"/>\x27+
4812
+ \x27<rect x="530" y="118" width="14" height="4" rx="2" fill="#c8a040" stroke="#a07828" stroke-width="1"/>\x27+
4813
+ // Door frame
4814
+ \x27<rect x="451" y="0" width="5" height="215" fill="#7a5030"/>\x27+
4815
+ \x27<rect x="544" y="0" width="5" height="215" fill="#7a5030"/>\x27+
4816
+ // Painting LEFT — abstract NHA art
4817
+ \x27<rect x="190" y="18" width="100" height="76" rx="3" fill="#f8f4ee" stroke="#8a7050" stroke-width="4" filter="url(#brShadow)"/>\x27+
4818
+ \x27<rect x="196" y="24" width="88" height="64" rx="1" fill="#1a1060"/>\x27+
4819
+ \x27<circle cx="240" cy="56" r="22" fill="#6366f1" opacity=".7"/>\x27+
4820
+ \x27<circle cx="240" cy="56" r="14" fill="#818cf8" opacity=".8"/>\x27+
4821
+ \x27<circle cx="240" cy="56" r="6" fill="#c7d2fe"/>\x27+
4822
+ \x27<text x="240" y="60" text-anchor="middle" font-size="10" font-weight="900" fill="white" font-family="system-ui">NHA</text>\x27+
4823
+ // Painting RIGHT — landscape
4824
+ \x27<rect x="710" y="18" width="110" height="76" rx="3" fill="#f8f4ee" stroke="#8a7050" stroke-width="4" filter="url(#brShadow)"/>\x27+
4825
+ \x27<rect x="716" y="24" width="98" height="64" rx="1" fill="#87CEEB"/>\x27+
4826
+ \x27<ellipse cx="765" cy="65" rx="48" ry="20" fill="#228B22"/>\x27+
4827
+ \x27<circle cx="748" cy="52" rx="14" ry="14" fill="#ffed4a" opacity=".9"/>\x27+
4828
+ \x27<ellipse cx="730" cy="62" rx="12" ry="16" fill="#1a5c1a"/>\x27+
4829
+ \x27<ellipse cx="780" cy="60" rx="10" ry="14" fill="#2a7a2a"/>\x27+
4830
+ // Chandelier
4831
+ \x27<line x1="500" y1="0" x2="500" y2="28" stroke="#aaa" stroke-width="4"/>\x27+
4832
+ \x27<ellipse cx="500" cy="36" rx="52" ry="14" fill="#f0d830" stroke="#c8a820" stroke-width="3"/>\x27+
4833
+ \x27<ellipse cx="500" cy="36" rx="45" ry="10" fill="#ffe850" opacity=".5"/>\x27+
4834
+ \x27<circle cx="470" cy="47" r="9" fill="#fffce0" filter="url(#brGlow)"/>\x27+
4835
+ \x27<circle cx="500" cy="50" r="9" fill="#fffce0" filter="url(#brGlow)"/>\x27+
4836
+ \x27<circle cx="530" cy="47" r="9" fill="#fffce0" filter="url(#brGlow)"/>\x27+
4837
+ \x27<circle cx="455" cy="40" r="6" fill="#ffe060" filter="url(#brGlow)"/>\x27+
4838
+ \x27<circle cx="545" cy="40" r="6" fill="#ffe060" filter="url(#brGlow)"/>\x27+
4839
+ \x27<polygon points="448,62 552,62 680,600 320,600" fill="rgba(255,252,180,.07)"/>\x27+
4840
+ // Cross-agent conversation lines overlay placeholder (updated dynamically)
4841
+ \x27<g id="brConvLines"></g>\x27+
4747
4842
  \x27</svg>\x27;
4748
4843
 
4749
4844
  var headerHtml = \x27<div class="br-header">\x27+
@@ -4758,8 +4853,14 @@ async function runStudio() {
4758
4853
  headerHtml+
4759
4854
  \x27<div class="br-room">\x27+
4760
4855
  bgSvg+
4761
- \x27<div style="position:absolute;bottom:10px;left:12px;font-size:36px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.2))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4762
- \x27<div style="position:absolute;bottom:10px;right:12px;font-size:36px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.2))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4856
+ // Decorative plants at corners
4857
+ \x27<div style="position:absolute;bottom:8px;left:10px;font-size:44px;z-index:5;filter:drop-shadow(0 3px 8px rgba(0,0,0,.3))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4858
+ \x27<div style="position:absolute;bottom:8px;right:10px;font-size:44px;z-index:5;filter:drop-shadow(0 3px 8px rgba(0,0,0,.3))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4859
+ // Small plants on window sills
4860
+ \x27<div style="position:absolute;top:112px;left:58px;font-size:20px;z-index:5">\x27+String.fromCodePoint(0x1F331)+\x27</div>\x27+
4861
+ \x27<div style="position:absolute;top:112px;right:58px;font-size:20px;z-index:5">\x27+String.fromCodePoint(0x1F331)+\x27</div>\x27+
4862
+ // Cross-agent communication SVG overlay (dynamic, updated per call)
4863
+ \x27<svg id="brCommSvg" style="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:8;overflow:visible"></svg>\x27+
4763
4864
  \x27<div style="position:relative;z-index:10;display:flex;flex-direction:column;justify-content:center;min-height:480px;padding:20px 16px;gap:0;box-sizing:border-box">\x27+
4764
4865
  \x27<div class="br-seats-row">\x27+topHtml+\x27</div>\x27+
4765
4866
  \x27<div style="position:relative;display:flex;align-items:center;width:100%;min-height:160px">\x27+
@@ -4821,49 +4922,14 @@ async function runStudio() {
4821
4922
  orchEl.style.setProperty(\x27--oc\x27, phaseColor);
4822
4923
  }
4823
4924
 
4824
- // Draw attention line from orchestrator to active agent seat
4825
- var orchEl2 = document.getElementById(\x27brOrch\x27);
4826
- var brRoom2 = orchEl2 ? orchEl2.closest(\x27.br-room\x27) : null;
4827
- if (brRoom2) {
4828
- var existLine = brRoom2.querySelector(\x27.br-attention-line\x27);
4829
- if (existLine) existLine.parentNode.removeChild(existLine);
4830
- if (activeLabel && phase !== \x27done\x27) {
4831
- var aLblSafe = activeLabel.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27);
4832
- var activeSeatEl = document.getElementById(\x27brseat_\x27+aLblSafe);
4833
- if (activeSeatEl && orchEl2) {
4834
- var roomRect = brRoom2.getBoundingClientRect();
4835
- var orchRect = orchEl2.getBoundingClientRect();
4836
- var seatRect = activeSeatEl.getBoundingClientRect();
4837
- var x1 = orchRect.left + orchRect.width/2 - roomRect.left;
4838
- var y1 = orchRect.top + orchRect.height/2 - roomRect.top;
4839
- var x2 = seatRect.left + seatRect.width/2 - roomRect.left;
4840
- var y2 = seatRect.top + seatRect.height/2 - roomRect.top;
4841
- var lineSvg = document.createElementNS(\x27http://www.w3.org/2000/svg\x27, \x27svg\x27);
4842
- lineSvg.setAttribute(\x27class\x27, \x27br-attention-line\x27);
4843
- lineSvg.style.cssText = \x27position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:10;overflow:visible\x27;
4844
- var lineEl = document.createElementNS(\x27http://www.w3.org/2000/svg\x27, \x27line\x27);
4845
- lineEl.setAttribute(\x27x1\x27, String(Math.round(x1)));
4846
- lineEl.setAttribute(\x27y1\x27, String(Math.round(y1)));
4847
- lineEl.setAttribute(\x27x2\x27, String(Math.round(x2)));
4848
- lineEl.setAttribute(\x27y2\x27, String(Math.round(y2)));
4849
- lineEl.setAttribute(\x27stroke\x27, \x27#6366f1\x27);
4850
- lineEl.setAttribute(\x27stroke-width\x27, \x272\x27);
4851
- lineEl.setAttribute(\x27stroke-dasharray\x27, \x276 4\x27);
4852
- lineEl.setAttribute(\x27opacity\x27, \x27.6\x27);
4853
- lineEl.style.animation = \x27brDashFlow 1s linear infinite\x27;
4854
- lineSvg.appendChild(lineEl);
4855
- brRoom2.appendChild(lineSvg);
4856
- }
4857
- }
4858
- }
4859
-
4860
- // Update each agent seat state
4925
+ // ── Update each agent seat state ────────────────────────────────────
4861
4926
  proposals.forEach(function(prop) {
4862
4927
  var lbl = prop.label || prop.agent;
4863
4928
  var safeLbl = lbl.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27);
4864
4929
  var seatEl = document.getElementById(\x27brseat_\x27+safeLbl);
4865
4930
  var bubbleEl = document.getElementById(\x27brbubble_\x27+safeLbl);
4866
4931
  var nameEl = document.getElementById(\x27brname_\x27+safeLbl);
4932
+ var charEl = document.getElementById(\x27brchar_\x27+safeLbl);
4867
4933
  var isDone = !!parlDoneAgents[lbl];
4868
4934
  var isActive = lbl === activeLabel;
4869
4935
 
@@ -4873,25 +4939,120 @@ async function runStudio() {
4873
4939
  (isDone ? \x27 br-seat--done\x27 : \x27\x27);
4874
4940
  seatEl.style.setProperty(\x27--sc\x27, phaseColor);
4875
4941
  }
4942
+ // Character animation: bob when active
4943
+ if (charEl) {
4944
+ charEl.style.animation = isActive ? \x27brCharBob .8s ease-in-out infinite\x27 : \x27\x27;
4945
+ charEl.style.filter = isActive
4946
+ ? (\x27drop-shadow(0 0 12px \x27+phaseColor+\x27)\x27)
4947
+ : (isDone ? \x27none\x27 : \x27grayscale(.4)\x27);
4948
+ }
4876
4949
  if (bubbleEl) {
4877
4950
  var actionStr2 = \x27\x27;
4878
4951
  if (phase===\x27r1\x27 && isActive) actionStr2 = \x27...analizza\x27;
4879
4952
  else if (phase===\x27r1\x27 && isDone) actionStr2 = \x27\u2714 bozza pronta\x27;
4880
- else if (phase===\x27r2\x27 && isActive) actionStr2 = \x27...legge + raffina\x27;
4953
+ else if (phase===\x27r2\x27 && isActive) actionStr2 = \x27...legge proposte\x27;
4881
4954
  else if (phase===\x27r2\x27 && isDone) actionStr2 = \x27\u2714 raffinato\x27;
4882
4955
  else if (phase===\x27r3\x27 && isActive) actionStr2 = \x27...media\x27;
4883
4956
  else if (phase===\x27done\x27) actionStr2 = \x27\u2714 consenso\x27;
4957
+ else if (!isActive && !isDone && phase===\x27r2\x27) actionStr2 = \x27legge...\x27;
4884
4958
  else if (!isActive && !isDone) actionStr2 = \x27in attesa\x27;
4885
4959
  bubbleEl.textContent = actionStr2;
4886
4960
  bubbleEl.style.display = actionStr2 ? \x27\x27 : \x27none\x27;
4887
4961
  bubbleEl.style.borderColor = isActive ? phaseColor : (isDone ? \x27rgba(0,0,0,.25)\x27 : \x27rgba(0,0,0,.15)\x27);
4888
4962
  bubbleEl.style.color = isActive ? phaseColor : (isDone ? \x27#111827\x27 : \x27#6b7280\x27);
4963
+ bubbleEl.style.background = isActive ? \x27rgba(255,255,255,.95)\x27 : \x27rgba(255,255,255,.82)\x27;
4964
+ bubbleEl.style.fontWeight = isActive ? \x27700\x27 : \x27500\x27;
4889
4965
  }
4890
4966
  if (nameEl) {
4891
4967
  nameEl.style.color = isDone ? \x27#111827\x27 : (isActive ? phaseColor : \x27#374151\x27);
4968
+ nameEl.style.fontWeight = isActive ? \x27800\x27 : \x27600\x27;
4892
4969
  }
4893
4970
  });
4894
4971
 
4972
+ // ── Cross-agent communication lines (R2/R3 only) ────────────────────
4973
+ // In R2: show lines from active agent to all done agents (cross-reading)
4974
+ // In R1/done: show orch→active line only
4975
+ var commSvg = document.getElementById(\x27brCommSvg\x27);
4976
+ var brRoom2 = commSvg ? commSvg.closest(\x27.br-room\x27) : null;
4977
+ if (commSvg && brRoom2) {
4978
+ commSvg.innerHTML = \x27\x27;
4979
+ var roomRect2 = brRoom2.getBoundingClientRect();
4980
+ var ns = \x27http://www.w3.org/2000/svg\x27;
4981
+
4982
+ function addCommLine(fromEl, toEl, color, dash, width, opacity, anim) {
4983
+ if (!fromEl || !toEl) return;
4984
+ var fr = fromEl.getBoundingClientRect();
4985
+ var tr = toEl.getBoundingClientRect();
4986
+ var lx1 = Math.round(fr.left + fr.width/2 - roomRect2.left);
4987
+ var ly1 = Math.round(fr.top + fr.height/2 - roomRect2.top);
4988
+ var lx2 = Math.round(tr.left + tr.width/2 - roomRect2.left);
4989
+ var ly2 = Math.round(tr.top + tr.height/2 - roomRect2.top);
4990
+ // Bezier curve for elegance
4991
+ var mx = (lx1+lx2)/2; var my = Math.min(ly1,ly2) - 30;
4992
+ var path = document.createElementNS(ns, \x27path\x27);
4993
+ path.setAttribute(\x27d\x27, \x27M\x27+lx1+\x27,\x27+ly1+\x27 Q\x27+mx+\x27,\x27+my+\x27 \x27+lx2+\x27,\x27+ly2);
4994
+ path.setAttribute(\x27stroke\x27, color);
4995
+ path.setAttribute(\x27stroke-width\x27, String(width||2));
4996
+ path.setAttribute(\x27stroke-dasharray\x27, dash||\x27\x27);
4997
+ path.setAttribute(\x27fill\x27, \x27none\x27);
4998
+ path.setAttribute(\x27opacity\x27, String(opacity||.6));
4999
+ if (anim) path.style.animation = anim;
5000
+ // Arrow marker at end
5001
+ var mk = document.createElementNS(ns, \x27marker\x27);
5002
+ var mkId = \x27arr\x27+Math.random().toString(36).slice(2,6);
5003
+ mk.setAttribute(\x27id\x27, mkId);
5004
+ mk.setAttribute(\x27markerWidth\x27,\x278\x27);mk.setAttribute(\x27markerHeight\x27,\x276\x27);
5005
+ mk.setAttribute(\x27refX\x27,\x278\x27);mk.setAttribute(\x27refY\x27,\x273\x27);
5006
+ mk.setAttribute(\x27orient\x27,\x27auto\x27);
5007
+ var poly = document.createElementNS(ns,\x27polygon\x27);
5008
+ poly.setAttribute(\x27points\x27,\x270 0, 8 3, 0 6\x27);
5009
+ poly.setAttribute(\x27fill\x27, color);
5010
+ mk.appendChild(poly);
5011
+ var defs2 = document.createElementNS(ns,\x27defs\x27);
5012
+ defs2.appendChild(mk);
5013
+ commSvg.appendChild(defs2);
5014
+ path.setAttribute(\x27marker-end\x27,\x27url(#\x27+mkId+\x27)\x27);
5015
+ commSvg.appendChild(path);
5016
+ // Floating emoji dot on path midpoint
5017
+ var dot = document.createElementNS(ns, \x27text\x27);
5018
+ dot.setAttribute(\x27x\x27, String(Math.round(mx)));
5019
+ dot.setAttribute(\x27y\x27, String(Math.round(my-8)));
5020
+ dot.setAttribute(\x27text-anchor\x27, \x27middle\x27);
5021
+ dot.setAttribute(\x27font-size\x27, \x2714\x27);
5022
+ dot.textContent = phase===\x27r2\x27 ? String.fromCodePoint(0x1F4AC) : (phase===\x27r3\x27 ? String.fromCodePoint(0x1F91D) : String.fromCodePoint(0x1F4E8));
5023
+ dot.style.animation = \x27brDotFloat 1.5s ease-in-out infinite\x27;
5024
+ commSvg.appendChild(dot);
5025
+ }
5026
+
5027
+ var orchEl2 = document.getElementById(\x27brOrch\x27);
5028
+ if (phase === \x27done\x27) {
5029
+ // All done: show web of connections between all agents
5030
+ proposals.forEach(function(pa, ia) {
5031
+ proposals.forEach(function(pb2, ib2) {
5032
+ if (ib2 <= ia) return;
5033
+ var ea = document.getElementById(\x27brseat_\x27+pa.label.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27));
5034
+ var eb = document.getElementById(\x27brseat_\x27+pb2.label.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27));
5035
+ addCommLine(ea, eb, \x27#22c55e\x27, \x273 3\x27, 1.5, 0.3, \x27\x27);
5036
+ });
5037
+ });
5038
+ } else if (activeLabel) {
5039
+ var aLblSafe2 = activeLabel.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27);
5040
+ var activeSeatEl2 = document.getElementById(\x27brseat_\x27+aLblSafe2);
5041
+ // Orch → active agent (always)
5042
+ addCommLine(orchEl2, activeSeatEl2, phaseColor, \x275 4\x27, 2.5, 0.75, \x27brDashFlow 1.2s linear infinite\x27);
5043
+ // R2/R3: active reads all done agents → show reading lines
5044
+ if (phase === \x27r2\x27 || phase === \x27r3\x27) {
5045
+ proposals.forEach(function(pp2) {
5046
+ var doneL = pp2.label || pp2.agent;
5047
+ if (doneL === activeLabel) return;
5048
+ if (!parlDoneAgents[doneL]) return;
5049
+ var doneSeat = document.getElementById(\x27brseat_\x27+doneL.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27));
5050
+ addCommLine(doneSeat, activeSeatEl2, \x27#f59e0b\x27, \x274 3\x27, 1.5, 0.5, \x27brDashFlow 1.8s linear infinite\x27);
5051
+ });
5052
+ }
5053
+ }
5054
+ }
5055
+
4895
5056
  // Persist across tab navigations
4896
5057
  if (pb.innerHTML && pb.innerHTML.length < 60000) { _parlPersistHtml = _PARL_STAMP + pb.innerHTML; }
4897
5058
 
@@ -6163,23 +6324,32 @@ input:focus,textarea:focus{border-color:var(--green3)}
6163
6324
  .br-room{position:relative;width:100%;min-height:480px;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18)}
6164
6325
  /* Seats rows above/below table */
6165
6326
  .br-seats-row{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end;justify-content:space-around}
6166
- /* Individual seat card light theme matching workflow stations */
6167
- .br-seat{display:flex;flex-direction:column;align-items:center;gap:2px;transition:transform .3s;padding:6px 8px;border-radius:12px;background:rgba(255,255,255,.82);border:1.5px solid rgba(200,180,160,.5);box-shadow:0 2px 8px rgba(0,0,0,.12);backdrop-filter:blur(4px);min-width:64px;cursor:default}
6168
- .br-seat--active{transform:scale(1.07);border-color:var(--sc,#6366f1);box-shadow:0 0 16px rgba(99,102,241,.35),0 2px 8px rgba(0,0,0,.12)}
6169
- .br-seat--done{border-color:rgba(0,0,0,.25);background:rgba(0,0,0,.06)}
6327
+ /* Agent seat — FREE (no box, just emoji + name floating) */
6328
+ .br-seat{display:flex;flex-direction:column;align-items:center;gap:2px;transition:transform .35s;padding:4px 6px;border-radius:10px;background:transparent;border:none;box-shadow:none;min-width:56px;cursor:default}
6329
+ .br-seat--active{transform:scale(1.14) translateY(-5px)}
6330
+ .br-seat--done{opacity:.88}
6170
6331
  /* Emoji character */
6171
- .br-char{font-size:36px;line-height:1;user-select:none;filter:drop-shadow(0 2px 5px rgba(0,0,0,.2))}
6172
- /* Orchestrator head seat */
6173
- .br-orch{display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 10px;flex-shrink:0}
6174
- .br-orch-speech{font-size:9px;font-weight:800;font-family:var(--mono);padding:3px 8px;border:1.5px solid #6366f1;border-radius:8px;background:rgba(255,255,255,.95);color:#4338ca;white-space:nowrap;animation:brSpeechPop .6s ease-in-out infinite alternate;pointer-events:none;margin-bottom:2px}
6175
- @keyframes brSpeechPop{0%{transform:scale(1) rotate(-1deg)}100%{transform:scale(1.05) rotate(1deg)}}
6176
- .br-orch-label{font-size:9px;font-family:var(--mono);font-weight:800;color:#6366f1;background:rgba(99,102,241,.12);border-radius:6px;padding:2px 7px}
6177
- /* Bubble above seat */
6178
- .br-bubble{font-size:8px;font-family:var(--mono);padding:3px 8px;border-radius:8px 8px 8px 2px;border:1px solid rgba(99,102,241,.35);background:rgba(255,255,255,.95);color:#1e1b4b;line-height:1.45;word-break:break-word;max-width:140px;white-space:normal;box-shadow:0 2px 6px rgba(0,0,0,.1);margin-bottom:2px}
6332
+ .br-char{font-size:40px;line-height:1;user-select:none;transition:filter .4s}
6333
+ @keyframes brCharBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
6334
+ /* Orchestrator head — large, no box */
6335
+ .br-orch{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 10px;flex-shrink:0;position:relative}
6336
+ .br-orch-inner{display:flex;flex-direction:column;align-items:center;gap:0;position:relative}
6337
+ .br-orch-crown{font-size:22px;line-height:1;display:block;text-align:center;animation:brCrownFloat 2s ease-in-out infinite}
6338
+ @keyframes brCrownFloat{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-3px) rotate(4deg)}}
6339
+ .br-orch-emoji{font-size:54px;line-height:1;display:block;filter:drop-shadow(0 0 16px #818cf8AA);transition:filter .3s}
6340
+ .br-orch--active .br-orch-emoji{animation:brOrchWalk 1.4s ease-in-out infinite alternate;filter:drop-shadow(0 0 20px #6366f1CC)}
6341
+ @keyframes brOrchWalk{0%{transform:translateX(0) scale(1)}100%{transform:translateX(14px) scale(1.07)}}
6342
+ .br-orch--done .br-orch-emoji{animation:orchBounce .7s ease forwards}
6343
+ .br-orch-speech{font-size:10px;font-weight:800;font-family:var(--mono);padding:4px 10px;border:2px solid #6366f1;border-radius:10px;background:rgba(255,255,255,.95);color:#4338ca;white-space:nowrap;animation:brSpeechPop .7s ease-in-out infinite alternate;pointer-events:none;margin-bottom:4px;box-shadow:0 2px 8px rgba(99,102,241,.25)}
6344
+ @keyframes brSpeechPop{0%{transform:scale(1) rotate(-1deg)}100%{transform:scale(1.06) rotate(1deg)}}
6345
+ .br-orch-label{font-size:9px;font-family:var(--mono);font-weight:800;color:#6366f1;background:rgba(99,102,241,.15);border-radius:6px;padding:2px 8px;margin-top:2px}
6346
+ /* Bubble above agent */
6347
+ .br-bubble{font-size:9px;font-family:var(--mono);padding:4px 9px;border-radius:10px 10px 10px 2px;border:1.5px solid rgba(99,102,241,.35);background:rgba(255,255,255,.96);color:#1e1b4b;line-height:1.4;word-break:break-word;max-width:120px;white-space:normal;box-shadow:0 2px 8px rgba(0,0,0,.12);margin-bottom:3px}
6179
6348
  /* Agent name pill */
6180
- .br-seat-name{font-size:9px;font-family:var(--mono);font-weight:700;color:#374151;text-align:center;white-space:normal;word-break:break-word;max-width:140px;line-height:1.3;margin-top:1px;background:rgba(0,0,0,.04);border-radius:4px;padding:1px 4px;transition:color .3s}
6181
- .br-seat--active .br-seat-name{color:#4338ca}
6349
+ .br-seat-name{font-size:9px;font-family:var(--mono);font-weight:600;color:#374151;text-align:center;white-space:normal;word-break:break-word;max-width:100px;line-height:1.3;margin-top:1px;background:rgba(255,255,255,.75);border-radius:4px;padding:1px 4px;transition:color .3s,font-weight .2s;backdrop-filter:blur(2px)}
6350
+ .br-seat--active .br-seat-name{color:#4338ca;font-weight:800}
6182
6351
  .br-seat--done .br-seat-name{color:#111827}
6352
+ @keyframes brDotFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
6183
6353
  /* Convergence */
6184
6354
  .br-convergence{margin-top:10px;padding:8px 12px;background:rgba(99,102,241,.06);border:1px solid rgba(99,102,241,.2);border-radius:8px}
6185
6355
  .br-conv-bar-outer{height:4px;background:rgba(99,102,241,.15);border-radius:4px;overflow:hidden;margin-bottom:6px}
@@ -6237,10 +6407,13 @@ input:focus,textarea:focus{border-color:var(--green3)}
6237
6407
  .iso-scene{background:#f0ede6;cursor:default;max-width:100%;overflow-x:auto;box-shadow:0 4px 24px rgba(0,0,0,.18);border-radius:12px;overflow:hidden}
6238
6408
  .iso-station{display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer;transition:filter .2s,transform .2s;padding:8px 4px;border-radius:12px;border:1.5px solid transparent;position:relative}
6239
6409
  .iso-station:hover{filter:brightness(1.06);transform:translateY(-2px)}
6240
- .iso-station.iso-orch-walking{animation:orchWalkGrid 1.8s ease-in-out infinite alternate}
6241
- @keyframes orchWalkGrid{0%{transform:translateX(0) scale(1)}100%{transform:translateX(24px) scale(1.04)}}
6242
- .iso-station.iso-orch-done{animation:orchBounce .7s ease forwards}
6410
+ .iso-char-mover{position:relative;transition:transform .3s}
6411
+ .iso-char-mover.iso-orch-walking{animation:orchWalkGrid 1.8s ease-in-out infinite alternate}
6412
+ @keyframes orchWalkGrid{0%{transform:translateX(0) scale(1)}100%{transform:translateX(18px) scale(1.05)}}
6413
+ .iso-char-mover.iso-orch-done{animation:orchBounce .7s ease forwards}
6243
6414
  @keyframes orchBounce{0%{transform:scale(1)}40%{transform:scale(1.18) translateY(-6px)}100%{transform:scale(1)}}
6415
+ .iso-fly-doc{position:absolute;top:-8px;right:-4px;font-size:16px;animation:flyDocSpin 1.2s ease-in-out infinite;z-index:20;pointer-events:none}
6416
+ @keyframes flyDocSpin{0%{transform:rotate(-15deg) translateY(0);opacity:.7}50%{transform:rotate(10deg) translateY(-8px);opacity:1}100%{transform:rotate(-15deg) translateY(0);opacity:.7}}
6244
6417
  .iso-desk{width:90%;height:16px;background:linear-gradient(180deg,#d4a448 0%,#b8832a 100%);border-radius:4px 4px 2px 2px;box-shadow:0 4px 0 #8a5e18,0 6px 10px rgba(0,0,0,.3);border-top:2px solid #e8c060;position:relative;margin-top:4px}
6245
6418
  .iso-desk::after{content:'';position:absolute;bottom:-4px;left:8px;right:8px;height:4px;background:#7a5010;border-radius:0 0 3px 3px}
6246
6419
  .iso-monitor{width:56px;height:40px;background:#12101e;border:2px solid #3a3070;border-radius:5px;display:flex;align-items:center;justify-content:center;position:relative;margin-bottom:-2px}