nothumanallowed 13.5.0 → 13.5.2

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.0",
3
+ "version": "13.5.2",
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.0';
8
+ export const VERSION = '13.5.2';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3465,11 +3465,11 @@ function buildWorkflowChar(n) {
3465
3465
  \x27<line x1="22" y1="41" x2="43" y2="41" stroke="#22c55e44" stroke-width="1" stroke-linecap="round"/>\x27
3466
3466
  :
3467
3467
  // Idle: dim standby screen — agent is waiting, screen lit but quiet
3468
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(63,63,120,.18)"/>\x27+
3469
- \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".7"/>\x27+
3470
- \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
3471
- \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
3472
- \x27<line x1="22" y1="42" x2="34" y2="42" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".3"/>\x27+
3468
+ \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(90,80,180,.35)"/>\x27+
3469
+ \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#9090cc" stroke-width="1" stroke-linecap="round" opacity=".8"/>\x27+
3470
+ \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#8080bb" stroke-width="1" stroke-linecap="round" opacity=".65"/>\x27+
3471
+ \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#7070aa" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
3472
+ \x27<line x1="22" y1="42" x2="34" y2="42" stroke="#6060a0" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
3473
3473
  // Standby dot — blinking cursor
3474
3474
  \x27<circle cx="22" cy="45" r="1" fill="#6366f1" opacity=".6" class="prl-doc-hold"/>\x27
3475
3475
  )+
@@ -3556,6 +3556,55 @@ function buildWorkflowChar(n) {
3556
3556
  return svg;
3557
3557
  }
3558
3558
 
3559
+ // ── Office room decorations — window, wall art, plants, lamp ──────────────────
3560
+ // Used in both workflow and parliament office blocks.
3561
+ function officeRoomDecor() {
3562
+ // SVG plant: pot + soil + stem + leaves (monstera-ish)
3563
+ var plantSvg = \x27<svg viewBox="0 0 20 36" width="20" height="36" xmlns="http://www.w3.org/2000/svg">\x27+
3564
+ // Pot
3565
+ \x27<path d="M4 27 L6 34 L14 34 L16 27 Z" fill="#2a1a0a" stroke="#3d2810" stroke-width=".8"/>\x27+
3566
+ // Pot rim
3567
+ \x27<rect x="3" y="25" width="14" height="3" rx="1.5" fill="#3d2810" stroke="#4d3215" stroke-width=".5"/>\x27+
3568
+ // Soil
3569
+ \x27<ellipse cx="10" cy="26.5" rx="6" ry="1.5" fill="#1a0f05"/>\x27+
3570
+ // Main stem
3571
+ \x27<path d="M10 25 C10 20 9 14 10 8" stroke="#1a4a10" stroke-width="1.2" fill="none" stroke-linecap="round"/>\x27+
3572
+ // Left leaf
3573
+ \x27<path d="M10 18 C6 14 3 15 4 19 C5 22 9 21 10 18" fill="#166534" opacity=".9"/>\x27+
3574
+ \x27<path d="M10 18 C7.5 16.5 6 17.5 7 19" stroke="#14532d" stroke-width=".5" fill="none"/>\x27+
3575
+ // Right leaf
3576
+ \x27<path d="M10 13 C14 9 17 10 16 14 C15 17 11 16 10 13" fill="#15803d" opacity=".9"/>\x27+
3577
+ \x27<path d="M10 13 C12.5 11.5 14 12.5 13 14" stroke="#14532d" stroke-width=".5" fill="none"/>\x27+
3578
+ // Top leaf
3579
+ \x27<path d="M10 8 C8 4 5 5 6 8 C7 11 10 10 10 8" fill="#166534" opacity=".85"/>\x27+
3580
+ \x27</svg>\x27;
3581
+ // Second plant (taller, cactus-ish)
3582
+ var plant2Svg = \x27<svg viewBox="0 0 20 36" width="20" height="36" xmlns="http://www.w3.org/2000/svg">\x27+
3583
+ // Pot
3584
+ \x27<path d="M4 27 L6 34 L14 34 L16 27 Z" fill="#2a1a0a" stroke="#3d2810" stroke-width=".8"/>\x27+
3585
+ \x27<rect x="3" y="25" width="14" height="3" rx="1.5" fill="#3d2810" stroke="#4d3215" stroke-width=".5"/>\x27+
3586
+ \x27<ellipse cx="10" cy="26.5" rx="6" ry="1.5" fill="#1a0f05"/>\x27+
3587
+ // Main trunk (cactus)
3588
+ \x27<path d="M9 25 L9 10 Q9 8 10 8 Q11 8 11 10 L11 25 Z" fill="#1a5c18" stroke="#145214" stroke-width=".5"/>\x27+
3589
+ // Left arm
3590
+ \x27<path d="M9 16 C5 16 4 14 4 12 Q4 10 6 10 L9 10" fill="#166534" stroke="#145214" stroke-width=".5"/>\x27+
3591
+ // Right arm
3592
+ \x27<path d="M11 19 C15 19 16 17 16 15 Q16 13 14 13 L11 13" fill="#15803d" stroke="#145214" stroke-width=".5"/>\x27+
3593
+ // Spines
3594
+ \x27<line x1="10" y1="20" x2="12" y2="19" stroke="#4ade80" stroke-width=".6" opacity=".4"/>\x27+
3595
+ \x27<line x1="10" y1="14" x2="8" y2="13" stroke="#4ade80" stroke-width=".6" opacity=".4"/>\x27+
3596
+ \x27</svg>\x27;
3597
+ return \x27<div class="prl-office-window"></div>\x27+
3598
+ \x27<div class="prl-office-window-light"></div>\x27+
3599
+ \x27<div class="prl-office-frame"></div>\x27+
3600
+ \x27<div class="prl-office-frame2"></div>\x27+
3601
+ \x27<div class="prl-office-poster"></div>\x27+
3602
+ \x27<div class="prl-office-lamp"></div>\x27+
3603
+ \x27<div class="prl-office-lamp2"></div>\x27+
3604
+ \x27<div class="prl-office-plant">\x27+plantSvg+\x27</div>\x27+
3605
+ \x27<div class="prl-office-plant2">\x27+plant2Svg+\x27</div>\x27;
3606
+ }
3607
+
3559
3608
  function renderStudioNodes() {
3560
3609
  var el = document.getElementById('studioNodes');
3561
3610
  if (!el) return;
@@ -3668,17 +3717,17 @@ function renderStudioNodes() {
3668
3717
  ? (\x27<div class="wf-sbraita-bubble">\x27+sbraitaText+\x27</div>\x27)
3669
3718
  : \x27\x27;
3670
3719
 
3720
+ // Phase label
3721
+ var doneCount = studioState.nodes.filter(function(n){return n.status===\x27done\x27;}).length;
3722
+ var totalCount = studioState.nodes.length;
3723
+ var wfMasterAnim = hasActive ? \x27prl-master-walk\x27 : (doneCount===totalCount && totalCount>0 ? \x27prl-master-done\x27 : \x27prl-master-walk\x27);
3671
3724
  var masterWfHtml = showMaster ? (
3672
- \x27<div class="prl-master prl-master-walk wf-master" style="bottom:20px">\x27+
3725
+ \x27<div class="prl-master \x27+wfMasterAnim+\x27 wf-master" style="bottom:20px">\x27+
3673
3726
  bubbleHtml+
3674
3727
  masterSvg2+
3675
3728
  \x27<div class="prl-master-label" style="color:\x27+masterColor3+\x27;font-size:8px">Orchestratore</div>\x27+
3676
3729
  \x27</div>\x27
3677
3730
  ) : \x27\x27;
3678
-
3679
- // Phase label
3680
- var doneCount = studioState.nodes.filter(function(n){return n.status===\x27done\x27;}).length;
3681
- var totalCount = studioState.nodes.length;
3682
3731
  var phaseLabel2 = hasActive
3683
3732
  ? (\x27Workflow in esecuzione \u2014 \x27+doneCount+\x27/\x27+totalCount+\x27 completati\x27)
3684
3733
  : (doneCount===totalCount && totalCount>0 ? \x27Workflow completato\x27 : \x27Workflow pianificato\x27);
@@ -3687,8 +3736,9 @@ function renderStudioNodes() {
3687
3736
  var html = \x27<div class="prl-wrap" style="border-color:\x27+phaseColor2+\x2744;padding-bottom:16px">\x27+
3688
3737
  \x27<div class="prl-header"><span class="prl-phase-chip" style="--pc:\x27+phaseColor2+\x27">\x27+phaseLabel2+\x27</span></div>\x27+
3689
3738
  \x27<div class="prl-office wf-office" style="min-height:160px">\x27+
3739
+ officeRoomDecor()+
3690
3740
  \x27<div class="prl-office-floor"></div>\x27+
3691
- \x27<div class="prl-desks-row" style="justify-content:center;flex-wrap:wrap;gap:10px;padding-bottom:8px">\x27+desksHtml2+\x27</div>\x27+
3741
+ \x27<div class="prl-desks-row" style="justify-content:center;flex-wrap:wrap;gap:10px;padding-bottom:8px;position:relative;z-index:2">\x27+desksHtml2+\x27</div>\x27+
3692
3742
  masterWfHtml+
3693
3743
  \x27</div>\x27+
3694
3744
  \x27</div>\x27;
@@ -4028,53 +4078,59 @@ function downloadStudioPDF() {
4028
4078
  '</div>' +
4029
4079
  '</body></html>';
4030
4080
 
4031
- // ── Generate PDF via browser native print dialog ──────────────────────────
4032
- // Renders the full NHA report HTML in a hidden iframe, waits for Chart.js to
4033
- // initialize all charts, then calls window.print() on the iframe.
4034
- // The CSS @media print block (already in NHA_CSS) handles all styling:
4035
- // - Light backgrounds for readability on paper
4036
- // - break-inside:avoid on .section/.card/.priority-item/.data-table
4037
- // - -webkit-print-color-adjust:exact for gradient headers and charts
4038
- // This approach never cuts text in the middle of a paragraph.
4081
+ // ── Generate PDF via hidden in-page iframe ─────────────────────────────────
4082
+ // Uses a hidden iframe instead of window.open() to avoid popup blockers.
4083
+ // The iframe loads the full report HTML (with Chart.js), waits for charts to
4084
+ // render, then calls contentWindow.print() browser handles all page breaks
4085
+ // via the @media print block already in NHA_CSS (break-inside:avoid, etc.)
4086
+ // User gets the native "Save as PDF" dialog from the browser print dialog.
4039
4087
  function doGeneratePdf() {
4040
4088
  var btn2 = document.getElementById('studioInlinePdfBtn');
4041
4089
  var dlBtn2 = document.querySelector('button[onclick="downloadStudioPDF()"]');
4042
4090
  function setBusy(b) {
4043
- if (btn2) { btn2.disabled = b; btn2.textContent = b ? 'Apertura stampa...' : '\u2913 PDF'; }
4044
- if (dlBtn2) { dlBtn2.disabled = b; dlBtn2.textContent = b ? 'Apertura stampa...' : '\u2913 Download PDF'; }
4091
+ if (btn2) { btn2.disabled = b; btn2.textContent = b ? 'Generando PDF...' : '\u2913 PDF'; }
4092
+ if (dlBtn2) { dlBtn2.disabled = b; dlBtn2.textContent = b ? 'Generando PDF...' : '\u2913 Download PDF'; }
4045
4093
  }
4046
4094
  setBusy(true);
4047
4095
 
4048
- // Open report in a new browser window and trigger print dialog.
4049
- // The browser handles all page-break logic natively — no rasterization,
4050
- // no text-cut artifacts. Charts render as vectors via Chart.js.
4051
- // The @media print CSS block (in NHA_CSS) handles light-mode override.
4052
- var printWin = window.open('', '_blank', 'width=900,height=700');
4053
- if (!printWin) {
4054
- // Popup blocked — fallback: open in current tab print
4055
- setBusy(false);
4056
- var fb = window.open(URL.createObjectURL(new Blob([html], {type:'text/html'})), '_blank');
4057
- if (fb) { setTimeout(function(){ fb.print(); }, 1500); }
4058
- return;
4059
- }
4060
- printWin.document.open();
4061
- printWin.document.write(html);
4062
- printWin.document.close();
4063
- // Wait for Chart.js to render all charts before printing
4064
- // (charts need ~500ms after DOMContentLoaded for animation frame)
4065
- printWin.onload = function() {
4096
+ // Remove any previous print iframe
4097
+ var oldIframe = document.getElementById('nhaPrintFrame');
4098
+ if (oldIframe) oldIframe.remove();
4099
+
4100
+ var iframe = document.createElement('iframe');
4101
+ iframe.id = 'nhaPrintFrame';
4102
+ iframe.style.cssText = 'position:fixed;top:-9999px;left:-9999px;width:900px;height:700px;border:none;opacity:0;pointer-events:none';
4103
+
4104
+ // Set up onload BEFORE appending — avoids WebKit race condition
4105
+ iframe.onload = function() {
4106
+ // Wait for Chart.js to initialize all charts (needs ~800ms for animation frames)
4066
4107
  setTimeout(function() {
4067
- printWin.focus();
4068
- printWin.print();
4108
+ try {
4109
+ iframe.contentWindow.focus();
4110
+ iframe.contentWindow.print();
4111
+ } catch(e2) {
4112
+ // Cross-origin fallback should not happen since we write the content
4113
+ }
4069
4114
  setBusy(false);
4070
- // Close the print window after a short delay (user may close it themselves)
4071
- setTimeout(function(){ try { printWin.close(); } catch(e3){} }, 3000);
4072
- }, 600);
4115
+ // Remove iframe after print dialog closes (delayed to allow Safari)
4116
+ setTimeout(function(){ try { iframe.remove(); } catch(e3){} }, 8000);
4117
+ }, 800);
4073
4118
  };
4074
- // Fallback if onload already fired
4075
- setTimeout(function() {
4076
- setBusy(false);
4077
- }, 4000);
4119
+
4120
+ document.body.appendChild(iframe);
4121
+
4122
+ // Write HTML into iframe document
4123
+ try {
4124
+ iframe.contentDocument.open();
4125
+ iframe.contentDocument.write(html);
4126
+ iframe.contentDocument.close();
4127
+ } catch(e4) {
4128
+ // If contentDocument write fails (very rare), fall back to srcdoc
4129
+ iframe.srcdoc = html;
4130
+ }
4131
+
4132
+ // Safety fallback: if onload never fires (e.g. Safari blank srcdoc), force after 3s
4133
+ setTimeout(function() { setBusy(false); }, 5000);
4078
4134
  }
4079
4135
  doGeneratePdf();
4080
4136
  }
@@ -4276,24 +4332,11 @@ async function runStudio() {
4276
4332
  var pb = document.getElementById(\x27studioParliamentBlock\x27);
4277
4333
  if (!pb) return;
4278
4334
  pb.style.display = \x27block\x27;
4279
- if (convergence != null) {
4280
- // Deliberation complete return to normal flow, anchored in place
4281
- pb.style.position = \x27\x27; pb.style.bottom = \x27\x27; pb.style.left = \x27\x27;
4282
- pb.style.transform = \x27\x27; pb.style.width = \x27\x27;
4283
- pb.style.top = \x27\x27; pb.style.zIndex = \x27\x27; pb.style.boxShadow = \x27\x27;
4284
- pb.style.maxWidth = \x27\x27;
4285
- } else {
4286
- // Fixed overlay at bottom of viewport so it never scrolls away
4287
- pb.style.position = \x27fixed\x27;
4288
- pb.style.bottom = \x2716px\x27;
4289
- pb.style.left = \x2750%\x27;
4290
- pb.style.transform = \x27translateX(-50%)\x27;
4291
- pb.style.width = \x27calc(100vw - 32px)\x27;
4292
- pb.style.maxWidth = \x27860px\x27;
4293
- pb.style.top = \x27\x27;
4294
- pb.style.zIndex = \x271010\x27;
4295
- pb.style.boxShadow = \x270 8px 40px rgba(99,102,241,.5),0 2px 0 rgba(99,102,241,.2)\x27;
4296
- }
4335
+ // Always in normal document flow — no fixed/absolute positioning
4336
+ pb.style.position = \x27\x27; pb.style.bottom = \x27\x27; pb.style.left = \x27\x27;
4337
+ pb.style.transform = \x27\x27; pb.style.width = \x27\x27;
4338
+ pb.style.top = \x27\x27; pb.style.zIndex = \x27\x27; pb.style.boxShadow = \x27\x27;
4339
+ pb.style.maxWidth = \x27\x27;
4297
4340
 
4298
4341
  // ── OFFICE CARTOON ANIMATION ─────────────────────────────────────────
4299
4342
  // Each agent = a character at a desk doing visible work.
@@ -4322,9 +4365,9 @@ async function runStudio() {
4322
4365
  var skinColors = [\x27#fbbf24\x27,\x27#f97316\x27,\x27#a78bfa\x27,\x27#34d399\x27,\x27#60a5fa\x27,\x27#f472b6\x27];
4323
4366
  var skinIdx = Math.abs(lbl.charCodeAt(0)+lbl.charCodeAt(lbl.length-1)) % skinColors.length;
4324
4367
  var skin = skinColors[skinIdx];
4325
- var deskColor = isDone ? \x27#1a3a1a\x27 : (isActive ? \x27#1a1a3e\x27 : \x27#1a1a2a\x27);
4326
- var deskBorder = isDone ? \x27#22c55e\x27 : (isActive ? phaseColor : \x27#333360\x27);
4327
- var shadow = isActive ? (\x270 0 18px \x27+phaseColor+\x2744\x27) : \x27none\x27;
4368
+ var deskColor = isDone ? \x27#253a25\x27 : (isActive ? \x27#282050\x27 : \x27#221c44\x27);
4369
+ var deskBorder = isDone ? \x27#22c55e\x27 : (isActive ? phaseColor : \x27#4a3880\x27);
4370
+ var shadow = isActive ? (\x270 0 18px \x27+phaseColor+\x2755\x27) : \x27none\x27;
4328
4371
 
4329
4372
  // Action text shown above character
4330
4373
  var actionStr = \x27\x27;
@@ -4411,15 +4454,15 @@ async function runStudio() {
4411
4454
  \x27<line x1="22" y1="41" x2="43" y2="41" stroke="#22c55e44" stroke-width="1" stroke-linecap="round"/>\x27
4412
4455
  :
4413
4456
  // Idle: dim standby screen — waiting, lit but quiet
4414
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(63,63,120,.18)"/>\x27+
4415
- \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".7"/>\x27+
4416
- \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
4417
- \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
4418
- \x27<line x1="22" y1="42" x2="34" y2="42" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".3"/>\x27+
4457
+ \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(90,80,180,.35)"/>\x27+
4458
+ \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#9090cc" stroke-width="1" stroke-linecap="round" opacity=".8"/>\x27+
4459
+ \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#8080bb" stroke-width="1" stroke-linecap="round" opacity=".65"/>\x27+
4460
+ \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#7070aa" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
4461
+ \x27<line x1="22" y1="42" x2="34" y2="42" stroke="#6060a0" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
4419
4462
  \x27<circle cx="22" cy="45" r="1" fill="#6366f1" opacity=".6" class="prl-doc-hold"/>\x27
4420
4463
  )+
4421
4464
  // Monitor camera dot
4422
- \x27<circle cx="35" cy="28.2" r=".9" fill="\x27+(isActive?phaseColor:(isDone?\x27#22c55e\x27:\x27#4040a0\x27))+\x27"/>\x27+
4465
+ \x27<circle cx="35" cy="28.2" r=".9" fill="\x27+(isActive?phaseColor:(isDone?\x27#22c55e\x27:\x27#6060c8\x27))+\x27"/>\x27+
4423
4466
  // ════ KEYBOARD (detailed, realistic) ════
4424
4467
  \x27<rect x="13" y="48" width="36" height="7" rx="2.5" fill="#0c0c1e" stroke="#202036" stroke-width="1"/>\x27+
4425
4468
  // Key rows
@@ -4551,7 +4594,7 @@ async function runStudio() {
4551
4594
  return \x27<div class="prl-desk\x27+(isActive?\x27 prl-desk--active\x27:\x27\x27)+(isDone?\x27 prl-desk--done\x27:\x27\x27)+\x27" style="--dc:\x27+phaseColor+\x27;box-shadow:\x27+shadow+\x27">\x27+
4552
4595
  (actionStr ? \x27<div class="prl-action-bubble\x27+(isActive?\x27 prl-action-bubble--active\x27:\x27\x27)+\x27">\x27+actionStr+\x27</div>\x27 : \x27\x27)+
4553
4596
  svgChar+
4554
- \x27<div class="prl-desk-name" style="color:\x27+(isDone?\x27#4ade80\x27:(isActive?phaseColor:\x27#6b7280\x27))+\x27">\x27+esc(lbl.slice(0,14))+\x27</div>\x27+
4597
+ \x27<div class="prl-desk-name" style="color:\x27+(isDone?\x27#4ade80\x27:(isActive?phaseColor:\x27#6b7280\x27))+\x27">\x27+esc(lbl)+\x27</div>\x27+
4555
4598
  \x27</div>\x27;
4556
4599
  }
4557
4600
 
@@ -4561,7 +4604,7 @@ async function runStudio() {
4561
4604
  // In R3: stands center with lightning bolt.
4562
4605
  var masterIcon = phase===\x27r3\x27 ? \x27\u26a1\x27 : (phase===\x27done\x27 ? \x27\u2714\x27 : \x27\u2666\x27);
4563
4606
  var masterColor2 = {r1:\x27#818cf8\x27,r2:\x27#818cf8\x27,r3:\x27#f59e0b\x27,done:\x27#22c55e\x27}[phase]||\x27#818cf8\x27;
4564
- var masterAnim = (phase===\x27r1\x27) ? \x27prl-master-walk\x27 : (phase===\x27r2\x27 ? \x27prl-master-supervise\x27 : \x27\x27);
4607
+ var masterAnim = (phase===\x27r1\x27) ? \x27prl-master-walk\x27 : (phase===\x27r2\x27 ? \x27prl-master-supervise\x27 : (phase===\x27done\x27 ? \x27prl-master-done\x27 : \x27prl-master-walk\x27));
4565
4608
  var masterSvg = \x27<svg viewBox="0 0 60 90" width="56" height="86" xmlns="http://www.w3.org/2000/svg" font-family="system-ui,sans-serif" style="filter:drop-shadow(0 0 12px \x27+masterColor2+\x27aa)">\x27+
4566
4609
  // ════ LEGS (walking when R1) ════
4567
4610
  // Left leg — trouser
@@ -4739,8 +4782,9 @@ async function runStudio() {
4739
4782
  \x27<div class="prl-wrap">\x27+
4740
4783
  \x27<div class="prl-header"><span class="prl-phase-chip" style="--pc:\x27+phaseColor+\x27">\x27+phaseLabel+\x27</span></div>\x27+
4741
4784
  \x27<div class="prl-office">\x27+
4785
+ officeRoomDecor()+
4742
4786
  \x27<div class="prl-office-floor"></div>\x27+
4743
- \x27<div class="prl-desks-row">\x27+desksHtml+\x27</div>\x27+
4787
+ \x27<div class="prl-desks-row" style="position:relative;z-index:2">\x27+desksHtml+\x27</div>\x27+
4744
4788
  masterHtml+
4745
4789
  flyingDocHtml+
4746
4790
  \x27</div>\x27+
@@ -4749,7 +4793,6 @@ async function runStudio() {
4749
4793
 
4750
4794
  // Force Safari compositing repaint
4751
4795
  void pb.offsetHeight;
4752
- pb.style.transform = \x27translateZ(0)\x27;
4753
4796
  requestAnimationFrame(function(){
4754
4797
  pb.style.opacity = \x270.99\x27;
4755
4798
  requestAnimationFrame(function(){ pb.style.opacity = \x271\x27; });
@@ -5894,7 +5937,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
5894
5937
  .studio-arrow--done{color:#22c55e}
5895
5938
  /* ── Workflow scene (office layout, replaces cramped pill nodes) ── */
5896
5939
  .studio-canvas{background:none!important;border:none!important;padding:0!important;margin-bottom:0!important}
5897
- #studioNodes .prl-office{border-radius:10px;border:1px solid var(--border);background:var(--bg2);margin-bottom:16px;min-height:200px;padding:16px 12px 8px;position:relative;overflow:visible}
5940
+ #studioNodes .prl-office{border-radius:10px;border:1px solid rgba(99,102,241,.25);margin-bottom:16px;min-height:200px;padding:16px 12px 12px;position:relative;overflow:hidden}
5898
5941
  .wf-office{display:block}
5899
5942
  .wf-desks-row{display:flex;align-items:flex-end;justify-content:center;gap:6px;flex-wrap:wrap;padding-bottom:10px}
5900
5943
  .wf-desk{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;transition:opacity .2s}
@@ -5909,26 +5952,60 @@ input:focus,textarea:focus{border-color:var(--green3)}
5909
5952
  .wf-sbraita-bubble::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#ef4444}
5910
5953
  @keyframes sbraitaPop{0%{transform:translateX(-50%) scale(1) rotate(-2deg)}100%{transform:translateX(-50%) scale(1.06) rotate(2deg)}}
5911
5954
  /* ── Parliament Office Cartoon ── */
5912
- .prl-wrap{background:#07070f;border:1.5px solid #6366f1;border-radius:14px;padding:14px 16px 12px;margin-bottom:16px;animation:stNodeIn .35s ease forwards;overflow:hidden}
5913
- #studioParliamentBlock[style*="fixed"] .prl-wrap{animation:stNodeIn .35s ease forwards,parlPulse 2.2s ease-in-out infinite}
5914
- #studioParliamentBlock[style*="fixed"]{backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
5915
- /* When canvas panel is open, shift parliament left so they don't overlap */
5916
- body.canvas-open #studioParliamentBlock[style*="fixed"]{left:16px!important;transform:none!important;max-width:calc(100vw - 520px)!important}
5955
+ .prl-wrap{background:#0b0918;border:1.5px solid #6366f1;border-radius:14px;padding:14px 16px 12px;margin-bottom:16px;animation:stNodeIn .35s ease forwards;overflow:hidden}
5917
5956
  @keyframes parlPulse{0%,100%{border-color:#6366f1;box-shadow:none}50%{border-color:#818cf8;box-shadow:0 0 20px rgba(99,102,241,.3)}}
5918
5957
  .prl-header{display:flex;align-items:center;margin-bottom:10px}
5919
5958
  .prl-phase-chip{font-size:10px;font-weight:800;font-family:var(--mono);letter-spacing:.3px;color:var(--pc,#6366f1);background:rgba(99,102,241,.12);border:1px solid rgba(99,102,241,.35);border-radius:20px;padding:3px 12px;display:inline-block}
5920
- /* Office scene container */
5921
- .prl-office{position:relative;min-height:130px;display:flex;align-items:flex-end;padding-bottom:8px;overflow:hidden}
5922
- /* Floor — gradient wood planks effect */
5923
- .prl-office-floor{position:absolute;bottom:0;left:0;right:0;height:8px;background:linear-gradient(90deg,#1c1a2e,#26243e,#1e1c32,#28263c,#1c1a2e);border-radius:4px;box-shadow:0 -1px 0 rgba(255,255,255,.05)}
5959
+ /* ── Office room — bright, lit, full scene ── */
5960
+ .prl-office{position:relative;min-height:160px;display:flex;align-items:flex-end;padding:0 0 14px 0;overflow:hidden;border-radius:10px;
5961
+ background:linear-gradient(180deg,#1a1440 0%,#221a52 40%,#2a2060 70%,#1e1a42 100%)}
5962
+ /* Back wall — ambient light from ceiling + panel lines */
5963
+ .prl-office::before{content:"";position:absolute;inset:0;background:
5964
+ radial-gradient(ellipse 80% 60% at 50% 0%,rgba(180,160,255,.18) 0%,transparent 70%),
5965
+ repeating-linear-gradient(90deg,transparent,transparent 79px,rgba(255,255,255,.04) 80px);pointer-events:none;z-index:0}
5966
+ /* Floor — warm parquet with shine */
5967
+ .prl-office-floor{position:absolute;bottom:0;left:0;right:0;height:16px;
5968
+ background:repeating-linear-gradient(90deg,#2a1c10 0px,#3d2a18 40px,#2c1e12 41px,#2a1c10 80px);
5969
+ border-top:2px solid rgba(180,120,60,.3);box-shadow:0 -1px 0 rgba(255,200,100,.08),inset 0 2px 4px rgba(255,180,80,.06);z-index:1}
5970
+ /* THREE centered windows — sky blue with sunlight */
5971
+ .prl-office-window{position:absolute;top:4px;left:50%;transform:translateX(-50%);width:120px;height:52px;display:flex;gap:4px;z-index:1;pointer-events:none}
5972
+ .prl-office-window::before,.prl-office-window::after{content:"";flex:1;background:linear-gradient(180deg,#7ecfff 0%,#a8e4ff 40%,#c8f0ff 100%);border:1.5px solid #4a8fbb;border-radius:3px;
5973
+ box-shadow:inset 0 0 8px rgba(255,255,255,.4),0 0 16px rgba(100,200,255,.25);position:relative}
5974
+ /* Center divider of each window pane */
5975
+ /* Sunlight shafts from windows */
5976
+ .prl-office-window-light{position:absolute;top:0;left:50%;transform:translateX(-50%);width:200px;height:100%;
5977
+ background:linear-gradient(175deg,rgba(200,240,255,.12) 0%,rgba(180,220,255,.06) 30%,transparent 60%);pointer-events:none;z-index:1}
5978
+ /* Chandelier hanging from ceiling — center */
5979
+ .prl-office-lamp{position:absolute;top:0;left:50%;transform:translateX(-50%);width:4px;height:18px;background:rgba(255,220,150,.3);z-index:3}
5980
+ .prl-office-lamp::before{content:"";position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:32px;height:14px;border-radius:50%;background:radial-gradient(ellipse,rgba(255,220,100,.5) 0%,rgba(255,180,50,.2) 60%,transparent 100%);box-shadow:0 0 30px rgba(255,200,80,.5),0 0 60px rgba(255,200,80,.2),0 0 100px rgba(255,200,80,.08)}
5981
+ .prl-office-lamp::after{content:"";position:absolute;bottom:-2px;left:50%;transform:translateX(-50%);width:20px;height:10px;background:radial-gradient(ellipse,rgba(255,220,150,.8) 0%,rgba(255,200,100,.4) 50%,transparent 100%);border-radius:50%;filter:blur(3px)}
5982
+ /* Standing lamp (floor lamp) — right side */
5983
+ .prl-office-lamp2{position:absolute;bottom:14px;right:28px;width:3px;height:44px;background:linear-gradient(180deg,#4a4060 0%,#3a3050 100%);border-radius:2px;z-index:2}
5984
+ .prl-office-lamp2::before{content:"";position:absolute;top:-6px;left:50%;transform:translateX(-50%);width:18px;height:10px;background:linear-gradient(135deg,#4a4060,#6a6080);border-radius:3px 3px 0 0;box-shadow:0 -4px 20px rgba(255,220,150,.4),0 -2px 40px rgba(255,200,80,.2)}
5985
+ .prl-office-lamp2::after{content:"";position:absolute;top:-3px;left:50%;transform:translateX(-50%);width:22px;height:16px;background:radial-gradient(ellipse,rgba(255,220,120,.6) 0%,rgba(255,200,80,.2) 60%,transparent 100%);border-radius:50%;filter:blur(4px)}
5986
+ /* Wall art frames — left+center+right */
5987
+ .prl-office-frame{position:absolute;top:6px;right:8px;width:30px;height:22px;border:2px solid rgba(180,160,255,.4);border-radius:2px;background:linear-gradient(135deg,#2a1060,#103060);box-shadow:0 2px 6px rgba(0,0,0,.4),inset 0 0 6px rgba(150,100,255,.15);z-index:1;overflow:hidden}
5988
+ .prl-office-frame::before{content:"";position:absolute;inset:2px;border-radius:1px;background:linear-gradient(135deg,#3a1a6e 0%,#0a2060 50%,#1a3a20 100%)}
5989
+ .prl-office-frame::after{content:"";position:absolute;top:4px;left:50%;transform:translateX(-50%);width:60%;height:1px;background:rgba(255,255,255,.2)}
5990
+ /* Second frame */
5991
+ .prl-office-frame2{position:absolute;top:6px;right:46px;width:22px;height:16px;border:2px solid rgba(180,160,255,.35);border-radius:2px;background:linear-gradient(135deg,#1a1030,#0a2030);box-shadow:0 2px 4px rgba(0,0,0,.3);z-index:1}
5992
+ .prl-office-frame2::before{content:"";position:absolute;inset:2px;background:linear-gradient(45deg,#2e1060,#102040);border-radius:1px}
5993
+ /* Poster left — inspirational */
5994
+ .prl-office-poster{position:absolute;top:6px;left:8px;width:28px;height:20px;border:1.5px solid rgba(100,200,255,.3);border-radius:2px;background:linear-gradient(135deg,#0a1840,#0a3040);box-shadow:0 2px 4px rgba(0,0,0,.3);z-index:1}
5995
+ .prl-office-poster::before{content:"";position:absolute;inset:2px;background:linear-gradient(180deg,#0a2060 0%,#103050 40%,#0a1040 100%);border-radius:1px}
5996
+ .prl-office-poster::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(100,200,255,.05) 3px);border-radius:1px}
5997
+ /* Plant left — larger, luminous */
5998
+ .prl-office-plant{position:absolute;bottom:14px;left:4px;width:22px;height:42px;z-index:2;pointer-events:none}
5999
+ /* Plant right */
6000
+ .prl-office-plant2{position:absolute;bottom:14px;right:8px;width:22px;height:42px;z-index:2;pointer-events:none}
5924
6001
  /* Desks row */
5925
6002
  .prl-desks-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;position:relative;z-index:2;padding-bottom:8px}
5926
- /* Individual desk card */
5927
- .prl-desk{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 6px 4px;border-radius:12px;background:#0a0a18;border:1.5px solid #252535;transition:border-color .4s,background .4s,box-shadow .4s;position:relative;min-width:80px}
5928
- .prl-desk--active{background:#0c0c20;border-color:var(--dc,#6366f1);box-shadow:0 0 20px rgba(99,102,241,.2),0 0 40px rgba(99,102,241,.08)}
5929
- .prl-desk--done{border-color:#1e3a1e;background:#0a150a}
6003
+ /* Individual desk card — illuminated */
6004
+ .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)}
6005
+ .prl-desk--active{background:#1e1a45;border-color:var(--dc,#6366f1);box-shadow:0 0 20px rgba(99,102,241,.3),0 0 40px rgba(99,102,241,.1),inset 0 1px 0 rgba(150,130,255,.15)}
6006
+ .prl-desk--done{border-color:#2a4a2a;background:#162516}
5930
6007
  /* Action bubble above character */
5931
- .prl-action-bubble{font-size:9px;color:#6b7280;font-family:var(--mono);padding:2px 6px;border-radius:8px;background:#111;border:1px solid #2a2a38;min-height:16px;text-align:center;transition:all .3s}
6008
+ .prl-action-bubble{font-size:9px;color:#6b7280;font-family:var(--mono);padding:2px 6px;border-radius:8px;background:#111;border:1px solid #2a2a38;min-height:16px;text-align:center;white-space:normal;word-break:break-word;max-width:88px;line-height:1.3;transition:all .3s}
5932
6009
  .prl-action-bubble--active{color:var(--dc,#6366f1);border-color:var(--dc,#6366f1);background:rgba(99,102,241,.08);animation:parlBubblePop .4s ease}
5933
6010
  @keyframes parlBubblePop{0%{transform:scale(.85);opacity:.5}100%{transform:scale(1);opacity:1}}
5934
6011
  /* Character SVG animations */
@@ -5939,7 +6016,7 @@ body.canvas-open #studioParliamentBlock[style*="fixed"]{left:16px!important;tran
5939
6016
  .prl-head{transform-origin:50% 100%;animation:parlHeadNod .8s ease-in-out infinite}
5940
6017
  .prl-doc-hold{transform-origin:center center;animation:parlDocBob .7s ease-in-out infinite}
5941
6018
  /* Agent name label */
5942
- .prl-desk-name{font-size:9px;font-family:var(--mono);font-weight:700;letter-spacing:.3px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:68px}
6019
+ .prl-desk-name{font-size:9px;font-family:var(--mono);font-weight:700;letter-spacing:.3px;text-align:center;white-space:normal;word-break:break-word;max-width:88px;line-height:1.3}
5943
6020
  /* MASTER ORCHESTRATOR */
5944
6021
  .prl-master{position:absolute;bottom:8px;right:8px;display:flex;flex-direction:column;align-items:center;gap:1px;z-index:3;transition:right .8s cubic-bezier(.4,0,.2,1)}
5945
6022
  .prl-master-label{font-size:8px;font-family:var(--mono);font-weight:700;letter-spacing:.4px;text-align:center;text-shadow:0 0 8px currentColor}
@@ -5956,18 +6033,20 @@ body.canvas-open #studioParliamentBlock[style*="fixed"]{left:16px!important;tran
5956
6033
  @keyframes parlMasterClipboard{0%,100%{transform:rotate(0deg) translateY(0)}30%{transform:rotate(-6deg) translateY(-1px)}70%{transform:rotate(4deg) translateY(1px)}}
5957
6034
  /* Whole body: subtle sway of a confident executive */
5958
6035
  @keyframes parlMasterBodySway{0%,100%{transform:translateY(0) rotate(0deg)}25%{transform:translateY(-2px) rotate(.6deg)}75%{transform:translateY(-1px) rotate(-.5deg)}}
5959
- .prl-master-walk{animation:parlMasterWalk 8s cubic-bezier(.45,0,.55,1) infinite}
5960
- .prl-master-walk .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1s ease-in-out infinite}
5961
- .prl-master-walk .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1s ease-in-out infinite}
5962
- .prl-master-walk .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 1.2s ease-in-out infinite}
5963
- .prl-master-walk .prl-master-arm-r{transform-origin:50% 0;animation:parlMasterArmR 1.2s ease-in-out infinite}
6036
+ .prl-master-walk{animation:parlMasterWalk 16s cubic-bezier(.45,0,.55,1) infinite}
6037
+ .prl-master-walk .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1.8s ease-in-out infinite}
6038
+ .prl-master-walk .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1.8s ease-in-out infinite}
6039
+ .prl-master-walk .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 2.2s ease-in-out infinite}
6040
+ .prl-master-walk .prl-master-arm-r{transform-origin:50% 0;animation:parlMasterArmR 2.2s ease-in-out infinite}
5964
6041
  /* R2 supervise: executive pacing — short back-and-forth at the active desk */
5965
6042
  @keyframes parlMasterSupervise{0%{right:8px}30%{right:28px}60%{right:10px}80%{right:24px}100%{right:8px}}
5966
- .prl-master-supervise{animation:parlMasterSupervise 4s ease-in-out infinite}
5967
- .prl-master-supervise .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1s ease-in-out infinite}
5968
- .prl-master-supervise .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1s ease-in-out infinite}
5969
- .prl-master-supervise .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 1.2s ease-in-out infinite}
5970
- .prl-master-supervise .prl-master-arm-r{transform-origin:50% 0;animation:parlMasterArmR 1.2s ease-in-out infinite}
6043
+ .prl-master-supervise{animation:parlMasterSupervise 8s ease-in-out infinite}
6044
+ .prl-master-supervise .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1.8s ease-in-out infinite}
6045
+ .prl-master-supervise .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1.8s ease-in-out infinite}
6046
+ .prl-master-supervise .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 2.2s ease-in-out infinite}
6047
+ .prl-master-supervise .prl-master-arm-r{transform-origin:50% 0;animation:parlMasterArmR 2.2s ease-in-out infinite}
6048
+ /* Done: standing still — no walk animation */
6049
+ .prl-master-done{animation:none}
5971
6050
  /* Flying documents: smooth parabolic arc between agents */
5972
6051
  .prl-fly-container{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;overflow:hidden;z-index:4}
5973
6052
  @keyframes parlFlyDoc{0%{transform:translate(0,70px) scale(.6) rotate(-20deg);opacity:0}15%{opacity:1;transform:translate(8%,20px) scale(.9) rotate(-5deg)}40%{transform:translate(30%,-15px) scale(1.1) rotate(3deg);opacity:1}65%{transform:translate(60%,5px) scale(.95) rotate(8deg);opacity:.9}85%{opacity:.6}100%{transform:translate(90%,60px) scale(.6) rotate(15deg);opacity:0}}