nothumanallowed 13.5.1 → 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.1",
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.1';
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
  )+
@@ -3598,7 +3598,9 @@ function officeRoomDecor() {
3598
3598
  \x27<div class="prl-office-window-light"></div>\x27+
3599
3599
  \x27<div class="prl-office-frame"></div>\x27+
3600
3600
  \x27<div class="prl-office-frame2"></div>\x27+
3601
+ \x27<div class="prl-office-poster"></div>\x27+
3601
3602
  \x27<div class="prl-office-lamp"></div>\x27+
3603
+ \x27<div class="prl-office-lamp2"></div>\x27+
3602
3604
  \x27<div class="prl-office-plant">\x27+plantSvg+\x27</div>\x27+
3603
3605
  \x27<div class="prl-office-plant2">\x27+plant2Svg+\x27</div>\x27;
3604
3606
  }
@@ -3715,17 +3717,17 @@ function renderStudioNodes() {
3715
3717
  ? (\x27<div class="wf-sbraita-bubble">\x27+sbraitaText+\x27</div>\x27)
3716
3718
  : \x27\x27;
3717
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);
3718
3724
  var masterWfHtml = showMaster ? (
3719
- \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+
3720
3726
  bubbleHtml+
3721
3727
  masterSvg2+
3722
3728
  \x27<div class="prl-master-label" style="color:\x27+masterColor3+\x27;font-size:8px">Orchestratore</div>\x27+
3723
3729
  \x27</div>\x27
3724
3730
  ) : \x27\x27;
3725
-
3726
- // Phase label
3727
- var doneCount = studioState.nodes.filter(function(n){return n.status===\x27done\x27;}).length;
3728
- var totalCount = studioState.nodes.length;
3729
3731
  var phaseLabel2 = hasActive
3730
3732
  ? (\x27Workflow in esecuzione \u2014 \x27+doneCount+\x27/\x27+totalCount+\x27 completati\x27)
3731
3733
  : (doneCount===totalCount && totalCount>0 ? \x27Workflow completato\x27 : \x27Workflow pianificato\x27);
@@ -4076,53 +4078,59 @@ function downloadStudioPDF() {
4076
4078
  '</div>' +
4077
4079
  '</body></html>';
4078
4080
 
4079
- // ── Generate PDF via browser native print dialog ──────────────────────────
4080
- // Renders the full NHA report HTML in a hidden iframe, waits for Chart.js to
4081
- // initialize all charts, then calls window.print() on the iframe.
4082
- // The CSS @media print block (already in NHA_CSS) handles all styling:
4083
- // - Light backgrounds for readability on paper
4084
- // - break-inside:avoid on .section/.card/.priority-item/.data-table
4085
- // - -webkit-print-color-adjust:exact for gradient headers and charts
4086
- // 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.
4087
4087
  function doGeneratePdf() {
4088
4088
  var btn2 = document.getElementById('studioInlinePdfBtn');
4089
4089
  var dlBtn2 = document.querySelector('button[onclick="downloadStudioPDF()"]');
4090
4090
  function setBusy(b) {
4091
- if (btn2) { btn2.disabled = b; btn2.textContent = b ? 'Apertura stampa...' : '\u2913 PDF'; }
4092
- 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'; }
4093
4093
  }
4094
4094
  setBusy(true);
4095
4095
 
4096
- // Open report in a new browser window and trigger print dialog.
4097
- // The browser handles all page-break logic natively — no rasterization,
4098
- // no text-cut artifacts. Charts render as vectors via Chart.js.
4099
- // The @media print CSS block (in NHA_CSS) handles light-mode override.
4100
- var printWin = window.open('', '_blank', 'width=900,height=700');
4101
- if (!printWin) {
4102
- // Popup blocked — fallback: open in current tab print
4103
- setBusy(false);
4104
- var fb = window.open(URL.createObjectURL(new Blob([html], {type:'text/html'})), '_blank');
4105
- if (fb) { setTimeout(function(){ fb.print(); }, 1500); }
4106
- return;
4107
- }
4108
- printWin.document.open();
4109
- printWin.document.write(html);
4110
- printWin.document.close();
4111
- // Wait for Chart.js to render all charts before printing
4112
- // (charts need ~500ms after DOMContentLoaded for animation frame)
4113
- 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)
4114
4107
  setTimeout(function() {
4115
- printWin.focus();
4116
- 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
+ }
4117
4114
  setBusy(false);
4118
- // Close the print window after a short delay (user may close it themselves)
4119
- setTimeout(function(){ try { printWin.close(); } catch(e3){} }, 3000);
4120
- }, 600);
4115
+ // Remove iframe after print dialog closes (delayed to allow Safari)
4116
+ setTimeout(function(){ try { iframe.remove(); } catch(e3){} }, 8000);
4117
+ }, 800);
4121
4118
  };
4122
- // Fallback if onload already fired
4123
- setTimeout(function() {
4124
- setBusy(false);
4125
- }, 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);
4126
4134
  }
4127
4135
  doGeneratePdf();
4128
4136
  }
@@ -4324,24 +4332,11 @@ async function runStudio() {
4324
4332
  var pb = document.getElementById(\x27studioParliamentBlock\x27);
4325
4333
  if (!pb) return;
4326
4334
  pb.style.display = \x27block\x27;
4327
- if (convergence != null) {
4328
- // Deliberation complete return to normal flow, anchored in place
4329
- pb.style.position = \x27\x27; pb.style.bottom = \x27\x27; pb.style.left = \x27\x27;
4330
- pb.style.transform = \x27\x27; pb.style.width = \x27\x27;
4331
- pb.style.top = \x27\x27; pb.style.zIndex = \x27\x27; pb.style.boxShadow = \x27\x27;
4332
- pb.style.maxWidth = \x27\x27;
4333
- } else {
4334
- // Fixed overlay at bottom of viewport so it never scrolls away
4335
- pb.style.position = \x27fixed\x27;
4336
- pb.style.bottom = \x2716px\x27;
4337
- pb.style.left = \x2750%\x27;
4338
- pb.style.transform = \x27translateX(-50%)\x27;
4339
- pb.style.width = \x27calc(100vw - 32px)\x27;
4340
- pb.style.maxWidth = \x27860px\x27;
4341
- pb.style.top = \x27\x27;
4342
- pb.style.zIndex = \x271010\x27;
4343
- pb.style.boxShadow = \x270 8px 40px rgba(99,102,241,.5),0 2px 0 rgba(99,102,241,.2)\x27;
4344
- }
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;
4345
4340
 
4346
4341
  // ── OFFICE CARTOON ANIMATION ─────────────────────────────────────────
4347
4342
  // Each agent = a character at a desk doing visible work.
@@ -4370,9 +4365,9 @@ async function runStudio() {
4370
4365
  var skinColors = [\x27#fbbf24\x27,\x27#f97316\x27,\x27#a78bfa\x27,\x27#34d399\x27,\x27#60a5fa\x27,\x27#f472b6\x27];
4371
4366
  var skinIdx = Math.abs(lbl.charCodeAt(0)+lbl.charCodeAt(lbl.length-1)) % skinColors.length;
4372
4367
  var skin = skinColors[skinIdx];
4373
- var deskColor = isDone ? \x27#1a3a1a\x27 : (isActive ? \x27#1a1a3e\x27 : \x27#1a1a2a\x27);
4374
- var deskBorder = isDone ? \x27#22c55e\x27 : (isActive ? phaseColor : \x27#333360\x27);
4375
- 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;
4376
4371
 
4377
4372
  // Action text shown above character
4378
4373
  var actionStr = \x27\x27;
@@ -4459,15 +4454,15 @@ async function runStudio() {
4459
4454
  \x27<line x1="22" y1="41" x2="43" y2="41" stroke="#22c55e44" stroke-width="1" stroke-linecap="round"/>\x27
4460
4455
  :
4461
4456
  // Idle: dim standby screen — waiting, lit but quiet
4462
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(63,63,120,.18)"/>\x27+
4463
- \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".7"/>\x27+
4464
- \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
4465
- \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#5b5b8e" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
4466
- \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+
4467
4462
  \x27<circle cx="22" cy="45" r="1" fill="#6366f1" opacity=".6" class="prl-doc-hold"/>\x27
4468
4463
  )+
4469
4464
  // Monitor camera dot
4470
- \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+
4471
4466
  // ════ KEYBOARD (detailed, realistic) ════
4472
4467
  \x27<rect x="13" y="48" width="36" height="7" rx="2.5" fill="#0c0c1e" stroke="#202036" stroke-width="1"/>\x27+
4473
4468
  // Key rows
@@ -4609,7 +4604,7 @@ async function runStudio() {
4609
4604
  // In R3: stands center with lightning bolt.
4610
4605
  var masterIcon = phase===\x27r3\x27 ? \x27\u26a1\x27 : (phase===\x27done\x27 ? \x27\u2714\x27 : \x27\u2666\x27);
4611
4606
  var masterColor2 = {r1:\x27#818cf8\x27,r2:\x27#818cf8\x27,r3:\x27#f59e0b\x27,done:\x27#22c55e\x27}[phase]||\x27#818cf8\x27;
4612
- 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));
4613
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+
4614
4609
  // ════ LEGS (walking when R1) ════
4615
4610
  // Left leg — trouser
@@ -4798,7 +4793,6 @@ async function runStudio() {
4798
4793
 
4799
4794
  // Force Safari compositing repaint
4800
4795
  void pb.offsetHeight;
4801
- pb.style.transform = \x27translateZ(0)\x27;
4802
4796
  requestAnimationFrame(function(){
4803
4797
  pb.style.opacity = \x270.99\x27;
4804
4798
  requestAnimationFrame(function(){ pb.style.opacity = \x271\x27; });
@@ -5943,7 +5937,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
5943
5937
  .studio-arrow--done{color:#22c55e}
5944
5938
  /* ── Workflow scene (office layout, replaces cramped pill nodes) ── */
5945
5939
  .studio-canvas{background:none!important;border:none!important;padding:0!important;margin-bottom:0!important}
5946
- #studioNodes .prl-office{border-radius:10px;border:1px solid rgba(99,102,241,.25);background:linear-gradient(180deg,#0e0c1e 0%,#13102a 55%,#1a172e 100%);margin-bottom:16px;min-height:200px;padding:16px 12px 12px;position:relative;overflow:hidden}
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}
5947
5941
  .wf-office{display:block}
5948
5942
  .wf-desks-row{display:flex;align-items:flex-end;justify-content:center;gap:6px;flex-wrap:wrap;padding-bottom:10px}
5949
5943
  .wf-desk{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;transition:opacity .2s}
@@ -5958,51 +5952,58 @@ input:focus,textarea:focus{border-color:var(--green3)}
5958
5952
  .wf-sbraita-bubble::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#ef4444}
5959
5953
  @keyframes sbraitaPop{0%{transform:translateX(-50%) scale(1) rotate(-2deg)}100%{transform:translateX(-50%) scale(1.06) rotate(2deg)}}
5960
5954
  /* ── Parliament Office Cartoon ── */
5961
- .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}
5962
- #studioParliamentBlock[style*="fixed"] .prl-wrap{animation:stNodeIn .35s ease forwards,parlPulse 2.2s ease-in-out infinite}
5963
- #studioParliamentBlock[style*="fixed"]{backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
5964
- /* When canvas panel is open, shift parliament left so they don't overlap */
5965
- 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}
5966
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)}}
5967
5957
  .prl-header{display:flex;align-items:center;margin-bottom:10px}
5968
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}
5969
- /* Office scene container room with wall, floor, plants, art */
5970
- .prl-office{position:relative;min-height:150px;display:flex;align-items:flex-end;padding:0 0 12px 0;overflow:hidden;border-radius:10px;
5971
- background:linear-gradient(180deg,#0e0c1e 0%,#13102a 55%,#1a172e 100%)}
5972
- /* Back wall — subtle panel lines */
5959
+ /* ── Office roombright, 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 */
5973
5963
  .prl-office::before{content:"";position:absolute;inset:0;background:
5974
- repeating-linear-gradient(90deg,transparent,transparent 79px,rgba(255,255,255,.025) 80px),
5975
- linear-gradient(180deg,rgba(30,28,60,.0) 0%,rgba(30,28,60,.5) 60%,rgba(10,10,30,.8) 100%);pointer-events:none;z-index:0}
5976
- /* Floor — parquet wood planks */
5977
- .prl-office-floor{position:absolute;bottom:0;left:0;right:0;height:14px;
5978
- background:repeating-linear-gradient(90deg,#1c1630 0px,#221e38 40px,#1a1630 41px,#1c1630 80px);
5979
- border-top:1px solid rgba(99,102,241,.15);box-shadow:0 -2px 8px rgba(0,0,0,.4);z-index:1}
5980
- /* Window on back wall (top-left) */
5981
- .prl-office-window{position:absolute;top:6px;left:10px;width:38px;height:50px;background:linear-gradient(180deg,#0d1a2e 0%,#162840 50%,#1e3a5a 100%);border:1.5px solid #2a3a50;border-radius:3px;box-shadow:inset 0 0 12px rgba(96,165,250,.15),0 0 8px rgba(96,165,250,.08);z-index:1;overflow:hidden}
5982
- .prl-office-window::before{content:"";position:absolute;left:50%;top:0;bottom:0;width:1px;background:rgba(255,255,255,.15)}
5983
- .prl-office-window::after{content:"";position:absolute;top:50%;left:0;right:0;height:1px;background:rgba(255,255,255,.15)}
5984
- /* Sunlight ray from window */
5985
- .prl-office-window-light{position:absolute;top:0;left:10px;width:80px;height:100%;background:linear-gradient(145deg,rgba(96,165,250,.06) 0%,transparent 60%);pointer-events:none;z-index:1}
5986
- /* Wall art frame (top center-right) */
5987
- .prl-office-frame{position:absolute;top:8px;right:12px;width:36px;height:28px;border:2px solid #2a2840;border-radius:2px;background:linear-gradient(135deg,#0d0a1e,#1a1030);box-shadow:0 2px 6px rgba(0,0,0,.5);z-index:1;overflow:hidden}
5988
- .prl-office-frame::before{content:"";position:absolute;inset:3px;border-radius:1px;background:linear-gradient(135deg,#1a0a2e 0%,#0a1a2e 50%,#0e2010 100%);opacity:.9}
5989
- .prl-office-frame::after{content:"";position:absolute;inset:0;border:1px solid rgba(255,255,255,.06);border-radius:1px}
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
5990
  /* Second frame */
5991
- .prl-office-frame2{position:absolute;top:8px;right:54px;width:24px;height:20px;border:2px solid #2a2840;border-radius:2px;background:linear-gradient(135deg,#0a1020,#1a1820);box-shadow:0 2px 6px rgba(0,0,0,.5);z-index:1}
5992
- .prl-office-frame2::before{content:"";position:absolute;inset:2px;background:linear-gradient(45deg,#1e1030,#102018);border-radius:1px}
5993
- /* Plant left */
5994
- .prl-office-plant{position:absolute;bottom:12px;left:2px;width:20px;height:36px;z-index:2;pointer-events:none}
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}
5995
5999
  /* Plant right */
5996
- .prl-office-plant2{position:absolute;bottom:12px;right:2px;width:20px;height:36px;z-index:2;pointer-events:none}
5997
- /* Ceiling lamp */
5998
- .prl-office-lamp{position:absolute;top:0;left:50%;transform:translateX(-50%);width:2px;height:14px;background:rgba(255,255,255,.15);z-index:1}
5999
- .prl-office-lamp::after{content:"";position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:16px;height:8px;border-radius:0 0 12px 12px;background:rgba(99,102,241,.25);box-shadow:0 4px 20px rgba(99,102,241,.3),0 2px 40px rgba(99,102,241,.1)}
6000
+ .prl-office-plant2{position:absolute;bottom:14px;right:8px;width:22px;height:42px;z-index:2;pointer-events:none}
6000
6001
  /* Desks row */
6001
6002
  .prl-desks-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;position:relative;z-index:2;padding-bottom:8px}
6002
- /* Individual desk card */
6003
- .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}
6004
- .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)}
6005
- .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}
6006
6007
  /* Action bubble above character */
6007
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}
6008
6009
  .prl-action-bubble--active{color:var(--dc,#6366f1);border-color:var(--dc,#6366f1);background:rgba(99,102,241,.08);animation:parlBubblePop .4s ease}
@@ -6032,18 +6033,20 @@ body.canvas-open #studioParliamentBlock[style*="fixed"]{left:16px!important;tran
6032
6033
  @keyframes parlMasterClipboard{0%,100%{transform:rotate(0deg) translateY(0)}30%{transform:rotate(-6deg) translateY(-1px)}70%{transform:rotate(4deg) translateY(1px)}}
6033
6034
  /* Whole body: subtle sway of a confident executive */
6034
6035
  @keyframes parlMasterBodySway{0%,100%{transform:translateY(0) rotate(0deg)}25%{transform:translateY(-2px) rotate(.6deg)}75%{transform:translateY(-1px) rotate(-.5deg)}}
6035
- .prl-master-walk{animation:parlMasterWalk 8s cubic-bezier(.45,0,.55,1) infinite}
6036
- .prl-master-walk .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1s ease-in-out infinite}
6037
- .prl-master-walk .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1s ease-in-out infinite}
6038
- .prl-master-walk .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 1.2s ease-in-out infinite}
6039
- .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}
6040
6041
  /* R2 supervise: executive pacing — short back-and-forth at the active desk */
6041
6042
  @keyframes parlMasterSupervise{0%{right:8px}30%{right:28px}60%{right:10px}80%{right:24px}100%{right:8px}}
6042
- .prl-master-supervise{animation:parlMasterSupervise 4s ease-in-out infinite}
6043
- .prl-master-supervise .prl-master-leg-l{transform-origin:50% 0;animation:parlMasterLegL 1s ease-in-out infinite}
6044
- .prl-master-supervise .prl-master-leg-r{transform-origin:50% 0;animation:parlMasterLegR 1s ease-in-out infinite}
6045
- .prl-master-supervise .prl-master-arm-l{transform-origin:50% 0;animation:parlMasterArmL 1.2s ease-in-out infinite}
6046
- .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}
6047
6050
  /* Flying documents: smooth parabolic arc between agents */
6048
6051
  .prl-fly-container{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;overflow:hidden;z-index:4}
6049
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}}