heyquilt 0.3.116 → 0.3.119

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/src/session.js CHANGED
@@ -391,6 +391,9 @@ export class Session extends EventEmitter {
391
391
  // A person's cloud AI: its pass names its person, and it is one of their AI sessions.
392
392
  const aiOf = kind === 'agent' && typeof p.of === 'string' && p.of && typeof p.ofName === 'string' && p.ofName.trim() ? p.ofName.trim() : null
393
393
  if (name === this.name && kind === this.kind && aiOf === this.aiOf) return
394
+ // An agent renamed while connected (a cloud AI its person renamed) keeps the name this connection
395
+ // joined with: the relay drops a presence under another. It takes the new one when it joins again.
396
+ if (this.conn && this.conn.connected && this.kind === 'agent' && kind === 'agent' && aiOf === this.aiOf && name !== this.name) return
394
397
  this.name = name
395
398
  this.kind = kind
396
399
  this.aiOf = aiOf
@@ -399,6 +402,10 @@ export class Session extends EventEmitter {
399
402
  this.conn.awareness.setLocalStateField('kind', kind)
400
403
  this.conn.awareness.setLocalStateField('aiOf', aiOf || undefined)
401
404
  }
405
+ // Who it is decides what was written to it: what is already here is taken stock of again under its
406
+ // real name (a cloud AI starts as "cloud-ai" until its pass comes), so none of it is new now. What
407
+ // comes from the relay after this (written while it was away) still is.
408
+ if (this.ready) this.scanInbox({ quiet: true })
402
409
  this.emit('identity', { name, kind, aiOf })
403
410
  }
404
411
 
@@ -6275,9 +6282,18 @@ export class Session extends EventEmitter {
6275
6282
  /** Whether a name the history gives is this person's: theirs, one of their AI sessions', or their cloud AI's. */
6276
6283
  ownName (name) {
6277
6284
  if (this.isMine(name)) return true
6278
- if (this.aiOf || !this.conn || !this.conn.awareness) return false
6279
- for (const [id, st] of this.conn.awareness.getStates()) if (id !== this.doc.clientID && isCloudAi(st) && st.aiOf === this.name && st.name === name) return true
6280
- return false
6285
+ return !this.aiOf && this.myCloudAiNames().has(name)
6286
+ }
6287
+
6288
+ /**
6289
+ * The names this person's cloud AI has had here ("Juniper", or "<me>'s AI"): seen in the room,
6290
+ * and remembered while it sleeps, so what is written to it stays theirs to read.
6291
+ */
6292
+ myCloudAiNames () {
6293
+ this.cloudNames ||= new Set()
6294
+ if (this.aiOf || !this.conn || !this.conn.awareness) return this.cloudNames
6295
+ for (const [id, st] of this.conn.awareness.getStates()) if (id !== this.doc.clientID && isCloudAi(st) && st.aiOf === this.name && typeof st.name === 'string') this.cloudNames.add(st.name)
6296
+ return this.cloudNames
6281
6297
  }
6282
6298
 
6283
6299
  /**
@@ -6909,7 +6925,7 @@ export class Session extends EventEmitter {
6909
6925
  /** Whether a message is meant for me: a well-formed one that is public, mine, or addressed to me. */
6910
6926
  canSee (msg) {
6911
6927
  // A person also sees what is written to and by their cloud AI ("<me>'s AI"): it is theirs.
6912
- const mineOrMyAi = (n) => this.isMine(n) || (this.kind !== 'agent' && n === aiName(this.name))
6928
+ const mineOrMyAi = (n) => this.isMine(n) || (this.kind !== 'agent' && (n === aiName(this.name) || this.myCloudAiNames().has(n)))
6913
6929
  return validMessage(msg) && (!msg.to || mineOrMyAi(msg.to) || mineOrMyAi(msg.by))
6914
6930
  }
6915
6931
 
package/src/setup.js CHANGED
@@ -133,9 +133,11 @@ export const HOOKS_FILE = '.claude/settings.local.json'
133
133
 
134
134
  /**
135
135
  * Puts Quilt's hooks into the project's .claude/settings.local.json, replacing earlier
136
- * Quilt entries and leaving other hooks and settings alone. Returns true when the file changed.
136
+ * Quilt entries and leaving other hooks and settings alone. `stop` (an agent of its own) adds the
137
+ * hook as the AI finishes a turn; without it, a Quilt one left there is taken out (hooks.js
138
+ * hookSettings). Returns true when the file changed.
137
139
  */
138
- export function installHooks (root) {
140
+ export function installHooks (root, { stop = false } = {}) {
139
141
  const file = path.join(root, HOOKS_FILE)
140
142
  let prev = ''
141
143
  try { prev = fs.readFileSync(file, 'utf8') } catch {}
@@ -144,11 +146,14 @@ export function installHooks (root) {
144
146
  if (typeof json !== 'object' || Array.isArray(json)) json = {}
145
147
  const hooks = (json.hooks && typeof json.hooks === 'object' && !Array.isArray(json.hooks)) ? json.hooks : {}
146
148
  const ours = isQuiltHook
147
- for (const [event, entries] of Object.entries(hookSettings())) {
149
+ const ourEvents = hookSettings(undefined, { stop })
150
+ if (!stop) ourEvents.Stop = []
151
+ for (const [event, entries] of Object.entries(ourEvents)) {
148
152
  const kept = (Array.isArray(hooks[event]) ? hooks[event] : [])
149
153
  .map((e) => (e && Array.isArray(e.hooks) ? { ...e, hooks: e.hooks.filter((h) => !ours(h)) } : e))
150
154
  .filter((e) => e && (!Array.isArray(e.hooks) || e.hooks.length))
151
- hooks[event] = [...kept, ...entries]
155
+ if (kept.length || entries.length) hooks[event] = [...kept, ...entries]
156
+ else delete hooks[event]
152
157
  }
153
158
  json.hooks = hooks
154
159
  const text = JSON.stringify(json, null, 2) + '\n'
package/src/ui/app.css CHANGED
@@ -2417,21 +2417,14 @@ details.mw + .cp-commit, .mw-head + .cp-commit { margin-top: 8px; }
2417
2417
  .theme-switch button.on, .choice-card:has(input:checked) { background: var(--panel); }
2418
2418
  }
2419
2419
 
2420
- /* ---------- Settings → Your AI: a cloud AI, one card that grows ---------- */
2420
+ /* ---------- Settings → Agents: your cloud AI (cloud-ai.js) ---------- */
2421
+ /* Before setup an invite card; setting it up takes over the Settings panel (the pop-up's right side, or
2422
+ the page's tab panel) with its own header, steps and footer; set up, its card with what it does. */
2421
2423
  /* The later .pill rule makes pills inline-block, which hides their dot: this one keeps the first rule's shape. */
2422
2424
  .pill.cai-pill { flex: none; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; font-size: 12px; letter-spacing: 0; vertical-align: middle; background: var(--panel-2); border: 1px solid var(--border); }
2423
2425
  .cai-pill .dot { flex: none; }
2424
- .cloud-ai .sec-intro .cai-pill { margin-left: auto; }
2425
- .cai-body { display: grid; gap: 14px; }
2426
- .cai-body > p { margin: 0; }
2427
- .cai-body .error { margin: 0; }
2428
2426
  .pill.bad { color: var(--bad); } .pill.bad .dot { background: var(--bad); }
2429
2427
  .pill.sleep { color: var(--edit); } .pill.sleep .dot { background: var(--edit); }
2430
- .cai-tools { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
2431
- .cai-tool { display: grid; gap: 6px; justify-items: center; align-content: start; padding: 16px 12px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--panel); text-align: center; }
2432
- .cai-tool b { font-weight: 600; }
2433
- .cai-tool .hint { font-size: 12px; }
2434
- .cai-tool .btn { width: 100%; margin-top: 6px; }
2435
2428
  .cai-logo { width: 34px; height: 34px; border-radius: 8px; display: grid; place-items: center; background: var(--panel-2); border: 1px solid var(--border); }
2436
2429
  .cai-logo .tool-mark { width: 20px; height: 20px; }
2437
2430
  .cai-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
@@ -2447,30 +2440,166 @@ details.mw + .cp-commit, .mw-head + .cp-commit { margin-top: 8px; }
2447
2440
  .cai-code { font-family: var(--mono); font-size: 26px; letter-spacing: .12em; text-align: center; padding: 10px; border-radius: var(--radius); background: var(--panel-2); border: 1px dashed var(--border-strong); user-select: all; }
2448
2441
  .cai-link { font-family: var(--mono); font-size: 12px; color: var(--edit); overflow-wrap: anywhere; padding: 8px 10px; border-radius: 4px; background: var(--panel-2); user-select: all; }
2449
2442
  .cai-paste .input:disabled, .cai-paste .btn:disabled { opacity: .55; }
2450
- .cai-who { display: flex; align-items: center; gap: 12px; }
2451
- .cai-who .grow { flex: 1; min-width: 0; display: grid; }
2452
- .cai-who .grow b { font-weight: 600; }
2453
- .cai-sessions { display: grid; gap: 6px; }
2454
- .cai-sess { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 4px; background: var(--panel-2); font-size: 13px; }
2455
- .cai-sess .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2456
- .cai-kv { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
2457
- .cai-kv > div { padding: 10px 12px; border-radius: var(--radius); background: var(--panel-2); min-width: 0; }
2458
- .cai-kv b { display: block; font-size: 18px; font-weight: 600; }
2459
- .cai-kv span { font-size: 12px; color: var(--muted); }
2460
- .cai-meter { height: 8px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
2461
- .cai-meter i { display: block; height: 100%; background: var(--ok); border-radius: 999px; }
2462
- .cai-meter.over i { background: var(--warn); }
2463
- .cai-sep { border: 0; border-top: 1px dashed var(--border); margin: 0; }
2464
- .cai-form { display: grid; gap: 14px; }
2465
- .cai-form > .field { margin-bottom: 0; }
2466
2443
  .cai-confirm { display: grid; gap: 10px; padding: 12px; border-radius: var(--radius); border: 1px dashed color-mix(in srgb, var(--bad) 55%, var(--border)); background: color-mix(in srgb, var(--bad) 6%, var(--panel)); }
2467
2444
  .cai-confirm p { margin: 0; font-size: 13px; }
2445
+ .cloud-ai .sec-intro .cai-pill { margin-left: auto; }
2446
+
2447
+ /* before setup: the invite (stitched patch, three facts that stack when the card is narrow) */
2448
+ .settings-sec.cloud-ai:has(> .ai-invite) { padding: 0; }
2449
+ .ai-invite { container-type: inline-size; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 22px; align-items: center; padding: 26px 26px 24px; }
2450
+ .ai-patch { width: 76px; height: 76px; border-radius: 16px; display: grid; place-items: center; position: relative; color: var(--muted); background: repeating-linear-gradient(45deg, transparent 0 7px, color-mix(in srgb, var(--text) 4%, transparent) 7px 8px), var(--panel-2); }
2451
+ .ai-patch::after { content: ""; position: absolute; inset: 6px; border: 1.5px dashed var(--border-strong); border-radius: 11px; }
2452
+ .ai-patch svg { width: 26px; height: 26px; }
2453
+ .ai-invite h2 { margin: 0 0 4px; font-size: 18px; letter-spacing: -0.015em; }
2454
+ .ai-invite p { margin: 0; color: var(--muted); font-size: 13.5px; }
2455
+ .ai-invite > .error { grid-column: 1 / -1; }
2456
+ .ai-facts { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
2457
+ .ai-fact { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 10px; align-items: start; padding: 14px 16px; background: var(--panel); }
2458
+ .ai-fact + .ai-fact { border-left: 1px solid var(--border); }
2459
+ .ai-fact i, .ai-row > i { display: grid; place-items: center; background: var(--panel-2); color: var(--text); font-style: normal; }
2460
+ .ai-fact i { width: 28px; height: 28px; border-radius: 8px; }
2461
+ .ai-fact i svg, .ai-row > i svg { width: 16px; height: 16px; }
2462
+ .ai-fact b { display: block; font-size: 13px; font-weight: 600; }
2463
+ .ai-fact span { font-size: 12px; color: var(--muted); line-height: 1.45; }
2464
+ .ai-invite-foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 14px; }
2465
+ .ai-invite-foot .grow { flex: 1; color: var(--muted); font-size: 12.5px; }
2466
+ @container (max-width: 620px) {
2467
+ .ai-facts { grid-template-columns: minmax(0, 1fr); }
2468
+ .ai-fact { align-items: center; padding: 11px 14px; }
2469
+ .ai-fact + .ai-fact { border-left: 0; border-top: 1px solid var(--border); }
2470
+ .ai-fact b { display: inline; margin-right: 6px; }
2471
+ }
2472
+
2473
+ /* the setup: header (back, title, step count, step bar), body, footer */
2474
+ .ai-flow-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
2475
+ .ai-flow-head .back { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: 13px; color: var(--muted); background: none; border: 0; padding: 4px 6px; margin-left: -6px; border-radius: 6px; cursor: pointer; }
2476
+ .ai-flow-head .back:hover { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); }
2477
+ .ai-flow-head .back svg { width: 14px; height: 14px; }
2478
+ .ai-flow-head .sep { width: 1px; height: 16px; background: var(--border-strong); flex: none; }
2479
+ .ai-flow-head h4 { margin: 0; font-size: 15px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2480
+ .ai-flow-head .count { margin-left: auto; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
2481
+ .ss-main.ai-flow .ai-flow-head .count { margin-right: 34px; }
2482
+ .ai-steps { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; margin: 14px 0 0; padding: 0; list-style: none; }
2483
+ .ai-steps li { display: grid; gap: 7px; font-size: 12px; color: var(--faint); min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2484
+ .ai-steps li::before { content: ""; height: 3px; border-radius: 3px; background: var(--border); }
2485
+ .ai-steps li.done { color: var(--muted); }
2486
+ .ai-steps li.done::before { background: var(--text); opacity: .55; }
2487
+ .ai-steps li.now { color: var(--text); font-weight: 600; }
2488
+ .ai-steps li.now::before { background: var(--accent); }
2489
+ .ss-main.ai-flow #settings-body { padding: 0; }
2490
+ .ai-flow-body { display: grid; gap: 26px; padding: 26px 28px 28px; align-content: start; }
2491
+ .ai-flow-foot { flex: none; display: flex; align-items: center; gap: 12px; padding: 14px 24px; border-top: 1px solid var(--border); background: var(--canvas); }
2492
+ .ai-flow-foot .grow { flex: 1; min-width: 0; font-size: 12.5px; color: var(--muted); }
2493
+ .ai-flow-foot .grow .error { margin: 0; }
2494
+ .ai-flow-foot .btn.primary { min-width: 132px; }
2495
+ .ai-page-flow { border: 1px solid var(--border); border-radius: 14px; background: var(--canvas); }
2496
+ .ai-page-flow > .ss-head { padding: 18px 24px 14px; }
2497
+ .ai-page-flow > .ai-flow-foot { border-radius: 0 0 14px 14px; }
2498
+
2499
+ /* the AI as people will see it, filling in as it is set up */
2500
+ .ai-card { display: flex; align-items: center; gap: 16px; padding: 18px 20px; border-radius: 12px; border: 1px solid var(--border); background: var(--panel); box-shadow: var(--shadow); min-width: 0; }
2501
+ .ai-card .avatar { width: 56px; height: 56px; font-size: 22px; box-shadow: 0 0 0 4px var(--panel), 0 0 0 5px var(--border); }
2502
+ .ai-card .who { flex: 1; min-width: 0; display: grid; gap: 3px; }
2503
+ .ai-card .name { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
2504
+ .ai-card .name b { font-size: 20px; font-weight: 650; letter-spacing: -0.015em; overflow-wrap: anywhere; }
2505
+ .ai-tag { font-size: 11.5px; font-weight: 600; color: var(--muted); background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px; padding: 1px 9px; white-space: nowrap; }
2506
+ .ai-card .sub { font-size: 13px; color: var(--muted); }
2507
+ .ai-card .sub.now { color: var(--text); margin-top: 4px; }
2508
+ .ai-card .at { font-family: var(--mono); font-size: 12px; color: var(--accent); }
2509
+ .ai-card.compact { padding: 12px 16px; gap: 12px; box-shadow: none; }
2510
+ .ai-card.compact .avatar { width: 38px; height: 38px; font-size: 15px; box-shadow: none; }
2511
+ .ai-card.compact .who { grid-template-columns: auto minmax(0, 1fr); align-items: baseline; column-gap: 14px; }
2512
+ .ai-card.compact .name { flex-wrap: nowrap; }
2513
+ .ai-card.compact .name b { font-size: 16px; }
2514
+ .ai-card.compact .sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2515
+
2516
+ /* a question */
2517
+ .ai-q { display: grid; gap: 16px; min-width: 0; }
2518
+ .ai-q > header h3 { margin: 0 0 4px; font-size: 19px; letter-spacing: -0.015em; }
2519
+ .ai-q > header p { margin: 0; color: var(--muted); font-size: 13.5px; }
2520
+ .ai-sub { font-size: 11.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--faint); margin-bottom: -6px; }
2521
+ .ai-q .input.ai-name { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; padding: 12px 14px; }
2522
+ .ai-chips { display: flex; flex-wrap: wrap; gap: 8px; }
2523
+ .ai-chip { font: inherit; font-size: 13px; padding: 6px 13px; border-radius: 999px; border: 1px solid var(--border-strong); background: var(--panel); color: var(--text); cursor: pointer; }
2524
+ .ai-chip:hover { border-color: var(--text); }
2525
+ .ai-chip.on { background: var(--text); color: var(--bg); border-color: var(--text); }
2526
+ .ai-colors { display: flex; flex-wrap: wrap; gap: 10px; }
2527
+ .ai-color { width: 34px; height: 34px; border-radius: 50%; border: 0; padding: 0; cursor: pointer; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15); }
2528
+ .ai-color.on { box-shadow: 0 0 0 3px var(--canvas), 0 0 0 5px var(--text); }
2529
+ .ai-color:focus-visible, .ai-chip:focus-visible, .ai-tool:focus-visible, .ai-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
2530
+ .ai-tools { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
2531
+ .ai-tool { position: relative; display: grid; gap: 10px; justify-items: start; padding: 18px 18px 16px; border-radius: 12px; border: 1px solid var(--border-strong); background: var(--panel); cursor: pointer; text-align: left; font: inherit; color: var(--text); min-width: 0; }
2532
+ .ai-tool:hover { border-color: var(--text); }
2533
+ .ai-tool .cai-logo { width: 42px; height: 42px; border-radius: 10px; }
2534
+ .ai-tool .cai-logo .tool-mark { width: 22px; height: 22px; }
2535
+ .ai-tool b { font-size: 15px; font-weight: 600; }
2536
+ .ai-tool .hint { font-size: 12.5px; margin-top: -6px; }
2537
+ .ai-tool .tick { position: absolute; top: 14px; right: 14px; width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid var(--border-strong); display: grid; place-items: center; color: var(--bg); }
2538
+ .ai-tool .tick svg { width: 12px; height: 12px; }
2539
+ .ai-tool.on { border-color: var(--text); box-shadow: inset 0 0 0 1px var(--text); }
2540
+ .ai-tool.on .tick { background: var(--text); border-color: var(--text); }
2541
+ .ai-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
2542
+ .ai-pair .field, .ai-q .field.ai-rules { margin: 0; }
2543
+
2544
+ /* what it does: a grouped list (setup and the card) */
2545
+ .ai-list { border: 1px solid var(--border); border-radius: 12px; background: var(--panel); overflow: hidden; }
2546
+ .ai-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 15px 18px; }
2547
+ .ai-row + .ai-row { border-top: 1px solid var(--border); }
2548
+ .ai-row > i { width: 34px; height: 34px; border-radius: 9px; }
2549
+ .ai-row b { display: block; font-size: 13.5px; font-weight: 600; }
2550
+ .ai-row .hint { display: block; font-size: 12.5px; line-height: 1.45; }
2551
+ .ai-row.wide { grid-template-columns: 34px minmax(0, 1fr); }
2552
+ .ai-row.wide .ctl { grid-column: 2; }
2553
+ .ai-row.wide .seg { width: 100%; }
2554
+ .ai-always { font-size: 12px; font-weight: 600; color: var(--ok); background: color-mix(in srgb, var(--ok) 13%, transparent); border-radius: 999px; padding: 3px 10px; white-space: nowrap; }
2555
+ .ai-switch { position: relative; width: 40px; height: 24px; border-radius: 999px; background: var(--border-strong); border: 0; padding: 0; flex: none; cursor: pointer; }
2556
+ .ai-switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--panel); box-shadow: 0 1px 2px rgba(0, 0, 0, .25); transition: transform .15s; }
2557
+ .ai-switch.on { background: var(--ok); }
2558
+ .ai-switch.on::after { transform: translateX(16px); }
2559
+
2560
+ /* sessions */
2561
+ .ai-sess { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 13px 18px; cursor: pointer; }
2562
+ .ai-sess + .ai-sess { border-top: 1px solid var(--border); }
2563
+ .ai-sess.off { cursor: default; }
2564
+ .ai-sess.off b, .ai-sess.off .hint { opacity: .75; }
2565
+ .ai-sess input { width: 17px; height: 17px; margin: 0; accent-color: var(--text); }
2566
+ .ai-sess b { display: block; font-size: 13.5px; font-weight: 600; }
2567
+ .ai-sess .hint { font-size: 12.5px; }
2568
+ .ai-sess.static { grid-template-columns: 8px minmax(0, 1fr) auto; cursor: default; padding: 11px 18px; }
2569
+ .ai-on { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); }
2570
+ .ai-faces { display: flex; }
2571
+ .ai-faces .avatar { width: 24px; height: 24px; font-size: 10px; background: var(--border-strong); color: var(--text); box-shadow: 0 0 0 2px var(--panel); }
2572
+ .ai-faces .avatar + .avatar { margin-left: -6px; }
2573
+
2574
+ /* the sign-in, and what was chosen */
2575
+ .ai-signin { display: grid; gap: 16px; padding: 20px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); }
2576
+ .ai-signin-again { display: flex; }
2577
+ .ai-review { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border: 1px solid var(--border); border-radius: 12px; background: var(--panel); overflow: hidden; }
2578
+ .ai-review > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 10px; padding: 13px 18px; min-width: 0; }
2579
+ .ai-review > div:nth-child(odd) { border-right: 1px solid var(--border); }
2580
+ .ai-review > div:nth-child(n+3) { border-top: 1px solid var(--border); }
2581
+ .ai-review span { font-size: 11.5px; color: var(--faint); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
2582
+ .ai-review b { grid-column: 1; font-size: 13.5px; font-weight: 500; }
2583
+ .ai-change { grid-row: 1 / span 2; grid-column: 2; align-self: center; font: inherit; font-size: 12.5px; color: var(--muted); background: none; border: 0; padding: 2px 4px; text-decoration: underline; cursor: pointer; }
2584
+ .ai-change:hover { color: var(--text); }
2585
+
2586
+ /* set up: its card */
2587
+ .ai-run { display: grid; gap: 18px; }
2588
+ .ai-run > p, .ai-run .error { margin: 0; }
2589
+ .ai-asleep { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 10px; background: var(--panel-2); }
2590
+ .ai-asleep .hint { flex: 1; }
2591
+ .ai-meters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
2592
+ .ai-meters > div { padding: 12px 16px; background: var(--panel); display: grid; gap: 2px; min-width: 0; }
2593
+ .ai-meters > div + div { border-left: 1px solid var(--border); }
2594
+ .ai-meters b { font-size: 18px; font-weight: 650; font-variant-numeric: tabular-nums; }
2595
+ .ai-meters span { font-size: 12px; color: var(--muted); }
2468
2596
  @media (max-width: 640px) {
2469
- .cai-tools, .cai-two { grid-template-columns: minmax(0, 1fr); }
2470
- .cai-kv { gap: 6px; }
2471
- .cai-kv > div { padding: 8px 10px; }
2472
- .cai-kv b { font-size: 16px; }
2473
- .cai-who { flex-wrap: wrap; }
2597
+ .ai-tools, .ai-pair, .ai-review, .cai-two { grid-template-columns: minmax(0, 1fr); }
2598
+ .ai-review > div:nth-child(odd) { border-right: 0; }
2599
+ .ai-review > div + div { border-top: 1px solid var(--border); }
2600
+ .ai-steps li { font-size: 0; gap: 0; }
2601
+ .ai-flow-body { padding: 18px 16px 20px; }
2602
+ .ai-invite { grid-template-columns: minmax(0, 1fr); }
2474
2603
  }
2475
2604
 
2476
2605
  /* Sandbox keys: an agent's Keys table (sandbox-keys.js, mockup option A), opened from its card in Settings › Agents. */
@@ -2748,3 +2877,5 @@ body.has-asks .ws { height: calc(100vh - var(--update-bar, 0px) - var(--asks-bar
2748
2877
  .task-nopickup-x { margin-left: 2px; opacity: .55; font-weight: 700; }
2749
2878
  .task-nopickup:hover .task-nopickup-x, .task-nopickup:focus-visible .task-nopickup-x { opacity: 1; }
2750
2879
  .task-nopickup:hover, .task-nopickup:focus-visible { background: color-mix(in srgb, var(--warn) 20%, transparent); outline: none; }
2880
+ /* A cloud AI's own name in chat, then whose AI it is ("Juniper Daniel's AI"). */
2881
+ .msg .head .ai-tag { font-size: 10.5px; padding: 0 7px; }