nothumanallowed 13.5.11 → 13.5.12

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.11",
3
+ "version": "13.5.12",
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.11';
8
+ export const VERSION = '13.5.12';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3918,164 +3918,136 @@ function renderStudioNodes() {
3918
3918
  : (doneCount===totalCount && totalCount>0 ? \x27Workflow completato\x27 : \x27Workflow pianificato\x27);
3919
3919
  var phaseColor2 = hasActive ? \x27#6366f1\x27 : (doneCount===totalCount && totalCount>0 ? \x27#22c55e\x27 : \x27#6b7280\x27);
3920
3920
 
3921
- // ── Layout: all nodes + orchestrator on a grid ────────────────────────────
3922
- // Include orchestrator as first "station" (desk 0), then all agents
3923
- // Total stations = nodes.length + 1 (orchestrator)
3924
- var totalStations = totalCount + 1;
3925
- // Grid: up to 3 per row, rows fill downward
3926
- var cols = Math.min(totalStations, 3);
3921
+ // ── CSS Grid layout: 100% width, responsive ──────────────────────────────
3922
+ // All stations (orch + agents) in a grid, max 4 per row
3923
+ var totalStations = totalCount + 1; // +1 for orchestrator
3924
+ var cols = totalStations <= 2 ? totalStations : (totalStations <= 4 ? 2 : (totalStations <= 6 ? 3 : 4));
3927
3925
  var rows = Math.ceil(totalStations / cols);
3928
3926
 
3929
- // Scene: square, 100% width of parent, dynamic height based on grid rows
3930
- // Each cell = 160px wide, 180px tall
3931
- var CELL_W = 160; var CELL_H = 180;
3932
- var SCENE_W = cols * CELL_W + 40; // +padding
3933
- var SCENE_H = Math.max(rows * CELL_H + 80, 400);
3934
-
3935
- // Plant emoji for decoration corners
3936
- var plantEmoji = String.fromCodePoint(0x1F331); // seedling
3937
- var bigPlant = String.fromCodePoint(0x1FAB4); // potted plant
3938
-
3939
- // ── Build station HTML ───────────────────────────────────────────────────
3940
- var stationsHtml = \x27\x27;
3941
-
3942
- // Station builder — shared for orchestrator and agents
3943
- function buildStation(stationIdx, label, emoji, toolEmoji, isOrch, isActive, isDone, isErr, idx) {
3944
- var col = stationIdx % cols;
3945
- var row2 = Math.floor(stationIdx / cols);
3946
- var left = 20 + col * CELL_W + CELL_W/2;
3947
- var top = 30 + row2 * CELL_H;
3948
- var zIdx = 100 + row2 * 10 + col;
3949
- var accentColor = isOrch ? \x27#818cf8\x27 : (isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : (isErr ? \x27#ef4444\x27 : \x27#aaa\x27)));
3950
-
3951
- // Desk — isometric CSS box using borders
3952
- var deskHtml = \x27<div class="iso-desk" style="--dc:\x27+accentColor+\x27"></div>\x27;
3953
-
3954
- // Monitor — small box on desk
3955
- var monHtml = \x27<div class="iso-monitor" style="border-color:\x27+accentColor+\x2788">\x27+
3956
- \x27<div class="iso-monitor-screen">\x27+(isOrch?\x27<span style="font-size:10px">&#128269;</span>\x27:(isDone?\x27<span style="color:#22c55e;font-size:10px">&#10003;</span>\x27:(isActive?\x27<span class="iso-monitor-blink"></span>\x27:\x27<span style="font-size:9px;opacity:.4">&#9632;</span>\x27)))+\x27</div>\x27+
3957
- \x27</div>\x27;
3958
-
3959
- // Tool badge — the emoji representing what this node does
3960
- var toolBadge = \x27<div class="iso-tool-badge" title="\x27+esc(label)+\x27">\x27+toolEmoji+\x27</div>\x27;
3961
-
3962
- // Agent/tool character emoji
3963
- var charEmojiHtml = isoCharSvg({emojiIdx: isOrch ? 99 : idx, isActive: isActive, isDone: isDone, scale: 1, accentColor: accentColor});
3964
-
3965
- // Status bubble
3927
+ // Each station rendered as a grid cell 100% fills parent
3928
+ // No pixel-based absolute positioning: use CSS grid % cells
3929
+ var gridTpl = \x27repeat(\x27+cols+\x27,1fr)\x27;
3930
+
3931
+ // Plant/deco emojis
3932
+ var bigPlant = String.fromCodePoint(0x1FAB4);
3933
+ var plantEmoji = String.fromCodePoint(0x1F331);
3934
+
3935
+ // Build all station cards (orchestrator first, then agents)
3936
+ function buildStation2(label, toolEmoji, isOrch, isActive, isDone, isErr, emojiIdx) {
3937
+ var accentColor = isOrch ? \x27#818cf8\x27 : (isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : (isErr ? \x27#ef4444\x27 : \x27#9ca3af\x27)));
3938
+ var nameBg = isDone ? \x27#dcfce7\x27 : (isActive ? \x27#ede9fe\x27 : (isOrch ? \x27#e0e7ff\x27 : \x27rgba(255,255,255,.85)\x27));
3939
+ var nameColor = isDone ? \x27#16a34a\x27 : (isActive ? \x27#4f46e5\x27 : (isOrch ? \x27#4338ca\x27 : (isErr ? \x27#dc2626\x27 : \x27#374151\x27)));
3940
+ var monScreen = isOrch
3941
+ ? \x27<span style="font-size:11px">&#128269;</span>\x27
3942
+ : (isDone ? \x27<span style="color:#22c55e;font-size:13px">&#10003;</span>\x27
3943
+ : (isActive ? \x27<span class="iso-monitor-blink"></span>\x27
3944
+ : \x27<span style="font-size:8px;opacity:.35;color:#818cf8">&#9632;</span>\x27));
3966
3945
  var bubbleText = isOrch
3967
- ? (hasActive ? (\x27Step \x27+doneCount+\x27/\x27+totalCount) : ((!hasActive && doneCount===totalCount && totalCount>0) ? \x27Completato!\x27 : \x27In attesa\x27))
3968
- : (isActive ? \x27...lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27)));
3969
- var bubbleColor = isOrch ? \x27#818cf8\x27 : (isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : \x27#ef4444\x27));
3970
- var bubbleHtml = (bubbleText || isOrch)
3971
- ? \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" id="isobubble_\x27+(isOrch?\x27orch\x27:idx)+\x27" style="border-color:\x27+bubbleColor+\x27;color:\x27+bubbleColor+\x27">\x27+esc(bubbleText)+\x27</div>\x27
3972
- : \x27<div style="height:22px"></div>\x27;
3973
-
3974
- // Name badge
3975
- var nameColor = isDone ? \x27#16a34a\x27 : (isActive ? \x27#6366f1\x27 : (isOrch ? \x27#818cf8\x27 : (isErr ? \x27#dc2626\x27 : \x27#374151\x27)));
3976
- var nameBg = isDone ? \x27#dcfce7\x27 : (isActive ? \x27#ede9fe\x27 : (isOrch ? \x27#e0e7ff\x27 : \x27#f3f4f6\x27));
3977
- var nameHtml = \x27<div class="iso-name" style="color:\x27+nameColor+\x27;background:\x27+nameBg+\x27">\x27+(isOrch?\x27\u2666 \x27:\x27\x27)+esc(label.slice(0,18))+\x27</div>\x27;
3978
-
3979
- // Orchestrator walk animation — walks between desks horizontally
3980
- var orchWalkStyle = \x27\x27;
3981
- if (isOrch && hasActive) {
3982
- var activeIdx = nodes.findIndex(function(nd){return nd.status===\x27running\x27;});
3983
- if (activeIdx >= 0) {
3984
- var targetStation = activeIdx + 1; // station index of active agent (orch is 0)
3985
- var targetCol = targetStation % cols;
3986
- var targetRow = Math.floor(targetStation / cols);
3987
- var targetLeft = 20 + targetCol * CELL_W + CELL_W/2;
3988
- var targetTop = 30 + targetRow * CELL_H;
3989
- orchWalkStyle = \x27--orch-tx:\x27+(targetLeft - left)+\x27px;--orch-ty:\x27+(targetTop - top)+\x27px\x27;
3990
- }
3991
- }
3992
- var orchClass = (isOrch && hasActive) ? \x27 iso-orch-walking\x27 : (isOrch && !hasActive && doneCount===totalCount && totalCount>0 ? \x27 iso-orch-done\x27 : \x27\x27);
3993
-
3994
- var clickHandler = isOrch ? \x27\x27 : \x27onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))"\x27;
3995
- var dataAttr = isOrch ? \x27\x27 : \x27data-agent-label="\x27+esc(label)+\x27"\x27;
3996
-
3997
- return \x27<div class="iso-station\x27+orchClass+\x27" \x27+dataAttr+\x27 style="position:absolute;left:\x27+left+\x27px;top:\x27+top+\x27px;z-index:\x27+zIdx+\x27;transform:translateX(-50%);\x27+orchWalkStyle+\x27" \x27+clickHandler+\x27>\x27+
3998
- bubbleHtml+
3999
- toolBadge+
4000
- charEmojiHtml+
4001
- deskHtml+
4002
- monHtml+
4003
- nameHtml+
3946
+ ? (hasActive ? (\x27Step \x27+doneCount+\x27/\x27+totalCount) : (doneCount===totalCount&&totalCount>0 ? \x27\u2714 Fatto!\x27 : \x27In attesa\x27))
3947
+ : (isActive ? \x27\u2022\u2022\u2022 lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27)));
3948
+ var bubbleBg = isOrch ? \x27rgba(99,102,241,.15)\x27 : (isActive ? \x27rgba(99,102,241,.12)\x27 : (isDone ? \x27rgba(34,197,94,.12)\x27 : \x27rgba(239,68,68,.12)\x27));
3949
+ var glowBox = isActive ? (\x270 0 0 3px \x27+accentColor+\x2744,0 8px 24px \x27+accentColor+\x2733\x27) : (isDone ? (\x270 0 0 2px #22c55e44\x27) : \x27none\x27);
3950
+ var orchWalkClass = (isOrch && hasActive) ? \x27 iso-orch-walking\x27 : (isOrch && doneCount===totalCount&&totalCount>0 ? \x27 iso-orch-done\x27 : \x27\x27);
3951
+ var charHtml = isoCharSvg({emojiIdx: isOrch ? 99 : emojiIdx, isActive: isActive, isDone: isDone, scale: 1.1, accentColor: accentColor});
3952
+ var clickAttr = isOrch ? \x27\x27 : (\x27data-agent-label="\x27+esc(label)+\x27" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))"\x27);
3953
+ 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+
3954
+ // bubble
3955
+ \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+
3956
+ // tool badge above character
3957
+ \x27<div class="iso-tool-badge">\x27+toolEmoji+\x27</div>\x27+
3958
+ // character emoji
3959
+ charHtml+
3960
+ // desk
3961
+ \x27<div class="iso-desk" style="width:85%;border-top-color:\x27+accentColor+\x2733"></div>\x27+
3962
+ // monitor on desk
3963
+ \x27<div class="iso-monitor" style="border-color:\x27+accentColor+\x2777"><div class="iso-monitor-screen">\x27+monScreen+\x27</div></div>\x27+
3964
+ // name
3965
+ \x27<div class="iso-name" style="color:\x27+nameColor+\x27;background:\x27+nameBg+\x27">\x27+(isOrch?\x27\u2666\xA0\x27:\x27\x27)+esc(label.slice(0,16))+\x27</div>\x27+
4004
3966
  \x27</div>\x27;
4005
3967
  }
4006
3968
 
4007
- // Orchestrator station (index 0)
4008
- var orchIsActive2 = hasActive;
4009
- var orchDone2 = !hasActive && doneCount === totalCount && totalCount > 0;
4010
- stationsHtml += buildStation(0, \x27Orchestratore\x27, String.fromCodePoint(0x1F451), String.fromCodePoint(0x1F4CB), true, orchIsActive2, orchDone2, false, -1);
4011
-
4012
- // Agent/tool stations (index 1..N)
3969
+ var stationsHtml = \x27\x27;
3970
+ // Orchestrator
3971
+ var orchDone2 = !hasActive && doneCount===totalCount && totalCount>0;
3972
+ stationsHtml += buildStation2(\x27Orchestratore\x27, String.fromCodePoint(0x1F4CB), true, hasActive, orchDone2, false, 99);
3973
+ // Agents
4013
3974
  nodes.forEach(function(n, idx) {
4014
- var isActive = n.status === \x27running\x27;
4015
- var isDone = n.status === \x27done\x27;
4016
- var isErr = n.status === \x27error\x27;
4017
- var lbl = n.label || n.agent;
4018
- var toolEmoji = getNodeEmoji(n);
4019
- stationsHtml += buildStation(idx + 1, lbl, AGENT_EMOJIS[idx % AGENT_EMOJIS.length], toolEmoji, false, isActive, isDone, isErr, idx);
3975
+ stationsHtml += buildStation2(
3976
+ n.label || n.agent,
3977
+ getNodeEmoji(n),
3978
+ false,
3979
+ n.status===\x27running\x27,
3980
+ n.status===\x27done\x27,
3981
+ n.status===\x27error\x27,
3982
+ idx
3983
+ );
4020
3984
  });
4021
3985
 
4022
- // ── Decorations: plants + door ───────────────────────────────────────────
4023
- var decoHtml =
4024
- \x27<div style="position:absolute;bottom:8px;left:8px;font-size:32px;line-height:1;filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))">\x27+bigPlant+\x27</div>\x27+
4025
- \x27<div style="position:absolute;bottom:8px;right:8px;font-size:32px;line-height:1;filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))">\x27+bigPlant+\x27</div>\x27+
4026
- \x27<div style="position:absolute;top:8px;right:14px;font-size:22px;line-height:1">\x27+plantEmoji+\x27</div>\x27+
4027
- // Door on back wall
4028
- \x27<div style="position:absolute;top:0;left:50%;transform:translateX(-50%);width:38px;height:54px;background:#c8a87a;border:2px solid #a07848;border-radius:4px 4px 0 0;z-index:1">\x27+
4029
- \x27<div style="position:absolute;right:5px;top:50%;width:6px;height:6px;border-radius:50%;background:#7a5a2a;transform:translateY(-50%)"></div>\x27+
4030
- \x27<div style="position:absolute;top:4px;left:4px;right:4px;height:16px;background:rgba(255,255,255,.15);border-radius:2px"></div>\x27+
4031
- \x27</div>\x27;
4032
-
4033
- // ── Floor SVG (fills the whole scene) ────────────────────────────────────
4034
- var floorSvg = \x27<svg viewBox="0 0 \x27+SCENE_W+\x27 \x27+SCENE_H+\x27" width="\x27+SCENE_W+\x27" height="\x27+SCENE_H+\x27" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;z-index:0;pointer-events:none">\x27;
4035
- // Back wall
4036
- floorSvg += \x27<rect x="0" y="0" width="\x27+SCENE_W+\x27" height="\x27+Math.round(SCENE_H*0.38)+\x27" fill="#f5f0ea"/>\x27;
3986
+ // Floor SVG uses a fixed coordinate space (1000×600) scaled 100% via CSS
3987
+ var FW = 1000; var FH = 600;
3988
+ var wallH = Math.round(FH * 0.30);
3989
+ 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;
3990
+ floorSvg += \x27<defs>\x27;
3991
+ 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;
3992
+ 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;
3993
+ floorSvg += \x27</defs>\x27;
3994
+ // Wall
3995
+ floorSvg += \x27<rect x="0" y="0" width="\x27+FW+\x27" height="\x27+wallH+\x27" fill="url(#wallGrad)"/>\x27;
4037
3996
  // Baseboard
4038
- floorSvg += \x27<rect x="0" y="\x27+Math.round(SCENE_H*0.38-4)+\x27" width="\x27+SCENE_W+\x27" height="6" fill="#d4c4a8" rx="1"/>\x27;
4039
- // Floor parquet planks
4040
- var floorY = Math.round(SCENE_H*0.38);
4041
- var plankColors = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#c4a068\x27];
4042
- var plankH = 28; var plankW = 80;
4043
- for (var fy = floorY; fy < SCENE_H; fy += plankH) {
4044
- var rowOff = (Math.floor((fy-floorY)/plankH) % 2) * (plankW/2);
4045
- for (var fx = -plankW + rowOff; fx < SCENE_W + plankW; fx += plankW) {
4046
- var pc = plankColors[Math.abs(Math.round(fx/plankW + fy/plankH)) % plankColors.length];
4047
- floorSvg += \x27<rect x="\x27+fx+\x27" y="\x27+fy+\x27" width="\x27+(plankW-1)+\x27" height="\x27+(plankH-1)+\x27" fill="\x27+pc+\x27" rx="1"/>\x27;
4048
- // Grain line
4049
- floorSvg += \x27<line x1="\x27+(fx+plankW*0.35)+\x27" y1="\x27+fy+\x27" x2="\x27+(fx+plankW*0.35)+\x27" y2="\x27+(fy+plankH-1)+\x27" stroke="rgba(0,0,0,.05)" stroke-width="1"/>\x27;
3997
+ floorSvg += \x27<rect x="0" y="\x27+(wallH-5)+\x27" width="\x27+FW+\x27" height="7" fill="#d4c4a8" rx="2"/>\x27;
3998
+ // Floor parquet
3999
+ var plankColors2 = [\x27#c8a06a\x27,\x27#bf9860\x27,\x27#d4aa72\x27,\x27#ba9458\x27,\x27#caa86e\x27];
4000
+ var pH = 32; var pW = 120;
4001
+ for (var fy = wallH; fy < FH+pH; fy += pH) {
4002
+ var ro2 = (Math.floor((fy-wallH)/pH) % 2) * (pW/2);
4003
+ for (var fx = -pW+ro2; fx < FW+pW; fx += pW) {
4004
+ var pc2 = plankColors2[Math.abs(Math.round(fx/pW+fy/pH*1.3)) % plankColors2.length];
4005
+ 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;
4006
+ 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;
4050
4007
  }
4051
4008
  }
4052
- // Window on back wall
4053
- floorSvg += \x27<rect x="20" y="18" width="60" height="50" rx="3" fill="#bbd8f5" stroke="#a8c4dc" stroke-width="2"/>\x27;
4054
- floorSvg += \x27<line x1="50" y1="18" x2="50" y2="68" stroke="#a8c4dc" stroke-width="1.5"/>\x27;
4055
- floorSvg += \x27<line x1="20" y1="43" x2="80" y2="43" stroke="#a8c4dc" stroke-width="1.5"/>\x27;
4056
- floorSvg += \x27<rect x="20" y="18" width="60" height="50" rx="3" fill="rgba(255,255,255,.15)"/>\x27;
4057
- if (SCENE_W > 350) {
4058
- floorSvg += \x27<rect x="\x27+(SCENE_W-100)+\x27" y="18" width="60" height="50" rx="3" fill="#bbd8f5" stroke="#a8c4dc" stroke-width="2"/>\x27;
4059
- floorSvg += \x27<line x1="\x27+(SCENE_W-70)+\x27" y1="18" x2="\x27+(SCENE_W-70)+\x27" y2="68" stroke="#a8c4dc" stroke-width="1.5"/>\x27;
4060
- floorSvg += \x27<line x1="\x27+(SCENE_W-100)+\x27" y1="43" x2="\x27+(SCENE_W-40)+\x27" y2="43" stroke="#a8c4dc" stroke-width="1.5"/>\x27;
4009
+ // Windows — 2 on left, 1 center-right
4010
+ function svgWindow(wx, wy, ww, wh) {
4011
+ 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;
4012
+ 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;
4013
+ 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;
4014
+ 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;
4015
+ return r;
4061
4016
  }
4017
+ floorSvg += svgWindow(40, 20, 100, 80);
4018
+ floorSvg += svgWindow(180, 20, 100, 80);
4019
+ floorSvg += svgWindow(FW-200, 20, 120, 80);
4020
+ // Door center
4021
+ 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;
4022
+ floorSvg += \x27<rect x="\x27+(FW/2-25)+\x27" y="8" width="50" height="36" rx="4" fill="rgba(255,255,255,.18)"/>\x27;
4023
+ floorSvg += \x27<circle cx="\x27+(FW/2+22)+\x27" cy="\x27+(wallH/2)+\x27" r="5" fill="#8a6028"/>\x27;
4062
4024
  // Chandelier
4063
- var chandX = Math.round(SCENE_W/2);
4064
- floorSvg += \x27<line x1="\x27+chandX+\x27" y1="0" x2="\x27+chandX+\x27" y2="24" stroke="#999" stroke-width="2"/>\x27;
4065
- floorSvg += \x27<ellipse cx="\x27+chandX+\x27" cy="28" rx="28" ry="8" fill="#e8d980" stroke="#c8b840" stroke-width="1.5"/>\x27;
4066
- floorSvg += \x27<circle cx="\x27+(chandX-18)+\x27" cy="32" r="5" fill="#fff8c0" filter="url(#bGlow)"/>\x27;
4067
- floorSvg += \x27<circle cx="\x27+chandX+\x27" cy="34" r="5" fill="#fff8c0" filter="url(#bGlow)"/>\x27;
4068
- floorSvg += \x27<circle cx="\x27+(chandX+18)+\x27" cy="32" r="5" fill="#fff8c0" filter="url(#bGlow)"/>\x27;
4069
- floorSvg += \x27<defs><filter id="bGlow" x="-100%" y="-100%" width="300%" height="300%"><feGaussianBlur stdDeviation="4" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs>\x27;
4025
+ floorSvg += \x27<line x1="\x27+(FW/2)+\x27" y1="0" x2="\x27+(FW/2)+\x27" y2="30" stroke="#bbb" stroke-width="3"/>\x27;
4026
+ floorSvg += \x27<ellipse cx="\x27+(FW/2)+\x27" cy="38" rx="50" ry="14" fill="#e8d960" stroke="#c8b030" stroke-width="2"/>\x27;
4027
+ floorSvg += \x27<circle cx="\x27+(FW/2-28)+\x27" cy="46" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4028
+ floorSvg += \x27<circle cx="\x27+(FW/2)+\x27" cy="50" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4029
+ floorSvg += \x27<circle cx="\x27+(FW/2+28)+\x27" cy="46" r="8" fill="#fffde0" filter="url(#bGlow2)"/>\x27;
4030
+ // Light cone
4031
+ 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;
4070
4032
  floorSvg += \x27</svg>\x27;
4071
4033
 
4034
+ // Decorations (CSS positioned, z-index above floor SVG)
4035
+ var decoHtml =
4036
+ \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+
4037
+ \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+
4038
+ \x27<div style="position:absolute;top:12px;left:310px;font-size:24px;line-height:1;z-index:5">\x27+plantEmoji+\x27</div>\x27+
4039
+ \x27<div style="position:absolute;top:12px;right:230px;font-size:24px;line-height:1;z-index:5">\x27+plantEmoji+\x27</div>\x27;
4040
+
4072
4041
  el.innerHTML =
4073
4042
  \x27<div class="prl-wrap" style="border-color:\x27+phaseColor2+\x2744;padding-bottom:8px">\x27+
4074
4043
  \x27<div class="prl-header"><span class="prl-phase-chip" style="--pc:\x27+phaseColor2+\x27">\x27+phaseLabel2+\x27</span></div>\x27+
4075
- \x27<div class="iso-scene-wrap">\x27+
4076
- \x27<div class="iso-scene" style="position:relative;width:\x27+SCENE_W+\x27px;min-width:\x27+SCENE_W+\x27px;height:\x27+SCENE_H+\x27px">\x27+
4044
+ \x27<div class="iso-scene" style="position:relative">\x27+
4077
4045
  floorSvg+
4078
4046
  decoHtml+
4047
+ // Grid overlay for stations
4048
+ \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+
4049
+ // Push agents to bottom half of scene (wall takes top ~30%)
4050
+ \x27<div style="grid-column:1/-1;height:calc(30% - 12px)"></div>\x27+
4079
4051
  stationsHtml+
4080
4052
  \x27</div>\x27+
4081
4053
  \x27</div>\x27+
@@ -6684,25 +6656,25 @@ input:focus,textarea:focus{border-color:var(--green3)}
6684
6656
  .prl-office-plant2{position:absolute;bottom:14px;right:8px;width:22px;height:42px;z-index:2;pointer-events:none}
6685
6657
  /* ── ISOMETRIC JRPG SCENE ── */
6686
6658
  .iso-scene-wrap{width:100%;overflow-x:auto;display:flex;justify-content:center}
6687
- .iso-scene{background:#f0ede6;cursor:default;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18)}
6688
- /* ── Station layout (new grid-based office) ── */
6689
- .iso-station{display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;transition:filter .2s}
6690
- .iso-station:hover{filter:brightness(1.08)}
6691
- .iso-station.iso-orch-walking{animation:orchWalk 2.2s ease-in-out infinite alternate}
6692
- @keyframes orchWalk{0%{transform:translateX(-50%)}100%{transform:translateX(calc(-50% + var(--orch-tx,0px))) translateY(var(--orch-ty,0px))}}
6693
- .iso-station.iso-orch-done{animation:orchDone .6s ease forwards}
6694
- @keyframes orchDone{0%{transform:translateX(-50%) scale(1)}50%{transform:translateX(-50%) scale(1.15)}100%{transform:translateX(-50%) scale(1)}}
6695
- /* Desk */
6696
- .iso-desk{width:90px;height:18px;background:linear-gradient(180deg,#d4a448 0%,#b8832a 100%);border-radius:4px 4px 2px 2px;box-shadow:0 4px 0 #8a5e18,0 6px 8px rgba(0,0,0,.25);border:1px solid #c49038;position:relative;margin-top:2px}
6697
- .iso-desk::after{content:'';position:absolute;bottom:-4px;left:6px;right:6px;height:4px;background:#8a5e18;border-radius:0 0 3px 3px}
6698
- /* Monitor on desk */
6699
- .iso-monitor{width:52px;height:38px;background:#1a1a2c;border:2px solid #3a3070;border-radius:4px;position:absolute;top:-44px;left:50%;transform:translateX(-50%);display:flex;align-items:center;justify-content:center}
6700
- .iso-monitor::before{content:'';position:absolute;bottom:-6px;left:50%;transform:translateX(-50%);width:8px;height:6px;background:#252436;border-radius:0 0 2px 2px}
6701
- .iso-monitor-screen{width:42px;height:28px;background:rgba(80,60,180,.3);border-radius:2px;display:flex;align-items:center;justify-content:center}
6702
- .iso-monitor-blink{width:6px;height:6px;border-radius:50%;background:#6366f1;animation:monBlink .8s ease-in-out infinite}
6703
- @keyframes monBlink{0%,100%{opacity:1;box-shadow:0 0 6px #6366f1}50%{opacity:.3;box-shadow:none}}
6704
- /* Tool badge emoji floating above desk */
6705
- .iso-tool-badge{font-size:18px;line-height:1;filter:drop-shadow(0 2px 4px rgba(0,0,0,.3));margin-bottom:-2px;user-select:none}
6659
+ .iso-scene{background:#f0ede6;cursor:default;overflow:hidden;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.18);width:100%}
6660
+ /* ── Station grid layout ── */
6661
+ .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}
6662
+ .iso-station:hover{filter:brightness(1.06);transform:translateY(-2px)}
6663
+ .iso-station.iso-orch-walking{animation:orchWalkGrid 1.8s ease-in-out infinite alternate}
6664
+ @keyframes orchWalkGrid{0%{transform:translateX(0) scale(1)}100%{transform:translateX(var(--orch-tx,24px)) scale(1.04)}}
6665
+ .iso-station.iso-orch-done{animation:orchBounce .7s ease forwards}
6666
+ @keyframes orchBounce{0%{transform:scale(1)}40%{transform:scale(1.18) translateY(-6px)}100%{transform:scale(1)}}
6667
+ /* Desk — CSS 3D look */
6668
+ .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}
6669
+ .iso-desk::after{content:'';position:absolute;bottom:-4px;left:8px;right:8px;height:4px;background:#7a5010;border-radius:0 0 3px 3px}
6670
+ /* Monitor — sits on desk */
6671
+ .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}
6672
+ .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}
6673
+ .iso-monitor-screen{width:44px;height:28px;background:rgba(60,40,160,.35);border-radius:2px;display:flex;align-items:center;justify-content:center}
6674
+ .iso-monitor-blink{width:7px;height:7px;border-radius:50%;background:#6366f1;animation:monBlink .9s ease-in-out infinite}
6675
+ @keyframes monBlink{0%,100%{opacity:1;box-shadow:0 0 8px #6366f1}50%{opacity:.25;box-shadow:none}}
6676
+ /* Tool badge */
6677
+ .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}
6706
6678
  /* Animated status chip for [bracket tokens] */
6707
6679
  .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}
6708
6680
  @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)}}
@@ -6715,7 +6687,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
6715
6687
  .iso-orch-wrap{transition:transform .2s}
6716
6688
  .iso-orch-wrap.prl-head{animation:isoCharBob 1.4s ease-in-out infinite}
6717
6689
  /* Thought bubble / speech bubble above character */
6718
- .iso-bubble{font-size:8px;font-family:var(--mono);padding:2px 7px;border-radius:10px 10px 10px 2px;border:1px solid #3a3060;background:rgba(10,8,20,.85);color:#6b7280;white-space:nowrap;max-width:110px;overflow:hidden;text-overflow:ellipsis;line-height:1.4;transition:all .25s;pointer-events:none;backdrop-filter:blur(4px)}
6690
+ .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:nowrap;max-width:130px;overflow:hidden;text-overflow:ellipsis;line-height:1.5;transition:all .25s;pointer-events:none;backdrop-filter:blur(6px);text-align:center}
6719
6691
  .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}
6720
6692
  .iso-bubble--orch{font-size:9px;padding:3px 9px;border-radius:12px;border-color:#818cf8;color:#a5b4fc;background:rgba(20,15,50,.9)}
6721
6693
  @keyframes isoBubblePop{0%{transform:scale(.8) translateY(4px);opacity:.4}100%{transform:scale(1) translateY(0);opacity:1}}