nothumanallowed 13.5.8 → 13.5.10

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.8",
3
+ "version": "13.5.10",
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.8';
8
+ export const VERSION = '13.5.10';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3310,6 +3310,7 @@ var studioState = {
3310
3310
  var studioAbortController = null;
3311
3311
  var parlActiveAgent = null; // active agent label during parliament streaming
3312
3312
  var parlDoneAgents = {}; // set of completed agent labels during parliament
3313
+ var _parlPersistHtml = null; // persists parliament block HTML across tab navigations
3313
3314
 
3314
3315
  function stopStudio() {
3315
3316
  if (!studioState.running) return;
@@ -3624,10 +3625,10 @@ function officeRoomDecor() {
3624
3625
  // Projects grid positions onto an isometric plane.
3625
3626
  // iso(col, row) → {x, y} pixel coordinates in the scene container.
3626
3627
  // Characters are positioned with position:absolute, scale by row for depth.
3627
- var ISO_TILE_W = 72;
3628
- var ISO_TILE_H = 36;
3629
- var ISO_ORIGIN_X = 300;
3630
- var ISO_ORIGIN_Y = 60;
3628
+ var ISO_TILE_W = 80;
3629
+ var ISO_TILE_H = 40;
3630
+ var ISO_ORIGIN_X = 500;
3631
+ var ISO_ORIGIN_Y = 80;
3631
3632
  function isoProject(col, row) {
3632
3633
  return {
3633
3634
  x: ISO_ORIGIN_X + (col - row) * (ISO_TILE_W / 2),
@@ -3635,236 +3636,200 @@ function isoProject(col, row) {
3635
3636
  };
3636
3637
  }
3637
3638
 
3638
- // Full bright office scene SVG background
3639
+ // Full bright office scene — wide SVG background (1000x560)
3639
3640
  function isoFloorSvg(cols, rows) {
3640
- var w = 640; var h = 320;
3641
- var out = \x27<svg viewBox="0 0 \x27+w+\x27 \x27+h+\x27" width="\x27+w+\x27" height="\x27+h+\x27" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;pointer-events:none;z-index:0">\x27;
3642
-
3643
- // ── BACK WALL (white/cream) ──────────────────────────────────────────
3644
- out += \x27<polygon points="0,100 320,20 320,120 0,200" fill="#f5f3ee"/>\x27;
3645
- out += \x27<polygon points="320,20 640,100 640,200 320,120" fill="#edeae3"/>\x27;
3646
- out += \x27<line x1="0" y1="100" x2="320" y2="20" stroke="#ccc" stroke-width="1.5"/>\x27;
3647
- out += \x27<line x1="320" y1="20" x2="640" y2="100" stroke="#bbb" stroke-width="1.5"/>\x27;
3648
- // Wall corner vertical line
3649
- out += \x27<line x1="320" y1="20" x2="320" y2="120" stroke="#c8c4bc" stroke-width="1"/>\x27;
3650
-
3651
- // ── WINDOWS — 3 centered on left wall ────────────────────────────────
3652
- // Win L1
3653
- out += \x27<polygon points="30,122 90,102 90,155 30,175" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3654
- out += \x27<line x1="60,112" y1="60" x2="60" y2="130" stroke="#aac8e8" stroke-width=".8"/>\x27;
3655
- out += \x27<line x1="30,148" y1="148" x2="90" y2="128" stroke="#aac8e8" stroke-width=".8"/>\x27;
3656
- out += \x27<polygon points="30,122 90,102 90,108 30,128" fill="#b8ddf8" opacity=".4"/>\x27;
3657
- out += \x27<polygon points="30,122 90,102 90,155 30,175" fill="rgba(200,230,255,.12)"/>\x27;
3658
- // Win L2 (center-left)
3659
- out += \x27<polygon points="110,102 175,80 175,132 110,154" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3660
- out += \x27<polygon points="110,102 175,80 175,88 110,110" fill="#b8ddf8" opacity=".4"/>\x27;
3661
- out += \x27<line x1="142" y1="91" x2="142" y2="143" stroke="#aac8e8" stroke-width=".8"/>\x27;
3662
- out += \x27<line x1="110" y1="128" x2="175" y2="106" stroke="#aac8e8" stroke-width=".8"/>\x27;
3663
- out += \x27<polygon points="110,102 175,80 175,132 110,154" fill="rgba(200,230,255,.10)"/>\x27;
3664
- // Win L3 (center)
3665
- out += \x27<polygon points="195,88 255,68 255,118 195,138" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3666
- out += \x27<polygon points="195,88 255,68 255,76 195,96" fill="#b8ddf8" opacity=".4"/>\x27;
3667
- out += \x27<line x1="225" y1="78" x2="225" y2="128" stroke="#aac8e8" stroke-width=".8"/>\x27;
3668
- out += \x27<line x1="195" y1="113" x2="255" y2="93" stroke="#aac8e8" stroke-width=".8"/>\x27;
3669
- // Sunlight shafts from windows
3670
- out += \x27<polygon points="50,155 90,140 120,260 80,275" fill="rgba(255,250,220,.06)"/>\x27;
3671
- out += \x27<polygon points="130,132 175,116 200,260 155,275" fill="rgba(255,250,220,.05)"/>\x27;
3672
- out += \x27<polygon points="210,116 255,100 270,260 225,275" fill="rgba(255,250,220,.04)"/>\x27;
3673
-
3674
- // ── ART on left wall ────────────────────────────────────────────────
3675
- // Frame 1 (small painting near top-right of left wall)
3676
- out += \x27<polygon points="275,72 310,60 310,90 275,102" fill="#e8e4dc" stroke="#bbb" stroke-width="1"/>\x27;
3677
- out += \x27<polygon points="278,74 307,63 307,88 278,99" fill="#7a9ed4"/>\x27;
3678
- out += \x27<polygon points="285,77 303,70 303,84 285,91" fill="#a8c4e8"/>\x27;
3679
- out += \x27<ellipse cx="294" cy="80" rx="5" ry="4" fill="#fff" opacity=".5"/>\x27;
3680
-
3681
- // ── PLANT (bottom-left corner) ───────────────────────────────────────
3682
- out += \x27<ellipse cx="30" cy="188" rx="10" ry="5" fill="#2d4a1e" opacity=".7"/>\x27;
3683
- out += \x27<rect x="25" y="178" width="10" height="10" rx="2" fill="#5a3a1a"/>\x27;
3684
- out += \x27<path d="M30 178 C25 165 18 155 22 148 C26 142 30 148 30 178" fill="#3a7a1e"/>\x27;
3685
- out += \x27<path d="M30 178 C35 162 42 155 38 148 C34 142 30 150 30 178" fill="#4a8a26"/>\x27;
3686
- out += \x27<path d="M30 175 C22 168 16 160 18 153" stroke="#3a7a1e" stroke-width="2" fill="none" stroke-linecap="round"/>\x27;
3687
- out += \x27<path d="M30 170 C38 165 44 158 42 151" stroke="#4a8a26" stroke-width="2" fill="none" stroke-linecap="round"/>\x27;
3688
-
3689
- // ── CEILING CHANDELIER with glow ─────────────────────────────────────
3690
- out += \x27<line x1="320" y1="0" x2="320" y2="18" stroke="#999" stroke-width="2"/>\x27;
3691
- // Chandelier body
3692
- out += \x27<ellipse cx="320" cy="18" rx="24" ry="7" fill="#d4c88a" stroke="#b8a860" stroke-width="1.5"/>\x27;
3693
- out += \x27<ellipse cx="320" cy="22" rx="20" ry="5" fill="#e8d898"/>\x27;
3694
- // Bulbs hanging down
3695
- out += \x27<circle cx="305" cy="28" r="5" fill="#fffbe8" filter="url(#glow)"/>\x27;
3696
- out += \x27<circle cx="320" cy="26" r="6" fill="#fffbe8" filter="url(#glow)"/>\x27;
3697
- out += \x27<circle cx="335" cy="28" r="5" fill="#fffbe8" filter="url(#glow)"/>\x27;
3698
- out += \x27<line x1="305" y1="22" x2="305" y2="28" stroke="#aaa" stroke-width=".8"/>\x27;
3699
- out += \x27<line x1="320" y1="22" x2="320" y2="26" stroke="#aaa" stroke-width=".8"/>\x27;
3700
- out += \x27<line x1="335" y1="22" x2="335" y2="28" stroke="#aaa" stroke-width=".8"/>\x27;
3701
- // Light cone glow on floor/walls
3702
- out += \x27<radialGradient id="chandelierGlow" cx="50%" cy="0%" r="60%"><stop offset="0%" stop-color="rgba(255,245,180,.22)"/><stop offset="100%" stop-color="rgba(255,245,180,0)"/></radialGradient>\x27;
3703
- out += \x27<filter id="glow"><feGaussianBlur stdDeviation="3" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27;
3704
- out += \x27<ellipse cx="320" cy="180" rx="200" ry="120" fill="url(#chandelierGlow)"/>\x27;
3705
-
3706
- // ── PARQUET FLOOR long narrow planks ───────────────────────────────
3707
- // Draw rectangular plank tiles in iso projection
3708
- var PLANK_W = ISO_TILE_W; var PLANK_H = ISO_TILE_H;
3709
- var plankColors = [\x27#b5854a\x27,\x27#a8783c\x27,\x27#bf9055\x27,\x27#c49a60\x27,\x27#a07234\x27];
3641
+ var W = 1000; var H = 560;
3642
+ var out = \x27<svg viewBox="0 0 \x27+W+\x27 \x27+H+\x27" width="\x27+W+\x27" height="\x27+H+\x27" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;pointer-events:none;z-index:0">\x27;
3643
+
3644
+ // ── DEFS ────────────────────────────────────────────────────────────
3645
+ out += \x27<defs>\x27;
3646
+ out += \x27<filter id="bGlow" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="6" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27;
3647
+ out += \x27<radialGradient id="lampGlow" cx="50%" cy="20%" r="70%"><stop offset="0%" stop-color="rgba(255,248,200,.28)"/><stop offset="100%" stop-color="rgba(255,248,200,0)"/></radialGradient>\x27;
3648
+ out += \x27<linearGradient id="wallL" x1="0" y1="0" x2="1" y2="0"><stop offset="0%" stop-color="#f8f6f0"/><stop offset="100%" stop-color="#ede9e0"/></linearGradient>\x27;
3649
+ out += \x27<linearGradient id="wallR" x1="0" y1="0" x2="1" y2="0"><stop offset="0%" stop-color="#e8e4dc"/><stop offset="100%" stop-color="#ddd8ce"/></linearGradient>\x27;
3650
+ out += \x27</defs>\x27;
3651
+
3652
+ // ── WALLS ────────────────────────────────────────────────────────────
3653
+ // Left wall (back-left)
3654
+ out += \x27<polygon points="0,200 500,40 500,280 0,440" fill="url(#wallL)"/>\x27;
3655
+ // Right wall (back-right)
3656
+ out += \x27<polygon points="500,40 1000,200 1000,440 500,280" fill="url(#wallR)"/>\x27;
3657
+ // Wall top ridge
3658
+ out += \x27<line x1="0" y1="200" x2="500" y2="40" stroke="#c8c0b0" stroke-width="2"/>\x27;
3659
+ out += \x27<line x1="500" y1="40" x2="1000" y2="200" stroke="#bbb0a0" stroke-width="2"/>\x27;
3660
+ out += \x27<line x1="500" y1="40" x2="500" y2="280" stroke="#c0b8a8" stroke-width="1.5"/>\x27;
3661
+
3662
+ // ── WINDOWS on left wall 3 evenly spaced ──────────────────────────
3663
+ // Helper: window at left-wall position (xL,yTop)→(xR,yTop-slope)
3664
+ // Left wall goes from (0,200)→(500,40), slope = -160/500 per x
3665
+ // Window 1
3666
+ out += \x27<polygon points="60,232 160,206 160,272 60,300" fill="#ceeaff" stroke="#90bcd8" stroke-width="1.5"/>\x27;
3667
+ out += \x27<polygon points="60,232 160,206 160,213 60,239" fill="#a8d8f8" opacity=".6"/>\x27;
3668
+ out += \x27<line x1="60" y1="266" x2="160" y2="239" stroke="#90bcd8" stroke-width="1"/>\x27;
3669
+ out += \x27<line x1="110" y1="219" x2="110" y2="286" stroke="#90bcd8" stroke-width="1"/>\x27;
3670
+ out += \x27<polygon points="60,232 160,206 160,272 60,300" fill="rgba(180,220,255,.1)"/>\x27;
3671
+ // Window 2
3672
+ out += \x27<polygon points="200,178 300,152 300,218 200,246" fill="#ceeaff" stroke="#90bcd8" stroke-width="1.5"/>\x27;
3673
+ out += \x27<polygon points="200,178 300,152 300,159 200,185" fill="#a8d8f8" opacity=".6"/>\x27;
3674
+ out += \x27<line x1="200" y1="212" x2="300" y2="185" stroke="#90bcd8" stroke-width="1"/>\x27;
3675
+ out += \x27<line x1="250" y1="165" x2="250" y2="232" stroke="#90bcd8" stroke-width="1"/>\x27;
3676
+ out += \x27<polygon points="200,178 300,152 300,218 200,246" fill="rgba(180,220,255,.1)"/>\x27;
3677
+ // Window 3
3678
+ out += \x27<polygon points="340,126 440,100 440,166 340,192" fill="#ceeaff" stroke="#90bcd8" stroke-width="1.5"/>\x27;
3679
+ out += \x27<polygon points="340,126 440,100 440,107 340,133" fill="#a8d8f8" opacity=".6"/>\x27;
3680
+ out += \x27<line x1="340" y1="159" x2="440" y2="133" stroke="#90bcd8" stroke-width="1"/>\x27;
3681
+ out += \x27<line x1="390" y1="113" x2="390" y2="179" stroke="#90bcd8" stroke-width="1"/>\x27;
3682
+ out += \x27<polygon points="340,126 440,100 440,166 340,192" fill="rgba(180,220,255,.1)"/>\x27;
3683
+ // Sun shafts
3684
+ out += \x27<polygon points="80,300 160,272 190,540 110,560" fill="rgba(255,248,200,.07)"/>\x27;
3685
+ out += \x27<polygon points="215,246 300,218 320,540 235,560" fill="rgba(255,248,200,.06)"/>\x27;
3686
+ out += \x27<polygon points="352,192 440,166 455,540 367,560" fill="rgba(255,248,200,.05)"/>\x27;
3687
+
3688
+ // ── PAINTING on left wall (between W2 and W3) ────────────────────────
3689
+ out += \x27<polygon points="463,112 490,104 490,132 463,140" fill="#e8e2d8" stroke="#c0b090" stroke-width="1.5"/>\x27;
3690
+ out += \x27<polygon points="466,114 488,107 488,130 466,137" fill="#5080b0"/>\x27;
3691
+ out += \x27<polygon points="469,116 488,110 488,120 469,123" fill="#7aa0c8"/>\x27;
3692
+ out += \x27<ellipse cx="478" cy="120" rx="5" ry="4" fill="#fff" opacity=".35"/>\x27;
3693
+
3694
+ // ── PLANT right wall corner ─────────────────────────────────────────
3695
+ out += \x27<ellipse cx="920" cy="360" rx="14" ry="7" fill="#2d5018" opacity=".6"/>\x27;
3696
+ out += \x27<rect x="912" y="348" width="14" height="14" rx="3" fill="#7a4a20"/>\x27;
3697
+ out += \x27<path d="M919 348 C912 328 900 312 905 300 C910 290 919 300 919 348" fill="#3a8020"/>\x27;
3698
+ out += \x27<path d="M919 348 C926 328 938 315 933 302 C928 292 919 303 919 348" fill="#4a9228"/>\x27;
3699
+ out += \x27<path d="M919 342 C908 332 900 322 902 312" stroke="#3a8020" stroke-width="2.5" fill="none" stroke-linecap="round"/>\x27;
3700
+ out += \x27<path d="M919 336 C930 326 938 318 936 306" stroke="#4a9228" stroke-width="2.5" fill="none" stroke-linecap="round"/>\x27;
3701
+
3702
+ // ── CHANDELIER ────────────────────────────────────────────────────────
3703
+ out += \x27<line x1="500" y1="0" x2="500" y2="30" stroke="#aaa" stroke-width="3"/>\x27;
3704
+ out += \x27<ellipse cx="500" cy="30" rx="38" ry="11" fill="#d8c870" stroke="#b8a850" stroke-width="2"/>\x27;
3705
+ out += \x27<ellipse cx="500" cy="36" rx="30" ry="8" fill="#ece090"/>\x27;
3706
+ out += \x27<line x1="478" y1="36" x2="478" y2="46" stroke="#aaa" stroke-width="1.2"/>\x27;
3707
+ out += \x27<line x1="500" y1="36" x2="500" y2="42" stroke="#aaa" stroke-width="1.2"/>\x27;
3708
+ out += \x27<line x1="522" y1="36" x2="522" y2="46" stroke="#aaa" stroke-width="1.2"/>\x27;
3709
+ out += \x27<circle cx="478" cy="50" r="8" fill="#fffbe0" filter="url(#bGlow)"/>\x27;
3710
+ out += \x27<circle cx="500" cy="46" r="10" fill="#fffbe0" filter="url(#bGlow)"/>\x27;
3711
+ out += \x27<circle cx="522" cy="50" r="8" fill="#fffbe0" filter="url(#bGlow)"/>\x27;
3712
+ // Light glow on scene
3713
+ out += \x27<ellipse cx="500" cy="320" rx="360" ry="220" fill="url(#lampGlow)"/>\x27;
3714
+
3715
+ // ── PARQUET FLOOR ──────────────────────────────────────────────────────
3716
+ var plankCols = [\x27#c8924a\x27,\x27#b8823c\x27,\x27#d4a055\x27,\x27#be9248\x27,\x27#a87838\x27];
3710
3717
  for (var r2 = 0; r2 < rows; r2++) {
3711
3718
  for (var c2 = 0; c2 < cols; c2++) {
3712
3719
  var pp = isoProject(c2, r2);
3713
- var ptx = pp.x; var pty = pp.y + 110;
3714
- var pIdx = (r2 * 3 + c2) % plankColors.length;
3715
- var pFill = plankColors[pIdx];
3716
- var ppts = ptx+\x27,\x27+pty+\x27 \x27+(ptx+PLANK_W/2)+\x27,\x27+(pty+PLANK_H/2)+\x27 \x27+ptx+\x27,\x27+(pty+PLANK_H)+\x27 \x27+(ptx-PLANK_W/2)+\x27,\x27+(pty+PLANK_H/2);
3717
- out += \x27<polygon points="\x27+ppts+\x27" fill="\x27+pFill+\x27" stroke="#8a6028" stroke-width=".7" opacity=".95"/>\x27;
3718
- // Plank grain lines (long horizontal across plank)
3719
- out += \x27<line x1="\x27+(ptx-PLANK_W/2+4)+\x27" y1="\x27+(pty+PLANK_H/2)+\x27" x2="\x27+(ptx+PLANK_W/2-4)+\x27" y2="\x27+(pty+PLANK_H/2)+\x27" stroke="rgba(0,0,0,.06)" stroke-width=".5"/>\x27;
3720
+ var ptx = pp.x; var pty = pp.y + 120;
3721
+ var pFill = plankCols[(r2*3+c2) % plankCols.length];
3722
+ var ppts = ptx+\x27,\x27+pty+\x27 \x27+(ptx+ISO_TILE_W/2)+\x27,\x27+(pty+ISO_TILE_H/2)+\x27 \x27+ptx+\x27,\x27+(pty+ISO_TILE_H)+\x27 \x27+(ptx-ISO_TILE_W/2)+\x27,\x27+(pty+ISO_TILE_H/2);
3723
+ out += \x27<polygon points="\x27+ppts+\x27" fill="\x27+pFill+\x27" stroke="#906820" stroke-width=".8"/>\x27;
3724
+ // long grain line along the plank
3725
+ out += \x27<line x1="\x27+(ptx-ISO_TILE_W/2+5)+\x27" y1="\x27+(pty+ISO_TILE_H/2)+\x27" x2="\x27+(ptx+ISO_TILE_W/2-5)+\x27" y2="\x27+(pty+ISO_TILE_H/2)+\x27" stroke="rgba(0,0,0,.08)" stroke-width=".6"/>\x27;
3720
3726
  }
3721
3727
  }
3722
- // Floor highlight (lamp reflection)
3723
- out += \x27<ellipse cx="320" cy="220" rx="90" ry="30" fill="rgba(255,250,200,.08)"/>\x27;
3728
+ out += \x27<ellipse cx="500" cy="380" rx="120" ry="40" fill="rgba(255,248,200,.1)"/>\x27;
3724
3729
 
3725
3730
  out += \x27</svg>\x27;
3726
3731
  return out;
3727
3732
  }
3728
- // Small isometric desk object at iso position — bright wood
3733
+
3734
+ // Isometric desk — proper 3D look: flat top surface + two visible faces + monitor + keyboard
3729
3735
  function isoDeskSvg(x, y, accentColor) {
3730
3736
  var ac = accentColor || \x27#888\x27;
3731
- var doneDesk = ac === \x27#22c55e\x27;
3732
- return \x27<svg viewBox="0 0 72 44" width="72" height="44" xmlns="http://www.w3.org/2000/svg" style="position:absolute;left:\x27+(x-36)+\x27px;top:\x27+(y+8)+\x27px;z-index:\x27+(Math.round(y))+\x27;pointer-events:none">\x27+
3733
- // Desk top face warm wood
3734
- \x27<polygon points="36,4 62,18 36,32 10,18" fill="#d4a855" stroke="#b8893a" stroke-width="1"/>\x27+
3735
- \x27<polygon points="36,4 62,18 36,32 10,18" fill="rgba(255,255,255,.08)"/>\x27+
3736
- // Grain lines on top
3737
- \x27<line x1="22" y1="18" x2="50" y2="10" stroke="rgba(0,0,0,.1)" stroke-width=".8"/>\x27+
3738
- \x27<line x1="22" y1="22" x2="50" y2="14" stroke="rgba(0,0,0,.07)" stroke-width=".8"/>\x27+
3739
- // Desk right face
3740
- \x27<polygon points="62,18 62,36 36,50 36,32" fill="#a8783c" stroke="#8a5c28" stroke-width=".8"/>\x27+
3741
- // Desk left face
3742
- \x27<polygon points="10,18 36,32 36,50 10,36" fill="#c49050" stroke="#9e7234" stroke-width=".8"/>\x27+
3743
- // Monitor on desk light screen
3744
- \x27<polygon points="28,10 44,16 44,26 28,20" fill="#1e2840" stroke="\x27+ac+\x27" stroke-width="1.2"/>\x27+
3745
- \x27<polygon points="29,11 43,17 43,25 29,19" fill="\x27+(doneDesk?\x27#0d2010\x27:\x27#0d1a2e\x27)+\x27"/>\x27+
3746
- // Screen glow lines
3747
- \x27<line x1="31" y1="14" x2="41" y2="18" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".8"/>\x27+
3748
- \x27<line x1="31" y1="17" x2="40" y2="20" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".5"/>\x27+
3749
- \x27<line x1="31" y1="20" x2="39" y2="23" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".3"/>\x27+
3737
+ var isDone = ac === \x27#22c55e\x27;
3738
+ var isActive = ac === \x27#6366f1\x27;
3739
+ var screenFill = isDone ? \x27#0a2010\x27 : (isActive ? \x27#0d102a\x27 : \x27#111828\x27);
3740
+ var screenGlow = isDone ? \x27#22c55e\x27 : (isActive ? \x27#818cf8\x27 : \x27#4466aa\x27);
3741
+ // Desk is 90x56 viewBox — wide enough to look like a real desk
3742
+ return \x27<svg viewBox="0 0 90 56" width="90" height="56" xmlns="http://www.w3.org/2000/svg" style="position:absolute;left:\x27+(x-45)+\x27px;top:\x27+(y+4)+\x27px;z-index:\x27+(Math.round(y))+\x27;pointer-events:none">\x27+
3743
+ // ── DESK LEGS (4 corners, visible as small rectangles) ──
3744
+ \x27<rect x="14" y="42" width="5" height="10" rx="1" fill="#8a5c20"/>\x27+
3745
+ \x27<rect x="56" y="47" width="5" height="8" rx="1" fill="#8a5c20"/>\x27+
3746
+ \x27<rect x="70" y="40" width="5" height="8" rx="1" fill="#7a4e18"/>\x27+
3747
+ \x27<rect x="28" y="36" width="5" height="8" rx="1" fill="#7a4e18"/>\x27+
3748
+ // ── DESK TOP SURFACE (iso diamond) ──
3749
+ \x27<polygon points="45,4 78,21 45,38 12,21" fill="#d4a448" stroke="#b88830" stroke-width="1.2"/>\x27+
3750
+ // wood grain on top
3751
+ \x27<line x1="28" y1="21" x2="62" y2="12" stroke="rgba(0,0,0,.09)" stroke-width=".9"/>\x27+
3752
+ \x27<line x1="24" y1="26" x2="58" y2="17" stroke="rgba(0,0,0,.07)" stroke-width=".9"/>\x27+
3753
+ \x27<line x1="32" y1="17" x2="66" y2="8" stroke="rgba(0,0,0,.06)" stroke-width=".7"/>\x27+
3754
+ // shine
3755
+ \x27<polygon points="45,4 78,21 74,23 45,8 16,23 12,21" fill="rgba(255,255,255,.12)"/>\x27+
3756
+ // ── RIGHT FACE ──
3757
+ \x27<polygon points="78,21 78,36 45,53 45,38" fill="#a87028" stroke="#906018" stroke-width=".8"/>\x27+
3758
+ // ── LEFT FACE ──
3759
+ \x27<polygon points="12,21 45,38 45,53 12,36" fill="#c08838" stroke="#a07028" stroke-width=".8"/>\x27+
3760
+ // ── MONITOR — proper isometric screen ──
3761
+ // Stand
3762
+ \x27<polygon points="54,14 62,18 62,22 54,18" fill="#555" stroke="#333" stroke-width=".6"/>\x27+
3763
+ // Screen back
3764
+ \x27<polygon points="54,4 72,12 72,24 54,16" fill="#2a2a3a" stroke="#222" stroke-width=".8"/>\x27+
3765
+ // Screen front (bezel)
3766
+ \x27<polygon points="55,5 71,13 71,23 55,15" fill="#1a1a28"/>\x27+
3767
+ // Screen content
3768
+ \x27<polygon points="57,7 69,13 69,21 57,15" fill="\x27+screenFill+\x27"/>\x27+
3769
+ \x27<line x1="58" y1="10" x2="68" y2="14" stroke="\x27+screenGlow+\x27" stroke-width="1" opacity=".9"/>\x27+
3770
+ \x27<line x1="58" y1="13" x2="67" y2="17" stroke="\x27+screenGlow+\x27" stroke-width=".9" opacity=".6"/>\x27+
3771
+ \x27<line x1="58" y1="16" x2="66" y2="19" stroke="\x27+screenGlow+\x27" stroke-width=".8" opacity=".4"/>\x27+
3772
+ // ── KEYBOARD ──
3773
+ \x27<polygon points="24,25 44,32 40,36 20,29" fill="#ddd" stroke="#bbb" stroke-width=".6"/>\x27+
3774
+ \x27<line x1="24" y1="28" x2="44" y2="34" stroke="#aaa" stroke-width=".5"/>\x27+
3775
+ \x27<line x1="28" y1="26" x2="28" y2="30" stroke="#aaa" stroke-width=".4"/>\x27+
3776
+ \x27<line x1="33" y1="28" x2="33" y2="32" stroke="#aaa" stroke-width=".4"/>\x27+
3777
+ \x27<line x1="38" y1="30" x2="38" y2="34" stroke="#aaa" stroke-width=".4"/>\x27+
3778
+ // ── PAPERS on desk ──
3779
+ \x27<polygon points="14,24 28,29 25,34 11,29" fill="#f8f6ee" stroke="#ddd" stroke-width=".6" transform="rotate(-6 20 29)"/>\x27+
3780
+ \x27<polygon points="15,23 29,28 26,33 12,28" fill="#fff" stroke="#eee" stroke-width=".5" transform="rotate(-3 21 28)"/>\x27+
3750
3781
  \x27</svg>\x27;
3751
3782
  }
3752
3783
  // Isometric JRPG sprite character — top-down 3/4 perspective, Pokemon-style
3784
+ // Agent emojis — rotate through professional/diverse set
3785
+ var AGENT_EMOJIS = [
3786
+ String.fromCodePoint(0x1F9D1,0x200D,0x1F4BB), // person at laptop
3787
+ String.fromCodePoint(0x1F469,0x200D,0x1F4BC), // woman office worker
3788
+ String.fromCodePoint(0x1F468,0x200D,0x1F4BC), // man office worker
3789
+ String.fromCodePoint(0x1F9D1,0x200D,0x1F52C), // scientist
3790
+ String.fromCodePoint(0x1F469,0x200D,0x1F4BB), // woman technologist
3791
+ String.fromCodePoint(0x1F468,0x200D,0x1F4BB), // man technologist
3792
+ String.fromCodePoint(0x1F9D1,0x200D,0x1F3A8), // artist
3793
+ String.fromCodePoint(0x1F9D1,0x200D,0x2696,0xFE0F), // judge
3794
+ ];
3795
+
3753
3796
  function isoCharSvg(opts) {
3754
- var skin = opts.skin || \x27#fbbf24\x27;
3755
- var shirt = opts.shirt || \x27#4f46e5\x27;
3756
- var hair = opts.hair || \x27#1a0e08\x27;
3757
3797
  var isActive = opts.isActive;
3758
3798
  var isDone = opts.isDone;
3759
3799
  var scale = opts.scale || 1;
3760
- var glow = isActive ? (\x27filter:drop-shadow(0 0 6px \x27+(opts.accentColor||shirt)+\x27)\x27) : (isDone ? \x27filter:drop-shadow(0 0 4px #22c55e44)\x27 : \x27\x27);
3761
- var armCls = isActive ? \x27class="prl-arm"\x27 : \x27\x27;
3762
- var headCls = isActive ? \x27class="prl-head"\x27 : \x27\x27;
3763
- var w = Math.round(48 * scale); var h = Math.round(64 * scale);
3764
- return \x27<svg viewBox="0 0 48 64" width="\x27+w+\x27" height="\x27+h+\x27" xmlns="http://www.w3.org/2000/svg" style="\x27+glow+\x27;display:block;overflow:visible">\x27+
3765
- // Shadow beneath character
3766
- \x27<ellipse cx="24" cy="62" rx="\x27+(11*scale)+\x27" ry="\x27+(4*scale)+\x27" fill="rgba(0,0,0,.3)"/>\x27+
3767
- // Legs
3768
- \x27<path d="M18 42 C17 50 16 56 15 60 C14 62 17 63 19 62 C21 61 21 56 21 50 L21 42 Z" fill="\x27+shirt+\x27cc" class="prl-master-leg-l"/>\x27+
3769
- \x27<path d="M24 42 C25 50 26 56 27 60 C28 62 25 63 23 62 C21 61 21 56 21 50 L21 42 Z" fill="\x27+shirt+\x27cc" class="prl-master-leg-r"/>\x27+
3770
- // Shoes
3771
- \x27<ellipse cx="16" cy="62" rx="4" ry="2" fill="#1a0e04" transform="rotate(-10 16 62)"/>\x27+
3772
- \x27<ellipse cx="26" cy="62" rx="4" ry="2" fill="#1a0e04" transform="rotate(10 26 62)"/>\x27+
3773
- // Body
3774
- \x27<rect x="13" y="26" width="20" height="18" rx="3" fill="\x27+shirt+\x27"/>\x27+
3775
- \x27<rect x="13" y="26" width="10" height="18" rx="3" fill="rgba(0,0,0,.1)"/>\x27+
3776
- // Collar
3777
- \x27<path d="M21 26 L18 30 L21 28 L24 30 Z" fill="\x27+skin+\x27"/>\x27+
3778
- // Arms
3779
- \x27<g \x27+armCls+\x27>\x27+
3780
- \x27<path d="M13 28 C8 30 6 35 6 39 C6 42 9 43 11 42 C13 41 13 37 14 33 Z" fill="\x27+shirt+\x27"/>\x27+
3781
- \x27<ellipse cx="7" cy="41" rx="4" ry="3" fill="\x27+skin+\x27" transform="rotate(-15 7 41)"/>\x27+
3782
- \x27<path d="M33 28 C38 30 40 35 40 39 C40 42 37 43 35 42 C33 41 33 37 32 33 Z" fill="\x27+shirt+\x27"/>\x27+
3783
- \x27<ellipse cx="39" cy="41" rx="4" ry="3" fill="\x27+skin+\x27" transform="rotate(15 39 41)"/>\x27+
3784
- \x27</g>\x27+
3785
- // Head
3786
- \x27<g \x27+headCls+\x27>\x27+
3787
- \x27<ellipse cx="21" cy="13" rx="11" ry="12" fill="\x27+skin+\x27"/>\x27+
3788
- \x27<path d="M10 13 C10 6 14 1 21 0 C28 1 32 6 32 13 C31 7 28 4 21 3 C14 4 11 7 10 13" fill="\x27+hair+\x27"/>\x27+
3789
- \x27<circle cx="16" cy="14" r="1.5" fill="#0a0a14"/>\x27+
3790
- \x27<circle cx="26" cy="14" r="1.5" fill="#0a0a14"/>\x27+
3791
- \x27<circle cx="16.7" cy="13" r=".7" fill="rgba(255,255,255,.9)"/>\x27+
3792
- (isDone ?
3793
- \x27<path d="M15 20 Q21 24 27 20" stroke="#8b4513" stroke-width="1.5" fill="none" stroke-linecap="round"/>\x27+
3794
- \x27<path d="M16 20.5 Q21 23 26 20.5 Q21 22 16 20.5" fill="#fff" opacity=".6"/>\x27
3795
- : isActive ?
3796
- \x27<path d="M15 19 Q21 21 27 19" stroke="#8b4513" stroke-width="1.4" fill="none" stroke-linecap="round"/>\x27
3797
- :
3798
- \x27<path d="M16 20 Q21 22 26 20" stroke="#8b4513" stroke-width="1.2" fill="none" stroke-linecap="round"/>\x27
3799
- )+
3800
- \x27</g>\x27+
3801
- \x27</svg>\x27;
3800
+ var accentColor = opts.accentColor || \x27#6366f1\x27;
3801
+ var idx = opts.emojiIdx || 0;
3802
+ var emoji = AGENT_EMOJIS[idx % AGENT_EMOJIS.length];
3803
+ var sz = Math.round(52 * scale);
3804
+ var glowColor = isActive ? accentColor : (isDone ? \x27#22c55e\x27 : \x27transparent\x27);
3805
+ var glowFilter = (isActive || isDone) ? (\x27filter:drop-shadow(0 0 8px \x27+glowColor+\x27aa)\x27) : \x27\x27;
3806
+ var badgeHtml = isDone
3807
+ ? \x27<div style="position:absolute;top:-4px;right:-4px;width:18px;height:18px;background:#22c55e;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fff;box-shadow:0 0 6px #22c55e88">&#10003;</div>\x27
3808
+ : (isActive
3809
+ ? \x27<div style="position:absolute;top:-4px;right:-4px;width:14px;height:14px;background:\x27+accentColor+\x27;border-radius:50%;animation:statusPulse 1s ease-in-out infinite;box-shadow:0 0 8px \x27+accentColor+\x27"></div>\x27
3810
+ : \x27\x27);
3811
+ var ringStyle = isActive
3812
+ ? (\x27outline:2.5px solid \x27+accentColor+\x27;box-shadow:0 0 16px \x27+accentColor+\x27AA\x27)
3813
+ : (isDone ? \x27outline:2px solid #22c55e88\x27 : \x27outline:none\x27);
3814
+ var animClass = isActive ? \x27 prl-head\x27 : \x27\x27;
3815
+ return \x27<div class="iso-char-wrap\x27+animClass+\x27" style="position:relative;display:inline-flex;align-items:center;justify-content:center;width:\x27+sz+\x27px;height:\x27+sz+\x27px;border-radius:50%;background:rgba(255,255,255,.15);\x27+ringStyle+\x27;\x27+glowFilter+\x27;transition:all .3s">\x27+
3816
+ \x27<span style="font-size:\x27+Math.round(36*scale)+\x27px;line-height:1;user-select:none">\x27+emoji+\x27</span>\x27+
3817
+ badgeHtml+
3818
+ \x27</div>\x27;
3802
3819
  }
3803
- // Orchestrator — bigger, crowned, JRPG boss sprite
3820
+ // Orchestrator — emoji-based, crowned
3804
3821
  function isoOrchSvg(hasActive, doneRatio) {
3805
- var mc = \x27#818cf8\x27;
3806
- var armCls = hasActive ? \x27class="prl-master-arm-l"\x27 : \x27\x27;
3807
- var armRCls = hasActive ? \x27class="prl-master-arm-r"\x27 : \x27\x27;
3808
- return \x27<svg viewBox="0 0 60 80" width="58" height="76" xmlns="http://www.w3.org/2000/svg" style="display:block;overflow:visible;filter:drop-shadow(0 0 10px \x27+mc+\x27aa)">\x27+
3809
- // Shadow
3810
- \x27<ellipse cx="30" cy="78" rx="16" ry="5" fill="rgba(0,0,0,.4)"/>\x27+
3811
- // Legs
3812
- \x27<path d="M24 52 C23 60 22 67 21 72 C20 75 22 76 24 76 C26 76 27 74 27 71 C28 65 28 58 28 52 Z" fill="#1e1c4a" class="prl-master-leg-l"/>\x27+
3813
- \x27<path d="M30 52 C31 60 32 67 33 72 C34 75 32 76 30 76 C28 76 27 74 27 71 C26 65 26 58 26 52 Z" fill="#1e1c4a" class="prl-master-leg-r"/>\x27+
3814
- // Shoes
3815
- \x27<ellipse cx="20" cy="74" rx="5" ry="2.5" fill="#0a0a14" transform="rotate(-8 20 74)"/>\x27+
3816
- \x27<ellipse cx="34" cy="74" rx="5" ry="2.5" fill="#0a0a14" transform="rotate(8 34 74)"/>\x27+
3817
- // Suit body
3818
- \x27<path d="M14 32 C13 30 16 27 27 25 C38 27 41 30 40 32 L41 52 L13 52 Z" fill="#252464"/>\x27+
3819
- \x27<path d="M14 32 C13 30 16 27 27 25 L27 52 L13 52 Z" fill="#1e1d52"/>\x27+
3820
- \x27<path d="M27 25 C38 27 41 30 40 32 L41 52 L27 52 Z" fill="#2a2870"/>\x27+
3821
- // Lapels
3822
- \x27<path d="M27 25 L21 33 L24 36 L27 29 Z" fill="#1a1940"/>\x27+
3823
- \x27<path d="M27 25 L33 33 L30 36 L27 29 Z" fill="#1a1940"/>\x27+
3824
- \x27<path d="M27 29 L24 36 L27 34 L30 36 Z" fill="#f0f0fa"/>\x27+
3825
- // Tie
3826
- \x27<path d="M27 33 L26 44 L27 48 L28 44 Z" fill="\x27+mc+\x27"/>\x27+
3827
- // Arms
3828
- \x27<g \x27+armCls+\x27 style="transform-origin:14px 35px">\x27+
3829
- \x27<path d="M14 35 C8 38 5 44 5 48 C5 51 8 52 10 51 C12 50 13 46 14 42 C15 39 14 36 14 35" fill="#252450"/>\x27+
3830
- \x27<ellipse cx="6" cy="51" rx="5" ry="3.5" fill="#d4a97a" transform="rotate(-15 6 51)"/>\x27+
3831
- \x27</g>\x27+
3832
- \x27<g \x27+armRCls+\x27 style="transform-origin:40px 35px">\x27+
3833
- \x27<path d="M40 35 C46 38 49 43 49 47 C49 50 46 51 44 50 C42 49 41 45 40 41 C39 38 40 36 40 35" fill="#252450"/>\x27+
3834
- // Clipboard
3835
- \x27<rect x="46" y="30" width="12" height="16" rx="2" fill="#1a1a2e" stroke="\x27+mc+\x2799" stroke-width="1.2"/>\x27+
3836
- \x27<rect x="49" y="28" width="6" height="4" rx="1" fill="\x27+mc+\x27"/>\x27+
3837
- \x27<line x1="48" y1="34" x2="56" y2="34" stroke="\x27+mc+\x27cc" stroke-width=".9"/>\x27+
3838
- \x27<line x1="48" y1="37" x2="56" y2="37" stroke="\x27+mc+\x27aa" stroke-width=".9"/>\x27+
3839
- \x27<line x1="48" y1="40" x2="54" y2="40" stroke="\x27+mc+\x2788" stroke-width=".9"/>\x27+
3840
- \x27</g>\x27+
3841
- // Neck
3842
- \x27<rect x="24" y="25" width="6" height="5" rx="2" fill="#d4a97a"/>\x27+
3843
- // Head
3844
- \x27<ellipse cx="27" cy="14" rx="13" ry="13" fill="#d4a97a"/>\x27+
3845
- \x27<path d="M14 14 C14 20 18 24 27 25 C36 24 40 20 40 14" fill="#d4a97a"/>\x27+
3846
- // Hair
3847
- \x27<path d="M14 14 C13 7 17 2 27 1 C37 2 41 7 40 14 C39 7 35 4 27 3 C19 4 15 7 14 14" fill="#1a0e08"/>\x27+
3848
- // Eyes
3849
- \x27<ellipse cx="22" cy="15" rx="3" ry="3.5" fill="#fff"/>\x27+
3850
- \x27<ellipse cx="32" cy="15" rx="3" ry="3.5" fill="#fff"/>\x27+
3851
- \x27<circle cx="22" cy="15.5" r="2" fill="#1e3a6e"/>\x27+
3852
- \x27<circle cx="32" cy="15.5" r="2" fill="#1e3a6e"/>\x27+
3853
- \x27<circle cx="22" cy="15.5" r="1.2" fill="#0a0a18"/>\x27+
3854
- \x27<circle cx="32" cy="15.5" r="1.2" fill="#0a0a18"/>\x27+
3855
- \x27<circle cx="23" cy="14" r=".8" fill="rgba(255,255,255,.9)"/>\x27+
3856
- (hasActive ?
3857
- \x27<path d="M21 21 Q27 25 33 21" stroke="#8b4513" stroke-width="1.8" fill="none" stroke-linecap="round"/>\x27+
3858
- \x27<ellipse cx="27" cy="22.5" rx="3.5" ry="2" fill="#5a1a0a" opacity=".6"/>\x27
3859
- :
3860
- \x27<path d="M21 22 Q27 25 33 22" stroke="#8b4513" stroke-width="1.6" fill="none" stroke-linecap="round"/>\x27
3861
- )+
3862
- // Crown
3863
- \x27<path d="M17 4 L20 9 L27 6 L34 9 L37 4 L27 1 Z" fill="#f59e0b"/>\x27+
3864
- \x27<circle cx="20" cy="9" r="2" fill="#fbbf24"/>\x27+
3865
- \x27<circle cx="27" cy="6" r="2" fill="#fbbf24"/>\x27+
3866
- \x27<circle cx="34" cy="9" r="2" fill="#fbbf24"/>\x27+
3867
- \x27</svg>\x27;
3822
+ void doneRatio;
3823
+ var orchEmoji = String.fromCodePoint(0x1F9D1, 0x200D, 0x1F4BC); // person in suit
3824
+ var glowColor = hasActive ? \x27#818cf8\x27 : \x27#22c55e\x27;
3825
+ var animClass = hasActive ? \x27 prl-head\x27 : \x27\x27;
3826
+ var crown = String.fromCodePoint(0x1F451); // crown emoji above
3827
+ return \x27<div class="iso-orch-wrap\x27+animClass+\x27" style="position:relative;display:inline-flex;flex-direction:column;align-items:center;gap:2px">\x27+
3828
+ \x27<span style="font-size:18px;line-height:1">\x27+crown+\x27</span>\x27+
3829
+ \x27<div style="position:relative;display:flex;align-items:center;justify-content:center;width:68px;height:68px;border-radius:50%;background:rgba(99,102,241,.15);outline:3px solid \x27+glowColor+\x27;box-shadow:0 0 20px \x27+glowColor+\x27AA">\x27+
3830
+ \x27<span style="font-size:42px;line-height:1;user-select:none">\x27+orchEmoji+\x27</span>\x27+
3831
+ \x27</div>\x27+
3832
+ \x27</div>\x27;
3868
3833
  }
3869
3834
 
3870
3835
  // Skin/shirt/hair palette per agent label
@@ -3915,9 +3880,9 @@ function renderStudioNodes() {
3915
3880
  // Bubble: only show when active (live text) or done (checkmark)
3916
3881
  var bubbleText = isActive ? \x27...lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27));
3917
3882
  var bubbleColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : \x27#ef4444\x27);
3918
- var charSvg = isoCharSvg({skin: pal.skin, shirt: pal.shirt, hair: pal.hair,
3919
- isActive: isActive, isDone: isDone, scale: charScale, accentColor: accentColor});
3920
- var charW = Math.round(48 * charScale); var charH = Math.round(64 * charScale);
3883
+ void pal; // palette no longer used for character rendering
3884
+ var charSvg = isoCharSvg({emojiIdx: idx, isActive: isActive, isDone: isDone, scale: charScale, accentColor: accentColor});
3885
+ var charW = Math.round(52 * charScale); var charH = Math.round(52 * charScale);
3921
3886
 
3922
3887
  agentsHtml += \x27<div class="iso-agent" data-agent-label="\x27+esc(lbl)+\x27" style="position:absolute;left:\x27+(px-charW/2)+\x27px;top:\x27+(py-charH)+\x27px;z-index:\x27+zIdx+\x27;display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))">\x27;
3923
3888
  // Bubble — bigger, left-aligned (no mirror issue)
@@ -4438,8 +4403,9 @@ async function runStudio() {
4438
4403
  // Keep attachmentContext — it was loaded before hitting Run
4439
4404
  parlActiveAgent = null;
4440
4405
  parlDoneAgents = {};
4406
+ _parlPersistHtml = null; // clear persisted parliament for fresh run
4441
4407
  var parlBlockEl = document.getElementById('studioParliamentBlock');
4442
- if (parlBlockEl) parlBlockEl.style.display = 'none';
4408
+ if (parlBlockEl) { parlBlockEl.innerHTML = ''; parlBlockEl.style.display = 'none'; }
4443
4409
  renderStudioNodes();
4444
4410
  renderStudioLog();
4445
4411
  renderStudioResult();
@@ -4600,84 +4566,35 @@ async function runStudio() {
4600
4566
  if (!parlBlockBuilt || !pb.innerHTML.trim()) {
4601
4567
  parlBlockBuilt = true;
4602
4568
 
4603
- // Build agent seat HTML (box + avatar)
4604
- function buildSeat(prop) {
4569
+ // Build agent seat HTML (emoji avatar)
4570
+ function buildSeat(prop, seatIdx) {
4605
4571
  var lbl = prop.label || prop.agent;
4606
- var ico = prop.icon || String.fromCharCode(9632);
4607
- var skinColors = [\x27#fbbf24\x27,\x27#f97316\x27,\x27#a78bfa\x27,\x27#34d399\x27,\x27#60a5fa\x27,\x27#f472b6\x27];
4608
- var skinIdx = Math.abs(lbl.charCodeAt(0)+(lbl.charCodeAt(lbl.length-1)||0)) % skinColors.length;
4609
- var skin = skinColors[skinIdx];
4610
- var shirtC = [\x27#4f46e5\x27,\x27#0891b2\x27,\x27#7c3aed\x27,\x27#059669\x27,\x27#dc2626\x27,\x27#d97706\x27][skinIdx];
4611
- var safeLbl = lbl.replace(/[^a-zA-Z0-9_-]/g,\x27_\x27);
4612
- // Mini agent SVG (seated, top-down perspective hint)
4613
- var agentSvg = \x27<svg viewBox="0 0 44 52" width="44" height="52" xmlns="http://www.w3.org/2000/svg">\x27+
4614
- // Chair back
4615
- \x27<rect x="6" y="2" width="32" height="6" rx="3" fill="#2a2050" stroke="#3a3070" stroke-width="1"/>\x27+
4616
- // Chair seat
4617
- \x27<rect x="6" y="32" width="32" height="12" rx="3" fill="#221840" stroke="#3a3060" stroke-width="1"/>\x27+
4618
- // Body / torso
4619
- \x27<rect x="14" y="8" width="16" height="22" rx="4" fill="\x27+shirtC+\x27" opacity=".9"/>\x27+
4620
- // Head
4621
- \x27<circle cx="22" cy="5" r="7" fill="\x27+skin+\x27"/>\x27+
4622
- // Eyes
4623
- \x27<circle cx="19.5" cy="4.5" r="1.2" fill="#0a0a14"/>\x27+
4624
- \x27<circle cx="24.5" cy="4.5" r="1.2" fill="#0a0a14"/>\x27+
4625
- // Arms on desk
4626
- \x27<rect x="7" y="26" width="9" height="5" rx="2" fill="\x27+skin+\x27" class="br-arm-l"/>\x27+
4627
- \x27<rect x="28" y="26" width="9" height="5" rx="2" fill="\x27+skin+\x27" class="br-arm-r"/>\x27+
4628
- // Monitor on desk in front of agent
4629
- \x27<rect x="12" y="37" width="20" height="13" rx="2" fill="#141028" stroke="#3a3070" stroke-width="1"/>\x27+
4630
- \x27<rect x="13" y="38" width="18" height="11" rx="1" fill="rgba(90,80,180,.35)"/>\x27+
4631
- \x27<line x1="14" y1="41" x2="30" y2="41" stroke="#9090cc" stroke-width=".8" opacity=".8"/>\x27+
4632
- \x27<line x1="14" y1="44" x2="28" y2="44" stroke="#7070aa" stroke-width=".8" opacity=".6"/>\x27+
4633
- // Agent badge
4634
- \x27<circle cx="22" cy="13" r="5" fill="#0f0f1e" stroke="\x27+shirtC+\x2780" stroke-width="1.2"/>\x27+
4635
- \x27<text x="22" y="16" text-anchor="middle" font-size="6" font-family="system-ui">\x27+ico+\x27</text>\x27+
4636
- \x27</svg>\x27;
4572
+ var safeLbl = lbl.replace(new RegExp('[^a-zA-Z0-9_-]','g'),\x27_\x27);
4573
+ var emojiIdx = Math.abs(lbl.charCodeAt(0)+(lbl.charCodeAt(lbl.length-1)||0)) % AGENT_EMOJIS.length;
4574
+ var agentEmoji = AGENT_EMOJIS[emojiIdx];
4575
+ void seatIdx;
4576
+ var agentAvatar = \x27<div style="font-size:36px;line-height:1;user-select:none;filter:drop-shadow(0 2px 4px rgba(0,0,0,.3))">\x27+agentEmoji+\x27</div>\x27;
4637
4577
  return \x27<div class="br-seat" id="brseat_\x27+safeLbl+\x27" data-lbl="\x27+esc(lbl)+\x27">\x27+
4638
4578
  \x27<div class="br-seat-box">\x27+
4639
4579
  \x27<div class="br-bubble" id="brbubble_\x27+safeLbl+\x27"></div>\x27+
4640
- agentSvg+
4580
+ agentAvatar+
4641
4581
  \x27<div class="br-seat-name" id="brname_\x27+safeLbl+\x27">\x27+esc(lbl)+\x27</div>\x27+
4642
4582
  \x27</div>\x27+
4643
4583
  \x27</div>\x27;
4644
4584
  }
4645
4585
 
4646
4586
  // Arrange seats in a circle around center table
4647
- // Positions computed from CSS: use CSS custom properties per seat index
4648
4587
  var seatsHtml = proposals.map(buildSeat).join(\x27\x27);
4649
4588
 
4650
- // Orchestrator at center (standing, prominent)
4651
- var orchSvg = \x27<svg viewBox="0 0 54 70" width="54" height="70" xmlns="http://www.w3.org/2000/svg" font-family="system-ui,sans-serif">\x27+
4652
- // Legs
4653
- \x27<path d="M20 45 C19 54 18 62 17 66 C16 68 18 69 20 69 C22 69 23 68 23 65 C24 59 24 52 25 45 Z" fill="#252460"/>\x27+
4654
- \x27<path d="M27 45 C28 54 29 62 30 66 C31 68 29 69 27 69 C25 69 24 68 24 65 C23 59 23 52 22 45 Z" fill="#252460"/>\x27+
4655
- // Suit
4656
- \x27<path d="M11 26 C10 24 13 21 22 19 C31 21 34 24 33 26 L34 45 L10 45 Z" fill="#252464"/>\x27+
4657
- \x27<path d="M11 26 C10 24 13 21 22 19 L22 45 L10 45 Z" fill="#1e1d52"/>\x27+
4658
- \x27<path d="M22 19 C31 21 34 24 33 26 L34 45 L22 45 Z" fill="#2a2870"/>\x27+
4659
- // Tie
4660
- \x27<path d="M22 22 L21 36 L22 40 L23 36 Z" fill="#818cf8"/>\x27+
4661
- // Arms gesturing (spread wide — presenting)
4662
- \x27<path d="M10 28 C4 30 1 36 2 41 C3 44 6 44 8 42 C10 40 11 36 12 32 C13 30 11 27 10 28" fill="#252464" class="br-orch-arm-l"/>\x27+
4663
- \x27<path d="M34 28 C40 30 43 36 42 41 C41 44 38 44 36 42 C34 40 33 36 32 32 C31 30 33 27 34 28" fill="#252464" class="br-orch-arm-r"/>\x27+
4664
- // Head
4665
- \x27<circle cx="22" cy="13" r="9" fill="#fbbf24"/>\x27+
4666
- \x27<circle cx="19" cy="12" r="1.5" fill="#0a0a14"/>\x27+
4667
- \x27<circle cx="25" cy="12" r="1.5" fill="#0a0a14"/>\x27+
4668
- \x27<circle cx="20" cy="11" r=".6" fill="rgba(255,255,255,.8)"/>\x27+
4669
- \x27<circle cx="26" cy="11" r=".6" fill="rgba(255,255,255,.8)"/>\x27+
4670
- // Mouth — speaking
4671
- \x27<path d="M18 16 Q22 20 26 16" stroke="#8b4513" stroke-width="1.6" fill="none" stroke-linecap="round"/>\x27+
4672
- // NHA badge
4673
- \x27<circle cx="16" cy="30" r="3" fill="#0d0d1e" stroke="#818cf888" stroke-width="1"/>\x27+
4674
- \x27<text x="16" y="32.5" text-anchor="middle" font-size="3.5" fill="#818cf8">N</text>\x27+
4675
- // Crown / authority marker
4676
- \x27<path d="M15 3 L17 8 L22 5 L27 8 L29 3 L22 0 Z" fill="#f59e0b"/>\x27+
4677
- \x27<circle cx="17" cy="8" r="1.5" fill="#fbbf24"/>\x27+
4678
- \x27<circle cx="22" cy="5" r="1.5" fill="#fbbf24"/>\x27+
4679
- \x27<circle cx="27" cy="8" r="1.5" fill="#fbbf24"/>\x27+
4680
- \x27</svg>\x27;
4589
+ // Orchestrator at center — emoji (crowned suit)
4590
+ var orchEmoji = String.fromCodePoint(0x1F9D1,0x200D,0x1F4BC);
4591
+ var crownEmoji = String.fromCodePoint(0x1F451);
4592
+ var orchSvgEl = crownEmoji; // crown above orchestrator emoji not SVG anymore
4593
+ var orchSvg = \x27<div style="display:flex;flex-direction:column;align-items:center;gap:2px">\x27+
4594
+ \x27<span style="font-size:22px;line-height:1">\x27+crownEmoji+\x27</span>\x27+
4595
+ \x27<div style="font-size:52px;line-height:1;filter:drop-shadow(0 0 12px #818cf8AA);user-select:none">\x27+orchEmoji+\x27</div>\x27+
4596
+ \x27</div>\x27;
4597
+ void orchSvgEl;
4681
4598
 
4682
4599
  // Center table (SVG oval)
4683
4600
  var tableSvg = \x27<svg viewBox="0 0 160 80" width="160" height="80" xmlns="http://www.w3.org/2000/svg">\x27+
@@ -5248,6 +5165,9 @@ async function runStudio() {
5248
5165
  flyingDocHtml += \x27</div>\x27;
5249
5166
  }
5250
5167
 
5168
+ // Persist across tab navigations (snapshot — animations won\x27t replay but structure is preserved)
5169
+ if (pb.innerHTML && pb.innerHTML.length < 60000) { _parlPersistHtml = pb.innerHTML; }
5170
+
5251
5171
  }
5252
5172
 
5253
5173
  // Show initial R1 block and scroll into view
@@ -5414,6 +5334,7 @@ async function runStudio() {
5414
5334
  }
5415
5335
  }
5416
5336
  if (parlFinal && parlFinal.style.display !== 'none' && parlFinal.innerHTML) {
5337
+ _parlPersistHtml = parlFinal.innerHTML; // persist so tab nav doesn't lose it
5417
5338
  doScroll(parlFinal);
5418
5339
  setTimeout(function(){ doScroll(resEl); }, 2200);
5419
5340
  } else if (resEl) {
@@ -5785,6 +5706,12 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
5785
5706
  }
5786
5707
 
5787
5708
  function renderStudio(el) {
5709
+ // Persist parliament block across tab navigations
5710
+ var existingParl = document.getElementById('studioParliamentBlock');
5711
+ if (existingParl && existingParl.innerHTML.trim()) {
5712
+ _parlPersistHtml = existingParl.innerHTML;
5713
+ }
5714
+
5788
5715
  var examplesHtml = STUDIO_EXAMPLES.map(function(ex) {
5789
5716
  return '<button class="studio-example-btn" onclick="document.getElementById(\\'studioTaskInput\\').value=' + JSON.stringify(ex) + '">' + esc(ex.slice(0, 52)) + (ex.length > 52 ? '...' : '') + '</button>';
5790
5717
  }).join('');
@@ -5930,16 +5857,18 @@ function renderStudio(el) {
5930
5857
  '</div>' +
5931
5858
 
5932
5859
  // ── AGENT SIDEBAR ──
5933
- '<div class="studio-tools-panel">' +
5934
- // Tab bar
5935
- '<div style="display:flex;gap:0;margin-bottom:10px;border:1px solid var(--border);border-radius:6px;overflow:hidden">' +
5936
- '<button id="sideTabTools" onclick="studioSideTab(\\x27tools\\x27)" style="flex:1;padding:5px;font-size:10px;font-weight:600;background:var(--green3);color:#fff;border:none;cursor:pointer">&#128295; Tools</button>' +
5937
- '<button id="sideTabAgents" onclick="studioSideTab(\\x27agents\\x27)" style="flex:1;padding:5px;font-size:10px;font-weight:600;background:var(--bg3);color:var(--dim);border:none;cursor:pointer">&#129302; Agents</button>' +
5860
+ '<div style="display:flex;flex-direction:column;gap:12px;width:220px;flex-shrink:0;position:sticky;top:16px;align-self:flex-start">' +
5861
+ '<div class="studio-tools-panel">' +
5862
+ // Tab bar
5863
+ '<div style="display:flex;gap:0;margin-bottom:10px;border:1px solid var(--border);border-radius:6px;overflow:hidden">' +
5864
+ '<button id="sideTabTools" onclick="studioSideTab(\\x27tools\\x27)" style="flex:1;padding:5px;font-size:10px;font-weight:600;background:var(--green3);color:#fff;border:none;cursor:pointer">&#128295; Tools</button>' +
5865
+ '<button id="sideTabAgents" onclick="studioSideTab(\\x27agents\\x27)" style="flex:1;padding:5px;font-size:10px;font-weight:600;background:var(--bg3);color:var(--dim);border:none;cursor:pointer">&#129302; Agents</button>' +
5866
+ '</div>' +
5867
+ '<div style="font-size:9px;color:var(--dim);margin-bottom:8px">Click to add to pipeline</div>' +
5868
+ '<div id="sideToolsList">'+toolsHtml+'</div>' +
5869
+ '<div id="sideAgentsList" style="display:none">'+specialistHtml+'</div>' +
5938
5870
  '</div>' +
5939
- '<div style="font-size:9px;color:var(--dim);margin-bottom:8px">Click to add to pipeline</div>' +
5940
- '<div id="sideToolsList">'+toolsHtml+'</div>' +
5941
- '<div id="sideAgentsList" style="display:none">'+specialistHtml+'</div>' +
5942
- '<div id="studioSessionsBar" style="margin-top:16px;display:none"></div>' +
5871
+ '<div id="studioSessionsBar" style="display:none;border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg2)"></div>' +
5943
5872
  '</div>' +
5944
5873
  '</div>';
5945
5874
 
@@ -5947,9 +5876,18 @@ function renderStudio(el) {
5947
5876
  renderStudioLog();
5948
5877
  renderStudioResult();
5949
5878
  renderStudioSessionsBar();
5950
- studioTokens = {in:0,out:0};
5879
+ // Restore token bar (preserve counts across re-renders)
5880
+ studioUpdateTokenBar();
5951
5881
  // Restore pipeline from state
5952
5882
  renderBuilderPipeline();
5883
+ // Restore parliament block if it was visible before tab navigation
5884
+ if (_parlPersistHtml) {
5885
+ var parlRestoreEl = document.getElementById('studioParliamentBlock');
5886
+ if (parlRestoreEl) {
5887
+ parlRestoreEl.innerHTML = _parlPersistHtml;
5888
+ parlRestoreEl.style.display = 'block';
5889
+ }
5890
+ }
5953
5891
  }
5954
5892
 
5955
5893
  // ---- STUDIO SIDEBAR TAB ----
@@ -6601,13 +6539,18 @@ input:focus,textarea:focus{border-color:var(--green3)}
6601
6539
  @keyframes statusPulse{0%,100%{opacity:.7;border-color:rgba(99,102,241,.3)}50%{opacity:1;border-color:rgba(99,102,241,.7);box-shadow:0 0 8px rgba(99,102,241,.3)}}
6602
6540
  .iso-status-dot{width:6px;height:6px;border-radius:50%;background:#6366f1;animation:dotBounce 1s ease-in-out infinite}
6603
6541
  .iso-agent{transition:filter .3s}
6604
- .iso-agent:hover{filter:brightness(1.15)}
6542
+ .iso-agent:hover{filter:brightness(1.1) saturate(1.2)}
6543
+ .iso-char-wrap{transition:transform .2s,box-shadow .3s}
6544
+ .iso-char-wrap.prl-head{animation:isoCharBob 1.2s ease-in-out infinite}
6545
+ @keyframes isoCharBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
6546
+ .iso-orch-wrap{transition:transform .2s}
6547
+ .iso-orch-wrap.prl-head{animation:isoCharBob 1.4s ease-in-out infinite}
6605
6548
  /* Thought bubble / speech bubble above character */
6606
6549
  .iso-bubble{font-size:8px;font-family:var(--mono);padding:2px 7px;border-radius:10px 10px 10px 2px;border:1px solid #3a3060;background:rgba(10,8,20,.85);color:#6b7280;white-space:nowrap;max-width:110px;overflow:hidden;text-overflow:ellipsis;line-height:1.4;transition:all .25s;pointer-events:none;backdrop-filter:blur(4px)}
6607
6550
  .iso-bubble--active{background:rgba(30,20,60,.9);border-color:#6366f1;color:#a5b4fc;animation:isoBubblePop .35s ease;white-space:normal;max-width:110px;word-break:break-word;line-height:1.35}
6608
6551
  .iso-bubble--orch{font-size:9px;padding:3px 9px;border-radius:12px;border-color:#818cf8;color:#a5b4fc;background:rgba(20,15,50,.9)}
6609
6552
  @keyframes isoBubblePop{0%{transform:scale(.8) translateY(4px);opacity:.4}100%{transform:scale(1) translateY(0);opacity:1}}
6610
- .iso-name{font-size:8px;font-family:var(--mono);font-weight:700;letter-spacing:.3px;text-align:center;max-width:80px;white-space:normal;word-break:break-word;line-height:1.3;text-shadow:0 1px 4px rgba(0,0,0,.8);pointer-events:none}
6553
+ .iso-name{font-size:10px;font-family:var(--mono);font-weight:700;letter-spacing:.3px;text-align:center;max-width:90px;white-space:normal;word-break:break-word;line-height:1.3;background:rgba(255,255,255,.85);border-radius:6px;padding:2px 6px;pointer-events:none;backdrop-filter:blur(4px)}
6611
6554
  /* Desks row — kept for boardroom compat */
6612
6555
  .prl-desks-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;position:relative;z-index:2;padding-bottom:8px}
6613
6556
  .prl-desk{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 6px 4px;border-radius:12px;background:#1a1535;border:1.5px solid #3a3060;transition:border-color .4s,background .4s,box-shadow .4s;position:relative;min-width:80px;box-shadow:0 2px 8px rgba(0,0,0,.3),inset 0 1px 0 rgba(255,255,255,.06)}
@@ -6683,7 +6626,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
6683
6626
  .studio-result__body{font-size:13px;color:var(--text);word-wrap:break-word;line-height:1.7}
6684
6627
  .studio-example-btn{display:inline-block;padding:5px 12px;border:1px solid var(--border2);border-radius:20px;font-size:10px;color:var(--dim);cursor:pointer;background:none;margin:0 4px 6px 0;transition:all .15s}
6685
6628
  .studio-example-btn:hover{border-color:var(--green3);color:var(--green);background:var(--greendim)}
6686
- .studio-tools-panel{width:220px;flex-shrink:0;border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg2);max-height:calc(100vh - 120px);overflow-y:auto;position:sticky;top:16px}
6629
+ .studio-tools-panel{width:100%;border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg2);max-height:calc(100vh - 200px);overflow-y:auto}
6687
6630
  .studio-tool-item{display:flex;align-items:flex-start;gap:8px;padding:8px;border-radius:6px;cursor:pointer;transition:background .15s;margin-bottom:4px}
6688
6631
  .studio-tool-item:hover{background:var(--bg3);border-radius:6px}
6689
6632
  .studio-tool-icon{font-size:16px;flex-shrink:0;margin-top:1px}