nothumanallowed 13.5.16 → 13.5.17

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.16",
3
+ "version": "13.5.17",
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.16';
8
+ export const VERSION = '13.5.17';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3798,16 +3798,13 @@ function isoCharSvg(opts) {
3798
3798
  var isDone = opts.isDone;
3799
3799
  var scale = opts.scale || 1;
3800
3800
  var accentColor = opts.accentColor || \x27#6366f1\x27;
3801
- var idx = opts.emojiIdx;
3802
- // idx === 99 means orchestrator — use crown+suit combo
3803
- var emoji = (idx === 99)
3804
- ? (String.fromCodePoint(0x1F451) + String.fromCodePoint(0x1F9D1,0x200D,0x1F4BC))
3805
- : AGENT_EMOJIS[(idx || 0) % AGENT_EMOJIS.length];
3801
+ var idx = opts.emojiIdx || 0;
3802
+ var emoji = AGENT_EMOJIS[idx % AGENT_EMOJIS.length];
3806
3803
  var sz = Math.round(52 * scale);
3807
3804
  var glowColor = isActive ? accentColor : (isDone ? \x27#22c55e\x27 : \x27transparent\x27);
3808
3805
  var glowFilter = (isActive || isDone) ? (\x27filter:drop-shadow(0 0 8px \x27+glowColor+\x27aa)\x27) : \x27\x27;
3809
3806
  var badgeHtml = isDone
3810
- ? \x27<div style="position:absolute;top:-4px;right:-4px;width:18px;height:18px;background:#1f2937;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fff;box-shadow:0 2px 6px rgba(0,0,0,.4)">&#10003;</div>\x27
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
3811
3808
  : (isActive
3812
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
3813
3810
  : \x27\x27);
@@ -3824,11 +3821,10 @@ function isoCharSvg(opts) {
3824
3821
  function isoOrchSvg(hasActive, doneRatio) {
3825
3822
  void doneRatio;
3826
3823
  var orchEmoji = String.fromCodePoint(0x1F9D1, 0x200D, 0x1F4BC); // person in suit
3827
- var glowColor = hasActive ? \x27#818cf8\x27 : \x27#374151\x27;
3828
3824
  var animClass = hasActive ? \x27 prl-head\x27 : \x27\x27;
3825
+ var glowFilter = hasActive ? \x27filter:drop-shadow(0 0 12px #818cf8AA)\x27 : \x27filter:drop-shadow(0 0 6px rgba(0,0,0,.25))\x27;
3829
3826
  var crown = String.fromCodePoint(0x1F451); // crown emoji above
3830
- var glowFilter = hasActive ? \x27filter:drop-shadow(0 0 12px #818cf8AA)\x27 : \x27filter:drop-shadow(0 0 6px rgba(0,0,0,.3))\x27;
3831
- return \x27<div class="iso-orch-wrap\x27+animClass+\x27" style="position:relative;display:inline-flex;flex-direction:column;align-items:center;gap:0">\x27+
3827
+ return \x27<div class="iso-orch-wrap\x27+animClass+\x27" style="display:inline-flex;flex-direction:column;align-items:center;gap:0">\x27+
3832
3828
  \x27<span style="font-size:18px;line-height:1;display:block;text-align:center">\x27+crown+\x27</span>\x27+
3833
3829
  \x27<span style="font-size:52px;line-height:1;user-select:none;display:block;\x27+glowFilter+\x27">\x27+orchEmoji+\x27</span>\x27+
3834
3830
  \x27</div>\x27;
@@ -3843,61 +3839,6 @@ function agentPalette(lbl) {
3843
3839
  return {skin: skins[i], shirt: shirts[i], hair: hairs[i]};
3844
3840
  }
3845
3841
 
3846
- // Tool emoji map — specific icon per agent/tool type, fallback to default
3847
- var TOOL_EMOJI_MAP = {
3848
- websearch: String.fromCodePoint(0x1F50D),
3849
- search: String.fromCodePoint(0x1F50D),
3850
- browser: String.fromCodePoint(0x1F310),
3851
- email: String.fromCodePoint(0x1F4E7),
3852
- gmail: String.fromCodePoint(0x1F4E7),
3853
- calendar: String.fromCodePoint(0x1F4C5),
3854
- github: String.fromCodePoint(0x1F431),
3855
- notion: String.fromCodePoint(0x1F4D3),
3856
- slack: String.fromCodePoint(0x1F4AC),
3857
- data: String.fromCodePoint(0x1F4CA),
3858
- analyst: String.fromCodePoint(0x1F4CA),
3859
- writer: String.fromCodePoint(0x270F,0xFE0F),
3860
- summary: String.fromCodePoint(0x1F4CB),
3861
- research: String.fromCodePoint(0x1F52C),
3862
- canvas: String.fromCodePoint(0x1F3A8),
3863
- security: String.fromCodePoint(0x1F6E1,0xFE0F),
3864
- devops: String.fromCodePoint(0x2699,0xFE0F),
3865
- code: String.fromCodePoint(0x1F4BB),
3866
- file: String.fromCodePoint(0x1F4C2),
3867
- drive: String.fromCodePoint(0x1F4BE),
3868
- maps: String.fromCodePoint(0x1F5FA,0xFE0F),
3869
- voice: String.fromCodePoint(0x1F3A4),
3870
- pdf: String.fromCodePoint(0x1F4DC),
3871
- document: String.fromCodePoint(0x1F4DC),
3872
- task: String.fromCodePoint(0x2705),
3873
- contacts: String.fromCodePoint(0x1F4F1),
3874
- reminder: String.fromCodePoint(0x23F0),
3875
- news: String.fromCodePoint(0x1F4F0),
3876
- image: String.fromCodePoint(0x1F5BC,0xFE0F),
3877
- video: String.fromCodePoint(0x1F3AC),
3878
- music: String.fromCodePoint(0x1F3B5),
3879
- translate: String.fromCodePoint(0x1F30D),
3880
- math: String.fromCodePoint(0x1F9EE),
3881
- sql: String.fromCodePoint(0x1F5C4,0xFE0F),
3882
- api: String.fromCodePoint(0x1F517),
3883
- test: String.fromCodePoint(0x1F9EA),
3884
- monitor: String.fromCodePoint(0x1F4F6),
3885
- _default: String.fromCodePoint(0x1F527) // wrench as fallback
3886
- };
3887
-
3888
- function getNodeEmoji(n) {
3889
- var lbl = (n.label || n.agent || '').toLowerCase();
3890
- var icon = n.icon || '';
3891
- // Check by label keywords
3892
- var keys = Object.keys(TOOL_EMOJI_MAP);
3893
- for (var ki = 0; ki < keys.length; ki++) {
3894
- if (keys[ki] !== '_default' && lbl.indexOf(keys[ki]) >= 0) return TOOL_EMOJI_MAP[keys[ki]];
3895
- }
3896
- // If icon looks like an emoji code point (not HTML entity), use it
3897
- if (icon && icon.length > 0 && icon.charCodeAt(0) > 127) return icon;
3898
- return TOOL_EMOJI_MAP._default;
3899
- }
3900
-
3901
3842
  function renderStudioNodes() {
3902
3843
  var el = document.getElementById('studioNodes');
3903
3844
  if (!el) return;
@@ -3912,142 +3853,78 @@ function renderStudioNodes() {
3912
3853
  var totalCount = nodes.length;
3913
3854
  var showMaster = hasActive || doneCount > 0;
3914
3855
 
3915
- var phaseLabel2 = hasActive
3916
- ? (\x27Workflow in esecuzione \u2014 \x27+doneCount+\x27/\x27+totalCount)
3917
- : (doneCount===totalCount && totalCount>0 ? \x27Workflow completato\x27 : \x27Workflow pianificato\x27);
3918
- var phaseColor2 = hasActive ? \x27#6366f1\x27 : (doneCount===totalCount && totalCount>0 ? \x27#1f2937\x27 : \x27#6b7280\x27);
3919
-
3920
- // ── CSS Grid layout: 100% width, responsive ──────────────────────────────
3921
- // All stations (orch + agents) in a grid, max 4 per row
3922
- var totalStations = totalCount + 1; // +1 for orchestrator
3923
- var cols = totalStations <= 2 ? totalStations : (totalStations <= 4 ? 2 : (totalStations <= 6 ? 3 : 4));
3924
- var rows = Math.ceil(totalStations / cols);
3925
-
3926
- // Each station rendered as a grid cell — 100% fills parent
3927
- // No pixel-based absolute positioning: use CSS grid % cells
3928
- var gridTpl = \x27repeat(\x27+cols+\x27,1fr)\x27;
3929
-
3930
- // Plant/deco emojis
3931
- var bigPlant = String.fromCodePoint(0x1FAB4);
3932
- var plantEmoji = String.fromCodePoint(0x1F331);
3933
-
3934
- // Build all station cards (orchestrator first, then agents)
3935
- function buildStation2(label, toolEmoji, isOrch, isActive, isDone, isErr, emojiIdx) {
3936
- var accentColor = isOrch ? \x27#818cf8\x27 : (isActive ? \x27#6366f1\x27 : (isDone ? \x27#374151\x27 : (isErr ? \x27#ef4444\x27 : \x27#9ca3af\x27)));
3937
- var nameBg = isDone ? \x27rgba(0,0,0,.1)\x27 : (isActive ? \x27#ede9fe\x27 : (isOrch ? \x27#e0e7ff\x27 : \x27rgba(255,255,255,.85)\x27));
3938
- var nameColor = isDone ? \x27#111827\x27 : (isActive ? \x27#4f46e5\x27 : (isOrch ? \x27#4338ca\x27 : (isErr ? \x27#dc2626\x27 : \x27#374151\x27)));
3939
- var monScreen = isOrch
3940
- ? \x27<span style="font-size:11px">&#128269;</span>\x27
3941
- : (isDone ? \x27<span style="color:#111827;font-size:13px">&#10003;</span>\x27
3942
- : (isActive ? \x27<span class="iso-monitor-blink"></span>\x27
3943
- : \x27<span style="font-size:8px;opacity:.35;color:#818cf8">&#9632;</span>\x27));
3944
- var bubbleText = isOrch
3945
- ? (hasActive ? (\x27Step \x27+doneCount+\x27/\x27+totalCount) : (doneCount===totalCount&&totalCount>0 ? \x27\u2714 Fatto!\x27 : \x27In attesa\x27))
3946
- : (isActive ? \x27\u2022\u2022\u2022 lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27)));
3947
- var bubbleBg = isOrch ? \x27rgba(99,102,241,.15)\x27 : (isActive ? \x27rgba(99,102,241,.12)\x27 : (isDone ? \x27rgba(0,0,0,.08)\x27 : \x27rgba(239,68,68,.12)\x27));
3948
- var glowBox = isActive ? (\x270 0 0 3px \x27+accentColor+\x2744,0 8px 24px \x27+accentColor+\x2733\x27) : (isDone ? (\x270 0 0 2px rgba(0,0,0,.25)\x27) : \x27none\x27);
3949
- var orchWalkClass = (isOrch && hasActive) ? \x27 iso-orch-walking\x27 : (isOrch && doneCount===totalCount&&totalCount>0 ? \x27 iso-orch-done\x27 : \x27\x27);
3950
- var charHtml = isoCharSvg({emojiIdx: isOrch ? 99 : emojiIdx, isActive: isActive, isDone: isDone, scale: 1.1, accentColor: accentColor});
3951
- var clickAttr = isOrch ? \x27\x27 : (\x27data-agent-label="\x27+esc(label)+\x27" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))"\x27);
3952
- return \x27<div class="iso-station\x27+orchWalkClass+\x27" \x27+clickAttr+\x27 style="box-shadow:\x27+glowBox+\x27;border-color:\x27+accentColor+\x27;transition:box-shadow .4s">\x27+
3953
- // bubble
3954
- \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" style="border-color:\x27+accentColor+\x27;color:\x27+accentColor+\x27;background:\x27+bubbleBg+\x27;visibility:\x27+(bubbleText||isOrch?\x27visible\x27:\x27hidden\x27)+\x27">\x27+esc(bubbleText)+\x27</div>\x27+
3955
- // tool badge above character
3956
- \x27<div class="iso-tool-badge">\x27+toolEmoji+\x27</div>\x27+
3957
- // character emoji
3958
- charHtml+
3959
- // desk
3960
- \x27<div class="iso-desk" style="width:85%;border-top-color:\x27+accentColor+\x2733"></div>\x27+
3961
- // monitor on desk
3962
- \x27<div class="iso-monitor" style="border-color:\x27+accentColor+\x2777"><div class="iso-monitor-screen">\x27+monScreen+\x27</div></div>\x27+
3963
- // name
3964
- \x27<div class="iso-name" style="color:\x27+nameColor+\x27;background:\x27+nameBg+\x27">\x27+(isOrch?\x27\u2666\xA0\x27:\x27\x27)+esc(label)+\x27</div>\x27+
3965
- \x27</div>\x27;
3966
- }
3856
+ // ── ISO scene dimensions ───────────────────────────────────────────────────
3857
+ var ISO_COLS = Math.max(nodes.length, 1);
3858
+ var SCENE_W = 640; var SCENE_H = 420;
3967
3859
 
3968
- var stationsHtml = \x27\x27;
3969
- // Orchestrator
3970
- var orchDone2 = !hasActive && doneCount===totalCount && totalCount>0;
3971
- stationsHtml += buildStation2(\x27Orchestratore\x27, String.fromCodePoint(0x1F4CB), true, hasActive, orchDone2, false, 99);
3972
- // Agents
3860
+ var agentsHtml = \x27\x27;
3973
3861
  nodes.forEach(function(n, idx) {
3974
- stationsHtml += buildStation2(
3975
- n.label || n.agent,
3976
- getNodeEmoji(n),
3977
- false,
3978
- n.status===\x27running\x27,
3979
- n.status===\x27done\x27,
3980
- n.status===\x27error\x27,
3981
- idx
3982
- );
3862
+ var isActive = n.status === \x27running\x27;
3863
+ var isDone = n.status === \x27done\x27;
3864
+ var isErr = n.status === \x27error\x27;
3865
+ var lbl = n.label || n.agent;
3866
+ var pal = agentPalette(lbl);
3867
+ var accentColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#374151\x27 : (isErr ? \x27#ef4444\x27 : \x27#999\x27));
3868
+
3869
+ // Spread agents evenly across front rows
3870
+ var colStep = ISO_COLS > 1 ? 5 / (ISO_COLS - 1) : 2;
3871
+ var col = (ISO_COLS === 1) ? 2.5 : idx * colStep;
3872
+ var row = 3.5;
3873
+ var pos = isoProject(col, row);
3874
+ var px = pos.x; var py = pos.y + 80;
3875
+ var charScale = 1.1;
3876
+ var zIdx = Math.round(py + 100);
3877
+
3878
+ // Bubble: only show when active (live text) or done (checkmark)
3879
+ var bubbleText = isActive ? \x27...lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27));
3880
+ var bubbleColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#374151\x27 : \x27#ef4444\x27);
3881
+ void pal; // palette no longer used for character rendering
3882
+ var charSvg = isoCharSvg({emojiIdx: idx, isActive: isActive, isDone: isDone, scale: charScale, accentColor: accentColor});
3883
+ var charW = Math.round(52 * charScale); var charH = Math.round(52 * charScale);
3884
+
3885
+ 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;
3886
+ // Bubble — bigger, left-aligned (no mirror issue)
3887
+ if (bubbleText || isActive) {
3888
+ agentsHtml += \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" id="isobubble_\x27+idx+\x27" style="border-color:\x27+bubbleColor+\x27;color:\x27+bubbleColor+\x27;min-width:80px;max-width:140px;font-size:10px;padding:4px 10px;text-align:left">\x27+esc(bubbleText)+\x27</div>\x27;
3889
+ } else {
3890
+ agentsHtml += \x27<div class="iso-bubble" id="isobubble_\x27+idx+\x27" style="visibility:hidden;min-width:80px"></div>\x27;
3891
+ }
3892
+ agentsHtml += charSvg;
3893
+ agentsHtml += \x27<div class="iso-name" style="font-size:10px;font-weight:700;color:\x27+(isDone?\x27#111827\x27:(isActive?\x27#818cf8\x27:(isErr?\x27#ef4444\x27:\x27#555\x27)))+\x27;text-shadow:0 1px 3px rgba(255,255,255,.8)">\x27+esc(lbl)+\x27</div>\x27;
3894
+ // Desk — lighter wood color for bright office
3895
+ agentsHtml += isoDeskSvg(px, py - charH/2, accentColor);
3896
+ agentsHtml += \x27</div>\x27;
3983
3897
  });
3984
3898
 
3985
- // Floor SVG — uses a fixed coordinate space (1000×600) scaled 100% via CSS
3986
- var FW = 1000; var FH = 600;
3987
- var wallH = Math.round(FH * 0.30);
3988
- var floorSvg = \x27<svg viewBox="0 0 \x27+FW+\x27 \x27+FH+\x27" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none">\x27;
3989
- floorSvg += \x27<defs>\x27;
3990
- floorSvg += \x27<filter id="bGlow2" x="-100%" y="-100%" width="300%" height="300%"><feGaussianBlur stdDeviation="5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27;
3991
- floorSvg += \x27<linearGradient id="wallGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#faf7f2"/><stop offset="1" stop-color="#ede8e0"/></linearGradient>\x27;
3992
- floorSvg += \x27</defs>\x27;
3993
- // Wall
3994
- floorSvg += \x27<rect x="0" y="0" width="\x27+FW+\x27" height="\x27+wallH+\x27" fill="url(#wallGrad)"/>\x27;
3995
- // Baseboard
3996
- floorSvg += \x27<rect x="0" y="\x27+(wallH-5)+\x27" width="\x27+FW+\x27" height="7" fill="#d4c4a8" rx="2"/>\x27;
3997
- // Floor parquet
3998
- var plankColors2 = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#caa86e\x27];
3999
- var pH = 32; var pW = 120;
4000
- for (var fy = wallH; fy < FH+pH; fy += pH) {
4001
- var ro2 = (Math.floor((fy-wallH)/pH) % 2) * (pW/2);
4002
- for (var fx = -pW+ro2; fx < FW+pW; fx += pW) {
4003
- var pc2 = plankColors2[Math.abs(Math.round(fx/pW+fy/pH*1.3)) % plankColors2.length];
4004
- floorSvg += \x27<rect x="\x27+Math.round(fx)+\x27" y="\x27+fy+\x27" width="\x27+(pW-2)+\x27" height="\x27+(pH-2)+\x27" fill="\x27+pc2+\x27" rx="2"/>\x27;
4005
- floorSvg += \x27<line x1="\x27+Math.round(fx+pW*0.4)+\x27" y1="\x27+fy+\x27" x2="\x27+Math.round(fx+pW*0.4)+\x27" y2="\x27+(fy+pH-2)+\x27" stroke="rgba(0,0,0,.04)" stroke-width="1.5"/>\x27;
4006
- }
4007
- }
4008
- // Windows — 2 on left, 1 center-right
4009
- function svgWindow(wx, wy, ww, wh) {
4010
- var r = \x27<rect x="\x27+wx+\x27" y="\x27+wy+\x27" width="\x27+ww+\x27" height="\x27+wh+\x27" rx="4" fill="#c8e6f8" stroke="#a8cce0" stroke-width="3"/>\x27;
4011
- r += \x27<rect x="\x27+wx+\x27" y="\x27+wy+\x27" width="\x27+ww+\x27" height="\x27+wh+\x27" rx="4" fill="rgba(255,255,255,.2)"/>\x27;
4012
- r += \x27<line x1="\x27+(wx+ww/2)+\x27" y1="\x27+wy+\x27" x2="\x27+(wx+ww/2)+\x27" y2="\x27+(wy+wh)+\x27" stroke="#a8cce0" stroke-width="2"/>\x27;
4013
- r += \x27<line x1="\x27+wx+\x27" y1="\x27+(wy+wh/2)+\x27" x2="\x27+(wx+ww)+\x27" y2="\x27+(wy+wh/2)+\x27" stroke="#a8cce0" stroke-width="2"/>\x27;
4014
- return r;
3899
+ // ── Orchestrator ──────────────────────────────────────────────────────────
3900
+ var orchHtml = \x27\x27;
3901
+ if (showMaster) {
3902
+ var oPh = isoProject(ISO_COLS / 2 + 0.5, 1.2);
3903
+ var orchDone = !hasActive && doneCount === totalCount;
3904
+ var orchAnim = hasActive ? \x27prl-master-walk\x27 : (orchDone ? \x27prl-master-done\x27 : \x27\x27);
3905
+ var orchStatus = hasActive
3906
+ ? (\x27Step \x27+doneCount+\x27/\x27+totalCount)
3907
+ : (orchDone ? \x27Completato!\x27 : \x27Pianificazione\x27);
3908
+ orchHtml = \x27<div class="prl-master \x27+orchAnim+\x27" id="wfOrch" style="position:absolute;left:\x27+(oPh.x-28)+\x27px;top:\x27+(oPh.y+60)+\x27px;z-index:50;display:flex;flex-direction:column;align-items:center;gap:3px">\x27+
3909
+ \x27<div class="iso-bubble iso-bubble--orch" id="wfOrchBubble" style="border-color:#6366f1;color:#6366f1;max-width:140px;font-size:10px;padding:4px 10px">\x27+esc(orchStatus)+\x27</div>\x27+
3910
+ isoOrchSvg(hasActive, doneCount / Math.max(totalCount,1))+
3911
+ \x27<div class="prl-master-label" style="color:#6366f1;font-size:9px;font-weight:700;text-shadow:0 1px 3px rgba(255,255,255,.8)">Orchestratore</div>\x27+
3912
+ \x27</div>\x27;
4015
3913
  }
4016
- floorSvg += svgWindow(40, 20, 100, 80);
4017
- floorSvg += svgWindow(180, 20, 100, 80);
4018
- floorSvg += svgWindow(FW-200, 20, 120, 80);
4019
- // Door center
4020
- floorSvg += \x27<rect x="\x27+(FW/2-35)+\x27" y="0" width="70" height="\x27+wallH+\x27" rx="0" fill="#c8a87a" stroke="#a07848" stroke-width="2"/>\x27;
4021
- floorSvg += \x27<rect x="\x27+(FW/2-25)+\x27" y="8" width="50" height="36" rx="4" fill="rgba(255,255,255,.18)"/>\x27;
4022
- floorSvg += \x27<circle cx="\x27+(FW/2+22)+\x27" cy="\x27+(wallH/2)+\x27" r="5" fill="#8a6028"/>\x27;
4023
- // Chandelier
4024
- floorSvg += \x27<line x1="\x27+(FW/2)+\x27" y1="0" x2="\x27+(FW/2)+\x27" y2="30" stroke="#bbb" stroke-width="3"/>\x27;
4025
- floorSvg += \x27<ellipse cx="\x27+(FW/2)+\x27" cy="38" rx="50" ry="14" fill="#e8d960" stroke="#c8b030" stroke-width="2"/>\x27;
4026
- floorSvg += \x27<circle cx="\x27+(FW/2-28)+\x27" cy="46" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4027
- floorSvg += \x27<circle cx="\x27+(FW/2)+\x27" cy="50" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4028
- floorSvg += \x27<circle cx="\x27+(FW/2+28)+\x27" cy="46" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4029
- // Light cone
4030
- floorSvg += \x27<polygon points="\x27+(FW/2-60)+\x27,60 \x27+(FW/2+60)+\x27,60 \x27+(FW/2+160)+\x27,\x27+FH+\x27 \x27+(FW/2-160)+\x27,\x27+FH+\x27" fill="rgba(255,252,200,.06)"/>\x27;
4031
- floorSvg += \x27</svg>\x27;
4032
-
4033
- // Decorations (CSS positioned, z-index above floor SVG)
4034
- var decoHtml =
4035
- \x27<div style="position:absolute;bottom:10px;left:12px;font-size:40px;line-height:1;filter:drop-shadow(0 3px 6px rgba(0,0,0,.25));z-index:5">\x27+bigPlant+\x27</div>\x27+
4036
- \x27<div style="position:absolute;bottom:10px;right:12px;font-size:40px;line-height:1;filter:drop-shadow(0 3px 6px rgba(0,0,0,.25));z-index:5">\x27+bigPlant+\x27</div>\x27+
4037
- \x27<div style="position:absolute;top:12px;left:310px;font-size:24px;line-height:1;z-index:5">\x27+plantEmoji+\x27</div>\x27+
4038
- \x27<div style="position:absolute;top:12px;right:230px;font-size:24px;line-height:1;z-index:5">\x27+plantEmoji+\x27</div>\x27;
3914
+
3915
+ var phaseLabel2 = hasActive
3916
+ ? (\x27Workflow in esecuzione \u2014 \x27+doneCount+\x27/\x27+totalCount)
3917
+ : (doneCount===totalCount && totalCount>0 ? \x27Workflow completato\x27 : \x27Workflow pianificato\x27);
3918
+ var phaseColor2 = hasActive ? \x27#6366f1\x27 : (doneCount===totalCount && totalCount>0 ? \x27#1f2937\x27 : \x27#6b7280\x27);
4039
3919
 
4040
3920
  el.innerHTML =
4041
3921
  \x27<div class="prl-wrap" style="border-color:\x27+phaseColor2+\x2744;padding-bottom:8px">\x27+
4042
3922
  \x27<div class="prl-header"><span class="prl-phase-chip" style="--pc:\x27+phaseColor2+\x27">\x27+phaseLabel2+\x27</span></div>\x27+
4043
- \x27<div class="iso-scene" style="position:relative">\x27+
4044
- floorSvg+
4045
- decoHtml+
4046
- // Grid overlay for stations
4047
- \x27<div style="position:relative;z-index:10;display:grid;grid-template-columns:\x27+gridTpl+\x27;gap:0;padding:12px 16px;box-sizing:border-box;align-items:end;min-height:440px">\x27+
4048
- // Push agents to bottom half of scene (wall takes top ~30%)
4049
- \x27<div style="grid-column:1/-1;height:calc(30% - 12px)"></div>\x27+
4050
- stationsHtml+
3923
+ \x27<div style="display:flex;justify-content:center;width:100%;overflow-x:auto">\x27+
3924
+ \x27<div class="iso-scene" style="position:relative;width:\x27+SCENE_W+\x27px;min-width:\x27+SCENE_W+\x27px;height:\x27+SCENE_H+\x27px;overflow:hidden;border-radius:12px;background:#f0ede6">\x27+
3925
+ isoFloorSvg(ISO_COLS + 2, 5)+
3926
+ agentsHtml+
3927
+ orchHtml+
4051
3928
  \x27</div>\x27+
4052
3929
  \x27</div>\x27+
4053
3930
  \x27</div>\x27;
@@ -4687,24 +4564,21 @@ async function runStudio() {
4687
4564
  if (!parlBlockBuilt || !pb.innerHTML.trim()) {
4688
4565
  parlBlockBuilt = true;
4689
4566
 
4690
- // ── SEAT builder — same style as workflow office stations ──────────
4567
+ // ── Seat card builder — emoji + bubble + name ──────────────────────
4691
4568
  function buildSeat(prop, seatIdx) {
4692
4569
  var lbl = prop.label || prop.agent;
4693
4570
  var safeLbl = lbl.replace(new RegExp('[^a-zA-Z0-9_-]','g'),\x27_\x27);
4694
4571
  var emojiIdx = Math.abs(lbl.charCodeAt(0)+(lbl.charCodeAt(lbl.length-1)||0)) % AGENT_EMOJIS.length;
4695
4572
  var agentEmoji = AGENT_EMOJIS[emojiIdx];
4696
4573
  void seatIdx;
4697
- // Each seat: bubble + emoji char + name — states updated surgically later
4698
4574
  return \x27<div class="br-seat" id="brseat_\x27+safeLbl+\x27" data-lbl="\x27+esc(lbl)+\x27">\x27+
4699
4575
  \x27<div class="br-bubble" id="brbubble_\x27+safeLbl+\x27" style="display:none"></div>\x27+
4700
- \x27<div class="br-char" style="font-size:38px;line-height:1;user-select:none;filter:drop-shadow(0 2px 6px rgba(0,0,0,.25))">\x27+agentEmoji+\x27</div>\x27+
4701
- \x27<div class="br-seat-name" id="brname_\x27+safeLbl+\x27">\x27+esc(lbl.slice(0,14))+\x27</div>\x27+
4576
+ \x27<div class="br-char">\x27+agentEmoji+\x27</div>\x27+
4577
+ \x27<div class="br-seat-name" id="brname_\x27+safeLbl+\x27">\x27+esc(lbl)+\x27</div>\x27+
4702
4578
  \x27</div>\x27;
4703
4579
  }
4704
4580
 
4705
- // ── Build seat rows: top row (facing down) + bottom row (facing up)
4706
- // For n agents: ceil(n/2) on top, floor(n/2) on bottom
4707
- // Orchestrator gets the "head" position (left end of table)
4581
+ // Split agents: even indices top, odd indices bottom
4708
4582
  var topSeats = [];
4709
4583
  var botSeats = [];
4710
4584
  proposals.forEach(function(prop, si) {
@@ -4713,55 +4587,41 @@ async function runStudio() {
4713
4587
  var topHtml = topSeats.map(buildSeat).join(\x27\x27);
4714
4588
  var botHtml = botSeats.map(buildSeat).join(\x27\x27);
4715
4589
 
4716
- // ── Orchestrator head seat ─────────────────────────────────────────
4590
+ // Orchestrator at left head of table
4717
4591
  var orchEmoji2 = String.fromCodePoint(0x1F9D1,0x200D,0x1F4BC);
4718
4592
  var crownEm = String.fromCodePoint(0x1F451);
4719
- var orchHeadHtml = \x27<div class="br-orch" id="brOrch" style="display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 10px">\x27+
4593
+ var orchHeadHtml = \x27<div class="br-orch" id="brOrch" style="display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 10px;flex-shrink:0">\x27+
4720
4594
  \x27<div class="br-orch-speech" id="brOrchSpeech" style="display:none"></div>\x27+
4721
- \x27<div style="font-size:16px;line-height:1">\x27+crownEm+\x27</div>\x27+
4722
- \x27<div style="font-size:44px;line-height:1;filter:drop-shadow(0 0 14px #818cf8BB)">\x27+orchEmoji2+\x27</div>\x27+
4723
- \x27<div class="br-orch-label" style="font-size:9px;font-weight:700;color:#6366f1;background:rgba(99,102,241,.12);border-radius:6px;padding:2px 7px;margin-top:2px">Orchestratore</div>\x27+
4595
+ \x27<span style="font-size:18px;line-height:1">\x27+crownEm+\x27</span>\x27+
4596
+ \x27<span style="font-size:48px;line-height:1;filter:drop-shadow(0 0 14px #818cf8BB)">\x27+orchEmoji2+\x27</span>\x27+
4597
+ \x27<div class="br-orch-label">Orchestratore</div>\x27+
4724
4598
  \x27</div>\x27;
4725
4599
 
4726
- // ── Conference table SVG — wide rectangle ──────────────────────────
4727
- // Table is drawn as background SVG, fills the center area
4600
+ // Conference table SVG — wide walnut rectangle
4728
4601
  var tblSvg = \x27<svg viewBox="0 0 1000 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:50%;left:0;width:100%;height:140px;transform:translateY(-50%);z-index:1;pointer-events:none">\x27+
4729
- // Shadow
4602
+ \x27<defs><linearGradient id="tblGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#5a3a18"/><stop offset="0.5" stop-color="#3d2510"/><stop offset="1" stop-color="#2a1808"/></linearGradient></defs>\x27+
4730
4603
  \x27<rect x="8" y="12" width="984" height="176" rx="20" fill="rgba(0,0,0,.22)"/>\x27+
4731
- // Table body — rich dark walnut
4732
4604
  \x27<rect x="0" y="4" width="1000" height="176" rx="18" fill="url(#tblGrad)"/>\x27+
4733
- // Top edge highlight
4734
4605
  \x27<rect x="0" y="4" width="1000" height="8" rx="8" fill="rgba(255,255,255,.08)"/>\x27+
4735
- // Wood grain lines
4736
- \x27<line x1="0" y1="50" x2="1000" y2="50" stroke="rgba(0,0,0,.06)" stroke-width="2"/>\x27+
4737
- \x27<line x1="0" y1="100" x2="1000" y2="100" stroke="rgba(0,0,0,.08)" stroke-width="2"/>\x27+
4738
- \x27<line x1="0" y1="150" x2="1000" y2="150" stroke="rgba(0,0,0,.06)" stroke-width="2"/>\x27+
4739
- // NHA monogram center
4740
- \x27<text x="500" y="115" text-anchor="middle" font-family="system-ui" font-size="52" font-weight="900" fill="rgba(150,130,255,.12)" letter-spacing="8">NHA</text>\x27+
4741
- // Laptop/papers scattered on table
4606
+ \x27<line x1="0" y1="60" x2="1000" y2="60" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4607
+ \x27<line x1="0" y1="100" x2="1000" y2="100" stroke="rgba(0,0,0,.09)" stroke-width="2"/>\x27+
4608
+ \x27<line x1="0" y1="140" x2="1000" y2="140" stroke="rgba(0,0,0,.07)" stroke-width="2"/>\x27+
4609
+ \x27<text x="500" y="115" text-anchor="middle" font-family="system-ui" font-size="52" font-weight="900" fill="rgba(150,130,255,.1)" letter-spacing="8">NHA</text>\x27+
4742
4610
  \x27<rect x="180" y="60" width="60" height="40" rx="4" fill="rgba(99,102,241,.18)" stroke="rgba(99,102,241,.35)" stroke-width="1.5"/>\x27+
4743
4611
  \x27<rect x="390" y="55" width="70" height="45" rx="4" fill="rgba(99,102,241,.14)" stroke="rgba(99,102,241,.3)" stroke-width="1.5"/>\x27+
4744
4612
  \x27<rect x="650" y="62" width="55" height="38" rx="4" fill="rgba(99,102,241,.18)" stroke="rgba(99,102,241,.35)" stroke-width="1.5"/>\x27+
4745
- \x27<rect x="820" y="58" width="50" height="36" rx="4" fill="rgba(99,102,241,.12)" stroke="rgba(99,102,241,.28)" stroke-width="1.5"/>\x27+
4746
- // Coffee cups
4747
- \x27<circle cx="300" cy="88" r="14" fill="rgba(180,120,60,.4)" stroke="rgba(180,120,60,.6)" stroke-width="1.5"/>\x27+
4613
+ \x27<circle cx="300" cy="90" r="14" fill="rgba(180,120,60,.4)" stroke="rgba(180,120,60,.6)" stroke-width="1.5"/>\x27+
4748
4614
  \x27<circle cx="750" cy="92" r="14" fill="rgba(180,120,60,.4)" stroke="rgba(180,120,60,.6)" stroke-width="1.5"/>\x27+
4749
- \x27<defs>\x27+
4750
- \x27<linearGradient id="tblGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#5a3a18"/><stop offset="0.5" stop-color="#3d2510"/><stop offset="1" stop-color="#2a1808"/></linearGradient>\x27+
4751
- \x27</defs>\x27+
4752
4615
  \x27</svg>\x27;
4753
4616
 
4754
- // ── Floor + wall SVG background (same as workflow scene) ───────────
4617
+ // Background: parquet floor + white wall + windows + chandelier + door
4755
4618
  var bgSvg = \x27<svg viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none">\x27+
4756
4619
  \x27<defs>\x27+
4757
4620
  \x27<filter id="brGlow" x="-100%" y="-100%" width="300%" height="300%"><feGaussianBlur stdDeviation="5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27+
4758
4621
  \x27<linearGradient id="brWall" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#faf7f2"/><stop offset="1" stop-color="#ede8e0"/></linearGradient>\x27+
4759
4622
  \x27</defs>\x27+
4760
- // Wall
4761
4623
  \x27<rect x="0" y="0" width="1000" height="210" fill="url(#brWall)"/>\x27+
4762
- // Baseboard
4763
4624
  \x27<rect x="0" y="205" width="1000" height="7" fill="#d4c4a8" rx="2"/>\x27+
4764
- // Parquet floor
4765
4625
  function() {
4766
4626
  var s2 = \x27\x27;
4767
4627
  var pColors = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#caa86e\x27];
@@ -4776,7 +4636,6 @@ async function runStudio() {
4776
4636
  }
4777
4637
  return s2;
4778
4638
  }()+
4779
- // Windows
4780
4639
  \x27<rect x="40" y="22" width="110" height="88" rx="5" fill="#c8e6f8" stroke="#a8cce0" stroke-width="3"/>\x27+
4781
4640
  \x27<line x1="95" y1="22" x2="95" y2="110" stroke="#a8cce0" stroke-width="2"/>\x27+
4782
4641
  \x27<line x1="40" y1="66" x2="150" y2="66" stroke="#a8cce0" stroke-width="2"/>\x27+
@@ -4785,11 +4644,9 @@ async function runStudio() {
4785
4644
  \x27<line x1="905" y1="22" x2="905" y2="110" stroke="#a8cce0" stroke-width="2"/>\x27+
4786
4645
  \x27<line x1="850" y1="66" x2="960" y2="66" stroke="#a8cce0" stroke-width="2"/>\x27+
4787
4646
  \x27<rect x="850" y="22" width="110" height="88" rx="5" fill="rgba(255,255,255,.18)"/>\x27+
4788
- // Door
4789
4647
  \x27<rect x="463" y="0" width="74" height="210" fill="#c8a87a" stroke="#a07848" stroke-width="2"/>\x27+
4790
4648
  \x27<rect x="472" y="10" width="56" height="50" rx="5" fill="rgba(255,255,255,.18)"/>\x27+
4791
4649
  \x27<circle cx="524" cy="108" r="6" fill="#8a6028"/>\x27+
4792
- // Chandelier
4793
4650
  \x27<line x1="500" y1="0" x2="500" y2="32" stroke="#bbb" stroke-width="3"/>\x27+
4794
4651
  \x27<ellipse cx="500" cy="42" rx="60" ry="16" fill="#e8d960" stroke="#c8b030" stroke-width="2"/>\x27+
4795
4652
  \x27<circle cx="468" cy="52" r="10" fill="#fffde0" filter="url(#brGlow)"/>\x27+
@@ -4798,7 +4655,6 @@ async function runStudio() {
4798
4655
  \x27<polygon points="440,66 560,66 680,600 320,600" fill="rgba(255,252,200,.05)"/>\x27+
4799
4656
  \x27</svg>\x27;
4800
4657
 
4801
- // ── Phase header ───────────────────────────────────────────────────
4802
4658
  var headerHtml = \x27<div class="br-header">\x27+
4803
4659
  \x27<span class="br-phase-chip" id="brPhaseChip"></span>\x27+
4804
4660
  \x27<div class="br-progress-wrap" id="brProgressWrap"><div class="br-progress-bar" id="brProgressBar"></div></div>\x27+
@@ -4806,30 +4662,20 @@ async function runStudio() {
4806
4662
 
4807
4663
  var convergeHtml = \x27<div class="br-convergence" id="brConvergence" style="display:none"></div>\x27;
4808
4664
 
4809
- // ── Assemble: full-width scene with table ──────────────────────────
4810
4665
  pb.innerHTML =
4811
4666
  \x27<div class="br-wrap">\x27+
4812
4667
  headerHtml+
4813
- \x27<div class="br-room" style="position:relative;width:100%;min-height:480px;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18)">\x27+
4668
+ \x27<div class="br-room">\x27+
4814
4669
  bgSvg+
4815
- // Decorations
4816
- \x27<div style="position:absolute;bottom:10px;left:12px;font-size:40px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.25))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4817
- \x27<div style="position:absolute;bottom:10px;right:12px;font-size:40px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.25))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4818
- \x27<div style="position:absolute;top:14px;left:180px;font-size:24px;z-index:5">\x27+String.fromCodePoint(0x1F331)+\x27</div>\x27+
4819
- \x27<div style="position:absolute;top:14px;right:180px;font-size:24px;z-index:5">\x27+String.fromCodePoint(0x1F331)+\x27</div>\x27+
4820
- // Layout: flex column — top row / [orch + table] / bottom row
4670
+ \x27<div style="position:absolute;bottom:10px;left:12px;font-size:36px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.2))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4671
+ \x27<div style="position:absolute;bottom:10px;right:12px;font-size:36px;z-index:5;filter:drop-shadow(0 3px 6px rgba(0,0,0,.2))">\x27+String.fromCodePoint(0x1FAB4)+\x27</div>\x27+
4821
4672
  \x27<div style="position:relative;z-index:10;display:flex;flex-direction:column;justify-content:center;min-height:480px;padding:20px 16px;gap:0;box-sizing:border-box">\x27+
4822
- // Top seats row (faces DOWN toward table)
4823
- \x27<div class="br-seats-row" style="justify-content:space-around;margin-bottom:8px">\x27+topHtml+\x27</div>\x27+
4824
- // Middle row: orchestrator head + table SVG
4673
+ \x27<div class="br-seats-row">\x27+topHtml+\x27</div>\x27+
4825
4674
  \x27<div style="position:relative;display:flex;align-items:center;width:100%;min-height:160px">\x27+
4826
- // Orch at left head of table
4827
4675
  orchHeadHtml+
4828
- // Table fills the rest of the middle row
4829
4676
  \x27<div style="position:relative;flex:1;min-height:140px">\x27+tblSvg+\x27</div>\x27+
4830
4677
  \x27</div>\x27+
4831
- // Bottom seats row (faces UP toward table)
4832
- \x27<div class="br-seats-row" style="justify-content:space-around;margin-top:8px">\x27+botHtml+\x27</div>\x27+
4678
+ \x27<div class="br-seats-row">\x27+botHtml+\x27</div>\x27+
4833
4679
  \x27</div>\x27+
4834
4680
  \x27</div>\x27+
4835
4681
  convergeHtml+
@@ -4955,420 +4801,8 @@ async function runStudio() {
4955
4801
  }
4956
4802
  });
4957
4803
 
4958
- // ── Old function stubs needed by remaining code paths ────────────────
4959
- function buildChar(prop, isDone, isActive, isOrchestratorTarget) {
4960
- var lbl = prop.label || prop.agent;
4961
- var ico = prop.icon || String.fromCharCode(9632);
4962
- // skin tones cycle through a palette for visual variety
4963
- var skinColors = [\x27#fbbf24\x27,\x27#f97316\x27,\x27#a78bfa\x27,\x27#34d399\x27,\x27#60a5fa\x27,\x27#f472b6\x27];
4964
- var skinIdx = Math.abs(lbl.charCodeAt(0)+lbl.charCodeAt(lbl.length-1)) % skinColors.length;
4965
- var skin = skinColors[skinIdx];
4966
- var deskColor = isDone ? \x27#253a25\x27 : (isActive ? \x27#282050\x27 : \x27#221c44\x27);
4967
- var deskBorder = isDone ? \x27#22c55e\x27 : (isActive ? phaseColor : \x27#4a3880\x27);
4968
- var shadow = isActive ? (\x270 0 18px \x27+phaseColor+\x2755\x27) : \x27none\x27;
4969
-
4970
- // Action text shown above character
4971
- var actionStr = \x27\x27;
4972
- if (phase===\x27r1\x27 && isActive) actionStr = \x27...analizza\x27;
4973
- else if (phase===\x27r1\x27 && isDone) actionStr = \x27\u2714 bozza pronta\x27;
4974
- else if (phase===\x27r2\x27 && isActive) actionStr = \x27...legge + raffina\x27;
4975
- else if (phase===\x27r2\x27 && isDone) actionStr = \x27\u2714 raffinato\x27;
4976
- else if (phase===\x27r3\x27 && isActive) actionStr = \x27...media\x27;
4977
- else if (phase===\x27done\x27) actionStr = \x27\u2714 consenso\x27;
4978
-
4979
- // SVG character (80px wide, 70px tall)
4980
- // Desk: rectangle at bottom. Chair back. Body. Head. Arms animated.
4981
- var armAnim = (isActive && phase!==\x27done\x27) ? \x27class="prl-arm"\x27 : \x27\x27;
4982
- var headAnim = (isActive && phase!==\x27done\x27) ? \x27class="prl-head"\x27 : \x27\x27;
4983
- var glowStyle = isActive ? (\x27filter:drop-shadow(0 0 6px \x27+phaseColor+\x27)\x27) : \x27\x27;
4984
-
4985
- // Document held up during R2 cross-reading
4986
- var docHtml = \x27\x27;
4987
- if (phase===\x27r2\x27 && isActive) {
4988
- docHtml = \x27<rect x="46" y="6" width="14" height="18" rx="2" fill="#0f0f1e" stroke="#22d3ee" stroke-width="1.5" class="prl-doc-hold"/>\x27+
4989
- \x27<line x1="49" y1="11" x2="57" y2="11" stroke="#22d3ee" stroke-width="1" opacity=".7"/>\x27+
4990
- \x27<line x1="49" y1="14" x2="57" y2="14" stroke="#22d3ee" stroke-width="1" opacity=".5"/>\x27+
4991
- \x27<line x1="49" y1="17" x2="54" y2="17" stroke="#22d3ee" stroke-width="1" opacity=".4"/>\x27;
4992
- }
4993
- if (phase===\x27r3\x27 && isActive) {
4994
- docHtml = \x27<rect x="46" y="6" width="14" height="18" rx="2" fill="#0f0f1e" stroke="#f59e0b" stroke-width="1.5" class="prl-doc-hold"/>\x27+
4995
- \x27<line x1="49" y1="11" x2="57" y2="11" stroke="#f59e0b" stroke-width="1" opacity=".7"/>\x27+
4996
- \x27<line x1="49" y1="14" x2="57" y2="14" stroke="#f59e0b" stroke-width="1" opacity=".5"/>\x27;
4997
- }
4998
-
4999
- // Shirt colors — vibrant, professional palette
5000
- var shirtColors = [\x27#4f46e5\x27,\x27#0891b2\x27,\x27#7c3aed\x27,\x27#059669\x27,\x27#dc2626\x27,\x27#d97706\x27];
5001
- var shirt = shirtColors[skinIdx];
5002
- // Hair colors — varied and realistic
5003
- var hairColors = [\x27#1a1a1a\x27,\x27#4a3728\x27,\x27#c4a35a\x27,\x27#8b0000\x27,\x27#2c4a7c\x27,\x27#3d2b1f\x27];
5004
- var hair = hairColors[skinIdx];
5005
- var monitorGlow = isActive ? (\x27filter:drop-shadow(0 0 5px \x27+phaseColor+\x2780)\x27) : \x27\x27;
5006
-
5007
- var svgChar = \x27<svg viewBox="0 0 80 96" width="76" height="90" xmlns="http://www.w3.org/2000/svg" style="\x27+glowStyle+\x27;display:block;margin:0 auto">\x27+
5008
- // ════ ISOMETRIC-STYLE DESK ════
5009
- // Desk top — parallelogram for 3D feel (top face)
5010
- \x27<path d="M4 55 L76 55 L76 63 L4 63 Z" fill="\x27+deskColor+\x27" stroke="\x27+deskBorder+\x27" stroke-width="1.2"/>\x27+
5011
- // Desk front face (darker) — 3D depth
5012
- \x27<path d="M4 63 L76 63 L76 70 L4 70 Z" fill="\x27+(isDone?\x27#0d2010\x27:(isActive?\x27#0c0c22\x27:\x27#0e0e1c\x27))+\x27"/>\x27+
5013
- // Desk left side face
5014
- \x27<path d="M4 55 L4 70 L4 70" fill="none"/>\x27+
5015
- // Desk front edge highlight
5016
- \x27<line x1="4" y1="63" x2="76" y2="63" stroke="\x27+deskBorder+\x2760" stroke-width=".8"/>\x27+
5017
- // Desk legs — rounded, tapered
5018
- \x27<path d="M10 70 C10 70 9 82 9 84 C9 86 11 87 13 87 C15 87 17 86 17 84 C17 82 16 70 16 70 Z" fill="#111128"/>\x27+
5019
- \x27<path d="M63 70 C63 70 62 82 62 84 C62 86 64 87 66 87 C68 87 70 86 70 84 C70 82 69 70 69 70 Z" fill="#111128"/>\x27+
5020
- // Desk shelf between legs
5021
- \x27<rect x="17" y="79" width="46" height="3" rx="1.5" fill="#161626"/>\x27+
5022
- // ════ MONITOR (sleek, thin-bezel) ════
5023
- // Monitor shadow on desk
5024
- \x27<ellipse cx="35" cy="56" rx="14" ry="2" fill="rgba(0,0,0,.4)"/>\x27+
5025
- // Monitor stand base
5026
- \x27<ellipse cx="35" cy="57" rx="7" ry="1.5" fill="#1a1a2e"/>\x27+
5027
- // Monitor stand pole
5028
- \x27<rect x="33" y="50" width="4" height="6" rx="1" fill="#1a1a2e"/>\x27+
5029
- // Monitor outer bezel — shadow/depth
5030
- \x27<rect x="17" y="26" width="36" height="25" rx="4" fill="#050510"/>\x27+
5031
- // Monitor bezel
5032
- \x27<rect x="18" y="27" width="34" height="23" rx="3" fill="#0d0d20" stroke="\x27+(isActive?phaseColor:\x27#252535\x27)+\x27" stroke-width="\x27+(isActive?\x272\x27:\x271\x27)+\x27" style="\x27+monitorGlow+\x27"/>\x27+
5033
- // Screen glass — idle=standby blue, done=green, active=lit
5034
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="\x27+(isDone?\x27#0a1a0a\x27:(isActive?\x27#0a0a18\x27:\x27#0e0e22\x27))+\x27"/>\x27+
5035
- // Screen content
5036
- (isActive ?
5037
- // Active: glowing code/data on screen
5038
- \x27<defs><linearGradient id="sg\x27+skinIdx+\x27" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="\x27+phaseColor+\x2722"/><stop offset="1" stop-color="\x27+phaseColor+\x2708"/></linearGradient></defs>\x27+
5039
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="url(#sg\x27+skinIdx+\x27)"/>\x27+
5040
- \x27<line x1="22" y1="32" x2="48" y2="32" stroke="\x27+phaseColor+\x27ee" stroke-width="1.2" stroke-linecap="round"/>\x27+
5041
- \x27<line x1="22" y1="35" x2="44" y2="35" stroke="\x27+phaseColor+\x27aa" stroke-width="1" stroke-linecap="round"/>\x27+
5042
- \x27<line x1="22" y1="38" x2="46" y2="38" stroke="\x27+phaseColor+\x2788" stroke-width="1" stroke-linecap="round"/>\x27+
5043
- \x27<line x1="22" y1="41" x2="40" y2="41" stroke="\x27+phaseColor+\x2766" stroke-width="1" stroke-linecap="round"/>\x27+
5044
- \x27<line x1="22" y1="44" x2="43" y2="44" stroke="\x27+phaseColor+\x2744" stroke-width="1" stroke-linecap="round"/>\x27+
5045
- \x27<rect x="22" y="30" width="10" height="2.5" rx="1" fill="\x27+phaseColor+\x2733"/>\x27
5046
- : isDone ?
5047
- // Done: green screen with completed output
5048
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="#0a1a0a88"/>\x27+
5049
- \x27<line x1="22" y1="32" x2="44" y2="32" stroke="#22c55e99" stroke-width="1" stroke-linecap="round"/>\x27+
5050
- \x27<line x1="22" y1="35" x2="46" y2="35" stroke="#22c55e77" stroke-width="1" stroke-linecap="round"/>\x27+
5051
- \x27<line x1="22" y1="38" x2="40" y2="38" stroke="#22c55e55" stroke-width="1" stroke-linecap="round"/>\x27+
5052
- \x27<line x1="22" y1="41" x2="43" y2="41" stroke="#22c55e44" stroke-width="1" stroke-linecap="round"/>\x27
5053
- :
5054
- // Idle: dim standby screen — waiting, lit but quiet
5055
- \x27<rect x="20" y="29" width="30" height="18" rx="2" fill="rgba(90,80,180,.35)"/>\x27+
5056
- \x27<line x1="22" y1="33" x2="46" y2="33" stroke="#9090cc" stroke-width="1" stroke-linecap="round" opacity=".8"/>\x27+
5057
- \x27<line x1="22" y1="36" x2="38" y2="36" stroke="#8080bb" stroke-width="1" stroke-linecap="round" opacity=".65"/>\x27+
5058
- \x27<line x1="22" y1="39" x2="44" y2="39" stroke="#7070aa" stroke-width="1" stroke-linecap="round" opacity=".5"/>\x27+
5059
- \x27<line x1="22" y1="42" x2="34" y2="42" stroke="#6060a0" stroke-width="1" stroke-linecap="round" opacity=".4"/>\x27+
5060
- \x27<circle cx="22" cy="45" r="1" fill="#6366f1" opacity=".6" class="prl-doc-hold"/>\x27
5061
- )+
5062
- // Monitor camera dot
5063
- \x27<circle cx="35" cy="28.2" r=".9" fill="\x27+(isActive?phaseColor:(isDone?\x27#22c55e\x27:\x27#6060c8\x27))+\x27"/>\x27+
5064
- // ════ KEYBOARD (detailed, realistic) ════
5065
- \x27<rect x="13" y="48" width="36" height="7" rx="2.5" fill="#0c0c1e" stroke="#202036" stroke-width="1"/>\x27+
5066
- // Key rows
5067
- \x27<rect x="14" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5068
- \x27<rect x="18" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5069
- \x27<rect x="22" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5070
- \x27<rect x="26" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5071
- \x27<rect x="30" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5072
- \x27<rect x="34" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5073
- \x27<rect x="38" y="49.5" width="3" height="2" rx=".5" fill="#181830"/>\x27+
5074
- \x27<rect x="15" y="52.5" width="5" height="2" rx=".5" fill="#181830"/>\x27+
5075
- \x27<rect x="21" y="52.5" width="5" height="2" rx=".5" fill="#181830"/>\x27+
5076
- \x27<rect x="27" y="52.5" width="5" height="2" rx=".5" fill="#181830"/>\x27+
5077
- \x27<rect x="33" y="52.5" width="5" height="2" rx=".5" fill="#181830"/>\x27+
5078
- // Spacebar
5079
- \x27<rect x="19" y="55" width="24" height="1.8" rx=".9" fill="#181830"/>\x27+
5080
- // ════ ERGONOMIC CHAIR ════
5081
- // Chair base
5082
- \x27<ellipse cx="34" cy="72" rx="12" ry="4" fill="#111124"/>\x27+
5083
- // Chair gas lift
5084
- \x27<rect x="32" y="65" width="4" height="8" rx="1" fill="#1a1a2c"/>\x27+
5085
- // Chair seat
5086
- \x27<path d="M22 60 Q22 56 34 56 Q46 56 46 60 L46 66 Q46 68 34 68 Q22 68 22 66 Z" fill="#1c1c2c" stroke="#2a2a3e" stroke-width="1"/>\x27+
5087
- // Chair backrest
5088
- \x27<path d="M24 44 Q23 38 34 37 Q45 38 44 44 L44 58 Q44 60 34 60 Q24 60 24 58 Z" fill="#191928" stroke="#2a2a3c" stroke-width="1"/>\x27+
5089
- // Chair backrest cushion
5090
- \x27<path d="M26 46 Q26 41 34 40 Q42 41 42 46 L42 57 Q42 58 34 58 Q26 58 26 57 Z" fill="#1e1e30"/>\x27+
5091
- // Chair headrest
5092
- \x27<path d="M28 37 Q28 33 34 33 Q40 33 40 37 L40 39 Q40 40 34 40 Q28 40 28 39 Z" fill="#191928" stroke="#2a2a3c" stroke-width="1"/>\x27+
5093
- // Chair armrests
5094
- \x27<path d="M22 55 L18 55 Q16 55 16 57 L16 60 Q16 62 18 62 L22 62 Q24 62 24 60 L24 55 Z" fill="#1c1c2c"/>\x27+
5095
- \x27<path d="M46 55 L50 55 Q52 55 52 57 L52 60 Q52 62 50 62 L46 62 Q44 62 44 60 L44 55 Z" fill="#1c1c2c"/>\x27+
5096
- // ════ TORSO / SHIRT ════
5097
- // shirt back visible above chair
5098
- \x27<path d="M27 58 Q27 54 34 53 Q41 54 41 58 L42 65 L26 65 Z" fill="\x27+shirt+\x27cc"/>\x27+
5099
- // shirt body
5100
- \x27<path d="M27 44 Q27 42 34 41 Q41 42 41 44 L42 58 L26 58 Z" fill="\x27+shirt+\x27"/>\x27+
5101
- // shirt shading (left side)
5102
- \x27<path d="M27 44 Q27 42 34 41 L34 58 L26 58 Z" fill="rgba(0,0,0,.12)"/>\x27+
5103
- // collar / V-neck
5104
- \x27<path d="M34 41 L31 46 L34 44.5 L37 46 Z" fill="\x27+skin+\x27ee"/>\x27+
5105
- // shirt wrinkle detail
5106
- \x27<line x1="34" y1="46" x2="34" y2="57" stroke="rgba(0,0,0,.08)" stroke-width="2" stroke-linecap="round"/>\x27+
5107
- // ════ ARMS (typing position) ════
5108
- \x27<g \x27+armAnim+\x27>\x27+
5109
- // Left upper arm
5110
- \x27<path d="M28 45 C24 47 22 50 21 53 C21 55 23 56 25 55 C27 54 27 52 28 49 Z" fill="\x27+shirt+\x27"/>\x27+
5111
- // Left forearm
5112
- \x27<path d="M21 53 C19 55 18 57 18 59 C18 61 20 62 22 61 C24 60 24 58 25 55 Z" fill="\x27+skin+\x27"/>\x27+
5113
- // Left hand
5114
- \x27<ellipse cx="19" cy="60" rx="4" ry="3" fill="\x27+skin+\x27" transform="rotate(-10 19 60)"/>\x27+
5115
- // Right upper arm
5116
- \x27<path d="M40 45 C44 47 46 50 47 53 C47 55 45 56 43 55 C41 54 41 52 40 49 Z" fill="\x27+shirt+\x27"/>\x27+
5117
- // Right forearm
5118
- \x27<path d="M47 53 C49 55 50 57 50 59 C50 61 48 62 46 61 C44 60 44 58 43 55 Z" fill="\x27+skin+\x27"/>\x27+
5119
- // Right hand
5120
- \x27<ellipse cx="49" cy="60" rx="4" ry="3" fill="\x27+skin+\x27" transform="rotate(10 49 60)"/>\x27+
5121
- \x27</g>\x27+
5122
- // ════ HEAD (smooth, expressive) ════
5123
- \x27<g \x27+headAnim+\x27>\x27+
5124
- // Neck with shadow
5125
- \x27<path d="M30 40 L38 40 L38 43 Q38 45 34 45 Q30 45 30 43 Z" fill="\x27+skin+\x27"/>\x27+
5126
- \x27<path d="M30 40 L34 40 L34 45 Q30 45 30 43 Z" fill="rgba(0,0,0,.08)"/>\x27+
5127
- // Head — well-proportioned ellipse
5128
- \x27<ellipse cx="34" cy="29" rx="11" ry="12.5" fill="\x27+skin+\x27"/>\x27+
5129
- // Cheek blush (subtle)
5130
- \x27<ellipse cx="26" cy="32" rx="3.5" ry="2" fill="\x27+skin+\x27" opacity=".6"/>\x27+
5131
- \x27<ellipse cx="42" cy="32" rx="3.5" ry="2" fill="\x27+skin+\x27" opacity=".6"/>\x27+
5132
- // Head shadow (right)
5133
- \x27<ellipse cx="41" cy="29" rx="5" ry="11" fill="rgba(0,0,0,.06)"/>\x27+
5134
- // Ears — detailed
5135
- \x27<path d="M23 28 C21 28 20 30 20 31.5 C20 33 21 34.5 23 34.5 C24 34.5 24.5 33.5 24 31.5 C24.5 29.5 24 28 23 28" fill="\x27+skin+\x27"/>\x27+
5136
- \x27<path d="M45 28 C47 28 48 30 48 31.5 C48 33 47 34.5 45 34.5 C44 34.5 43.5 33.5 44 31.5 C43.5 29.5 44 28 45 28" fill="\x27+skin+\x27"/>\x27+
5137
- \x27<path d="M23.5 30 C22.5 30.5 22.5 32.5 23.5 33" stroke="\x27+skin+\x27" stroke-width="1" fill="none" opacity=".5"/>\x27+
5138
- // Hair — styled, voluminous
5139
- \x27<path d="M23 28 C22 22 24 16 34 15 C44 16 46 22 45 28 C44 22 42 18 34 17 C26 18 24 22 23 28" fill="\x27+hair+\x27"/>\x27+
5140
- \x27<path d="M23 27 C22 24 23 19 26 17 C24 20 23 24 24 27" fill="\x27+hair+\x2788"/>\x27+
5141
- // Hair highlight
5142
- \x27<path d="M28 17 C30 15 33 15 36 16 C33 14 29 15 28 17" fill="rgba(255,255,255,.12)"/>\x27+
5143
- // Eyebrows — expressive
5144
- \x27<path d="M27 23 Q29.5 21.5 32 23" stroke="\x27+hair+\x27" stroke-width="1.6" fill="none" stroke-linecap="round"/>\x27+
5145
- \x27<path d="M36 23 Q38.5 21.5 41 23" stroke="\x27+hair+\x27" stroke-width="1.6" fill="none" stroke-linecap="round"/>\x27+
5146
- // Eyes — full detail: white + iris + pupil + highlight
5147
- \x27<ellipse cx="30" cy="27.5" rx="3" ry="3.5" fill="#fff" stroke="\x27+skin+\x2740" stroke-width=".5"/>\x27+
5148
- \x27<ellipse cx="38" cy="27.5" rx="3" ry="3.5" fill="#fff" stroke="\x27+skin+\x2740" stroke-width=".5"/>\x27+
5149
- // Iris
5150
- \x27<circle cx="30" cy="28" r="2.2" fill="#3d4a6b"/>\x27+
5151
- \x27<circle cx="38" cy="28" r="2.2" fill="#3d4a6b"/>\x27+
5152
- // Pupil
5153
- \x27<circle cx="30" cy="28" r="1.3" fill="#0a0a14"/>\x27+
5154
- \x27<circle cx="38" cy="28" r="1.3" fill="#0a0a14"/>\x27+
5155
- // Eye shine
5156
- \x27<circle cx="31" cy="27" r=".8" fill="rgba(255,255,255,.9)"/>\x27+
5157
- \x27<circle cx="39" cy="27" r=".8" fill="rgba(255,255,255,.9)"/>\x27+
5158
- \x27<circle cx="29.5" cy="29" r=".35" fill="rgba(255,255,255,.4)"/>\x27+
5159
- // Lower eyelid line
5160
- \x27<path d="M27 30 Q30 31.5 33 30" stroke="\x27+skin+\x27" stroke-width=".7" fill="none" opacity=".5"/>\x27+
5161
- \x27<path d="M35 30 Q38 31.5 41 30" stroke="\x27+skin+\x27" stroke-width=".7" fill="none" opacity=".5"/>\x27+
5162
- // Nose — soft curved
5163
- \x27<path d="M33 31 Q33 33 34 33.5 Q35 34 35 33 Q36 33 36 31" stroke="\x27+skin+\x27" stroke-width="1.1" fill="none" stroke-linecap="round" opacity=".7"/>\x27+
5164
- \x27<ellipse cx="31.5" cy="33.5" rx="1.2" ry=".7" fill="rgba(0,0,0,.08)"/>\x27+
5165
- \x27<ellipse cx="36.5" cy="33.5" rx="1.2" ry=".7" fill="rgba(0,0,0,.08)"/>\x27+
5166
- // Mouth — expressive
5167
- (isDone ?
5168
- // Big smile when done
5169
- \x27<path d="M29 37 Q34 42 39 37" stroke="#8b4513" stroke-width="1.8" fill="none" stroke-linecap="round"/>\x27+
5170
- \x27<path d="M29 37 Q34 41 39 37" stroke="rgba(255,255,255,.3)" stroke-width=".5" fill="none" stroke-linecap="round"/>\x27+
5171
- // Teeth
5172
- \x27<path d="M30 37.5 Q34 41 38 37.5 Q34 40 30 37.5" fill="#fff" opacity=".8"/>\x27
5173
- :
5174
- // Focused expression
5175
- \x27<path d="M30.5 37 Q34 38.5 37.5 37" stroke="#8b4513" stroke-width="1.4" fill="none" stroke-linecap="round"/>\x27
5176
- )+
5177
- // Agent badge/pin on shirt
5178
- \x27<circle cx="38.5" cy="48" r="5.5" fill="#0f0f1e" stroke="\x27+shirt+\x2780" stroke-width="1.2"/>\x27+
5179
- \x27<circle cx="38.5" cy="48" r="4" fill="#161622"/>\x27+
5180
- \x27<text x="38.5" y="51" text-anchor="middle" font-size="6">\x27+ico+\x27</text>\x27+
5181
- \x27</g>\x27+
5182
- // ════ DONE BADGE (top right corner, polished) ════
5183
- (isDone ?
5184
- \x27<circle cx="67" cy="9" r="10" fill="#0a2010"/>\x27+
5185
- \x27<circle cx="67" cy="9" r="8" fill="#16a34a"/>\x27+
5186
- \x27<circle cx="67" cy="9" r="6" fill="#22c55e"/>\x27+
5187
- \x27<path d="M62.5 9 L65.5 12 L71.5 5" stroke="#fff" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>\x27
5188
- : \x27\x27)+
5189
- docHtml+
5190
- \x27</svg>\x27;
5191
-
5192
- 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+
5193
- (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)+
5194
- svgChar+
5195
- \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+
5196
- \x27</div>\x27;
5197
- }
5198
-
5199
- // ── MASTER ORCHESTRATOR walking animation ─────────────────────────
5200
- // In R1: walks left-right between desks (CSS animation).
5201
- // In R2: stands at the active agent's desk.
5202
- // In R3: stands center with lightning bolt.
5203
- var masterIcon = phase===\x27r3\x27 ? \x27\u26a1\x27 : (phase===\x27done\x27 ? \x27\u2714\x27 : \x27\u2666\x27);
5204
- var masterColor2 = {r1:\x27#818cf8\x27,r2:\x27#818cf8\x27,r3:\x27#f59e0b\x27,done:\x27#22c55e\x27}[phase]||\x27#818cf8\x27;
5205
- 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));
5206
- 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+
5207
- // ════ LEGS (walking when R1) ════
5208
- // Left leg — trouser
5209
- \x27<path d="M22 55 C21 63 19 72 18 77 C17 80 18 82 21 82 C23 82 24 80 24 77 C25 71 25 62 26 55 Z" fill="#1e1c4a" class="prl-master-leg-l"/>\x27+
5210
- // Right leg — trouser
5211
- \x27<path d="M28 55 C29 63 31 72 32 77 C33 80 32 82 29 82 C27 82 26 80 26 77 C25 71 25 62 24 55 Z" fill="#1e1c4a" class="prl-master-leg-r"/>\x27+
5212
- // Left shoe — detailed
5213
- \x27<path d="M16 79 C14 79 13 81 14 83 C15 85 18 85 21 84 C23 83 24 82 23 80 C22 79 19 79 16 79" fill="#0a0a14"/>\x27+
5214
- \x27<path d="M16 79 C15 80 14 82 15 83" stroke="#1a1a2e" stroke-width=".8" fill="none"/>\x27+
5215
- // Right shoe
5216
- \x27<path d="M34 79 C36 79 37 81 36 83 C35 85 32 85 29 84 C27 83 26 82 27 80 C28 79 31 79 34 79" fill="#0a0a14"/>\x27+
5217
- // Trouser crease
5218
- \x27<line x1="23" y1="55" x2="21" y2="77" stroke="rgba(255,255,255,.08)" stroke-width="1" stroke-linecap="round"/>\x27+
5219
- \x27<line x1="27" y1="55" x2="29" y2="77" stroke="rgba(255,255,255,.08)" stroke-width="1" stroke-linecap="round"/>\x27+
5220
- // ════ TORSO — Premium dark suit ════
5221
- // Suit jacket base
5222
- \x27<path d="M13 32 C12 30 15 27 25 25 C35 27 38 30 37 32 L38 55 L12 55 Z" fill="#252450"/>\x27+
5223
- // Left suit front panel
5224
- \x27<path d="M13 32 C12 30 15 27 25 25 L25 55 L12 55 Z" fill="#1e1d44"/>\x27+
5225
- // Right suit front panel (lighter)
5226
- \x27<path d="M25 25 C35 27 38 30 37 32 L38 55 L25 55 Z" fill="#272660"/>\x27+
5227
- // Suit lapels — left
5228
- \x27<path d="M25 25 L19 33 L22 36 L25 29 Z" fill="#1a1940" stroke="#252450" stroke-width=".5"/>\x27+
5229
- // Suit lapels — right
5230
- \x27<path d="M25 25 L31 33 L28 36 L25 29 Z" fill="#1a1940" stroke="#252450" stroke-width=".5"/>\x27+
5231
- // White shirt / tie visible between lapels
5232
- \x27<path d="M25 29 L22 36 L25 34 L28 36 Z" fill="#f0f0fa"/>\x27+
5233
- // Tie — authority color
5234
- \x27<path d="M25 33 L24 44 L25 48 L26 44 Z" fill="\x27+masterColor2+\x27"/>\x27+
5235
- \x27<path d="M24 44 L25 48 L26 44 L25 43 Z" fill="\x27+masterColor2+\x27cc"/>\x27+
5236
- // Tie knot
5237
- \x27<path d="M23.5 32 L26.5 32 L25 34 Z" fill="\x27+masterColor2+\x27"/>\x27+
5238
- // Suit pocket square
5239
- \x27<path d="M33 35 L36 33 L37 36 L34 37 Z" fill="\x27+masterColor2+\x2799"/>\x27+
5240
- // Suit buttons
5241
- \x27<circle cx="25" cy="42" r="1.2" fill="\x27+masterColor2+\x27aa"/>\x27+
5242
- \x27<circle cx="25" cy="46" r="1.2" fill="\x27+masterColor2+\x27aa"/>\x27+
5243
- // Suit lapel badge / NHA logo
5244
- \x27<circle cx="20" cy="36" r="2.5" fill="#0d0d1e" stroke="\x27+masterColor2+\x2799" stroke-width="1"/>\x27+
5245
- \x27<text x="20" y="39" text-anchor="middle" font-size="4" fill="\x27+masterColor2+\x27">N</text>\x27+
5246
- // ════ ARMS ════
5247
- \x27<g class="prl-master-arm-l">\x27+
5248
- // Left upper arm
5249
- \x27<path d="M13 34 C8 37 6 42 6 46 C6 49 9 50 11 49 C13 48 13 45 14 41 C15 38 14 35 13 34" fill="#252450"/>\x27+
5250
- // Left forearm
5251
- \x27<path d="M6 46 C4 48 4 51 5 53 C6 55 9 55 10 53 C11 51 10 48 10 46 Z" fill="#d4a97a"/>\x27+
5252
- // Left hand
5253
- \x27<ellipse cx="7" cy="54" rx="4.5" ry="3.5" fill="#d4a97a" transform="rotate(-15 7 54)"/>\x27+
5254
- \x27</g>\x27+
5255
- // Right arm — holds clipboard
5256
- \x27<g class="prl-master-arm-r">\x27+
5257
- // Right upper arm
5258
- \x27<path d="M37 34 C42 37 44 41 44 45 C44 48 41 49 39 48 C37 47 37 44 37 40 C37 37 37 35 37 34" fill="#252450"/>\x27+
5259
- // Right forearm
5260
- \x27<path d="M44 44 C46 46 47 49 46 52 C45 54 42 54 41 52 C40 50 41 47 41 45 Z" fill="#d4a97a"/>\x27+
5261
- // Right hand
5262
- \x27<ellipse cx="45" cy="52" rx="4" ry="3" fill="#d4a97a" transform="rotate(15 45 52)"/>\x27+
5263
- // Clipboard — premium design
5264
- \x27<rect x="43" y="32" width="14" height="19" rx="2.5" fill="#1a1a2e" stroke="\x27+masterColor2+\x2799" stroke-width="1.5"/>\x27+
5265
- // Clipboard clip
5266
- \x27<rect x="47" y="30" width="6" height="5" rx="1.5" fill="\x27+masterColor2+\x27" stroke="\x27+masterColor2+\x27" stroke-width="1"/>\x27+
5267
- \x27<rect x="48" y="31" width="4" height="3" rx="1" fill="#0f0f1e"/>\x27+
5268
- // Clipboard lines
5269
- \x27<line x1="46" y1="36" x2="54" y2="36" stroke="\x27+masterColor2+\x27cc" stroke-width="1" stroke-linecap="round"/>\x27+
5270
- \x27<line x1="46" y1="39" x2="54" y2="39" stroke="\x27+masterColor2+\x27aa" stroke-width="1" stroke-linecap="round"/>\x27+
5271
- \x27<line x1="46" y1="42" x2="54" y2="42" stroke="\x27+masterColor2+\x2788" stroke-width="1" stroke-linecap="round"/>\x27+
5272
- \x27<line x1="46" y1="45" x2="50" y2="45" stroke="\x27+masterColor2+\x2766" stroke-width="1" stroke-linecap="round"/>\x27+
5273
- // Data chart on clipboard
5274
- \x27<rect x="46" y="37" width="3" height="2" rx=".5" fill="\x27+masterColor2+\x2744"/>\x27+
5275
- \x27<rect x="50" y="36" width="3" height="3" rx=".5" fill="\x27+masterColor2+\x2766"/>\x27+
5276
- \x27</g>\x27+
5277
- // ════ HEAD — authoritative, confident ════
5278
- // Neck
5279
- \x27<path d="M22 25 L28 25 L28 29 Q28 31 25 31 Q22 31 22 29 Z" fill="#d4a97a"/>\x27+
5280
- \x27<path d="M22 25 L25 25 L25 31 Q22 31 22 29 Z" fill="rgba(0,0,0,.1)"/>\x27+
5281
- // Head shape
5282
- \x27<ellipse cx="25" cy="15" rx="12" ry="13" fill="#d4a97a"/>\x27+
5283
- // Jaw/chin
5284
- \x27<path d="M14 15 C14 22 18 26 25 27 C32 26 36 22 36 15" fill="#d4a97a"/>\x27+
5285
- // Head shading
5286
- \x27<ellipse cx="32" cy="15" rx="6" ry="11" fill="rgba(0,0,0,.07)"/>\x27+
5287
- // Ears
5288
- \x27<path d="M13 13 C11 13 10 15 10 17 C10 19 11 20 13 20 C14 20 14.5 19 14 17 C14.5 15 14 13 13 13" fill="#d4a97a"/>\x27+
5289
- \x27<path d="M37 13 C39 13 40 15 40 17 C40 19 39 20 37 20 C36 20 35.5 19 36 17 C35.5 15 36 13 37 13" fill="#d4a97a"/>\x27+
5290
- \x27<path d="M13.5 15 C12.5 16 12.5 18 13.5 19" stroke="#c4935a" stroke-width="1" fill="none"/>\x27+
5291
- // Hair — executive styled, neat
5292
- \x27<path d="M13 14 C12 7 16 2 25 1 C34 2 38 7 37 14 C36 7 32 4 25 3 C18 4 14 7 13 14" fill="#1a0e08"/>\x27+
5293
- // Side part
5294
- \x27<path d="M22 3 C21 4 21 6 22 8" stroke="rgba(255,255,255,.15)" stroke-width="1.5" fill="none" stroke-linecap="round"/>\x27+
5295
- // Hair sheen
5296
- \x27<path d="M20 3 C22 1 27 1 30 2 C27 0 22 1 20 3" fill="rgba(255,255,255,.1)"/>\x27+
5297
- // Eyebrows — thick, authoritative
5298
- \x27<path d="M16.5 11 Q19 9.5 21.5 11" stroke="#1a0e08" stroke-width="1.8" fill="none" stroke-linecap="round"/>\x27+
5299
- \x27<path d="M28.5 11 Q31 9.5 33.5 11" stroke="#1a0e08" stroke-width="1.8" fill="none" stroke-linecap="round"/>\x27+
5300
- // Eyes — confident, forward-looking
5301
- \x27<ellipse cx="19.5" cy="14.5" rx="3.2" ry="3.5" fill="#fff" stroke="#d4a97a" stroke-width=".4"/>\x27+
5302
- \x27<ellipse cx="30.5" cy="14.5" rx="3.2" ry="3.5" fill="#fff" stroke="#d4a97a" stroke-width=".4"/>\x27+
5303
- \x27<circle cx="19.5" cy="15" r="2.3" fill="#1e3a6e"/>\x27+
5304
- \x27<circle cx="30.5" cy="15" r="2.3" fill="#1e3a6e"/>\x27+
5305
- \x27<circle cx="19.5" cy="15" r="1.3" fill="#0a0a18"/>\x27+
5306
- \x27<circle cx="30.5" cy="15" r="1.3" fill="#0a0a18"/>\x27+
5307
- \x27<circle cx="20.5" cy="13.7" r=".9" fill="rgba(255,255,255,.95)"/>\x27+
5308
- \x27<circle cx="31.5" cy="13.7" r=".9" fill="rgba(255,255,255,.95)"/>\x27+
5309
- // Nose — subtle
5310
- \x27<path d="M24 18 Q24 20 25 20.5 Q26 21 26 19.5" stroke="#c4935a" stroke-width="1.1" fill="none" stroke-linecap="round" opacity=".8"/>\x27+
5311
- \x27<ellipse cx="22.5" cy="20.5" rx="1.3" ry=".8" fill="rgba(0,0,0,.1)"/>\x27+
5312
- \x27<ellipse cx="27.5" cy="20.5" rx="1.3" ry=".8" fill="rgba(0,0,0,.1)"/>\x27+
5313
- // Confident smile
5314
- \x27<path d="M19.5 24 Q25 27.5 30.5 24" stroke="#8b4513" stroke-width="1.8" fill="none" stroke-linecap="round"/>\x27+
5315
- \x27<path d="M20 24.5 Q25 27 30 24.5 Q25 26.5 20 24.5" fill="#fff" opacity=".7"/>\x27+
5316
- // Crown / authority badge above head — pure SVG geometry (no font-dependent text)
5317
- \x27<circle cx="25" cy="-4" r="9" fill="\x27+masterColor2+\x2722" stroke="\x27+masterColor2+\x2766" stroke-width="1.5"/>\x27+
5318
- (phase===\x27r3\x27 ?
5319
- // Lightning bolt for R3 mediation
5320
- \x27<path d="M27 -12 L22 -4 L25.5 -4 L23 4 L29 -3 L25.5 -3 Z" fill="\x27+masterColor2+\x27" stroke="\x27+masterColor2+\x2788" stroke-width=".6" stroke-linejoin="round"/>\x27
5321
- : phase===\x27done\x27 ?
5322
- // Checkmark for done
5323
- \x27<path d="M19 -4 L23.5 0.5 L31 -9" stroke="\x27+masterColor2+\x27" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>\x27
5324
- :
5325
- // Diamond (authority) for r1/r2
5326
- \x27<path d="M25 -13 L30 -4 L25 5 L20 -4 Z" fill="\x27+masterColor2+\x27" stroke="\x27+masterColor2+\x27cc" stroke-width=".8"/>\x27+
5327
- \x27<path d="M25 -13 L30 -4 L25 -3 L20 -4 Z" fill="\x27+masterColor2+\x27aa"/>\x27
5328
- )+
5329
- \x27</svg>\x27;
5330
-
5331
- var masterLabel2 = {r1:\x27Orchestratore\x27,r2:\x27Coordina\x27,r3:\x27HERALD\x27,done:\x27Completato\x27}[phase]||\x27MASTER\x27;
5332
- var masterHtml = \x27<div class="prl-master \x27+masterAnim+\x27">\x27+masterSvg+\x27<div class="prl-master-label" style="color:\x27+masterColor2+\x27">\x27+masterLabel2+\x27</div></div>\x27;
5333
-
5334
- // ── Flying document animation for R2 (agent-to-agent) ────────────
5335
- // One flying doc per active cross-reading event, CSS keyframe arc.
5336
- var flyingDocHtml = \x27\x27;
5337
- if (phase===\x27r2\x27 && activeLabel) {
5338
- var others2 = proposals.filter(function(x){return (x.label||x.agent)!==activeLabel;});
5339
- flyingDocHtml = \x27<div class="prl-fly-container" aria-hidden="true">\x27;
5340
- others2.forEach(function(other, oi) {
5341
- var delay = (oi * 0.35).toFixed(2);
5342
- flyingDocHtml += \x27<div class="prl-fly-doc" style="animation-delay:\x27+delay+\x27s;animation-duration:\x27+(1.5+oi*0.2).toFixed(1)+\x27s">\x27+
5343
- // Document — dog-ear corner, realistic paper look
5344
- \x27<svg viewBox="0 0 22 28" width="22" height="28">\x27+
5345
- \x27<defs><filter id="dsf\x27+oi+\x27" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="1" dy="2" stdDeviation="2" flood-color="#22d3ee" flood-opacity=".5"/></filter></defs>\x27+
5346
- // Paper body
5347
- \x27<path d="M2 1 L16 1 L21 6 L21 27 Q21 28 20 28 L2 28 Q1 28 1 27 L1 2 Q1 1 2 1" fill="#0c0c1e" stroke="#22d3ee" stroke-width="1.5" filter="url(#dsf\x27+oi+\x27)"/>\x27+
5348
- // Dog-ear fold
5349
- \x27<path d="M16 1 L16 6 L21 6" fill="none" stroke="#22d3ee" stroke-width="1.2"/>\x27+
5350
- \x27<path d="M16 1 L21 6 L16 6 Z" fill="#0f0f28"/>\x27+
5351
- // Header bar (colored)
5352
- \x27<rect x="2" y="2" width="13" height="3" rx="1" fill="#22d3ee22"/>\x27+
5353
- // Text lines
5354
- \x27<line x1="3" y1="9" x2="19" y2="9" stroke="#22d3ee" stroke-width="1" opacity=".8" stroke-linecap="round"/>\x27+
5355
- \x27<line x1="3" y1="12" x2="17" y2="12" stroke="#22d3ee" stroke-width="1" opacity=".6" stroke-linecap="round"/>\x27+
5356
- \x27<line x1="3" y1="15" x2="19" y2="15" stroke="#22d3ee" stroke-width="1" opacity=".5" stroke-linecap="round"/>\x27+
5357
- \x27<line x1="3" y1="18" x2="14" y2="18" stroke="#22d3ee" stroke-width="1" opacity=".4" stroke-linecap="round"/>\x27+
5358
- // Chart bar (mini)
5359
- \x27<rect x="3" y="21" width="3" height="5" rx=".5" fill="#22d3ee44"/>\x27+
5360
- \x27<rect x="7" y="19" width="3" height="7" rx=".5" fill="#22d3ee66"/>\x27+
5361
- \x27<rect x="11" y="22" width="3" height="4" rx=".5" fill="#22d3ee44"/>\x27+
5362
- \x27<rect x="15" y="20" width="3" height="6" rx=".5" fill="#22d3ee55"/>\x27+
5363
- \x27</svg></div>\x27;
5364
- });
5365
- flyingDocHtml += \x27</div>\x27;
5366
- }
5367
-
5368
- // Persist across tab navigations — stamp version to invalidate stale HTML on update
5369
- if (pb.innerHTML && pb.innerHTML.length < 60000) {
5370
- _parlPersistHtml = \x27<!-- nha-v13.5.16 -->\x27 + pb.innerHTML;
5371
- }
4804
+ // Persist across tab navigations
4805
+ if (pb.innerHTML && pb.innerHTML.length < 60000) { _parlPersistHtml = pb.innerHTML; }
5372
4806
 
5373
4807
  }
5374
4808
 
@@ -5536,7 +4970,7 @@ async function runStudio() {
5536
4970
  }
5537
4971
  }
5538
4972
  if (parlFinal && parlFinal.style.display !== 'none' && parlFinal.innerHTML) {
5539
- _parlPersistHtml = \x27<!-- nha-v13.5.16 -->\x27 + parlFinal.innerHTML; // persist so tab nav doesn't lose it
4973
+ _parlPersistHtml = parlFinal.innerHTML; // persist so tab nav doesn't lose it
5540
4974
  doScroll(parlFinal);
5541
4975
  setTimeout(function(){ doScroll(resEl); }, 2200);
5542
4976
  } else if (resEl) {
@@ -5910,9 +5344,8 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
5910
5344
  function renderStudio(el) {
5911
5345
  // Persist parliament block across tab navigations
5912
5346
  var existingParl = document.getElementById('studioParliamentBlock');
5913
- if (existingParl && existingParl.innerHTML.trim() && _parlPersistHtml === null) {
5914
- // Only snapshot if not already persisted (avoid overwriting stamped version with un-stamped)
5915
- _parlPersistHtml = \x27<!-- nha-v13.5.16 -->\x27 + existingParl.innerHTML;
5347
+ if (existingParl && existingParl.innerHTML.trim()) {
5348
+ _parlPersistHtml = existingParl.innerHTML;
5916
5349
  }
5917
5350
 
5918
5351
  var examplesHtml = STUDIO_EXAMPLES.map(function(ex) {
@@ -6084,14 +5517,12 @@ function renderStudio(el) {
6084
5517
  // Restore pipeline from state
6085
5518
  renderBuilderPipeline();
6086
5519
  // Restore parliament block if it was visible before tab navigation
6087
- if (_parlPersistHtml && _parlPersistHtml.indexOf(\x27<!-- nha-v13.5.16 -->\x27) === 0) {
6088
- var parlRestoreEl = document.getElementById(\x27studioParliamentBlock\x27);
5520
+ if (_parlPersistHtml) {
5521
+ var parlRestoreEl = document.getElementById('studioParliamentBlock');
6089
5522
  if (parlRestoreEl) {
6090
- parlRestoreEl.innerHTML = _parlPersistHtml.slice(\x27<!-- nha-v13.5.16 -->\x27.length);
6091
- parlRestoreEl.style.display = \x27block\x27;
5523
+ parlRestoreEl.innerHTML = _parlPersistHtml;
5524
+ parlRestoreEl.style.display = 'block';
6092
5525
  }
6093
- } else {
6094
- _parlPersistHtml = null; // stale — discard
6095
5526
  }
6096
5527
  }
6097
5528
 
@@ -6629,37 +6060,38 @@ input:focus,textarea:focus{border-color:var(--green3)}
6629
6060
  .wf-sbraita-bubble::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#ef4444}
6630
6061
  @keyframes sbraitaPop{0%{transform:translateX(-50%) scale(1) rotate(-2deg)}100%{transform:translateX(-50%) scale(1.06) rotate(2deg)}}
6631
6062
  /* ── Parliament Boardroom — bright office, same palette as workflow scene ── */
6632
- /* Outer wrapper — matches prl-wrap but with slight warm tint */
6633
6063
  .br-wrap{background:var(--bg2);border:1.5px solid var(--border);border-radius:14px;padding:12px 14px;margin-bottom:16px;animation:stNodeIn .35s ease forwards;overflow:hidden}
6634
- /* Header: phase chip + progress */
6635
6064
  .br-header{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
6636
6065
  .br-phase-chip{font-size:10px;font-weight:800;font-family:var(--mono);letter-spacing:.3px;color:var(--pc,#6366f1);background:rgba(99,102,241,.1);border:1px solid var(--pc,rgba(99,102,241,.35));border-radius:20px;padding:3px 12px;display:inline-block;transition:color .4s,border-color .4s}
6637
6066
  .br-progress-wrap{flex:1;height:3px;background:var(--border);border-radius:4px;overflow:hidden;min-width:60px}
6638
6067
  .br-progress-bar{height:100%;background:linear-gradient(90deg,#6366f1,#22d3ee);border-radius:4px;transition:width .5s ease;width:0%}
6639
- /* Boardroom scene — no background (bgSvg covers it) */
6068
+ /* Boardroom scene — bgSvg covers background */
6640
6069
  .br-room{position:relative;width:100%;min-height:480px;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18)}
6641
6070
  /* Seats rows above/below table */
6642
- .br-seats-row{display:flex;flex-wrap:wrap;gap:6px;align-items:flex-end;justify-content:space-around}
6643
- /* Individual seat card */
6071
+ .br-seats-row{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end;justify-content:space-around}
6072
+ /* Individual seat card — light theme matching workflow stations */
6644
6073
  .br-seat{display:flex;flex-direction:column;align-items:center;gap:2px;transition:transform .3s;padding:6px 8px;border-radius:12px;background:rgba(255,255,255,.82);border:1.5px solid rgba(200,180,160,.5);box-shadow:0 2px 8px rgba(0,0,0,.12);backdrop-filter:blur(4px);min-width:64px;cursor:default}
6645
6074
  .br-seat--active{transform:scale(1.07);border-color:var(--sc,#6366f1);box-shadow:0 0 16px rgba(99,102,241,.35),0 2px 8px rgba(0,0,0,.12)}
6646
6075
  .br-seat--done{border-color:rgba(0,0,0,.25);background:rgba(0,0,0,.06)}
6076
+ /* Emoji character */
6077
+ .br-char{font-size:36px;line-height:1;user-select:none;filter:drop-shadow(0 2px 5px rgba(0,0,0,.2))}
6647
6078
  /* Orchestrator head seat */
6648
6079
  .br-orch{display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 10px;flex-shrink:0}
6649
- .br-orch-speech{font-size:9px;font-weight:800;font-family:var(--mono);letter-spacing:.4px;padding:3px 8px;border:1.5px solid #6366f1;border-radius:8px;background:rgba(255,255,255,.95);color:#4338ca;white-space:nowrap;animation:brSpeechPop .6s ease-in-out infinite alternate;pointer-events:none;margin-bottom:2px}
6080
+ .br-orch-speech{font-size:9px;font-weight:800;font-family:var(--mono);padding:3px 8px;border:1.5px solid #6366f1;border-radius:8px;background:rgba(255,255,255,.95);color:#4338ca;white-space:nowrap;animation:brSpeechPop .6s ease-in-out infinite alternate;pointer-events:none;margin-bottom:2px}
6650
6081
  @keyframes brSpeechPop{0%{transform:scale(1) rotate(-1deg)}100%{transform:scale(1.05) rotate(1deg)}}
6651
- .br-orch-label{font-size:9px;font-family:var(--mono);font-weight:800;color:#6366f1;background:rgba(99,102,241,.12);border-radius:6px;padding:2px 7px;text-align:center;letter-spacing:.4px}
6652
- /* Bubble above seat showing streaming text */
6653
- .br-bubble{font-size:8px;font-family:var(--mono);padding:3px 8px;border-radius:8px 8px 8px 2px;border:1px solid rgba(99,102,241,.35);background:rgba(255,255,255,.95);color:#1e1b4b;min-height:14px;text-align:left;line-height:1.45;transition:border-color .3s;word-break:break-word;max-width:100px;white-space:normal;box-shadow:0 2px 6px rgba(0,0,0,.12);margin-bottom:2px}
6082
+ .br-orch-label{font-size:9px;font-family:var(--mono);font-weight:800;color:#6366f1;background:rgba(99,102,241,.12);border-radius:6px;padding:2px 7px}
6083
+ /* Bubble above seat */
6084
+ .br-bubble{font-size:8px;font-family:var(--mono);padding:3px 8px;border-radius:8px 8px 8px 2px;border:1px solid rgba(99,102,241,.35);background:rgba(255,255,255,.95);color:#1e1b4b;line-height:1.45;word-break:break-word;max-width:140px;white-space:normal;box-shadow:0 2px 6px rgba(0,0,0,.1);margin-bottom:2px}
6654
6085
  /* Agent name pill */
6655
- .br-seat-name{font-size:9px;font-family:var(--mono);font-weight:700;color:#374151;text-align:center;white-space:normal;word-break:break-word;max-width:90px;line-height:1.3;margin-top:1px;transition:color .3s;background:rgba(0,0,0,.04);border-radius:4px;padding:1px 4px}
6086
+ .br-seat-name{font-size:9px;font-family:var(--mono);font-weight:700;color:#374151;text-align:center;white-space:normal;word-break:break-word;max-width:140px;line-height:1.3;margin-top:1px;background:rgba(0,0,0,.04);border-radius:4px;padding:1px 4px;transition:color .3s}
6656
6087
  .br-seat--active .br-seat-name{color:#4338ca}
6657
6088
  .br-seat--done .br-seat-name{color:#111827}
6658
6089
  /* Convergence */
6659
- .br-convergence{margin-top:10px;padding:8px 12px;background:rgba(34,197,94,.06);border:1px solid rgba(34,197,94,.22);border-radius:8px}
6660
- .br-conv-bar-outer{height:4px;background:rgba(34,197,94,.15);border-radius:4px;overflow:hidden;margin-bottom:6px}
6661
- .br-conv-bar-inner{height:100%;background:linear-gradient(90deg,#22c55e,#4ade80);border-radius:4px;transition:width .8s ease}
6662
- .br-conv-text{font-size:9px;color:#111827;line-height:1.55}
6090
+ .br-convergence{margin-top:10px;padding:8px 12px;background:rgba(99,102,241,.06);border:1px solid rgba(99,102,241,.2);border-radius:8px}
6091
+ .br-conv-bar-outer{height:4px;background:rgba(99,102,241,.15);border-radius:4px;overflow:hidden;margin-bottom:6px}
6092
+ .br-conv-bar-inner{height:100%;background:linear-gradient(90deg,#6366f1,#818cf8);border-radius:4px;transition:width .8s ease}
6093
+ .br-conv-text{font-size:9px;color:#86efac;line-height:1.55}
6094
+ @keyframes brDashFlow{0%{stroke-dashoffset:20}100%{stroke-dashoffset:0}}
6663
6095
  /* Keep old prl-* classes for workflow (not touched) */
6664
6096
  .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}
6665
6097
  @keyframes parlPulse{0%,100%{border-color:#6366f1;box-shadow:none}50%{border-color:#818cf8;box-shadow:0 0 20px rgba(99,102,241,.3)}}
@@ -6708,26 +6140,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
6708
6140
  /* Plant right */
6709
6141
  .prl-office-plant2{position:absolute;bottom:14px;right:8px;width:22px;height:42px;z-index:2;pointer-events:none}
6710
6142
  /* ── ISOMETRIC JRPG SCENE ── */
6711
- .iso-scene-wrap{width:100%;overflow-x:auto;display:flex;justify-content:center}
6712
- .iso-scene{background:#f0ede6;cursor:default;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18);width:100%}
6713
- /* ── Station grid layout ── */
6714
- .iso-station{display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer;transition:filter .2s,transform .2s;padding:8px 4px;border-radius:12px;border:1.5px solid transparent;position:relative}
6715
- .iso-station:hover{filter:brightness(1.06);transform:translateY(-2px)}
6716
- .iso-station.iso-orch-walking{animation:orchWalkGrid 1.8s ease-in-out infinite alternate}
6717
- @keyframes orchWalkGrid{0%{transform:translateX(0) scale(1)}100%{transform:translateX(var(--orch-tx,24px)) scale(1.04)}}
6718
- .iso-station.iso-orch-done{animation:orchBounce .7s ease forwards}
6719
- @keyframes orchBounce{0%{transform:scale(1)}40%{transform:scale(1.18) translateY(-6px)}100%{transform:scale(1)}}
6720
- /* Desk — CSS 3D look */
6721
- .iso-desk{width:90%;height:16px;background:linear-gradient(180deg,#d4a448 0%,#b8832a 100%);border-radius:4px 4px 2px 2px;box-shadow:0 4px 0 #8a5e18,0 6px 10px rgba(0,0,0,.3);border-top:2px solid #e8c060;position:relative;margin-top:4px}
6722
- .iso-desk::after{content:'';position:absolute;bottom:-4px;left:8px;right:8px;height:4px;background:#7a5010;border-radius:0 0 3px 3px}
6723
- /* Monitor — sits on desk */
6724
- .iso-monitor{width:56px;height:40px;background:#12101e;border:2px solid #3a3070;border-radius:5px;display:flex;align-items:center;justify-content:center;position:relative;margin-bottom:-2px}
6725
- .iso-monitor::after{content:'';position:absolute;bottom:-5px;left:50%;transform:translateX(-50%);width:10px;height:5px;background:#252436;border-radius:0 0 3px 3px}
6726
- .iso-monitor-screen{width:44px;height:28px;background:rgba(60,40,160,.35);border-radius:2px;display:flex;align-items:center;justify-content:center}
6727
- .iso-monitor-blink{width:7px;height:7px;border-radius:50%;background:#6366f1;animation:monBlink .9s ease-in-out infinite}
6728
- @keyframes monBlink{0%,100%{opacity:1;box-shadow:0 0 8px #6366f1}50%{opacity:.25;box-shadow:none}}
6729
- /* Tool badge */
6730
- .iso-tool-badge{font-size:22px;line-height:1;filter:drop-shadow(0 2px 5px rgba(0,0,0,.35));user-select:none;margin-bottom:1px}
6143
+ .iso-scene{background:#f0ede6;cursor:default;max-width:100%;overflow-x:auto;box-shadow:0 4px 24px rgba(0,0,0,.18)}
6731
6144
  /* Animated status chip for [bracket tokens] */
6732
6145
  .iso-status-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(99,102,241,.1);border:1px solid rgba(99,102,241,.3);border-radius:20px;padding:3px 10px;font-size:11px;font-family:var(--mono);color:#818cf8;animation:statusPulse 2s ease-in-out infinite}
6733
6146
  @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)}}
@@ -6740,8 +6153,8 @@ input:focus,textarea:focus{border-color:var(--green3)}
6740
6153
  .iso-orch-wrap{transition:transform .2s}
6741
6154
  .iso-orch-wrap.prl-head{animation:isoCharBob 1.4s ease-in-out infinite}
6742
6155
  /* Thought bubble / speech bubble above character */
6743
- .iso-bubble{font-size:9px;font-family:var(--mono);padding:3px 9px;border-radius:12px;border:1px solid #ccc;background:rgba(255,255,255,.9);color:#6b7280;white-space:normal;word-break:break-word;max-width:160px;line-height:1.4;transition:all .25s;pointer-events:none;backdrop-filter:blur(6px);text-align:center}
6744
- .iso-bubble--active{background:rgba(30,20,60,.9);border-color:#6366f1;color:#a5b4fc;animation:isoBubblePop .35s ease;white-space:normal;max-width:160px;word-break:break-word;line-height:1.35}
6156
+ .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:normal;max-width:160px;line-height:1.4;transition:all .25s;pointer-events:none;backdrop-filter:blur(4px)}
6157
+ .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}
6745
6158
  .iso-bubble--orch{font-size:9px;padding:3px 9px;border-radius:12px;border-color:#818cf8;color:#a5b4fc;background:rgba(20,15,50,.9)}
6746
6159
  @keyframes isoBubblePop{0%{transform:scale(.8) translateY(4px);opacity:.4}100%{transform:scale(1) translateY(0);opacity:1}}
6747
6160
  .iso-name{font-size:10px;font-family:var(--mono);font-weight:700;letter-spacing:.3px;text-align:center;max-width:160px;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)}