Files
clawmates/handoff/visualizations/Clawmates Dashboard.dc.html
T
Omar SobhandClaude Opus 4.8 39bacbd1d2 World page: live WebGL Gource-style visualization (Phases A+B)
Replaces the static React-Flow world forest with a real-time WebGL view of the
swarm working, plus the live event contract that feeds it.

Phase A — the live contract + feed:
- frontend/src/lib/live/taxonomy.ts — the 13-event Clawmates Event Taxonomy as
  typed TS (the shared World/Observe contract).
- frontend/src/lib/live/useClawmatesLive.ts — native shared-singleton live client
  (EventSource to /api/world/live, typed fan-out, replay-of-last-state to late
  subscribers, refcounted, synthetic fallback so views are always alive).
- crates/cm-api/src/routes/world.rs — GET /api/world/live, authed + workspace-
  scoped SSE emitting the taxonomy (real agent.status from live-container state,
  a topology.update of the workspace's agents, telemetry with real doorsPending),
  mirroring run_events_sse. normalize() seam documented for run_events->world.touch.

Phase B — the WebGL engine:
- frontend/src/components/world/engine.ts — Gource-inspired force-directed model:
  org/company/team tree (sibling repulsion + parent spring + friction), agent
  pawns that converge on the touched node and beam it, world nodes that glow with
  heat and fade when idle. Framework-agnostic (renderer-independent) state+math.
- frontend/src/components/world/WorldCanvas.tsx — three.js scene (ortho cam,
  UnrealBloom), render loop syncing engine state, camera auto-fit, HTML labels,
  raycast click->select, Hierarchy/Flat/Live formation switch.
- Dashboard.tsx: swap <WorldFlow/> -> <WorldCanvas/> at the world-tier seam
  (shared claw-tier pieces untouched; WorldFlow.tsx kept for now).
- Adds three (+ @types/three).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-23 21:23:34 -07:00

651 lines
65 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: #08080a; }
body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
@keyframes cm-flow { to { stroke-dashoffset: -24; } }
@keyframes cm-blink { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes cm-halo { 0% { transform: scale(.7); opacity: .55; } 100% { transform: scale(1.9); opacity: 0; } }
@keyframes cm-fade { from { opacity: 0; } to { opacity: 1; } }
</style>
</helmet>
<div style="width:100%; height:100vh; min-height:640px; background:#08080a; display:flex; flex-direction:column; color:#f3f3f5; overflow:hidden;">
<!-- TOP BAR -->
<div style="height:54px; flex:none; display:flex; align-items:center; gap:14px; padding:0 18px; border-bottom:1px solid rgba(255,255,255,.06); background:linear-gradient(180deg,#0d0d10,#0a0a0c);">
<div style="display:flex; align-items:center; gap:10px;">
<svg width="22" height="22" viewBox="0 0 22 22" fill="none">
<path d="M11 3 L18.5 17 L3.5 17 Z" stroke="#ff6f61" stroke-width="1.3" stroke-linejoin="round" opacity="0.55"></path>
<circle cx="11" cy="3.5" r="2.4" fill="#ff6f61"></circle><circle cx="18" cy="17" r="2.4" fill="#ff6f61"></circle><circle cx="4" cy="17" r="2.4" fill="#ff6f61"></circle>
</svg>
<span style="font-size:15px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">Clawmates</span>
</div>
<div style="width:1px; height:22px; background:rgba(255,255,255,.08);"></div>
<div style="display:flex; align-items:center; gap:6px; font-family:'JetBrains Mono',monospace; font-size:12px;">
<span style="cursor:pointer; border-radius:6px;" style="{{ crumbOrg }}" onClick="{{ goOrg }}">Acme Org</span>
<span style="color:#3a3a40;">/</span>
<span style="cursor:pointer; border-radius:6px;" style="{{ crumbCo }}" onClick="{{ goCompany }}">Acme Corp</span>
<span style="color:#3a3a40;">/</span>
<span style="cursor:pointer; border-radius:6px;" style="{{ crumbTeam }}" onClick="{{ goTeam }}">Growth Team</span>
<sc-if value="{{ isClaw }}" hint-placeholder-val="{{ false }}">
<span style="color:#3a3a40;">/</span>
<span style="cursor:pointer; border-radius:6px;" style="{{ crumbClaw }}">{{ selName }}</span>
</sc-if>
</div>
<div style="flex:1;"></div>
<div style="display:flex; align-items:center; gap:7px; font-family:'JetBrains Mono',monospace; font-size:11px; color:#5fd08a; padding:5px 10px; border:1px solid rgba(95,208,138,.25); border-radius:7px; background:rgba(95,208,138,.06);">
<span style="width:7px; height:7px; border-radius:50%; background:#5fd08a; animation:cm-blink 1.6s infinite;"></span>
6 claws · running
</div>
<div style="display:flex; align-items:center; gap:7px; padding:6px 12px; border-radius:8px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); color:#2a0d0a; font-size:12px; font-weight:700; cursor:pointer;">
<span style="font-size:15px; line-height:1;">+</span> Deploy from template
</div>
<div style="width:32px; height:32px; border-radius:8px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:#2a0d0a;">O</div>
</div>
<!-- BODY -->
<div style="flex:1; display:flex; min-height:0;">
<!-- STRUCTURE RAIL -->
<div style="width:60px; flex:none; border-right:1px solid rgba(255,255,255,.06); background:#0a0a0c; display:flex; flex-direction:column; align-items:center; padding:14px 0;">
<div style="display:flex; flex-direction:column; gap:6px; align-items:center;">
<div style="position:relative; width:42px; height:48px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:10px; cursor:pointer; color:{{ railOrgColor }}; background:{{ railOrgBg }};" onClick="{{ goOrg }}">
<sc-if value="{{ railOrgOn }}" hint-placeholder-val="{{ false }}"><span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<svg width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="7.5" stroke="currentColor" stroke-width="1.4" fill="none"></circle><circle cx="10" cy="10" r="2.6" fill="currentColor"></circle></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:8px;">ORG</span>
</div>
<div style="position:relative; width:42px; height:48px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:10px; cursor:pointer; color:{{ railCoColor }}; background:{{ railCoBg }};" onClick="{{ goCompany }}">
<sc-if value="{{ railCoOn }}" hint-placeholder-val="{{ false }}"><span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<svg width="20" height="20" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:8px;">CO</span>
</div>
<div style="position:relative; width:42px; height:48px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:10px; cursor:pointer; color:{{ railTeamColor }}; background:{{ railTeamBg }};" onClick="{{ goTeam }}">
<sc-if value="{{ railTeamOn }}" hint-placeholder-val="{{ true }}"><span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<svg width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="5" r="2.2" fill="currentColor"></circle><circle cx="5" cy="13.5" r="2.2" fill="currentColor"></circle><circle cx="15" cy="13.5" r="2.2" fill="currentColor"></circle><path d="M10 5 L5 13.5 M10 5 L15 13.5 M5 13.5 L15 13.5" stroke="currentColor" stroke-width="1.1" opacity=".5"></path></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:8px;">TEAM</span>
</div>
<div style="position:relative; width:42px; height:48px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:10px; cursor:pointer; color:{{ railClawColor }}; background:{{ railClawBg }};" onClick="{{ goClawView }}">
<sc-if value="{{ railClawOn }}" hint-placeholder-val="{{ true }}"><span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<svg width="20" height="20" viewBox="0 0 20 20"><rect x="4" y="4" width="12" height="12" rx="3.5" stroke="currentColor" stroke-width="1.4" fill="none"></rect><circle cx="10" cy="10" r="2.4" fill="currentColor"></circle></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:8px;">CLAW</span>
</div>
</div>
<div style="flex:1;"></div>
<div style="width:30px; height:30px; border-radius:8px; border:1px dashed rgba(255,255,255,.16); display:flex; align-items:center; justify-content:center; color:#ff6f61; font-size:18px; font-weight:300; cursor:pointer;">+</div>
</div>
<!-- CONTEXT LIST -->
<div style="width:252px; flex:none; border-right:1px solid rgba(255,255,255,.06); background:#0b0b0e; display:flex; flex-direction:column; min-height:0;">
<sc-if value="{{ isTeam }}" hint-placeholder-val="{{ true }}">
<div style="padding:16px 16px 12px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:6px;">TEAM · 6 CLAWS</div>
<div style="font-size:18px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">Growth Team</div>
</div>
<div style="display:flex; gap:18px; padding:0 16px; border-bottom:1px solid rgba(255,255,255,.06);">
<div style="font-size:12px; font-weight:600; color:#f3f3f5; padding-bottom:9px; border-bottom:2px solid #ff6f61;">Members</div>
<div style="font-size:12px; font-weight:500; color:#6a6a72; padding-bottom:9px; border-bottom:2px solid transparent; cursor:pointer;">Templates</div>
</div>
<div style="flex:1; overflow-y:auto; padding:8px;">
<div style="display:flex; flex-direction:column; gap:2px;">
<sc-for list="{{ nodes }}" as="m" hint-placeholder-count="6">
<div style="display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:9px; cursor:pointer; position:relative; transition:background .15s; background:{{ m.rowBg }};" onClick="{{ m.onSelect }}">
<sc-if value="{{ m.selected }}" hint-placeholder-val="{{ false }}"><span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:{{ m.grad }}; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; color:{{ m.ink }};">{{ m.initial }}</div>
<div style="flex:1; min-width:0;">
<div style="font-size:13px; font-weight:600; color:{{ m.labelColor }};">{{ m.name }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">{{ m.role }}</div>
</div>
<span style="width:7px; height:7px; border-radius:50%; background:{{ m.statusColor }};"></span>
</div>
</sc-for>
</div>
</div>
<div style="flex:none; padding:10px 12px; border-top:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; justify-content:center; gap:7px; height:34px; border-radius:8px; background:rgba(255,111,97,.1); border:1px solid rgba(255,111,97,.25); color:#ff8a7a; font-size:12px; font-weight:600; cursor:pointer;">
<span style="font-size:15px; line-height:1;">+</span> Deploy claw from template
</div>
</div>
</sc-if>
<sc-if value="{{ isCompany }}" hint-placeholder-val="{{ false }}">
<div style="padding:16px 16px 12px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:6px;">COMPANY · 4 TEAMS</div>
<div style="font-size:18px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">Acme Corp</div>
</div>
<div style="display:flex; gap:18px; padding:0 16px; border-bottom:1px solid rgba(255,255,255,.06);">
<div style="font-size:12px; font-weight:600; color:#f3f3f5; padding-bottom:9px; border-bottom:2px solid #ff6f61;">Teams</div>
<div style="font-size:12px; font-weight:500; color:#6a6a72; padding-bottom:9px; border-bottom:2px solid transparent; cursor:pointer;">Templates</div>
</div>
<div style="flex:1; overflow-y:auto; padding:8px;">
<div style="display:flex; flex-direction:column; gap:2px;">
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#141417; border:1px solid rgba(255,255,255,.08); display:flex; align-items:center; justify-content:center;"><span style="width:8px; height:8px; border-radius:2px; background:#5ec8d8;"></span></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#eaeaee;">Intake Team</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">star-MoE · 3</div></div>
</div>
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer; background:rgba(255,111,97,.12); border:1px solid rgba(255,111,97,.28); position:relative;" onClick="{{ enterTeam }}">
<span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span>
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#1a1216; border:1px solid rgba(255,111,97,.3); display:flex; align-items:center; justify-content:center;"><span style="width:8px; height:8px; border-radius:50%; background:#ff6f61;"></span></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#fff;">Growth Team</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#ff8a7a;">hub-spoke · 6 · running</div></div>
</div>
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#141417; border:1px solid rgba(255,255,255,.08); display:flex; align-items:center; justify-content:center;"><span style="width:8px; height:8px; border-radius:50%; background:#5ec8d8;"></span></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#eaeaee;">Research Team</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">blackboard · 4</div></div>
</div>
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#141417; border:1px solid rgba(255,255,255,.08); display:flex; align-items:center; justify-content:center;"><span style="width:8px; height:8px; border-radius:2px; background:#3a3a40;"></span></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#eaeaee;">Ops Team</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">holacratic · 5</div></div>
</div>
</div>
</div>
<div style="flex:none; padding:10px 12px; border-top:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; justify-content:center; gap:7px; height:34px; border-radius:8px; background:rgba(255,111,97,.1); border:1px solid rgba(255,111,97,.25); color:#ff8a7a; font-size:12px; font-weight:600; cursor:pointer;">
<span style="font-size:15px; line-height:1;">+</span> Deploy team from template
</div>
</div>
</sc-if>
<sc-if value="{{ isOrg }}" hint-placeholder-val="{{ false }}">
<div style="padding:16px 16px 12px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:6px;">ORG · 3 COMPANIES</div>
<div style="font-size:18px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">Acme Org</div>
</div>
<div style="display:flex; gap:18px; padding:0 16px; border-bottom:1px solid rgba(255,255,255,.06);">
<div style="font-size:12px; font-weight:600; color:#f3f3f5; padding-bottom:9px; border-bottom:2px solid #ff6f61;">Companies</div>
<div style="font-size:12px; font-weight:500; color:#6a6a72; padding-bottom:9px; border-bottom:2px solid transparent; cursor:pointer;">Templates</div>
</div>
<div style="flex:1; overflow-y:auto; padding:8px;">
<div style="display:flex; flex-direction:column; gap:2px;">
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer; background:rgba(255,111,97,.12); border:1px solid rgba(255,111,97,.28); position:relative;" onClick="{{ goCompany }}">
<span style="position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span>
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#1a1216; border:1px solid rgba(255,111,97,.3); display:flex; align-items:center; justify-content:center; color:#ff6f61;"><svg width="15" height="15" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#fff;">Acme Corp</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#ff8a7a;">4 teams · 18 claws</div></div>
</div>
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer;" onClick="{{ goCompany }}">
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#141417; border:1px solid rgba(255,255,255,.08); display:flex; align-items:center; justify-content:center; color:#6a6a72;"><svg width="15" height="15" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#eaeaee;">Helix Labs</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">2 teams · 9 claws</div></div>
</div>
<div style="display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px; cursor:pointer;" onClick="{{ goCompany }}">
<div style="width:30px; height:30px; flex:none; border-radius:8px; background:#141417; border:1px solid rgba(255,255,255,.08); display:flex; align-items:center; justify-content:center; color:#6a6a72;"><svg width="15" height="15" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg></div>
<div style="flex:1;"><div style="font-size:13px; font-weight:600; color:#eaeaee;">Vega Studio</div><div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">1 team · 4 claws</div></div>
</div>
</div>
</div>
<div style="flex:none; padding:10px 12px; border-top:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; justify-content:center; gap:7px; height:34px; border-radius:8px; background:rgba(255,111,97,.1); border:1px solid rgba(255,111,97,.25); color:#ff8a7a; font-size:12px; font-weight:600; cursor:pointer;">
<span style="font-size:15px; line-height:1;">+</span> Deploy company from template
</div>
</div>
</sc-if>
<sc-if value="{{ isClaw }}" hint-placeholder-val="{{ false }}">
<div style="padding:14px 16px 12px;">
<div style="display:flex; align-items:center; gap:8px; font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72; cursor:pointer; margin-bottom:12px;" onClick="{{ goTeam }}">← Growth Team</div>
<div style="display:flex; align-items:center; gap:11px;">
<div style="width:42px; height:42px; flex:none; border-radius:11px; background:{{ selGrad }}; display:flex; align-items:center; justify-content:center; font-size:17px; font-weight:700; color:{{ selInk }};">{{ selInitial }}</div>
<div style="min-width:0;">
<div style="font-size:17px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">{{ selName }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">{{ selRole }} · Growth Team</div>
</div>
</div>
<div style="margin-top:11px; display:flex; align-items:center; gap:7px; padding:7px 10px; border-radius:8px; background:#101014; border:1px solid rgba(255,255,255,.07);">
<span style="width:7px; height:7px; border-radius:50%; background:#ff6f61;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#9a9aa2;">Claude Sonnet 4.5</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5fd08a;">online</span>
</div>
</div>
<div style="padding:0 12px 6px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; padding:6px 6px 8px;">COMPARTMENTS</div>
<div style="display:flex; flex-direction:column; gap:1px;">
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; background:rgba(255,111,97,.1); color:#f3f3f5; font-size:12px; font-weight:600;"><span style="width:6px; height:6px; border-radius:50%; background:#ff6f61;"></span>Anatomy</div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#ff6f61;"></span>Skills <span style="flex:1;"></span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5a5a62;">7</span></div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#5ec8d8;"></span>Tools <span style="flex:1;"></span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5a5a62;">4</span></div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#c98af0;"></span>Personality</div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#e8b465;"></span>Capabilities</div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#5fd08a;"></span>Memory</div>
<div style="display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:8px; color:#9a9aa2; font-size:12px; cursor:pointer;"><span style="width:6px; height:6px; border-radius:50%; background:#6fd0c0;"></span>Safety · §15</div>
</div>
</div>
</sc-if>
</div>
<!-- CANVAS -->
<div style="flex:1; position:relative; min-width:0; overflow:hidden;">
<sc-if value="{{ isTeam }}" hint-placeholder-val="{{ true }}">
<div style="position:absolute; inset:0; display:flex; flex-direction:column; background:radial-gradient(120% 90% at 55% 40%, #0e0e13 0%, #08080a 70%);">
<!-- topology morph selector (reserved band) -->
<div style="flex:none; display:flex; align-items:center; gap:10px; padding:14px 18px 10px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; flex:none;">TOPOLOGY</span>
<div style="flex:1; min-width:0; display:flex; gap:6px; overflow-x:auto; white-space:nowrap; padding-bottom:2px;">
<sc-for list="{{ topos }}" as="t" hint-placeholder-count="6">
<div style="flex:none; font-family:'JetBrains Mono',monospace; font-size:11px; font-weight:600; padding:5px 11px; border-radius:7px; cursor:pointer; transition:all .2s; {{ t.style }}" onClick="{{ t.onPick }}">{{ t.label }}</div>
</sc-for>
</div>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#5ec8d8; flex:none; cursor:pointer; padding:5px 10px; border:1px solid rgba(94,200,216,.22); border-radius:7px;">⇄ compare all</span>
</div>
<!-- current topology caption -->
<div style="flex:none; padding:0 18px 4px;">
<div style="font-size:22px; font-weight:700; color:#f3f3f5; letter-spacing:-.01em;">{{ topoLabel }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#6a6a72; margin-top:2px;">{{ topoKind }}</div>
</div>
<span style="position:absolute; bottom:14px; left:18px; right:18px; z-index:5; font-family:'JetBrains Mono',monospace; font-size:10px; color:#3a3a40;">click a claw to open its computer · pick a topology to re-wire the team</span>
<!-- graph stage -->
<div style="position:relative; flex:1; min-height:0;">
<svg viewBox="0 0 100 100" preserveAspectRatio="none" style="position:absolute; inset:0; width:100%; height:100%;">
<sc-for list="{{ linkPaths }}" as="lk" hint-placeholder-count="5">
<path d="{{ lk.d }}" fill="none" stroke="{{ lk.stroke }}" stroke-width="{{ lk.width }}" stroke-dasharray="{{ lk.dash }}" vector-effect="non-scaling-stroke" style="{{ lk.anim }} transition:stroke .3s;"></path>
</sc-for>
</svg>
<sc-for list="{{ nodes }}" as="n" hint-placeholder-count="6">
<div style="position:absolute; left:{{ n.x }}; top:{{ n.y }}; transform:translate(-50%,-50%); transition:left .55s cubic-bezier(.4,0,.2,1), top .55s cubic-bezier(.4,0,.2,1); display:flex; flex-direction:column; align-items:center; gap:7px; z-index:3; cursor:pointer;" onClick="{{ n.onSelect }}">
<div style="position:relative; width:50px; height:50px;">
<sc-if value="{{ n.running }}" hint-placeholder-val="{{ false }}"><div style="position:absolute; inset:0; border-radius:50%; background:rgba(94,200,216,.4); animation:cm-halo 1.8s ease-out infinite;"></div></sc-if>
<sc-if value="{{ n.selected }}" hint-placeholder-val="{{ false }}"><div style="position:absolute; inset:-6px; border-radius:50%; border:2px solid #ff6f61; box-shadow:0 0 0 4px rgba(255,111,97,.12);"></div></sc-if>
<div style="position:relative; width:50px; height:50px; border-radius:50%; background:{{ n.grad }}; display:flex; align-items:center; justify-content:center; font-size:18px; font-weight:700; color:{{ n.ink }}; box-shadow:0 0 28px rgba(0,0,0,.45);">{{ n.initial }}</div>
<span style="position:absolute; right:-1px; bottom:-1px; width:12px; height:12px; border-radius:50%; background:{{ n.statusColor }}; border:2px solid #0a0a0c;"></span>
</div>
<div style="text-align:center;">
<div style="font-size:12px; font-weight:600; color:{{ n.labelColor }};">{{ n.name }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">{{ n.role }}</div>
</div>
</div>
</sc-for>
</div>
</div>
</sc-if>
<sc-if value="{{ isCompany }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute; inset:0; background:#08080a; background-image:linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px); background-size:28px 28px;">
<div style="position:absolute; top:16px; left:18px; z-index:5; display:flex; align-items:center; gap:10px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.1em; color:#e8b465; padding:4px 9px; border-radius:6px; border:1px solid rgba(232,196,106,.25); background:rgba(232,196,106,.07);">PIPELINE</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#5a5a62;">company topology · click a team to enter its claws</span>
</div>
<div style="position:absolute; top:14px; right:18px; z-index:5; font-family:'JetBrains Mono',monospace; font-size:10px; color:#5a5a62;">x:248 y:112 · z:1.0×</div>
<svg viewBox="0 0 100 100" preserveAspectRatio="none" style="position:absolute; inset:0; width:100%; height:100%;">
<path d="M16,34 H31 V22 H46" fill="none" stroke="rgba(94,200,216,.5)" stroke-width="1.6" stroke-dasharray="3 4" vector-effect="non-scaling-stroke" style="animation:cm-flow 1.1s linear infinite;"></path>
<path d="M16,34 H30 V66 H44" fill="none" stroke="rgba(232,196,106,.45)" stroke-width="1.6" stroke-dasharray="3 4" vector-effect="non-scaling-stroke" style="animation:cm-flow 1.4s linear infinite;"></path>
<path d="M46,22 H63 V46 H80" fill="none" stroke="rgba(255,111,97,.55)" stroke-width="1.8" stroke-dasharray="3 4" vector-effect="non-scaling-stroke" style="animation:cm-flow .9s linear infinite;"></path>
<path d="M44,66 H62 V46 H80" fill="none" stroke="rgba(255,255,255,.12)" stroke-width="1.5" vector-effect="non-scaling-stroke"></path>
</svg>
<div style="position:absolute; left:16%; top:34%; transform:translate(-50%,-50%); width:158px; z-index:3; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(255,255,255,.09); padding:11px 12px; box-shadow:0 8px 24px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:8px;"><span style="width:7px; height:7px; border-radius:2px; background:#5ec8d8;"></span><span style="font-size:13px; font-weight:700; color:#eaeaee;">Intake Team</span></div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72; margin-bottom:9px;">star-MoE · 3 claws</div>
<div style="display:flex; gap:4px;"><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#6fd0c0,#4aa3b8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#8a9af0,#5a6ad8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#e8c46a,#d89a3a);"></span></div>
</div>
</div>
<div style="position:absolute; left:46%; top:22%; transform:translate(-50%,-50%); width:170px; z-index:4; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="border-radius:12px; background:#141014; border:1.5px solid #ff6f61; padding:11px 12px; box-shadow:0 0 0 4px rgba(255,111,97,.1), 0 10px 28px rgba(0,0,0,.5);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:8px;"><span style="width:7px; height:7px; border-radius:50%; background:#ff6f61; animation:cm-blink 1.5s infinite;"></span><span style="font-size:13px; font-weight:700; color:#fff;">Growth Team</span><span style="flex:1;"></span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#ff8a7a;">▾ enter</span></div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#ff8a7a; margin-bottom:9px;">hub-spoke · 6 claws · running</div>
<div style="display:flex; gap:4px;"><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#ff9a6a,#ff6f4a);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#6fd0c0,#4aa3b8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#8a9af0,#5a6ad8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#e8c46a,#d89a3a);"></span><span style="width:15px; height:15px; border-radius:5px; background:#1a1a1e; display:flex; align-items:center; justify-content:center; font-family:'JetBrains Mono',monospace; font-size:8px; color:#8a8a92;">+2</span></div>
</div>
</div>
<div style="position:absolute; left:44%; top:66%; transform:translate(-50%,-50%); width:158px; z-index:3; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(255,255,255,.09); padding:11px 12px; box-shadow:0 8px 24px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:8px;"><span style="width:7px; height:7px; border-radius:50%; background:#5ec8d8; animation:cm-blink 1.7s infinite;"></span><span style="font-size:13px; font-weight:700; color:#eaeaee;">Research Team</span></div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72; margin-bottom:9px;">blackboard · 4 claws</div>
<div style="display:flex; gap:4px;"><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#8a9af0,#5a6ad8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#6fd0c0,#4aa3b8);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#c98af0,#9a5ad8);"></span><span style="width:15px; height:15px; border-radius:5px; background:#1a1a1e; display:flex; align-items:center; justify-content:center; font-family:'JetBrains Mono',monospace; font-size:8px; color:#8a8a92;">+1</span></div>
</div>
</div>
<div style="position:absolute; left:80%; top:46%; transform:translate(-50%,-50%); width:152px; z-index:3; cursor:pointer;" onClick="{{ enterTeam }}">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(255,255,255,.09); padding:11px 12px; box-shadow:0 8px 24px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:8px;"><span style="width:7px; height:7px; border-radius:50%; background:#3a3a40;"></span><span style="font-size:13px; font-weight:700; color:#eaeaee;">Ops Team</span></div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72; margin-bottom:9px;">holacratic · 5 claws</div>
<div style="display:flex; gap:4px;"><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#e8c46a,#d89a3a);"></span><span style="width:15px; height:15px; border-radius:5px; background:linear-gradient(135deg,#ff9a6a,#ff6f4a);"></span><span style="width:15px; height:15px; border-radius:5px; background:#1a1a1e; display:flex; align-items:center; justify-content:center; font-family:'JetBrains Mono',monospace; font-size:8px; color:#8a8a92;">+3</span></div>
</div>
</div>
<span style="position:absolute; bottom:16px; left:18px; z-index:5; font-family:'JetBrains Mono',monospace; font-size:10px; color:#3a3a40;">↑ zoom out to Org · ↓ click a team to enter</span>
</div>
</sc-if>
<sc-if value="{{ isOrg }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute; inset:0; background:radial-gradient(120% 90% at 50% 40%, #0e0e13 0%, #08080a 70%);">
<div style="position:absolute; top:16px; left:18px; z-index:5; display:flex; align-items:center; gap:10px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.1em; color:#c98af0; padding:4px 9px; border-radius:6px; border:1px solid rgba(201,138,240,.25); background:rgba(201,138,240,.07);">PORTFOLIO</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#5a5a62;">org topology · click a company to descend</span>
</div>
<svg viewBox="0 0 100 100" preserveAspectRatio="none" style="position:absolute; inset:0; width:100%; height:100%;">
<path d="M50,46 L26,28" fill="none" stroke="rgba(255,111,97,.5)" stroke-width="1.8" stroke-dasharray="3 4" vector-effect="non-scaling-stroke" style="animation:cm-flow 1s linear infinite;"></path>
<path d="M50,46 L76,30" fill="none" stroke="rgba(255,255,255,.12)" stroke-width="1.5" vector-effect="non-scaling-stroke"></path>
<path d="M50,46 L62,74" fill="none" stroke="rgba(255,255,255,.12)" stroke-width="1.5" vector-effect="non-scaling-stroke"></path>
</svg>
<div style="position:absolute; left:50%; top:46%; transform:translate(-50%,-50%); display:flex; flex-direction:column; align-items:center; gap:9px; z-index:3;">
<div style="width:60px; height:60px; border-radius:16px; background:#141417; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center; color:#9a9aa2; box-shadow:0 0 30px rgba(0,0,0,.5);"><svg width="26" height="26" viewBox="0 0 20 20"><circle cx="10" cy="10" r="7.5" stroke="currentColor" stroke-width="1.4" fill="none"></circle><circle cx="10" cy="10" r="2.6" fill="currentColor"></circle></svg></div>
<div style="text-align:center;"><div style="font-size:13px; font-weight:700; color:#fff;">Acme Org</div><div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">3 companies</div></div>
</div>
<div style="position:absolute; left:26%; top:28%; transform:translate(-50%,-50%); display:flex; flex-direction:column; align-items:center; gap:8px; z-index:3; cursor:pointer;" onClick="{{ goCompany }}">
<div style="width:54px; height:54px; border-radius:14px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center; color:#2a0d0a; box-shadow:0 0 26px rgba(255,111,97,.4);"><svg width="22" height="22" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.6" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.6" fill="none"></rect></svg></div>
<div style="text-align:center;"><div style="font-size:12px; font-weight:700; color:#fff;">Acme Corp</div><div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#ff8a7a;">4 teams · enter ▸</div></div>
</div>
<div style="position:absolute; left:76%; top:30%; transform:translate(-50%,-50%); display:flex; flex-direction:column; align-items:center; gap:8px; z-index:3; cursor:pointer;" onClick="{{ goCompany }}">
<div style="width:48px; height:48px; border-radius:13px; background:#141417; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center; color:#8a8a92;"><svg width="20" height="20" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg></div>
<div style="text-align:center;"><div style="font-size:12px; font-weight:600; color:#dcdce2;">Helix Labs</div><div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">2 teams</div></div>
</div>
<div style="position:absolute; left:62%; top:74%; transform:translate(-50%,-50%); display:flex; flex-direction:column; align-items:center; gap:8px; z-index:3; cursor:pointer;" onClick="{{ goCompany }}">
<div style="width:48px; height:48px; border-radius:13px; background:#141417; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center; color:#8a8a92;"><svg width="20" height="20" viewBox="0 0 20 20"><rect x="3.5" y="5" width="6" height="11" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect><rect x="10.5" y="2.5" width="6" height="13.5" rx="1" stroke="currentColor" stroke-width="1.4" fill="none"></rect></svg></div>
<div style="text-align:center;"><div style="font-size:12px; font-weight:600; color:#dcdce2;">Vega Studio</div><div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">1 team</div></div>
</div>
</div>
</sc-if>
<sc-if value="{{ isClaw }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute; inset:0; display:flex; flex-direction:column; background:radial-gradient(120% 90% at 50% 42%, #100e13 0%, #08080a 70%);">
<div style="flex:none; display:flex; align-items:center; gap:10px; padding:14px 18px 6px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.1em; color:#ff8a7a; padding:4px 9px; border-radius:6px; border:1px solid rgba(255,111,97,.25); background:rgba(255,111,97,.07);">ANATOMY</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#6a6a72;">what {{ selName }} is made of · compartments wired to the core</span>
</div>
<div style="position:relative; flex:1; min-height:0; overflow:auto; padding:22px 20px 28px;">
<div style="max-width:820px; margin:0 auto; display:flex; flex-direction:column; align-items:center; gap:20px;">
<!-- core -->
<div style="display:flex; flex-direction:column; align-items:center; gap:9px;">
<div style="position:relative; width:78px; height:78px;">
<div style="position:absolute; inset:-7px; border-radius:50%; border:1.5px solid rgba(255,111,97,.35);"></div>
<div style="position:absolute; inset:0; border-radius:50%; background:rgba(255,111,97,.32); animation:cm-halo 2s ease-out infinite;"></div>
<div style="position:relative; width:78px; height:78px; border-radius:50%; background:{{ selGrad }}; display:flex; align-items:center; justify-content:center; font-size:28px; font-weight:700; color:{{ selInk }}; box-shadow:0 0 44px rgba(255,111,97,.45);">{{ selInitial }}</div>
</div>
<div style="text-align:center;">
<div style="font-size:14px; font-weight:700; color:#fff;">{{ selName }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#8a8a92; letter-spacing:.04em;">CLAUDE SONNET · CORE</div>
</div>
</div>
<div style="width:100%; display:grid; grid-template-columns:repeat(auto-fit, minmax(196px, 1fr)); gap:14px; align-items:start;">
<!-- SKILLS -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(255,111,97,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(255,111,97,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M10 1 L3 10 H8 L7 17 L15 7 H9 Z" fill="#ff6f61"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#ff8a7a;">SKILLS</span><span style="flex:1;"></span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5a5a62;">7</span></div>
<div style="display:flex; flex-wrap:wrap; gap:4px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Web research</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Summarize</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Data viz</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#8a8a92; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.03);">+4</span>
</div>
</div>
</div>
<!-- PERSONALITY -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(201,138,240,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(201,138,240,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><circle cx="9" cy="6" r="3.4" fill="#c98af0"></circle><path d="M3 16c0-3.3 2.7-6 6-6s6 2.7 6 6" fill="#c98af0"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#c98af0;">PERSONALITY</span></div>
<div style="display:flex; flex-wrap:wrap; gap:4px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Analytical</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Concise</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Skeptical</span>
</div>
</div>
</div>
<!-- MEMORY -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(95,208,138,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(95,208,138,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><rect x="3" y="3" width="12" height="12" rx="2" fill="none" stroke="#5fd08a" stroke-width="1.6"></rect><path d="M6 7h6M6 11h4" stroke="#5fd08a" stroke-width="1.4"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#5fd08a;">MEMORY</span></div>
<div style="display:flex; flex-direction:column; gap:5px; font-family:'JetBrains Mono',monospace; font-size:10px; color:#9a9aa2;">
<div style="display:flex;"><span style="flex:1;">Long-term</span><span style="color:#cfcfd5;">2,418 notes</span></div>
<div style="display:flex;"><span style="flex:1;">Recent ctx</span><span style="color:#cfcfd5;">18 msgs</span></div>
</div>
</div>
</div>
<!-- TOOLS -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(94,200,216,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(94,200,216,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M4 3v12M4 4h8l-2 3 2 3H4" fill="none" stroke="#5ec8d8" stroke-width="1.5" stroke-linejoin="round"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#5ec8d8;">TOOLS · DOORS</span></div>
<div style="display:flex; flex-direction:column; gap:4px; font-family:'JetBrains Mono',monospace; font-size:10px;">
<div style="display:flex; align-items:center;"><span style="flex:1; color:#cfcfd5;">Email</span><span style="color:#5fd08a;">gated ✓</span></div>
<div style="display:flex; align-items:center;"><span style="flex:1; color:#cfcfd5;">Slack</span><span style="color:#5fd08a;">gated ✓</span></div>
<div style="display:flex; align-items:center;"><span style="flex:1; color:#cfcfd5;">Browser</span><span style="color:#5fd08a;">gated ✓</span></div>
<div style="display:flex; align-items:center;"><span style="flex:1; color:#7a7a82;">Shell</span><span style="color:#e8b465;">blocked </span></div>
</div>
</div>
</div>
<!-- CAPABILITIES -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(232,196,106,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(232,196,106,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><circle cx="9" cy="9" r="6" fill="none" stroke="#e8b465" stroke-width="1.6"></circle><path d="M9 5v4l3 2" stroke="#e8b465" stroke-width="1.4" fill="none"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#e8b465;">CAPABILITIES</span></div>
<div style="display:flex; flex-wrap:wrap; gap:4px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">File mgmt</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Scheduling</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:3px 7px; border-radius:5px; background:rgba(255,255,255,.05);">Code exec</span>
</div>
</div>
</div>
<!-- SAFETY -->
<div style="width:100%;">
<div style="border-radius:12px; background:#0f0f13; border:1px solid rgba(111,208,192,.22); padding:11px; box-shadow:0 8px 22px rgba(0,0,0,.4);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:9px;"><span style="width:18px; height:18px; border-radius:5px; background:rgba(111,208,192,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M9 2l5 2v4c0 4-2.5 6.5-5 8-2.5-1.5-5-4-5-8V4z" fill="none" stroke="#6fd0c0" stroke-width="1.5" stroke-linejoin="round"></path></svg></span><span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#6fd0c0;">SAFETY · §15</span></div>
<div style="display:flex; flex-direction:column; gap:5px; font-family:'JetBrains Mono',monospace; font-size:10px; color:#9a9aa2;">
<div style="display:flex;"><span style="flex:1;">Sandbox</span><span style="color:#6fd0c0;">isolated</span></div>
<div style="display:flex;"><span style="flex:1;">Network</span><span style="color:#6fd0c0;">none</span></div>
</div>
</div>
</div>
</div>
<span style="text-align:center; font-family:'JetBrains Mono',monospace; font-size:10px; color:#3a3a40;">click a compartment to inspect · the computer panel runs this claw's apps & routines</span>
</div>
</div>
</div>
</sc-if>
</div>
<!-- COMPUTER PANEL -->
<sc-if value="{{ showComputer }}" hint-placeholder-val="{{ true }}">
<div style="width:330px; flex:none; border-left:1px solid rgba(255,255,255,.06); background:#0b0b0e; display:flex; flex-direction:column; min-height:0; animation:cm-fade .25s ease;">
<div style="padding:16px 16px 12px; border-bottom:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; gap:10px;">
<div style="position:relative; width:38px; height:38px;">
<div style="width:38px; height:38px; border-radius:10px; background:{{ selGrad }}; display:flex; align-items:center; justify-content:center; font-size:16px; font-weight:700; color:{{ selInk }};">{{ selInitial }}</div>
<span style="position:absolute; right:-2px; bottom:-2px; width:11px; height:11px; border-radius:50%; background:#5fd08a; border:2px solid #0b0b0e;"></span>
</div>
<div style="flex:1;">
<div style="font-size:14px; font-weight:700; color:#f3f3f5;">{{ selName }}'s Computer</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#5ec8d8;">● sandbox live · no network</div>
</div>
<div style="width:26px; height:26px; border-radius:7px; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center; color:#6a6a72; font-size:13px; cursor:pointer;"></div>
</div>
</div>
<div style="flex:1; overflow-y:auto; padding:16px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:12px;">APPS</div>
<div style="display:grid; grid-template-columns:repeat(4,1fr); gap:10px 6px; margin-bottom:22px;">
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;">
<div style="width:48px; height:48px; border-radius:13px; background:#fff; display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="26" height="26" viewBox="0 0 26 26"><circle cx="13" cy="13" r="11" fill="#fff" stroke="#e0e0e0"></circle><circle cx="13" cy="13" r="4.4" fill="#4a90e2"></circle><path d="M13 8.6 H24" stroke="#ea4335" stroke-width="3.6"></path><path d="M9.2 11 L4 3.4" stroke="#34a853" stroke-width="3.6"></path><path d="M13 17.4 L7.5 22.5" stroke="#fbbc05" stroke-width="3.6"></path></svg></div>
<span style="font-size:10px; color:#b5b5bd;">Browser</span>
</div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;">
<div style="width:48px; height:48px; border-radius:13px; background:#fff; display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="22" height="22" viewBox="0 0 22 22"><rect x="9" y="2" width="4" height="11" rx="2" fill="#36c5f0"></rect><rect x="9" y="13" width="4" height="7" rx="2" fill="#2eb67d"></rect><rect x="2" y="9" width="11" height="4" rx="2" fill="#ecb22e"></rect><rect x="9" y="9" width="11" height="4" rx="2" fill="#e01e5a"></rect></svg></div>
<span style="font-size:10px; color:#b5b5bd;">Slack</span>
</div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;">
<div style="width:48px; height:48px; border-radius:13px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="22" height="22" viewBox="0 0 22 22"><path d="M3 5a2 2 0 012-2h12a2 2 0 012 2v8a2 2 0 01-2 2H8l-4 4v-4H5a2 2 0 01-2-2z" fill="#fff"></path></svg></div>
<span style="font-size:10px; color:#b5b5bd;">Claw Chat</span>
</div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;">
<div style="width:48px; height:48px; border-radius:13px; border:1.5px dashed rgba(255,255,255,.18); display:flex; align-items:center; justify-content:center; color:#ff6f61; font-size:22px; font-weight:300; cursor:pointer;">+</div>
<span style="font-size:10px; color:#8a8a92;">Add Apps</span>
</div>
</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:10px;">NOW RUNNING</div>
<div style="display:flex; flex-direction:column; gap:8px;">
<div style="padding:10px 11px; border-radius:10px; background:#101014; border:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:6px;">
<span style="width:6px; height:6px; border-radius:50%; background:#5ec8d8; animation:cm-blink 1.4s infinite;"></span>
<span style="font-size:12px; font-weight:600; color:#e6e6ea;">Q3 competitor scan</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5ec8d8;">loop · step 14</span>
</div>
<div style="height:4px; border-radius:2px; background:rgba(255,255,255,.08); overflow:hidden;"><div style="width:62%; height:100%; background:linear-gradient(90deg,#5ec8d8,#4aa3b8);"></div></div>
</div>
<div style="padding:10px 11px; border-radius:10px; background:#101014; border:1px solid rgba(255,255,255,.06); display:flex; align-items:center; gap:7px;">
<span style="width:6px; height:6px; border-radius:50%; background:#e8b465;"></span>
<span style="font-size:12px; font-weight:600; color:#e6e6ea;">Daily digest</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#e8b465;">cron · 08:00</span>
</div>
</div>
</div>
<div style="flex:none; margin:0 12px 14px; padding:12px; border-radius:14px; background:#121216; border:1px solid rgba(255,255,255,.07); display:flex; justify-content:space-around;">
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M10 1 L3 10 H8 L7 17 L15 7 H9 Z" fill="#fff"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Skills</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M2 5a1.5 1.5 0 011.5-1.5H7l1.5 1.5h6A1.5 1.5 0 0116 6.5v7A1.5 1.5 0 0114.5 15h-11A1.5 1.5 0 012 13.5z" fill="#fff"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Files</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M9 2a5 5 0 00-5 5c0 4-1.5 5-1.5 5h13S14 11 14 7a5 5 0 00-5-5z" fill="#fff"></path><path d="M7.5 15a1.5 1.5 0 003 0" fill="#fff"></path></svg></div><span style="font-size:10px; color:#ff8a7a;">Routines</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><circle cx="9" cy="9" r="2.6" fill="#fff"></circle><path d="M9 1.5v2M9 14.5v2M1.5 9h2M14.5 9h2M3.7 3.7l1.4 1.4M12.9 12.9l1.4 1.4M14.3 3.7l-1.4 1.4M5.1 12.9l-1.4 1.4" stroke="#fff" stroke-width="1.5"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Settings</span></div>
</div>
</div>
</sc-if>
</div>
<!-- STATUS BAR -->
<div style="height:28px; flex:none; display:flex; align-items:center; gap:18px; padding:0 16px; border-top:1px solid rgba(255,255,255,.06); background:#0a0a0c; font-family:'JetBrains Mono',monospace; font-size:10px; color:#5a5a62;">
<span style="color:#5fd08a;">● durable runner ok</span>
<span>checkpoint 3s ago</span>
<span style="flex:1;"></span>
<span>§15 sandbox: isolated</span>
<span style="color:#5ec8d8;">2 doors awaiting approval</span>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script>
class Component extends DCLogic {
state = { tier: 'team', topology: 'hub-spoke', selected: 'morpheus' };
renderVals() {
const s = this.state;
const claws = [
{ id:'atlas', name:'Atlas', role:'team lead', initial:'A', grad:'linear-gradient(135deg,#ff9a6a,#ff6f4a)', ink:'#2a0d05', status:'online' },
{ id:'iris', name:'Iris', role:'researcher', initial:'I', grad:'linear-gradient(135deg,#6fd0c0,#4aa3b8)', ink:'#06201f', status:'running' },
{ id:'echo', name:'Echo', role:'researcher', initial:'E', grad:'linear-gradient(135deg,#8a9af0,#5a6ad8)', ink:'#0a0e2a', status:'running' },
{ id:'nova', name:'Nova', role:'writer', initial:'N', grad:'linear-gradient(135deg,#e8c46a,#d89a3a)', ink:'#2a1d05', status:'online' },
{ id:'sable', name:'Sable', role:'critic', initial:'S', grad:'linear-gradient(135deg,#c98af0,#9a5ad8)', ink:'#1a0a2a', status:'idle' },
{ id:'morpheus',name:'Morpheus',role:'analyst', initial:'M', grad:'linear-gradient(135deg,#ff8a7a,#ff5f57)', ink:'#2a0d0a', status:'online' },
];
const POS = {
'hub-spoke': [[50,48],[22,26],[24,72],[50,15],[78,28],[78,70]],
'pipeline': [[11,50],[27,50],[42,50],[58,50],[73,50],[89,50]],
'ring': [[50,15],[80,32],[80,68],[50,85],[20,68],[20,32]],
'mesh': [[31,26],[69,24],[85,52],[67,80],[31,80],[15,52]],
'swarm': [[40,38],[60,32],[66,55],[48,66],[33,55],[53,47]],
'debate': [[26,22],[26,50],[26,78],[74,22],[74,50],[74,78]],
};
const LNK = {
'hub-spoke': [[0,1],[0,2],[0,3],[0,4],[0,5]],
'pipeline': [[0,1],[1,2],[2,3],[3,4],[4,5]],
'ring': [[0,1],[1,2],[2,3],[3,4],[4,5],[5,0]],
'mesh': [[0,1],[1,2],[2,3],[3,4],[4,5],[5,0],[0,3],[1,4],[2,5]],
'swarm': [[0,1],[0,2],[0,3],[0,4],[0,5],[1,3],[2,4]],
'debate': [[0,3],[1,4],[2,5],[0,4],[1,3],[1,5],[2,4]],
};
const pos = POS[s.topology] || POS['hub-spoke'];
const lnks = LNK[s.topology] || [];
const sc = st => st==='running' ? '#5ec8d8' : st==='online' ? '#5fd08a' : '#3a3a40';
const selIdx = claws.findIndex(c => c.id === s.selected);
const nodes = claws.map((c, i) => ({
name:c.name, role:c.role, initial:c.initial, grad:c.grad, ink:c.ink,
x: pos[i][0] + '%', y: pos[i][1] + '%',
selected: c.id === s.selected,
running: c.status === 'running',
statusColor: sc(c.status),
labelColor: c.id === s.selected ? '#ffffff' : '#dcdce2',
rowBg: c.id === s.selected ? 'rgba(255,111,97,.12)' : 'transparent',
onSelect: () => this.setState({ selected: c.id, tier: 'claw' }),
}));
const linkPaths = lnks.map(([a,b]) => {
const ax=pos[a][0], ay=pos[a][1], bx=pos[b][0], by=pos[b][1];
let stroke='rgba(255,255,255,.12)', width=1.5, dash='0', anim='';
if (a===selIdx || b===selIdx) { stroke='rgba(255,111,97,.6)'; width=1.8; dash='3 4'; anim='animation:cm-flow .9s linear infinite;'; }
else if (a===1||a===2||b===1||b===2) { stroke='rgba(94,200,216,.5)'; width=1.6; dash='3 4'; anim='animation:cm-flow 1.2s linear infinite;'; }
return { d:`M ${ax},${ay} L ${bx},${by}`, stroke, width, dash, anim };
});
const topoMeta = {
'hub-spoke':{label:'Hub-Spoke',kind:'one coordinator routes every claw'},
'pipeline': {label:'Pipeline', kind:'output of each claw feeds the next'},
'ring': {label:'Ring', kind:'cyclic hand-off around the loop'},
'mesh': {label:'Mesh', kind:'every claw talks to every claw'},
'swarm': {label:'Swarm', kind:'parallel claws, loose coordination'},
'debate': {label:'Debate', kind:'adversarial cross-examination'},
};
const topos = ['hub-spoke','pipeline','ring','mesh','swarm','debate'].map(id => {
const active = id === s.topology;
return {
id, label: topoMeta[id].label, active,
style: active
? 'background:rgba(255,111,97,.14); border:1px solid rgba(255,111,97,.45); color:#ff8a7a;'
: 'background:#101014; border:1px solid rgba(255,255,255,.08); color:#9a9aa2;',
onPick: () => this.setState({ topology: id }),
};
});
const sel = claws.find(c => c.id === s.selected) || null;
const crumb = on => on
? 'color:#fff; background:rgba(255,111,97,.14); border:1px solid rgba(255,111,97,.3); padding:3px 8px; border-radius:6px;'
: 'color:#6a6a72; padding:3px 5px;';
const railC = on => on ? '#ff6f61' : '#5a5a62';
const railB = on => on ? 'rgba(255,111,97,.1)' : 'transparent';
const isClaw = s.tier==='claw';
return {
isOrg:s.tier==='org', isCompany:s.tier==='company', isTeam:s.tier==='team', isClaw,
showComputer: isClaw,
nodes, linkPaths, topos,
topoLabel: topoMeta[s.topology].label, topoKind: topoMeta[s.topology].kind,
selName: sel?sel.name:'', selGrad: sel?sel.grad:'', selInk: sel?sel.ink:'',
selInitial: sel?sel.initial:'', selRole: sel?sel.role:'',
crumbOrg:crumb(s.tier==='org'), crumbCo:crumb(s.tier==='company'), crumbTeam:crumb(s.tier==='team'), crumbClaw:crumb(isClaw),
railOrgColor:railC(s.tier==='org'), railOrgBg:railB(s.tier==='org'), railOrgOn:s.tier==='org',
railCoColor:railC(s.tier==='company'), railCoBg:railB(s.tier==='company'), railCoOn:s.tier==='company',
railTeamColor:railC(s.tier==='team'), railTeamBg:railB(s.tier==='team'), railTeamOn:s.tier==='team',
railClawColor:railC(isClaw), railClawBg:railB(isClaw), railClawOn:isClaw,
goClawView:()=>this.setState({tier:'claw'}),
goOrg:()=>this.setState({tier:'org'}),
goCompany:()=>this.setState({tier:'company'}),
goTeam:()=>this.setState({tier:'team'}),
enterTeam:()=>this.setState({tier:'team'}),
selectClawTeam:(id)=>this.setState({selected:id, tier:'team'}),
};
}
}
</script>
</body>
</html>