clay-server 2.23.1 → 2.24.0-beta.1

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/lib/public/app.js CHANGED
@@ -77,6 +77,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
77
77
  var cachedMatesList = []; // Cached list of mates for user strip
78
78
  var cachedAvailableBuiltins = []; // Deleted built-in mates available for re-add
79
79
 
80
+ // Claude Code avatar (mascot image served from public root)
81
+ var CLAUDE_CODE_AVATAR = "/claude-code-avatar.png";
82
+
80
83
  // --- Mate project switching ---
81
84
  var mateProjectSlug = null;
82
85
  var savedMainSlug = null; // main project slug saved during mate DM
@@ -562,14 +565,62 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
562
565
  if (!ws || ws.readyState !== 1) return;
563
566
  // Check mate skill updates before opening mate DM
564
567
  if (typeof targetUserId === "string" && targetUserId.indexOf("mate_") === 0) {
565
- requireClayMateInterview(function () {
566
- ws.send(JSON.stringify({ type: "dm_open", targetUserId: targetUserId }));
568
+ showMateOnboarding(function () {
569
+ requireClayMateInterview(function () {
570
+ ws.send(JSON.stringify({ type: "dm_open", targetUserId: targetUserId }));
571
+ });
567
572
  });
568
573
  return;
569
574
  }
570
575
  ws.send(JSON.stringify({ type: "dm_open", targetUserId: targetUserId }));
571
576
  }
572
577
 
578
+ var MATE_ONBOARDING_KEY = "clay-mate-onboarding-shown";
579
+
580
+ function showMateOnboarding(callback) {
581
+ try {
582
+ if (localStorage.getItem(MATE_ONBOARDING_KEY)) { callback(); return; }
583
+ } catch (e) {}
584
+
585
+ var overlay = document.createElement("div");
586
+ overlay.className = "mate-onboarding-overlay";
587
+ overlay.innerHTML =
588
+ '<div class="mate-onboarding-card">' +
589
+ '<h2 class="mate-onboarding-title">Meet your Mates</h2>' +
590
+ '<p class="mate-onboarding-desc">' +
591
+ 'Mates are AI teammates powered by your Claude Code.<br>Each one has a distinct role, builds its own knowledge, and gets sharper over time.' +
592
+ '</p>' +
593
+ '<ul class="mate-onboarding-features">' +
594
+ '<li><span class="mate-onboarding-bullet">\uD83C\uDFAD</span><div><strong>Specialized personas</strong><br><span class="mate-onboarding-sub">Architect, reviewer, researcher, chief of staff, and more</span></div></li>' +
595
+ '<li><span class="mate-onboarding-bullet">\uD83D\uDD04</span><div><strong>Persistent memory</strong><br><span class="mate-onboarding-sub">Every conversation makes them smarter about you and your work</span></div></li>' +
596
+ '<li><span class="mate-onboarding-bullet">\uD83D\uDCAC</span><div><strong>Shared context across the team</strong><br><span class="mate-onboarding-sub">What one mate learns, the others can reference</span></div></li>' +
597
+ '<li><span class="mate-onboarding-bullet">\uD83D\uDCDA</span><div><strong>Self-growing knowledge base</strong><br><span class="mate-onboarding-sub">They accumulate notes, decisions, and observations on their own</span></div></li>' +
598
+ '</ul>' +
599
+ '<button class="mate-onboarding-btn">Let\u2019s go</button>' +
600
+ '</div>';
601
+
602
+ document.body.appendChild(overlay);
603
+
604
+ // Animate in
605
+ requestAnimationFrame(function () {
606
+ overlay.classList.add("visible");
607
+ });
608
+
609
+ function dismissOnboarding() {
610
+ try { localStorage.setItem(MATE_ONBOARDING_KEY, "1"); } catch (e) {}
611
+ fetch("/api/user/mate-onboarded", { method: "POST" }).catch(function () {});
612
+ overlay.classList.remove("visible");
613
+ setTimeout(function () { overlay.remove(); callback(); }, 200);
614
+ }
615
+
616
+ overlay.querySelector(".mate-onboarding-btn").addEventListener("click", dismissOnboarding);
617
+
618
+ // Click outside to dismiss
619
+ overlay.addEventListener("click", function (e) {
620
+ if (e.target === overlay) dismissOnboarding();
621
+ });
622
+ }
623
+
573
624
  function enterDmMode(key, targetUser, messages) {
574
625
  console.log("[DEBUG enterDmMode] key=" + key, "isMate=" + (targetUser && targetUser.isMate), "messages=" + (messages ? messages.length : 0));
575
626
  // Clean up previous DM/mate state before entering new one
@@ -1289,12 +1340,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1289
1340
  if (msg.dmFavorites) cachedDmFavorites = msg.dmFavorites;
1290
1341
  if (msg.dmConversations) cachedDmConversations = msg.dmConversations;
1291
1342
  renderUserStrip(msg.allUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers, cachedMatesList);
1292
- // Update my info in body.dataset if in mate DM (fixes stale data after refresh)
1293
- if (document.body.classList.contains("mate-dm-active")) {
1343
+ // Update my info in body.dataset if in mate DM or wide view (fixes stale data after refresh)
1344
+ if (document.body.classList.contains("mate-dm-active") || document.body.classList.contains("wide-view")) {
1294
1345
  var refreshedMyUser = cachedAllUsers.find(function (u) { return u.id === myUserId; });
1295
1346
  if (refreshedMyUser) {
1296
- document.body.dataset.myDisplayName = refreshedMyUser.displayName || "";
1347
+ document.body.dataset.myDisplayName = refreshedMyUser.displayName || refreshedMyUser.username || "";
1297
1348
  document.body.dataset.myAvatarUrl = userAvatarUrl(refreshedMyUser, 36);
1349
+ try { localStorage.setItem("clay_my_user", JSON.stringify({ displayName: refreshedMyUser.displayName, username: refreshedMyUser.username, avatarStyle: refreshedMyUser.avatarStyle, avatarSeed: refreshedMyUser.avatarSeed, avatarCustom: refreshedMyUser.avatarCustom })); } catch(e) {}
1298
1350
  }
1299
1351
  }
1300
1352
  // Render my avatar (always present, hidden behind user-island)
@@ -1444,6 +1496,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1444
1496
  $("paste-modal").querySelector(".paste-modal-close").addEventListener("click", function() {
1445
1497
  $("paste-modal").classList.add("hidden");
1446
1498
  });
1499
+ $("paste-modal").querySelector(".paste-modal-copy").addEventListener("click", function() {
1500
+ var body = $("paste-modal-body");
1501
+ if (body) copyToClipboard(body.textContent, "Copied to clipboard");
1502
+ });
1447
1503
  $("mermaid-modal").querySelector(".confirm-backdrop").addEventListener("click", closeMermaidModal);
1448
1504
  $("mermaid-modal").querySelector(".mermaid-modal-btn[title='Close']").addEventListener("click", closeMermaidModal);
1449
1505
  $("image-modal").querySelector(".confirm-backdrop").addEventListener("click", closeImageModal);
@@ -2868,38 +2924,38 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
2868
2924
  }
2869
2925
 
2870
2926
 
2871
- // Mate DM: wrap avatar + header + bubble in DM-like layout
2872
- if (document.body.classList.contains("mate-dm-active") && document.body.dataset.myAvatarUrl) {
2873
- var avi = document.createElement("img");
2874
- avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
2875
- avi.src = document.body.dataset.myAvatarUrl;
2876
- div.appendChild(avi);
2927
+ // Always render avatar + header structure (CSS controls visibility)
2928
+ var _myU = cachedAllUsers.find(function (u) { return u.id === myUserId; });
2929
+ if (!_myU) {
2930
+ try { _myU = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch(e) {}
2931
+ }
2877
2932
 
2878
- var contentWrap = document.createElement("div");
2879
- contentWrap.className = "dm-bubble-content";
2933
+ var avi = document.createElement("img");
2934
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
2935
+ avi.src = document.body.dataset.myAvatarUrl || userAvatarUrl(_myU || { id: myUserId }, 36);
2936
+ div.appendChild(avi);
2880
2937
 
2881
- var header = document.createElement("div");
2882
- header.className = "dm-bubble-header";
2883
- var myDisplayName = document.body.dataset.myDisplayName || "";
2884
- if (!myDisplayName) {
2885
- var myU = cachedAllUsers.find(function (u) { return u.id === myUserId; });
2886
- myDisplayName = (myU && myU.displayName) || "Me";
2887
- }
2888
- var nameSpan = document.createElement("span");
2889
- nameSpan.className = "dm-bubble-name";
2890
- nameSpan.textContent = myDisplayName;
2891
- header.appendChild(nameSpan);
2892
- var timeSpan = document.createElement("span");
2893
- timeSpan.className = "dm-bubble-time";
2894
- var nowH = new Date();
2895
- timeSpan.textContent = String(nowH.getHours()).padStart(2, "0") + ":" + String(nowH.getMinutes()).padStart(2, "0");
2896
- header.appendChild(timeSpan);
2897
- contentWrap.appendChild(header);
2898
- contentWrap.appendChild(bubble);
2899
- div.appendChild(contentWrap);
2900
- } else {
2901
- div.appendChild(bubble);
2902
- }
2938
+ var contentWrap = document.createElement("div");
2939
+ contentWrap.className = "dm-bubble-content";
2940
+
2941
+ var header = document.createElement("div");
2942
+ header.className = "dm-bubble-header";
2943
+ var myDisplayName = document.body.dataset.myDisplayName || "";
2944
+ if (!myDisplayName) {
2945
+ myDisplayName = (_myU && (_myU.displayName || _myU.username)) || "Me";
2946
+ }
2947
+ var nameSpan = document.createElement("span");
2948
+ nameSpan.className = "dm-bubble-name";
2949
+ nameSpan.textContent = myDisplayName;
2950
+ header.appendChild(nameSpan);
2951
+ var timeSpan = document.createElement("span");
2952
+ timeSpan.className = "dm-bubble-time";
2953
+ var nowH = new Date();
2954
+ timeSpan.textContent = String(nowH.getHours()).padStart(2, "0") + ":" + String(nowH.getMinutes()).padStart(2, "0");
2955
+ header.appendChild(timeSpan);
2956
+ contentWrap.appendChild(header);
2957
+ contentWrap.appendChild(bubble);
2958
+ div.appendChild(contentWrap);
2903
2959
 
2904
2960
  // Action bar below bubble (icons visible on hover)
2905
2961
  var actions = document.createElement("div");
@@ -2933,40 +2989,34 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
2933
2989
  currentMsgEl = document.createElement("div");
2934
2990
  currentMsgEl.className = "msg-assistant";
2935
2991
  currentMsgEl.dataset.turn = turnCounter;
2936
- // Inject mate avatar + header for DM bubble style
2937
- if (document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl) {
2938
- var avi = document.createElement("img");
2939
- avi.className = "dm-bubble-avatar dm-bubble-avatar-mate";
2940
- avi.src = document.body.dataset.mateAvatarUrl;
2941
- currentMsgEl.appendChild(avi);
2942
-
2943
- var contentWrap = document.createElement("div");
2944
- contentWrap.className = "dm-bubble-content";
2945
-
2946
- var header = document.createElement("div");
2947
- header.className = "dm-bubble-header";
2948
- var nameSpan = document.createElement("span");
2949
- nameSpan.className = "dm-bubble-name";
2950
- nameSpan.textContent = (dmTargetUser && dmTargetUser.displayName) || "Mate";
2951
- header.appendChild(nameSpan);
2952
- var timeSpan = document.createElement("span");
2953
- timeSpan.className = "dm-bubble-time";
2954
- var nowA = new Date();
2955
- timeSpan.textContent = String(nowA.getHours()).padStart(2, "0") + ":" + String(nowA.getMinutes()).padStart(2, "0");
2956
- header.appendChild(timeSpan);
2957
- contentWrap.appendChild(header);
2958
-
2959
- var mdDiv = document.createElement("div");
2960
- mdDiv.className = "md-content";
2961
- mdDiv.dir = "auto";
2962
- contentWrap.appendChild(mdDiv);
2963
- currentMsgEl.appendChild(contentWrap);
2964
- } else {
2965
- var mdDiv = document.createElement("div");
2966
- mdDiv.className = "md-content";
2967
- mdDiv.dir = "auto";
2968
- currentMsgEl.appendChild(mdDiv);
2969
- }
2992
+ // Always render avatar + header structure (CSS controls visibility)
2993
+ var _isDm2 = document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl;
2994
+ var avi = document.createElement("img");
2995
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-mate";
2996
+ avi.src = _isDm2 ? document.body.dataset.mateAvatarUrl : CLAUDE_CODE_AVATAR;
2997
+ currentMsgEl.appendChild(avi);
2998
+
2999
+ var contentWrap = document.createElement("div");
3000
+ contentWrap.className = "dm-bubble-content";
3001
+
3002
+ var header = document.createElement("div");
3003
+ header.className = "dm-bubble-header";
3004
+ var nameSpan = document.createElement("span");
3005
+ nameSpan.className = "dm-bubble-name";
3006
+ nameSpan.textContent = _isDm2 ? ((dmTargetUser && dmTargetUser.displayName) || "Mate") : "Claude Code";
3007
+ header.appendChild(nameSpan);
3008
+ var timeSpan = document.createElement("span");
3009
+ timeSpan.className = "dm-bubble-time";
3010
+ var nowA = new Date();
3011
+ timeSpan.textContent = String(nowA.getHours()).padStart(2, "0") + ":" + String(nowA.getMinutes()).padStart(2, "0");
3012
+ header.appendChild(timeSpan);
3013
+ contentWrap.appendChild(header);
3014
+
3015
+ var mdDiv = document.createElement("div");
3016
+ mdDiv.className = "md-content";
3017
+ mdDiv.dir = "auto";
3018
+ contentWrap.appendChild(mdDiv);
3019
+ currentMsgEl.appendChild(contentWrap);
2970
3020
  addToMessages(currentMsgEl);
2971
3021
  currentFullText = "";
2972
3022
  }
@@ -149,7 +149,6 @@
149
149
  z-index: 50;
150
150
  padding: 6px 16px;
151
151
  background: color-mix(in srgb, var(--bg) 92%, transparent);
152
- backdrop-filter: blur(8px);
153
152
  border-bottom: 1px solid var(--border);
154
153
  }
155
154
  #debate-info-float.hidden { display: none; }
@@ -577,6 +576,41 @@
577
576
  background: color-mix(in srgb, var(--accent) 10%, transparent);
578
577
  }
579
578
 
579
+ /* --- Title bar PDF button (matches find-in-session-btn / terminal-toggle-btn pattern) --- */
580
+ #debate-pdf-btn {
581
+ display: flex;
582
+ align-items: center;
583
+ justify-content: center;
584
+ background: none;
585
+ border: 1px solid transparent;
586
+ border-radius: 8px;
587
+ color: var(--text-dimmer);
588
+ cursor: pointer;
589
+ padding: 4px;
590
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
591
+ }
592
+
593
+ #debate-pdf-btn .lucide { width: 15px; height: 15px; }
594
+ #debate-pdf-btn:hover { color: var(--text-secondary); background: rgba(var(--overlay-rgb),0.04); border-color: var(--border); }
595
+ #debate-pdf-btn:disabled { opacity: 0.5; cursor: default; }
596
+
597
+ /* --- Ended banner PDF button --- */
598
+ .debate-ended-pdf-btn {
599
+ display: inline-flex;
600
+ align-items: center;
601
+ gap: 4px;
602
+ }
603
+
604
+ .debate-ended-pdf-btn svg {
605
+ width: 14px;
606
+ height: 14px;
607
+ }
608
+
609
+ .debate-ended-pdf-btn:disabled {
610
+ opacity: 0.5;
611
+ cursor: default;
612
+ }
613
+
580
614
  /* --- Error --- */
581
615
  .debate-error {
582
616
  padding: 8px 20px;
@@ -57,7 +57,8 @@
57
57
  display: none;
58
58
  }
59
59
 
60
- #file-panel-refresh.spinning { animation: spin-once 0.5s ease; }
60
+ #file-panel-refresh.spinning,
61
+ #file-viewer-refresh.spinning { animation: spin-once 0.5s ease; }
61
62
  @keyframes spin-once { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
62
63
 
63
64
  /* --- File tree --- */
@@ -1392,6 +1392,29 @@ select.wt-modal-input {
1392
1392
 
1393
1393
  /* --- Per-project presence avatars --- */
1394
1394
  /* --- Mobile: hide icon strip --- */
1395
+ /* --- Skeleton loading placeholders --- */
1396
+ @keyframes skeleton-shimmer {
1397
+ 0% { opacity: 0.15; }
1398
+ 50% { opacity: 0.25; }
1399
+ 100% { opacity: 0.15; }
1400
+ }
1401
+ .skeleton-icon-strip-item {
1402
+ width: 38px;
1403
+ height: 38px;
1404
+ border-radius: 12px;
1405
+ background: var(--text-muted, #888);
1406
+ margin: 5px auto;
1407
+ animation: skeleton-shimmer 1.5s ease-in-out infinite;
1408
+ }
1409
+ .skeleton-icon-strip-user {
1410
+ width: 34px;
1411
+ height: 34px;
1412
+ border-radius: 50%;
1413
+ background: var(--text-muted, #888);
1414
+ margin: 4px auto;
1415
+ animation: skeleton-shimmer 1.5s ease-in-out infinite;
1416
+ }
1417
+
1395
1418
  @media (max-width: 768px) {
1396
1419
  #icon-strip {
1397
1420
  display: none;
@@ -120,6 +120,13 @@
120
120
  color: var(--text);
121
121
  }
122
122
 
123
+ .paste-modal-actions {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 4px;
127
+ }
128
+
129
+ .paste-modal-copy,
123
130
  .paste-modal-close {
124
131
  display: flex;
125
132
  align-items: center;
@@ -133,6 +140,7 @@
133
140
  transition: color 0.15s, background 0.15s;
134
141
  }
135
142
 
143
+ .paste-modal-copy:hover,
136
144
  .paste-modal-close:hover { color: var(--text); background: rgba(var(--overlay-rgb), 0.06); }
137
145
 
138
146
  .paste-modal-body {
@@ -364,6 +372,64 @@
364
372
  #attach-image-btn:hover,
365
373
  #schedule-btn:hover { background: rgba(var(--overlay-rgb), 0.06); color: var(--text); }
366
374
 
375
+ #ask-mate-btn {
376
+ height: 28px;
377
+ padding: 0 10px;
378
+ border-radius: 10px;
379
+ border: 1px solid transparent;
380
+ background:
381
+ linear-gradient(var(--bg, #282a36), var(--bg, #282a36)) padding-box,
382
+ linear-gradient(135deg, #4ecdc4 0%, #4ecdc4 25%, #556bf7, #a855f7, #f857a6, #ff6b6b) border-box;
383
+ color: transparent;
384
+ cursor: pointer;
385
+ display: flex;
386
+ align-items: center;
387
+ gap: 5px;
388
+ font-family: 'Nunito', sans-serif;
389
+ font-size: 13px;
390
+ font-weight: 800;
391
+ letter-spacing: 0.2px;
392
+ transition: transform 0.1s, box-shadow 0.3s, border-color 0.3s;
393
+ touch-action: manipulation;
394
+ position: relative;
395
+ overflow: hidden;
396
+ z-index: 0;
397
+ }
398
+ #ask-mate-btn::before {
399
+ content: "";
400
+ position: absolute;
401
+ inset: 0;
402
+ background: linear-gradient(135deg, #4ecdc4 0%, #4ecdc4 32%, #556bf7 34%, #556bf7 50%, #a855f7 52%, #a855f7 68%, #f857a6 70%, #f857a6 84%, #ff6b6b 86%, #ff6b6b 100%);
403
+ border-radius: inherit;
404
+ opacity: 0;
405
+ transform: scale(0.3);
406
+ transition: opacity 0.3s ease, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
407
+ z-index: -1;
408
+ }
409
+ .ask-mate-label {
410
+ white-space: nowrap;
411
+ background: linear-gradient(135deg, #4ecdc4 0%, #4ecdc4 25%, #556bf7, #a855f7, #f857a6, #ff6b6b);
412
+ -webkit-background-clip: text;
413
+ background-clip: text;
414
+ -webkit-text-fill-color: transparent;
415
+ transition: opacity 0.2s;
416
+ }
417
+ #ask-mate-btn:hover::before {
418
+ opacity: 1;
419
+ transform: scale(1);
420
+ }
421
+ #ask-mate-btn:hover {
422
+ border-color: transparent;
423
+ background: transparent;
424
+ transform: translateY(-1px);
425
+ box-shadow: 0 2px 12px rgba(148, 130, 247, 0.4);
426
+ }
427
+ #ask-mate-btn:hover .ask-mate-label {
428
+ background: none;
429
+ -webkit-text-fill-color: #fff;
430
+ }
431
+ #ask-mate-btn:active { transform: translateY(-1px) scale(0.95); }
432
+
367
433
  #send-btn {
368
434
  flex-shrink: 0;
369
435
  width: 36px;
@@ -239,8 +239,6 @@
239
239
  position: absolute;
240
240
  inset: 0;
241
241
  background: rgba(var(--shadow-rgb, 0,0,0), 0.5);
242
- backdrop-filter: blur(2px);
243
- -webkit-backdrop-filter: blur(2px);
244
242
  }
245
243
  .ralph-wizard-card {
246
244
  position: relative;
@@ -63,8 +63,6 @@
63
63
  position: absolute;
64
64
  inset: 0;
65
65
  background: rgba(var(--shadow-rgb, 0,0,0), 0.5);
66
- backdrop-filter: blur(2px);
67
- -webkit-backdrop-filter: blur(2px);
68
66
  }
69
67
  .mate-wizard-card {
70
68
  position: relative;
@@ -860,6 +858,103 @@ body.mate-dm-active #layout.sidebar-collapsed .mate-collapsed-info {
860
858
  background: #c0392b;
861
859
  }
862
860
 
861
+ /* --- Mate onboarding modal --- */
862
+ .mate-onboarding-overlay {
863
+ position: fixed;
864
+ inset: 0;
865
+ background: rgba(0,0,0,0);
866
+ z-index: 999;
867
+ display: flex;
868
+ align-items: center;
869
+ justify-content: center;
870
+ transition: background 0.2s ease;
871
+ }
872
+ .mate-onboarding-overlay.visible {
873
+ background: rgba(0,0,0,0.45);
874
+ }
875
+ .mate-onboarding-card {
876
+ background: var(--bg-primary, #fff);
877
+ border: 1px solid var(--border-subtle);
878
+ border-radius: 16px;
879
+ padding: 32px 36px;
880
+ max-width: 400px;
881
+ width: 90%;
882
+ box-shadow: 0 12px 48px rgba(0,0,0,0.2);
883
+ text-align: center;
884
+ transform: translateY(20px) scale(0.96);
885
+ opacity: 0;
886
+ transition: transform 0.25s ease, opacity 0.25s ease;
887
+ }
888
+ .mate-onboarding-overlay.visible .mate-onboarding-card {
889
+ transform: translateY(0) scale(1);
890
+ opacity: 1;
891
+ }
892
+ .mate-onboarding-icon {
893
+ font-size: 40px;
894
+ margin-bottom: 8px;
895
+ }
896
+ .mate-onboarding-title {
897
+ font-size: 20px;
898
+ font-weight: 700;
899
+ color: var(--text);
900
+ margin: 0 0 10px;
901
+ }
902
+ .mate-onboarding-desc {
903
+ font-size: 14px;
904
+ color: var(--text-secondary);
905
+ line-height: 1.5;
906
+ margin: 0 0 18px;
907
+ }
908
+ .mate-onboarding-features {
909
+ list-style: none;
910
+ padding: 0;
911
+ margin: 0 0 24px;
912
+ text-align: left;
913
+ }
914
+ .mate-onboarding-features li {
915
+ font-size: 13px;
916
+ color: var(--text);
917
+ padding: 8px 0;
918
+ display: flex;
919
+ align-items: flex-start;
920
+ gap: 10px;
921
+ line-height: 1.4;
922
+ }
923
+ .mate-onboarding-sub {
924
+ color: var(--text-muted);
925
+ font-size: 12px;
926
+ }
927
+ .mate-onboarding-bullet {
928
+ font-size: 16px;
929
+ flex-shrink: 0;
930
+ width: 24px;
931
+ text-align: center;
932
+ }
933
+ .mate-onboarding-note {
934
+ font-size: 11px;
935
+ color: var(--text-muted);
936
+ text-align: center;
937
+ margin: 0 0 16px;
938
+ }
939
+ .mate-onboarding-btn {
940
+ width: 100%;
941
+ padding: 10px 0;
942
+ border: none;
943
+ border-radius: 10px;
944
+ background: var(--accent);
945
+ color: #fff;
946
+ font-size: 14px;
947
+ font-weight: 600;
948
+ cursor: pointer;
949
+ transition: background 0.15s, transform 0.1s;
950
+ }
951
+ .mate-onboarding-btn:hover {
952
+ filter: brightness(1.08);
953
+ }
954
+ .mate-onboarding-btn:active {
955
+ transform: scale(0.98);
956
+ }
957
+
863
958
  .mate-sidebar-avatar {
864
959
  width: 28px;
865
960
  height: 28px;
@@ -2143,20 +2238,32 @@ body.mate-dm-active .notes-archive-header button:hover {
2143
2238
  object-fit: cover;
2144
2239
  margin-top: 2px;
2145
2240
  }
2146
- body.mate-dm-active .dm-bubble-avatar {
2241
+ body.mate-dm-active .dm-bubble-avatar,
2242
+ body.wide-view .dm-bubble-avatar {
2147
2243
  display: block;
2148
2244
  }
2149
2245
 
2150
2246
  /* --- DM bubble header (name + time) --- */
2247
+ /* Content wrapper: full width by default so child % sizing works,
2248
+ becomes flex child in DM/wide modes */
2151
2249
  .dm-bubble-content {
2152
- flex: 1;
2153
- min-width: 0;
2250
+ width: 100%;
2154
2251
  }
2155
2252
  .dm-bubble-header {
2156
- display: flex;
2253
+ display: none;
2157
2254
  align-items: baseline;
2158
2255
  gap: 8px;
2159
2256
  }
2257
+ body.mate-dm-active .dm-bubble-header,
2258
+ body.wide-view .dm-bubble-header {
2259
+ display: flex;
2260
+ }
2261
+ body.mate-dm-active .dm-bubble-content,
2262
+ body.wide-view .dm-bubble-content {
2263
+ width: auto;
2264
+ flex: 1;
2265
+ min-width: 0;
2266
+ }
2160
2267
  .dm-bubble-name {
2161
2268
  font-weight: 700;
2162
2269
  font-size: 15px;
@@ -43,11 +43,36 @@
43
43
  flex-shrink: 0;
44
44
  }
45
45
 
46
+ .mention-item-info {
47
+ flex: 1;
48
+ min-width: 0;
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 1px;
52
+ }
46
53
  .mention-item-name {
47
54
  font-size: 14px;
48
55
  font-weight: 600;
49
56
  color: var(--text);
50
- flex: 1;
57
+ }
58
+ .mention-item-bio {
59
+ font-size: 12px;
60
+ color: var(--text-muted);
61
+ white-space: nowrap;
62
+ overflow: hidden;
63
+ text-overflow: ellipsis;
64
+ }
65
+ .mention-item-badge {
66
+ display: inline-block;
67
+ font-size: 9px;
68
+ font-weight: 800;
69
+ letter-spacing: 0.5px;
70
+ padding: 1px 5px;
71
+ border-radius: 3px;
72
+ background: var(--accent-12, rgba(255,184,108,0.12));
73
+ color: var(--accent, #ffb86c);
74
+ vertical-align: middle;
75
+ margin-left: 5px;
51
76
  }
52
77
 
53
78
  .mention-item-dot {