@threadcrumbs/threadnauts 1.0.0 → 1.2.0

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/dist/index.html CHANGED
@@ -6,9 +6,9 @@
6
6
  <meta name="color-scheme" content="dark" />
7
7
  <title>Threadnauts</title>
8
8
  <link rel="icon" href="/favicon.svg?app=threadnauts" type="image/svg+xml" />
9
- <script type="module" crossorigin src="/assets/index-xHGM7fhg.js"></script>
10
- <link rel="modulepreload" crossorigin href="/assets/shared-B_T8JlmU.js">
11
- <link rel="stylesheet" crossorigin href="/assets/index-C-3KPMaV.css">
9
+ <script type="module" crossorigin src="/assets/index-C46d6g6p.js"></script>
10
+ <link rel="modulepreload" crossorigin href="/assets/shared-DiTtF988.js">
11
+ <link rel="stylesheet" crossorigin href="/assets/index-PzTcyxAK.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="app"><div class="boot"><div class="inner">
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "files": [
3
3
  {
4
- "path": "assets/pro-CzWQdIWB.js",
5
- "sha256": "c8efff1a414cc14b05a5dc343b65e33779f69fcecd257a1f34a84653025e7c63",
6
- "bytes": 171280
4
+ "path": "assets/pro-lBnPFibL.js",
5
+ "sha256": "e8e7df01da6e616fb37a60ddc2657b63681cfd34adf8fb37116ecad906845a6e",
6
+ "bytes": 233030
7
7
  }
8
8
  ]
9
9
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@threadcrumbs/threadnauts",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "A 3D colony sim where every coding-agent thread on your machine is a little bot building something.",
6
- "license": "UNLICENSED",
7
- "author": "Jake McKown",
6
+ "license": "SEE LICENSE IN LICENSE.md",
7
+ "author": "Threadcrumbs LLC",
8
8
  "homepage": "https://threadnauts.io",
9
9
  "bugs": {
10
10
  "url": "https://threadnauts.io/#contact",
@@ -49,7 +49,8 @@
49
49
  "icons": "node tools/build-world-icons.mjs",
50
50
  "site": "node tools/build-site.mjs",
51
51
  "test": "node --test \"test/**/*.test.mjs\"",
52
- "prepack": "pnpm run build"
52
+ "prepack": "pnpm run build",
53
+ "auto-publish": "node ../common/tools/release.mjs"
53
54
  },
54
55
  "dependencies": {
55
56
  "@threadcrumbs/common": "^0.1.0"
package/server/api.mjs CHANGED
@@ -81,6 +81,7 @@ const emptyState = () => ({
81
81
  hiddenProjects: [],
82
82
  viewedAt: {},
83
83
  trinkets: {},
84
+ accents: {},
84
85
  districts: 0,
85
86
  settings: null,
86
87
  updatedAt: 0,
@@ -89,9 +90,26 @@ const emptyState = () => ({
89
90
  const asObject = (v) => (v && typeof v === 'object' && !Array.isArray(v) ? v : {})
90
91
  const asArray = (v) => (Array.isArray(v) ? v : [])
91
92
 
93
+ const BUSY_CODES = new Set(['EPERM', 'EBUSY', 'EACCES'])
94
+ const BUSY_WAITS_MS = [50, 150, 400]
95
+ const BUSY_MESSAGE = 'Another program has colony.json open. Threadnauts will try again.'
96
+ const isBusy = (err) => BUSY_CODES.has(err?.code)
97
+
98
+ async function whileBusy(operation) {
99
+ for (const wait of BUSY_WAITS_MS) {
100
+ try {
101
+ return await operation()
102
+ } catch (err) {
103
+ if (!isBusy(err)) throw err
104
+ await new Promise((resolve) => setTimeout(resolve, wait))
105
+ }
106
+ }
107
+ return operation()
108
+ }
109
+
92
110
  async function readState() {
93
111
  try {
94
- const raw = migrate(JSON.parse(await fsp.readFile(STATE_FILE, 'utf8')))
112
+ const raw = migrate(JSON.parse(await whileBusy(() => fsp.readFile(STATE_FILE, 'utf8'))))
95
113
  return {
96
114
  version: STATE_VERSION,
97
115
  archived: asArray(raw.archived),
@@ -103,11 +121,13 @@ async function readState() {
103
121
  hiddenProjects: asArray(raw.hiddenProjects).map(String).filter(Boolean),
104
122
  viewedAt: asObject(raw.viewedAt),
105
123
  trinkets: asObject(raw.trinkets),
124
+ accents: asObject(raw.accents),
106
125
  districts: Number(raw.districts) || 0,
107
126
  settings: raw.settings && typeof raw.settings === 'object' ? raw.settings : null,
108
127
  updatedAt: Number(raw.updatedAt) || 0,
109
128
  }
110
- } catch {
129
+ } catch (err) {
130
+ if (isBusy(err)) throw err
111
131
  return emptyState()
112
132
  }
113
133
  }
@@ -141,6 +161,7 @@ async function writeState(next) {
141
161
  hiddenProjects: asArray(next.hiddenProjects).map(String).filter(Boolean),
142
162
  viewedAt: asObject(next.viewedAt),
143
163
  trinkets: asObject(next.trinkets),
164
+ accents: asObject(next.accents),
144
165
  districts: Number(next.districts) || 0,
145
166
  settings: next.settings && typeof next.settings === 'object' ? next.settings : null,
146
167
  updatedAt: Date.now(),
@@ -151,7 +172,7 @@ async function writeState(next) {
151
172
  // colony.json names the repos you work in and where they are: the owner's business, not
152
173
  // every account on the machine's. A fresh file per write, so the mode always applies.
153
174
  await fsp.writeFile(tmp, JSON.stringify(state, null, 2), { mode: 0o600 })
154
- await fsp.rename(tmp, STATE_FILE)
175
+ await whileBusy(() => fsp.rename(tmp, STATE_FILE))
155
176
  } catch (err) {
156
177
  await fsp.rm(tmp, { force: true }).catch(() => {})
157
178
  throw err
@@ -474,7 +495,7 @@ export async function middleware(req, res, next) {
474
495
  if (url.pathname === '/api/state' && req.method === 'PUT') {
475
496
  const body = await readJsonBody(req)
476
497
  const base = Number(body.baseUpdatedAt) || 0
477
- return serialise(async () => {
498
+ return await serialise(async () => {
478
499
  const current = await readState()
479
500
  if (base && current.updatedAt !== base) return send(res, 409, current)
480
501
  return send(res, 200, await writeState(body))
@@ -532,6 +553,7 @@ export async function middleware(req, res, next) {
532
553
 
533
554
  return send(res, 404, { error: 'Unknown endpoint' })
534
555
  } catch (err) {
556
+ if (isBusy(err)) return send(res, 503, { error: BUSY_MESSAGE })
535
557
  return send(res, 500, { error: String(err && err.message ? err.message : err) })
536
558
  }
537
559
  }
@@ -1 +0,0 @@
1
- .boot{position:fixed;inset:0;display:grid;place-items:center;background:var(--bg, #0a0b0f);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;z-index:50;transition:opacity .5s ease}.boot.gone{opacity:0;pointer-events:none}.boot .inner{text-align:center}.boot h1{margin:0 0 22px;line-height:0}.boot h1 svg{width:min(280px,calc(100vw - 32px));height:auto}.boot p{margin:0;color:var(--dim, #6f6e78);font-size:13px}.boot .bar{width:168px;height:3px;margin:18px auto 0;border-radius:3px;background:#ffffff1a;overflow:hidden}.boot .bar>i{display:block;height:100%;width:40%;border-radius:3px;background:var(--accent, #c96442);will-change:transform;animation:sweep 1.1s ease-in-out -.4s infinite}@keyframes sweep{0%{transform:translate(-110%)}to{transform:translate(320%)}}:root{--bg: #0a0b0f;--panel: rgba(16, 17, 22, .82);--panel-solid: #14151b;--line: rgba(255, 255, 255, .09);--line-strong: rgba(255, 255, 255, .16);--text: #f2f0ec;--muted: #9b9aa3;--dim: #6f6e78;--accent: #c96442;--accent-text: #e3865f;--green: #4f9a63;--blue: #4f7ec9;--amber: #c9a24f;--red: #c94f4f;--teal: #2fd4c4;--working: #e7c869;--working-plate: #332b12;--asking: #8fb4ee;--asking-plate: #1a2b46;--delegating: #7fd2d8;--delegating-plate: #13302f;--done: #89d391;--done-plate: #16301f;--error: #e88b8b;--error-plate: #3d1c1c;--celebrating: #e89bd6;--celebrating-plate: #3a1a33;--idle: #a3a2c8;--idle-plate: #1d1f2e;--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--radius: 14px;--shadow: 0 12px 40px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .4);color-scheme:dark}[data-status=working]{--status: var(--working);--status-plate: var(--working-plate)}[data-status=asking]{--status: var(--asking);--status-plate: var(--asking-plate)}[data-status=delegating]{--status: var(--delegating);--status-plate: var(--delegating-plate)}[data-status=done]{--status: var(--done);--status-plate: var(--done-plate)}[data-status=error]{--status: var(--error);--status-plate: var(--error-plate)}[data-status=celebrating]{--status: var(--celebrating);--status-plate: var(--celebrating-plate)}[data-status=idle]{--status: var(--idle);--status-plate: var(--idle-plate)}@keyframes pulse{50%{opacity:.35}}*{box-sizing:border-box}i.icon{display:inline-grid;place-items:center;flex:none;width:14px;height:14px;font-style:normal}i.icon svg{display:block;width:100%;height:100%}i.icon .bar-off{opacity:.25}.status{display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 9px;border-radius:999px;background:var(--status-plate);color:var(--status);font-size:11px;font-weight:600;white-space:nowrap}.status .pip{width:7px;height:7px;border-radius:50%;background:currentColor;flex:none}.status:is([data-status=working],[data-status=asking],[data-status=delegating]) .pip{animation:pulse 1.6s ease-in-out infinite}.harness-mark{display:inline-grid;place-items:center;flex:none;width:18px;height:18px;border-radius:5px;background:var(--dim);color:#fff;font-size:8.5px;font-style:normal;font-weight:750;letter-spacing:-.02em}.harness-mark[data-harness=claude-code]{background:#c96442}.harness-mark[data-harness=codex]{background:#10a37f}.harness-mark[data-harness=cursor]{background:#e8e6e3;color:#111}.harness-mark[data-harness=antigravity]{background:#4285f4}.harness-mark[data-harness=hermes]{background:#8b5cf6}.harness-mark[data-harness=opencode]{background:#3f3f46;box-shadow:inset 0 0 0 1px var(--line-strong)}.harness-mark[data-harness=kilocode]{background:#f8f675;color:#111}.meta-row{display:flex;flex-wrap:wrap;align-items:center;gap:3px 12px;min-width:0;font-size:11.5px;color:var(--muted)}.meta{display:inline-flex;align-items:center;gap:5px;min-width:0;max-width:100%}.meta i.icon{color:var(--dim)}.meta-model i.icon,.meta-effort i.icon{color:var(--accent-text)}.meta-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}html,body,#app{margin:0;padding:0;height:100%;overflow:hidden;background:var(--bg)}body{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:var(--text);-webkit-font-smoothing:antialiased;user-select:none}.world-canvas{position:absolute;inset:0;width:100%;height:100%;display:block;touch-action:none}#app{position:relative}.hud{position:absolute;inset:0;pointer-events:none;overflow:clip;z-index:10;transition:opacity .22s ease,transform .22s ease;--side: 334px}.hud.hidden>:not(.thread-pop){opacity:0!important;visibility:hidden!important;pointer-events:none!important;transition:opacity .22s ease,visibility 0s linear .22s!important}.hud.hidden>:not(.thread-pop) *{pointer-events:none!important}.hud>:where(:not(.thread-pop)){transition:opacity .22s ease,visibility 0s}.panel{background:var(--panel);backdrop-filter:blur(18px) saturate(1.3);-webkit-backdrop-filter:blur(18px) saturate(1.3);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);pointer-events:auto}.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;height:34px;min-width:34px;padding:0 11px;border-radius:10px;border:1px solid var(--line);background:#ffffff0d;color:var(--text);font:inherit;font-size:13px;cursor:pointer;transition:background .14s ease,border-color .14s ease,transform 90ms ease;pointer-events:auto}.btn:hover{background:#ffffff1c;border-color:var(--line-strong)}.btn:active{transform:scale(.96)}.btn.icon{padding:0;width:34px}.btn.primary{background:var(--accent);border-color:transparent;color:#fff;font-weight:600}.btn.primary:hover{background:#d97553}.btn.ghost{background:transparent}.btn[aria-pressed=true]{background:#c9644238;border-color:#c964428c;color:#ffb193}.btn svg{width:16px;height:16px;flex:none}.rail{position:absolute;left:14px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:4px;padding:6px}.rail .btn{width:40px;height:40px;padding:0;border:none;background:transparent}.rail .btn:hover{background:#ffffff1a}.rail .btn svg{width:19px;height:19px}.rail .sep{height:1px;background:var(--line);margin:4px 6px}.settings{position:absolute;top:14px;right:14px;bottom:14px;width:320px;z-index:2;display:flex;flex-direction:column;overflow:hidden;transition:transform .24s cubic-bezier(.22,1,.36,1),opacity .2s ease}.settings.closed{transform:translate(calc(100% + 20px));opacity:0;pointer-events:none}.settings header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px 10px;font-weight:650;font-size:15px;flex:none}.settings .body{overflow-y:auto;overscroll-behavior:contain;padding:0 16px 16px;flex:1;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent}.settings .body::-webkit-scrollbar{width:8px}.settings .body::-webkit-scrollbar-thumb{background:#ffffff24;border-radius:8px}.group{margin-top:14px}.group>h3{margin:0 0 9px;font-size:11px;font-weight:650;letter-spacing:.08em;text-transform:uppercase;color:var(--dim)}.row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:34px;padding:3px 0;font-size:13.5px}.row .label{display:flex;flex-direction:column;gap:2px;min-width:0}.row .label .hint{font-size:11px;color:var(--dim);line-height:1.3}.row.overridden .label>span:first-child:after{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--accent);margin-left:6px;vertical-align:middle}.toggle{position:relative;width:42px;height:24px;border-radius:999px;border:none;background:#ffffff24;cursor:pointer;flex:none;transition:background .16s ease;pointer-events:auto}.toggle:after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;transition:transform .18s cubic-bezier(.22,1,.36,1);box-shadow:0 1px 3px #0006}.toggle[aria-checked=true]{background:var(--teal)}.toggle[aria-checked=true]:after{transform:translate(18px)}.select{appearance:none;height:30px;padding:0 28px 0 11px;border-radius:9px;border:1px solid var(--line);background:#ffffff0f url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%239b9aa3' stroke-width='1.6'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E") no-repeat right 8px center / 12px;color:var(--text);font:inherit;font-size:13px;cursor:pointer;flex:none;pointer-events:auto}.select:focus-visible{outline:2px solid var(--accent)}.slider{-webkit-appearance:none;appearance:none;width:118px;height:22px;background:transparent;cursor:pointer;flex:none;pointer-events:auto}.slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;background:#ffffff29}.slider::-moz-range-track{height:4px;border-radius:3px;background:#ffffff29}.slider::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;margin-top:-5px;border-radius:50%;background:var(--text);box-shadow:0 1px 4px #00000080}.slider::-moz-range-thumb{width:14px;height:14px;border:none;border-radius:50%;background:var(--text)}.value{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;min-width:34px;text-align:right}.chips{display:flex;gap:5px;flex-wrap:wrap}.chip{flex:1 1 auto;height:30px;padding:0 10px;border-radius:9px;border:1px solid var(--line);background:#ffffff0d;color:var(--muted);font:inherit;font-size:12.5px;cursor:pointer;transition:all .14s ease;pointer-events:auto}.chip:hover{background:#ffffff1a;color:var(--text)}.chip[aria-pressed=true]{background:#2fd4c429;border-color:#2fd4c480;color:#7fe8dd;font-weight:600}.planet-group{margin:12px 0 7px;font-size:11.5px;font-weight:600;color:var(--muted)}.group>h3+.planet-group{margin-top:0}.planets{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.planet{position:relative;display:flex;flex-direction:column;align-items:center;gap:7px;padding:11px 4px 9px;border-radius:12px;border:1px solid var(--line);background:#ffffff0a;color:var(--muted);font:inherit;font-size:12px;cursor:pointer;transition:all .16s ease;pointer-events:auto}.planet:hover{background:#ffffff17}.planet[aria-pressed=true]{border-color:var(--teal);background:#2fd4c41f;color:var(--text);font-weight:600}.planet .world-icon,.planet .world-icon-slot{display:block;width:38px;height:38px;border-radius:50%;box-shadow:0 3px 10px #00000073}.planet .world-icon-slot{background:radial-gradient(circle at 50% 36%,var(--slot-sky),var(--slot-sky) 52%,var(--slot-ground) 53%)}.planet:hover .world-icon{transform:scale(1.06)}.planet .world-icon{transition:transform .16s ease}.planet span{text-align:center;line-height:1.2}.planet .pro-lock{position:absolute;top:6px;right:6px;display:none;place-items:center;width:18px;height:18px;border-radius:50%;background:#0a0b0fc7;color:var(--accent)}.planet .pro-lock svg{width:11px;height:11px}.planet.locked .pro-lock{display:grid}.thread-pop{position:absolute;top:0;left:0;width:320px;padding:10px 14px 12px;display:none;flex-direction:column;gap:8px;will-change:transform;--nib-y: 50%}.thread-pop.on{display:flex}.thread-pop .nib{position:absolute;top:var(--nib-y);left:-6px;width:11px;height:11px;margin-top:-6px;background:var(--panel);border-left:1px solid var(--line);border-bottom:1px solid var(--line);transform:rotate(45deg);border-radius:0 0 0 3px}.thread-pop.flip .nib{left:auto;right:-6px;transform:rotate(-135deg)}.thread-pop .top{display:flex;align-items:center;gap:12px}.thread-pop .portrait{position:relative;flex:none}.thread-pop .avatar{width:46px;height:46px;border-radius:12px;display:grid;place-items:center;background:#06070c;border:1px solid var(--line);overflow:hidden}.thread-pop .avatar canvas{width:100%;height:100%;image-rendering:auto}.thread-pop .info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.thread-pop .card-head{display:flex;align-items:center;gap:10px}.thread-pop .card-status{flex:1;min-width:0;display:flex}.thread-pop .card-status .status{height:24px;padding:0 10px;gap:8px;font-size:13px;min-width:0;overflow:hidden;text-overflow:ellipsis}.thread-pop .ctx-mini{flex:none;display:inline-flex;align-items:center;gap:8px;height:28px;margin:-2px 0;padding:0 6px;border:1px solid transparent;border-radius:8px;background:transparent;color:var(--muted);font:inherit;font-size:13px;font-variant-numeric:tabular-nums;cursor:pointer;transition:background .14s ease,border-color .14s ease}.thread-pop .ctx-mini[hidden]{display:none}.thread-pop .ctx-mini:hover{background:#ffffff12;border-color:var(--line);color:var(--text)}.gauge-mini{--dial: #101727;--dial-track: #2f4466;--needle: #eef8ff;--needle-glow: rgba(127, 207, 255, .55);--hub: #e8ecf2;flex:none;width:22px;height:22px;overflow:visible}.gauge-dial{fill:var(--dial);stroke:var(--line-strong);stroke-width:2}.gauge-track,.gauge-fill{fill:none;stroke-width:10;stroke-linecap:round}.gauge-track{stroke:var(--dial-track)}.gauge-fill{stroke:var(--accent);transition:stroke-dasharray .4s ease}.gauge[data-level=full] .gauge-fill{stroke:var(--error)}.gauge[data-level=unknown] .gauge-fill{stroke:none}.gauge-needle{stroke:var(--needle);stroke-width:6;stroke-linecap:round;filter:drop-shadow(0 0 1px var(--needle-glow));transition:transform .7s cubic-bezier(.34,1.4,.64,1)}.gauge[data-level=unknown] .gauge-needle{opacity:.35}.gauge-hub{fill:var(--hub)}.thread-pop .title{display:flex;align-items:center;gap:8px;max-width:100%;font-size:16px;font-weight:600;line-height:1.3}.thread-pop .title-harness{display:flex;flex:none}.thread-pop .title-harness:empty{display:none}.thread-pop .title-harness .harness-mark{width:22px;height:22px;border-radius:6px;font-size:10px}.thread-pop .title-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.thread-pop .meta-row{gap:4px 12px;font-size:13px}.thread-pop .meta-row:empty{display:none}.thread-pop .now{font-family:var(--mono);font-size:13px;color:var(--status);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.thread-pop .now:empty{display:none}.thread-pop #btn-deselect{flex:none;margin:-2px -6px -2px 0;width:26px;min-width:26px;height:26px}.thread-pop #btn-deselect svg{width:14px;height:14px}.thread-pop .actions{display:flex;gap:6px}.thread-pop .actions .btn{height:32px}.thread-pop #btn-open{flex:1;min-width:0;white-space:nowrap}.thread-pop .actions .btn.icon{width:32px;min-width:32px}.side{position:absolute;top:14px;right:14px;bottom:14px;width:320px;display:flex;flex-direction:column;overflow:hidden;transition:transform .24s cubic-bezier(.22,1,.36,1),opacity .22s ease}.side.covered{visibility:hidden;pointer-events:none}.side .brand{display:block;flex:none;margin:16px 15px 14px;border-radius:10px;text-decoration:none}.side .brand svg{display:block;width:100%;height:auto}.side .brand:focus-visible{outline:2px solid var(--accent);outline-offset:6px}.side .toolbar{display:flex;align-items:center;justify-content:flex-start;gap:4px;padding:8px 15px;flex:none;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.side .toolbar .btn{width:30px;min-width:30px;height:30px}.side .toolbar .btn svg{width:15px;height:15px}.stats{display:flex;flex-wrap:wrap;gap:5px;padding:11px 15px;flex:none;border-bottom:1px solid var(--line)}.stat{display:inline-flex;align-items:center;gap:6px;height:27px;padding:0 9px;border-radius:999px;background:#ffffff0d;border:1px solid var(--line);color:inherit;font:inherit;font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap;cursor:pointer;transition:background .14s ease,border-color .14s ease;pointer-events:auto}.stat:hover{background:#ffffff1a;border-color:var(--line-strong)}.stat[data-empty=true]{opacity:.4}.stat .pip{width:7px;height:7px;border-radius:50%;background:currentColor;flex:none}.stat .n{font-weight:650}.stat .lbl{color:var(--muted)}.stat.working{color:var(--working)}.stat.asking{color:var(--asking)}.stat.delegating{color:var(--delegating)}.stat.done{color:var(--done)}.stat.error{color:var(--error)}.stat.celebrating{color:var(--celebrating)}.stat.quiet{color:var(--idle)}.stat.idle{color:#b6b5be}.side-body,.side .projects-pane,.side .project-detail{flex:1;min-height:0;display:flex;flex-direction:column}.side .project-detail,.side.drilled .projects-pane{display:none}.side.drilled .project-detail{display:flex}.side .sec-head{display:flex;align-items:center;gap:8px;padding:11px 15px 7px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);flex:none}.sec-count,.side .repo .count{padding:1px 8px;border-radius:999px;background:#ffffff12;color:var(--muted);font-size:11px;font-weight:600;letter-spacing:0;text-transform:none;font-variant-numeric:tabular-nums}.side .projects{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:0 9px 12px;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent}.stats #btn-threadgauge{flex-basis:100%;height:30px;margin-top:4px;padding:0 10px;gap:8px;font-size:12.5px;text-decoration:none}.stats #btn-threadgauge[hidden]{display:none}.stats #btn-threadgauge .gauge-mini{width:18px;height:18px}.stats #btn-threadgauge .gauge-dial{fill:none}.side .repo.off-map{padding-block:5px;cursor:default}.side div.repo.off-map:hover{background:transparent}.side .repo.off-map .n,.side .repo.off-map .count,.side .repo.off-map i.repo-icon,.side .org-row.off-map .n,.side .org-row.off-map i.org-icon{color:var(--dim)}.thread-pop #btn-viewed[hidden]{display:none}.side .show-repo{height:28px;padding:0 10px;font-size:12px;flex:none}.side .repo{display:flex;align-items:center;gap:9px;padding:9px 10px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--text);font:inherit;font-size:13px;text-align:left;cursor:pointer;transition:background .14s ease,border-color .14s ease;pointer-events:auto}.side .repo:hover{background:#ffffff12}.side .repo[aria-pressed=true]{background:#ffffff17;border-color:var(--line-strong)}.side .repo .n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side i.repo-icon,.side i.org-icon{width:16px;height:16px}.side i.org-icon{color:#c9c7d1}.side .org-row{display:flex;align-items:center;gap:9px;padding:9px 10px 5px;font-size:13px;font-weight:650;color:var(--text);pointer-events:auto}.side .org-row .n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side .org-row .count{padding:1px 8px;border-radius:999px;background:#ffffff12;color:var(--muted);font-size:11px;font-weight:600;font-variant-numeric:tabular-nums}.side *+.org-row{margin-top:6px}.side .org-repos{display:flex;flex-direction:column;gap:2px;margin-left:17px;padding-left:6px;border-left:1px solid var(--line-strong)}.side .who i.repo-icon{width:20px;height:20px}.side .alarm{width:6px;height:6px;border-radius:50%;background:var(--blue);flex:none;animation:pulse 1.4s ease-in-out infinite}.side .back{align-self:flex-start;margin:9px 9px 2px;height:28px;padding:0 9px 0 5px;font-size:12px;color:var(--muted);border-color:transparent;flex:none}.side .back svg{width:15px;height:15px}.side .who{display:flex;align-items:center;gap:9px;padding:2px 10px 10px 15px;flex:none}.side .who .text{flex:1;min-width:0}.side .name{font-weight:650;font-size:15px;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side .path{font-size:11px;color:var(--dim);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side .project-actions{display:flex;flex-direction:column;gap:6px;padding:0 15px 13px;flex:none}.side .project-actions .btn{height:36px}.side .pair{display:flex;gap:6px}.side .pair .btn{flex:1;min-width:0}.side .btn:disabled{opacity:.4;cursor:default;pointer-events:none}.side .threads-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:11px 15px 8px;border-top:1px solid var(--line);font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);flex:none}.side .threads-head .wants{color:var(--dim);text-transform:none;letter-spacing:0;font-size:11.5px}.side .threads-head .want.asking{color:var(--asking)}.side .threads-head .want.done{color:var(--done)}.side .threads-head .want.error{color:var(--error)}.side .threads{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:0 9px 12px;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent}.side .projects::-webkit-scrollbar,.side .threads::-webkit-scrollbar{width:8px}.side .projects::-webkit-scrollbar-thumb,.side .threads::-webkit-scrollbar-thumb{background:#ffffff24;border-radius:8px}.side .thread{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:4px 8px;padding:8px 9px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--text);font:inherit;text-align:left;cursor:pointer;transition:background .14s ease,border-color .14s ease;pointer-events:auto}.side .thread:hover{background:#ffffff12}.side .thread[aria-pressed=true]{background:#ffffff17;border-color:var(--line-strong)}.side .thread .pip{width:8px;height:8px;border-radius:50%;background:currentColor;flex:none}.side .thread .t{font-size:12.5px;line-height:1.3;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side .thread .when{font-size:11px;color:var(--dim);white-space:nowrap}.side .thread .wt{grid-column:2 / -1;display:flex;align-items:center;gap:5px;min-width:0;font-size:10.5px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.side .thread .wt i.icon{width:12px;height:12px}.side .thread.working{color:var(--working)}.side .thread.asking{color:var(--asking)}.side .thread.delegating{color:var(--delegating)}.side .thread.done{color:var(--done)}.side .thread.error{color:var(--error)}.side .thread.celebrating{color:var(--celebrating)}.side .thread.idle{color:#7c7b86}.toasts{position:absolute;bottom:14px;right:calc(14px + var(--side));display:flex;flex-direction:column;align-items:flex-end;gap:7px}.toast{padding:9px 13px;border-radius:10px;font-size:12.5px;max-width:320px;animation:toast-in .26s cubic-bezier(.22,1,.36,1)}.toast.err{border-color:#c94f4f80;color:#ffb4b4}.toast.with-action{display:flex;align-items:center;gap:12px;padding-block:6px}.toast .toast-action{height:28px;padding:0 11px;font-size:12px;flex:none;color:var(--accent-text)}.toast.leaving{animation:toast-out .22s ease forwards}@keyframes toast-in{0%{opacity:0;transform:translateY(10px)}}@keyframes toast-out{to{opacity:0;transform:translate(16px)}}.fps{position:absolute;left:14px;bottom:14px;padding:7px 11px;font-size:11.5px;font-variant-numeric:tabular-nums;color:var(--muted);line-height:1.55;display:none}.fps.on{display:block}.fps b{color:var(--text);font-weight:600}.help{z-index:4;position:absolute;inset:0;display:none;place-items:center;padding:calc(20px + var(--safe-t, 0px)) 20px calc(20px + var(--safe-b, 0px));background:#06070bb8;backdrop-filter:blur(6px);pointer-events:auto}.help.open{display:grid}#btn-record.recording{color:#ff6b6b}.rec-chip{position:absolute;top:14px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:6px 12px;border:1px solid var(--line);border-radius:999px;background:#0a0b0fc7;color:var(--text);font-size:12px;font-variant-numeric:tabular-nums;pointer-events:none}.rec-chip[hidden]{display:none}.rec-chip i{width:8px;height:8px;border-radius:50%;background:#ff5a5a;animation:rec-pulse 1.2s ease-in-out infinite}@keyframes rec-pulse{50%{opacity:.35}}.upgrade{z-index:5;position:absolute;inset:0;display:none;place-items:center;background:#06070bb8;backdrop-filter:blur(6px);pointer-events:auto}.upgrade.open{display:grid}.upgrade .sheet{width:min(360px,calc(100vw - 40px));padding:24px 24px 20px;display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center}.upgrade .world-icon{display:block;width:84px;height:84px;border-radius:50%;box-shadow:0 6px 18px #00000080}.upgrade h3{margin:6px 0 0;font-size:17px}.upgrade p.sub{margin:0 0 8px;color:var(--muted);font-size:13px;line-height:1.5}.upgrade-actions{display:flex;gap:8px;align-self:stretch}.upgrade-actions .btn{flex:1;text-decoration:none}.upgrade-key{align-self:stretch;margin-top:8px;padding-top:14px;border-top:1px solid var(--line);text-align:left}.upgrade-key[hidden]{display:none}.upgrade-key-label{margin:0 0 8px;color:var(--muted);font-size:12.5px}.license-status{margin:0 0 9px;color:var(--muted);font-size:13px;line-height:1.45}.license-form{display:flex;gap:8px}.license-form[hidden]{display:none}.license-key{flex:1;min-width:0;height:34px;padding:0 10px;border-radius:10px;border:1px solid var(--line);background:#00000047;color:var(--text);font:12.5px ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;user-select:text}.license-key::placeholder{color:var(--dim)}.license-key:focus{outline:none;border-color:#c96442b3}.license-form .btn:disabled{opacity:.6;cursor:default}.license-message{margin:7px 0 0;color:var(--muted);font-size:12px;line-height:1.4}.license-message:empty{display:none}.license-message.err{color:var(--error)}.license-status a{color:#ffb193}.license-message a{color:inherit;text-decoration:underline}.license-get{display:inline-block;margin-top:9px;color:#ffb193;font-size:12.5px}.license-get[hidden]{display:none}.help .sheet{display:flex;flex-direction:column;width:min(920px,100%);max-height:calc(100vh - 40px - var(--safe-t, 0px) - var(--safe-b, 0px));max-height:calc(100dvh - 40px - var(--safe-t, 0px) - var(--safe-b, 0px));overflow:hidden}.help-body{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:18px 24px 8px}.help-foot{flex:none;display:flex;justify-content:flex-end;padding:10px 24px 12px;border-top:1px solid var(--line)}.help h2{margin:0 0 10px;line-height:0}.help h2 svg{width:223px;height:auto}.help p.sub{margin:0 0 14px;color:var(--muted);font-size:13px;line-height:1.5}.help-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px 28px}.help h3{margin:0 0 4px;color:var(--dim);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}.help .k+h3{margin-top:14px}.help .legend-row{break-inside:avoid}@media(max-width:900px){.help-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.help-grid .legend{grid-column:1 / -1;columns:2;column-gap:28px}.help-grid .legend h3{column-span:all}}.help .k{display:flex;justify-content:space-between;gap:14px;align-items:baseline;padding:4px 0;font-size:13px;border-bottom:1px solid rgba(255,255,255,.05)}.help .k span{color:var(--muted)}kbd{display:inline-block;min-width:20px;padding:2px 6px;border-radius:5px;border:1px solid var(--line-strong);background:#ffffff12;font:inherit;font-size:11px;font-weight:600;text-align:center;white-space:nowrap}.help .legend-row{display:flex;align-items:center;gap:9px;padding:4px 0;font-size:13px;color:var(--muted)}.help .legend-row .badge{width:20px;height:20px;border-radius:6px;display:grid;place-items:center;font-size:11px;font-weight:700;flex:none}.help .legend-row .badge svg{width:14px;height:14px;fill:currentColor}.hint-pill{position:absolute;top:78px;left:50%;transform:translate(-50%);padding:8px 14px;font-size:12.5px;color:var(--muted);opacity:0;transition:opacity .3s ease}.hint-pill.on{opacity:1}.world-loading{position:absolute;inset:0;z-index:30;display:grid;grid-template-columns:minmax(0,364px);place-content:center;place-items:center;padding:16px;background:#08090d29;-webkit-backdrop-filter:blur(7px) saturate(1.08);backdrop-filter:blur(7px) saturate(1.08);opacity:0;pointer-events:none;transition:opacity .32s ease}.world-loading[hidden]{display:none}.world-loading.on{opacity:1;pointer-events:auto;transition:opacity .18s ease-out .15s}.world-loading-still{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none;opacity:0;transition:opacity .34s ease}.world-loading-still.on{opacity:1;transition:none}.world-loading-still[hidden]{display:none}.world-loading-card{position:relative;width:100%;padding:20px 22px 16px;border:1px solid var(--line-strong);border-radius:24px;background:radial-gradient(ellipse 80% 46% at 50% 30%,var(--loading-glow, transparent),transparent 72%),#101116bd;box-shadow:var(--shadow);text-align:center;transform:translateY(6px) scale(.98);transition:transform .32s cubic-bezier(.22,1,.36,1)}.world-loading.on .world-loading-card{transform:none;transition-delay:.15s}.world-loading-kicker{margin:0;font-size:11px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}.world-loading-name{margin:4px 0 0;font-size:22px;font-weight:650;letter-spacing:-.01em;color:var(--text)}.world-loading-stage{max-width:280px;min-height:1.4em;margin:8px auto 0;font-size:13px;line-height:1.4;color:var(--muted);text-wrap:balance}.world-loading-bar{position:relative;width:220px;max-width:100%;height:4px;margin:12px auto 0;border-radius:4px;background:#ffffff1a;overflow:hidden}.world-loading-bar>i{display:block;height:100%;background:var(--accent);transform:scaleX(0);transform-origin:left center;transition:transform .42s cubic-bezier(.22,1,.36,1)}.world-loading-bar:after{content:"";position:absolute;top:0;bottom:0;left:0;width:36%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.28),transparent);animation:loading-sheen 1.6s ease-in-out infinite}.world-loading-tally{min-height:1.5em;margin:10px 0 0;font-size:11.5px;line-height:1.5;color:var(--dim);font-variant-numeric:tabular-nums}.loader-bot{position:relative;width:128px;height:140px;margin:0 auto 10px}.loader-bot span{position:absolute;display:block}.loader-bot svg{display:block;width:100%;height:100%}.loader-bot-shadow{left:30px;right:30px;bottom:4px;height:10px;border-radius:50%;background:radial-gradient(closest-side,rgba(0,0,0,.55),transparent);animation:loader-shadow 16.5s ease-in-out infinite}.loader-bot-head{left:0;top:12px;width:128px;height:116px;transform-origin:50% 94%;animation:loader-head 16.5s ease-in-out infinite}.loader-bot-hull{position:absolute;inset:0}.loader-bot-light-dim{inset:0;animation:loader-light 16.5s ease-in-out infinite}.loader-bot-light{left:43.81%;top:24.97%;width:12.37%;height:6.16%;border-radius:3px;background:radial-gradient(circle at 38% 35%,#ffd9c4,var(--accent) 62%);box-shadow:0 0 12px 3px #c96442bf;animation:loader-pulse 2.4s ease-in-out infinite}.loader-bot-screen{left:28.22%;top:38.09%;width:43.56%;height:49.23%;border-radius:38%;overflow:hidden}.loader-bot-screen:after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,rgba(4,8,26,.2) 0 1px,transparent 1px 2px);pointer-events:none}.loader-bot-eyes{inset:0;animation:loader-blink 16.5s ease-in-out infinite}.loader-face{inset:0;opacity:0;fill:var(--bot-eye);filter:drop-shadow(0 0 2.4px var(--bot-eye-glow)) drop-shadow(0 0 5px var(--bot-eye-glow));animation:loader-face 16.5s step-end infinite;animation-delay:calc((var(--beat) - 11) * 1.5s)}.loader-bot-glass{inset:0}@keyframes loading-sheen{0%{transform:translate(-110%)}to{transform:translate(300%)}}@keyframes loader-face{0%{opacity:1}9.0909%,to{opacity:0}}@keyframes loader-head{0%,9.091%,28.485%,32.121%,35.152%,45.455%,55.152%,58.182%,61.515%,72.727%,84.848%,87.273%,90.909%,93.939%,96.97%,to{transform:translate(0) rotate(0) scale(1)}4.545%{transform:translateY(-3px) rotate(0) scale(1)}12.121%,16.97%{transform:translate(-6px) rotate(-9deg) scale(1)}20%,25.455%{transform:translate(6px) rotate(9deg) scale(1)}30.303%{transform:translateY(-10px) rotate(0) scale(1.04)}33.636%{transform:translateY(-4px) rotate(0) scale(1)}37.576%,43.03%{transform:translate(-2px) rotate(-11deg) scale(1)}48.182%{transform:translateY(-3px) rotate(7deg) scale(1)}53.333%{transform:translateY(-3px) rotate(5deg) scale(1)}56.667%,59.697%{transform:translate(0) rotate(0) scale(1.09)}65.455%,70.303%{transform:translate(0) rotate(-6deg) scale(1)}67.879%{transform:translate(0) rotate(6deg) scale(1)}78.182%{transform:translateY(6px) rotate(6deg) scale(1)}81.818%{transform:translateY(7px) rotate(7deg) scale(1)}83.03%{transform:translateY(-14px) rotate(0) scale(1.05)}86.061%{transform:translateY(-3px) rotate(0) scale(1)}92.424%{transform:translateY(-12px) rotate(-4deg) scale(1)}95.455%{transform:translateY(-12px) rotate(4deg) scale(1)}}@keyframes loader-shadow{0%,9.091%,28.485%,32.121%,35.152%,45.455%,55.152%,72.727%,84.848%,87.273%,90.909%,93.939%,96.97%,to{transform:translate(0) scale(1);opacity:1}4.545%,48.182%,53.333%{transform:translate(0) scale(.92);opacity:1}12.121%,16.97%{transform:translate(-6px) scale(1);opacity:1}20%,25.455%{transform:translate(6px) scale(1);opacity:1}30.303%{transform:translate(0) scale(.7);opacity:.6}33.636%,86.061%{transform:translate(0) scale(.88);opacity:.9}78.182%,81.818%{transform:translate(0) scale(1.1);opacity:1}83.03%{transform:translate(0) scale(.6);opacity:.55}92.424%,95.455%{transform:translate(0) scale(.65);opacity:.6}}@keyframes loader-blink{0%,5%,6.2%,22.4%,23.6%,to{transform:scaleY(1)}5.6%,23%{transform:scaleY(.1)}}@keyframes loader-light{0%,72.727%,83.03%,to{opacity:1}78.182%,81.818%{opacity:.2}}@keyframes loader-pulse{0%,to{opacity:.6}50%{opacity:1}}@media(max-width:400px){.world-loading-card{padding:16px 12px 14px}}@media(max-width:350px){.loader-bot{zoom:.85}}@media(prefers-reduced-motion:reduce){.world-loading *,.world-loading *:before,.world-loading *:after{animation:none!important}.loader-face:first-child{opacity:1}}@media(max-width:820px){.settings,.side{width:min(320px,calc(100vw - 28px))}.hud{--side: 0px}.rail{top:10px;left:10px;transform:none;flex-direction:row;gap:2px;padding:4px}.rail .btn{width:38px;height:38px}.rail .sep{width:1px;height:auto;margin:6px 3px}.stats{gap:5px}.stat .lbl{display:none}.legend{max-width:calc(100vw - 28px)}.hint-pill{top:60px}}@media(max-width:600px){.hud{--edge: 10px;--safe-b: env(safe-area-inset-bottom, 0px);--safe-t: env(safe-area-inset-top, 0px);--peek: 118px}.side{top:auto;left:var(--edge);right:var(--edge);bottom:calc(var(--edge) + var(--safe-b));width:auto;height:min(64vh,560px);max-height:calc(100% - 70px - var(--safe-t));transform:translateY(calc(100% - var(--peek)));border-radius:18px}.side.open{transform:translateY(0)}.side .grab{display:block}.side .brand{display:none}.side .toolbar{padding:4px 8px 8px 15px;border-top:0;cursor:pointer}.side .toolbar .btn{width:36px;min-width:36px;height:36px}.stats{padding:10px 15px}.side .repo,.side .thread{min-height:42px}.side .project-detail .back{min-height:40px}.settings{top:calc(var(--edge) + var(--safe-t));left:var(--edge);right:var(--edge);bottom:calc(var(--edge) + var(--safe-b));width:auto;border-radius:18px}.settings.closed{transform:translateY(calc(100% + 40px))}.settings header{padding-top:16px}.settings .body .btn,.settings .body select{min-height:38px}.rail{top:calc(var(--edge) + var(--safe-t))}.thread-pop.on{left:var(--edge);right:var(--edge);bottom:calc(var(--edge) + var(--safe-b) + var(--peek) + 10px);top:auto;width:auto;transform:none!important;will-change:auto}.thread-pop .nib{display:none}.toasts{left:var(--edge);right:var(--edge);bottom:calc(var(--edge) + var(--safe-b) + var(--peek) + 10px);align-items:center}.toast{max-width:100%}.fps{left:auto;right:var(--edge);top:calc(var(--edge) + var(--safe-t));bottom:auto}.hint-pill{top:calc(60px + var(--safe-t));max-width:calc(100vw - 40px);text-align:center}.help{padding:calc(10px + var(--safe-t)) 10px calc(10px + var(--safe-b))}.help .sheet{max-height:calc(100vh - 20px - var(--safe-t) - var(--safe-b));max-height:calc(100dvh - 20px - var(--safe-t) - var(--safe-b))}.help-body{padding:18px 16px 8px}.help-foot{padding:10px 16px 14px}.help-grid{grid-template-columns:minmax(0,1fr)}.help-grid .legend{columns:auto}}.side .grab{display:none;width:38px;height:4px;margin:8px auto 0;border-radius:2px;background:#ffffff38}@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}.world-canvas{cursor:grab}.state-sheet{position:absolute;top:14px;left:14px;z-index:30;padding:10px 12px;border-radius:var(--radius);background:#0e0f14e0;box-shadow:var(--shadow);font-size:12px;color:var(--text)}.state-sheet-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:6px}.state-sheet table{border-collapse:collapse;font-variant-numeric:tabular-nums}.state-sheet th,.state-sheet td{padding:2px 8px 2px 0;text-align:left;font-weight:500}.state-sheet th{color:var(--dim)}.state-sheet td i{display:inline-block;width:9px;height:9px;margin-right:6px;border-radius:50%}.state-sheet tr.off td{color:var(--error);font-weight:650}.state-sheet-labels{position:absolute;inset:0;overflow:hidden;pointer-events:none}.state-sheet-label{position:absolute;top:0;left:0;padding:1px 6px;border-radius:6px;background:#0a0b0fcc;font-size:11px;pointer-events:none}.state-sheet-label.working{color:var(--working)}.state-sheet-label.delegating{color:var(--delegating)}.state-sheet-label.asking{color:var(--asking)}.state-sheet-label.done{color:var(--done)}.state-sheet-label.error{color:var(--error)}.state-sheet-label.celebrating{color:var(--celebrating)}.state-sheet-label.idle{color:var(--idle)}