fraim-hub 2.0.220 → 2.0.221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-hub",
3
- "version": "2.0.220",
3
+ "version": "2.0.221",
4
4
  "description": "FRAIM Hub local companion package.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -93,7 +93,7 @@
93
93
  "dotenv": "^16.4.7",
94
94
  "electron": "^41.2.2",
95
95
  "express": "^5.2.1",
96
- "fraim": "2.0.220",
96
+ "fraim": "2.0.221",
97
97
  "mongodb": "^7.0.0",
98
98
  "node-cron": "4.2.1",
99
99
  "node-edge-tts": "^1.2.10",
@@ -3403,16 +3403,52 @@ function syncTemplatePickerVisibility() {
3403
3403
  }
3404
3404
 
3405
3405
  // Stable list of [dropdownId, btnId] pairs for the three coaching dropdowns.
3406
- const COACH_DROPDOWN_PAIRS = [
3407
- ['positive-reinforcement-dropdown', 'positive-reinforcement-btn'],
3408
- ['negative-reinforcement-dropdown', 'negative-reinforcement-btn'],
3409
- ['conviction-dropdown', 'conviction-btn'],
3410
- ];
3411
-
3412
- // R4/R5/R6: open a coaching dropdown by its menu element id.
3413
- function openCoachDropdown(dropdownId, btnId) {
3414
- const dropdown = els[dropdownId] || document.getElementById(dropdownId);
3415
- if (!dropdown) return;
3406
+ const COACH_DROPDOWN_PAIRS = [
3407
+ ['positive-reinforcement-dropdown', 'positive-reinforcement-btn'],
3408
+ ['negative-reinforcement-dropdown', 'negative-reinforcement-btn'],
3409
+ ['conviction-dropdown', 'conviction-btn'],
3410
+ ];
3411
+
3412
+ function positionCoachDropdown(dropdown, btn) {
3413
+ if (!dropdown || !btn || dropdown.hidden) return;
3414
+ const margin = 6;
3415
+ const viewportPad = 8;
3416
+ const rect = btn.getBoundingClientRect();
3417
+ const minWidth = Math.max(200, Math.ceil(rect.width));
3418
+ dropdown.style.minWidth = minWidth + 'px';
3419
+ dropdown.style.maxWidth = Math.max(220, window.innerWidth - viewportPad * 2) + 'px';
3420
+ dropdown.style.visibility = 'hidden';
3421
+ dropdown.style.transform = 'none';
3422
+ const menuRect = dropdown.getBoundingClientRect();
3423
+ const menuWidth = Math.max(menuRect.width, minWidth);
3424
+ const menuHeight = menuRect.height || 160;
3425
+ const viewportMaxLeft = Math.max(viewportPad, window.innerWidth - menuWidth - viewportPad);
3426
+ const wouldOverflowRight = rect.left + menuWidth > window.innerWidth - viewportPad;
3427
+ const idealLeft = wouldOverflowRight ? rect.right - menuWidth : rect.left;
3428
+ const left = Math.min(Math.max(viewportPad, idealLeft), viewportMaxLeft);
3429
+ const bottomTop = rect.bottom + margin;
3430
+ const top = bottomTop + menuHeight <= window.innerHeight - viewportPad
3431
+ ? bottomTop
3432
+ : Math.max(viewportPad, rect.top - menuHeight - margin);
3433
+ dropdown.style.left = Math.round(left) + 'px';
3434
+ dropdown.style.top = Math.round(top) + 'px';
3435
+ dropdown.style.maxHeight = Math.max(120, window.innerHeight - top - viewportPad) + 'px';
3436
+ dropdown.style.visibility = '';
3437
+ }
3438
+
3439
+ function positionOpenCoachDropdowns() {
3440
+ for (const [dropdownId, btnId] of COACH_DROPDOWN_PAIRS) {
3441
+ const dropdown = els[dropdownId] || document.getElementById(dropdownId);
3442
+ if (!dropdown || dropdown.hidden) continue;
3443
+ const btn = els[btnId] || document.getElementById(btnId);
3444
+ positionCoachDropdown(dropdown, btn);
3445
+ }
3446
+ }
3447
+
3448
+ // R4/R5/R6: open a coaching dropdown by its menu element id.
3449
+ function openCoachDropdown(dropdownId, btnId) {
3450
+ const dropdown = els[dropdownId] || document.getElementById(dropdownId);
3451
+ if (!dropdown) return;
3416
3452
  // Close all other coaching dropdowns first.
3417
3453
  for (const [id] of COACH_DROPDOWN_PAIRS) {
3418
3454
  const other = els[id] || document.getElementById(id);
@@ -3420,29 +3456,14 @@ function openCoachDropdown(dropdownId, btnId) {
3420
3456
  other.hidden = true;
3421
3457
  const otherBtnId = id.replace('-dropdown', '-btn');
3422
3458
  const otherBtn = els[otherBtnId] || document.getElementById(otherBtnId);
3423
- if (otherBtn) otherBtn.setAttribute('aria-expanded', 'false');
3424
- }
3425
- }
3426
- // Position the fixed dropdown above the trigger button so it escapes overflow:hidden ancestors.
3427
- // If the trigger is too near the top, open downward instead.
3428
- const btn = els[btnId] || document.getElementById(btnId);
3429
- if (btn) {
3430
- const rect = btn.getBoundingClientRect();
3431
- const spaceAbove = rect.top;
3432
- const dropdownHeight = 200; // conservative estimate before the element is visible
3433
- if (spaceAbove >= dropdownHeight) {
3434
- dropdown.style.left = rect.left + 'px';
3435
- dropdown.style.top = (rect.top - 4) + 'px';
3436
- dropdown.style.transform = 'translateY(-100%)';
3437
- } else {
3438
- dropdown.style.left = rect.left + 'px';
3439
- dropdown.style.top = (rect.bottom + 4) + 'px';
3440
- dropdown.style.transform = 'none';
3441
- }
3442
- }
3443
- dropdown.hidden = false;
3444
- if (btn) btn.setAttribute('aria-expanded', 'true');
3445
- }
3459
+ if (otherBtn) otherBtn.setAttribute('aria-expanded', 'false');
3460
+ }
3461
+ }
3462
+ const btn = els[btnId] || document.getElementById(btnId);
3463
+ dropdown.hidden = false;
3464
+ positionCoachDropdown(dropdown, btn);
3465
+ if (btn) btn.setAttribute('aria-expanded', 'true');
3466
+ }
3446
3467
 
3447
3468
  // R4/R5/R6: open a dropdown and move focus to the first menu item (keyboard activation path).
3448
3469
  function openCoachDropdownFocused(dropdownId, btnId) {
@@ -3452,13 +3473,15 @@ function openCoachDropdownFocused(dropdownId, btnId) {
3452
3473
  }
3453
3474
 
3454
3475
  // R4/R5/R6: close a coaching dropdown.
3455
- function closeCoachDropdown(dropdownId, btnId) {
3456
- const dropdown = els[dropdownId] || document.getElementById(dropdownId);
3457
- if (!dropdown) return;
3458
- dropdown.hidden = true;
3459
- const btn = els[btnId] || document.getElementById(btnId);
3460
- if (btn) btn.setAttribute('aria-expanded', 'false');
3461
- }
3476
+ function closeCoachDropdown(dropdownId, btnId) {
3477
+ const dropdown = els[dropdownId] || document.getElementById(dropdownId);
3478
+ if (!dropdown) return;
3479
+ dropdown.hidden = true;
3480
+ dropdown.style.visibility = '';
3481
+ dropdown.style.maxHeight = '';
3482
+ const btn = els[btnId] || document.getElementById(btnId);
3483
+ if (btn) btn.setAttribute('aria-expanded', 'false');
3484
+ }
3462
3485
 
3463
3486
  // R4/R5/R6: close all coaching dropdowns.
3464
3487
  function closeAllCoachDropdowns() {
@@ -6018,10 +6041,11 @@ async function continueRun(text, options) {
6018
6041
  const coachingJobId = state.pendingCoachingJobId || undefined;
6019
6042
  clearPendingCoachingJob();
6020
6043
  if (!opts.preserveReviewApproved) conv.reviewApproved = false;
6021
- // #549 R6/AC6.1: Clear the stopped flag before starting the new run so
6022
- // stopped-state indicators are removed on the next render tick.
6023
- conv.stopped = false;
6024
- conv.status = 'running';
6044
+ // #549 R6/AC6.1: Clear the stopped flag before starting the new run so
6045
+ // stopped-state indicators are removed on the next render tick.
6046
+ conv.stopped = false;
6047
+ delete conv.pauseReason;
6048
+ conv.status = 'running';
6025
6049
  upsertConversation(conv);
6026
6050
  refreshStatusSurfaces(); // #533 R5: also recolor the tree/area dots back to working
6027
6051
  renderActive();
@@ -6146,9 +6170,12 @@ function foldRunIntoConversation(conv, run) {
6146
6170
  conv.artifacts = [];
6147
6171
  }
6148
6172
  // Update status.
6149
- if (run.status === 'completed') conv.status = 'completed';
6150
- else if (run.status === 'failed') conv.status = 'failed';
6151
- else conv.status = 'running';
6173
+ if (run.status === 'completed') conv.status = 'completed';
6174
+ else if (run.status === 'failed') conv.status = 'failed';
6175
+ else {
6176
+ conv.status = 'running';
6177
+ delete conv.pauseReason;
6178
+ }
6152
6179
  // Issue #904: carry auxiliary exit classification so conversationUiState
6153
6180
  // can derive the correct pill without heuristics.
6154
6181
  if (run.pauseReason !== undefined) conv.pauseReason = run.pauseReason;
@@ -7097,15 +7124,17 @@ function wireEvents() {
7097
7124
  });
7098
7125
  }
7099
7126
  for (const [dropdownId, btnId] of COACH_DROPDOWN_PAIRS) wireCoachDropdownBtn(btnId, dropdownId);
7100
- document.addEventListener('click', (e) => {
7101
- const openDropdown = COACH_DROPDOWN_PAIRS
7102
- .some(([id]) => { const d = els[id] || document.getElementById(id); return d && !d.hidden; });
7103
- if (!openDropdown) return;
7104
- const inDropdown = e.target.closest('.coach-dropdown');
7105
- if (!inDropdown) closeAllCoachDropdowns();
7106
- });
7107
- // Keyboard navigation for coaching dropdowns (WCAG 2.1 SC 2.1.1).
7108
- document.addEventListener('keydown', (e) => {
7127
+ document.addEventListener('click', (e) => {
7128
+ const openDropdown = COACH_DROPDOWN_PAIRS
7129
+ .some(([id]) => { const d = els[id] || document.getElementById(id); return d && !d.hidden; });
7130
+ if (!openDropdown) return;
7131
+ const inDropdown = e.target.closest('.coach-dropdown');
7132
+ if (!inDropdown) closeAllCoachDropdowns();
7133
+ });
7134
+ window.addEventListener('resize', positionOpenCoachDropdowns);
7135
+ document.addEventListener('scroll', positionOpenCoachDropdowns, true);
7136
+ // Keyboard navigation for coaching dropdowns (WCAG 2.1 SC 2.1.1).
7137
+ document.addEventListener('keydown', (e) => {
7109
7138
  if (!['ArrowDown', 'ArrowUp', 'Escape'].includes(e.key)) return;
7110
7139
  for (const [dropdownId, btnId] of COACH_DROPDOWN_PAIRS) {
7111
7140
  const dropdown = els[dropdownId] || document.getElementById(dropdownId);
@@ -1382,12 +1382,15 @@ img.coach-employee-avatar { object-fit: cover; border-radius: 4px; }
1382
1382
  position: relative;
1383
1383
  display: inline-flex;
1384
1384
  }
1385
- .coach-dropdown-menu {
1386
- position: fixed;
1387
- min-width: 200px;
1388
- background: var(--surface);
1389
- border: 1px solid var(--line);
1390
- border-radius: 8px;
1385
+ .coach-dropdown-menu {
1386
+ position: fixed;
1387
+ min-width: 200px;
1388
+ max-height: min(280px, calc(100vh - 16px));
1389
+ box-sizing: border-box;
1390
+ overflow-y: auto;
1391
+ background: var(--surface);
1392
+ border: 1px solid var(--line);
1393
+ border-radius: 8px;
1391
1394
  box-shadow: var(--shadow-lg);
1392
1395
  padding: 4px;
1393
1396
  z-index: var(--z-dropdown-menu);
@@ -3013,9 +3016,13 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3013
3016
  /* Learnings */
3014
3017
  .learn-card { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 12px 16px; display: flex; align-items: flex-start; gap: 12px; margin-bottom: 8px; }
3015
3018
  .lc-scope { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 2px 8px; border-radius: 8px; flex-shrink: 0; white-space: nowrap; }
3016
- .scope-org { background: var(--accent-soft); color: var(--accent); }
3017
- .scope-mgr { background: rgba(139,95,191,.12); color: #7b46bc; }
3018
- .scope-proj { background: rgba(46,125,50,.1); color: var(--done); }
3019
+ .scope-org { background: var(--accent-soft); color: var(--accent); }
3020
+ .scope-mgr { background: rgba(139,95,191,.12); color: #7b46bc; }
3021
+ .scope-proj { background: rgba(46,125,50,.1); color: var(--done); }
3022
+ :root[data-theme="dark"] .scope-mgr {
3023
+ background: rgba(172,135,255,.18);
3024
+ color: #d6c5ff;
3025
+ }
3019
3026
  .lc-body { flex: 1; min-width: 0; }
3020
3027
  .lc-text { font-size: 13px; color: var(--text); line-height: 1.55; }
3021
3028
  .lc-meta { font-size: 11px; color: var(--muted); margin-top: 3px; }
@@ -3036,8 +3043,13 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3036
3043
  /* Overview grid */
3037
3044
  #proj-overview { flex: 1; overflow-y: auto; }
3038
3045
  .proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; padding: 20px 18px; }
3039
- .proj-card { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; cursor: pointer; transition: box-shadow .12s; }
3040
- .proj-card:hover { box-shadow: 0 4px 14px rgba(0,0,0,.10); }
3046
+ .proj-card { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; cursor: pointer; transition: box-shadow .12s; }
3047
+ .proj-card:hover { box-shadow: 0 4px 14px rgba(0,0,0,.10); }
3048
+ :root[data-theme="dark"] .proj-card {
3049
+ background: color-mix(in srgb, var(--surface) 92%, var(--bg));
3050
+ border-color: rgba(255,255,255,.12);
3051
+ }
3052
+ :root[data-theme="dark"] .proj-card:hover { box-shadow: 0 4px 18px rgba(0,0,0,.34); }
3041
3053
  .proj-card-add { display: flex; align-items: center; justify-content: center; border-style: dashed; color: var(--muted); font-size: 13px; min-height: 120px; }
3042
3054
  .proj-name { font-size: 14px; font-weight: 700; margin-bottom: 4px; }
3043
3055
  .proj-brief { font-size: 12px; color: var(--muted); line-height: 1.4; margin-bottom: 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
@@ -3075,7 +3087,7 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3075
3087
  .area-rail-info-btn:hover { background: var(--bg); }
3076
3088
  .area-rail-info-btn.info-active { color: var(--accent); background: var(--accent-soft); }
3077
3089
  /* #594 R2: area-level conversation panel (Company/Manager tab inline run view) — kept for reference */
3078
- .area-page-conv { display: flex; flex-direction: column; gap: 0; margin: 0 0 20px; background: var(--card, #fff); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
3090
+ .area-page-conv { display: flex; flex-direction: column; gap: 0; margin: 0 0 20px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
3079
3091
  .area-conv-topline { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
3080
3092
  .area-conv-thread { flex: 1; max-height: 340px; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
3081
3093
  .area-conv-empty { font-size: 13px; color: var(--muted); margin: 0; }
@@ -3083,7 +3095,7 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3083
3095
  .area-conv-msg--manager .area-conv-msg-text { align-self: flex-end; background: var(--accent-soft, #eef4ff); border-radius: 10px 10px 2px 10px; padding: 8px 12px; font-size: 13px; color: var(--text); max-width: 80%; margin: 0; }
3084
3096
  .area-conv-msg--employee .area-conv-msg-text { align-self: flex-start; background: var(--surface, #f8f8f8); border: 1px solid var(--line); border-radius: 10px 10px 10px 2px; padding: 8px 12px; font-size: 13px; color: var(--text); max-width: 80%; margin: 0; white-space: pre-wrap; }
3085
3097
  .area-conv-coach { display: flex; align-items: flex-end; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--line); background: var(--bg, #fafafa); }
3086
- .area-conv-coach-ta { flex: 1; resize: none; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--card, #fff); outline: none; min-height: 38px; }
3098
+ .area-conv-coach-ta { flex: 1; resize: none; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--surface); outline: none; min-height: 38px; }
3087
3099
  .area-conv-coach-ta:focus { border-color: var(--accent); }
3088
3100
  .area-conv-coach-send { flex-shrink: 0; font-size: 13px; font-weight: 600; color: #fff; background: var(--accent, #0071e3); border: none; border-radius: 8px; padding: 8px 16px; cursor: pointer; height: 38px; }
3089
3101
  .area-conv-coach-send:hover { filter: brightness(1.08); }
@@ -3109,16 +3121,35 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3109
3121
  .obi-cancel { font-size: 14px; font-weight: 500; color: var(--muted, #666); background: none; border: none; padding: 10px 14px; cursor: pointer; }
3110
3122
  .obi-start { font-size: 14px; font-weight: 600; color: #fff; background: var(--accent, #1f6feb); border: none; border-radius: 8px; padding: 10px 18px; cursor: pointer; }
3111
3123
  .obi-start:hover { filter: brightness(1.05); }
3112
- .ctx-acc { border: 1px solid var(--line); border-radius: 12px; margin-bottom: 10px; overflow: hidden; background: var(--surface); }
3113
- .ctx-acc > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 9px; padding: 11px 14px; font-size: 12px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
3114
- .ctx-acc > summary::-webkit-details-marker { display: none; }
3115
- .ctx-acc > summary:hover { background: var(--bg); }
3124
+ .ctx-acc { border: 1px solid var(--line); border-radius: 12px; margin-bottom: 10px; overflow: hidden; background: var(--surface); }
3125
+ .ctx-acc > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 9px; padding: 11px 14px; font-size: 12px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
3126
+ .ctx-acc > summary::-webkit-details-marker { display: none; }
3127
+ .ctx-acc > summary:hover { background: var(--bg); }
3116
3128
  .ctx-acc > summary .ca-chev { font-size: 10px; color: var(--muted); transition: transform .15s; }
3117
3129
  .ctx-acc[open] > summary .ca-chev { transform: rotate(90deg); }
3118
3130
  .ctx-acc > summary .ca-note { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 11px; color: var(--muted); }
3119
3131
  /* #ai-hub-polish F2: a long section must not bury the others. Cap the body and
3120
3132
  let it scroll internally so every accordion header stays reachable. */
3121
- .ctx-acc-body { padding: 4px 14px 14px; max-height: min(62vh, 620px); overflow-y: auto; }
3133
+ .ctx-acc-body { padding: 4px 14px 14px; max-height: min(62vh, 620px); overflow-y: auto; }
3134
+
3135
+ :root[data-theme="dark"] .ctx-acc {
3136
+ background: #242424;
3137
+ border-color: rgba(255,255,255,.13);
3138
+ box-shadow: 0 1px 0 rgba(255,255,255,.03) inset;
3139
+ }
3140
+ :root[data-theme="dark"] .ctx-acc > summary {
3141
+ background: #262626;
3142
+ color: #b7b7b7;
3143
+ }
3144
+ :root[data-theme="dark"] .ctx-acc > summary:hover {
3145
+ background: #2e2e2e;
3146
+ }
3147
+ :root[data-theme="dark"] .ctx-acc[open] > summary {
3148
+ border-bottom: 1px solid rgba(255,255,255,.10);
3149
+ }
3150
+ :root[data-theme="dark"] .ctx-acc-body {
3151
+ background: #202020;
3152
+ }
3122
3153
 
3123
3154
  /* #ai-hub-polish F1: ease the open/close instead of snapping. Animate the
3124
3155
  <details> content slot; interpolate-size lets block-size animate to/from auto.
@@ -3148,14 +3179,14 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3148
3179
  min-height: 0;
3149
3180
  position: relative;
3150
3181
  }
3151
- .proj-switch-mask {
3182
+ .proj-switch-mask {
3152
3183
  position: absolute;
3153
3184
  inset: 0;
3154
3185
  z-index: 30;
3155
3186
  display: none;
3156
3187
  align-items: center;
3157
3188
  justify-content: center;
3158
- background: rgba(250, 250, 250, .74);
3189
+ background: color-mix(in srgb, var(--bg) 74%, transparent);
3159
3190
  backdrop-filter: blur(2px);
3160
3191
  pointer-events: auto;
3161
3192
  }
@@ -3175,10 +3206,10 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
3175
3206
  font-size: 13px;
3176
3207
  font-weight: 600;
3177
3208
  }
3178
- .proj-switch-spinner {
3209
+ .proj-switch-spinner {
3179
3210
  width: 16px;
3180
3211
  height: 16px;
3181
- border: 2px solid rgba(0, 0, 0, .14);
3212
+ border: 2px solid color-mix(in srgb, var(--text) 14%, transparent);
3182
3213
  border-top-color: var(--accent);
3183
3214
  border-radius: 50%;
3184
3215
  flex: 0 0 auto;
@@ -4310,10 +4341,18 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
4310
4341
  .stat-lbl { font-size: 12px; color: var(--muted); margin-top: 2px; }
4311
4342
 
4312
4343
  /* ── D18: Profile card — better shadow to match mock ── */
4313
- .card.area-profile {
4314
- box-shadow: 0 1px 3px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04);
4315
- border: none;
4316
- }
4344
+ .card.area-profile {
4345
+ box-shadow: var(--shadow);
4346
+ border: none;
4347
+ }
4348
+ :root[data-theme="dark"] .card.area-profile {
4349
+ background: #2a2a2a;
4350
+ border: 1px solid rgba(255,255,255,.12);
4351
+ box-shadow: var(--shadow-lg);
4352
+ }
4353
+ :root[data-theme="dark"] .syn-row {
4354
+ border-bottom-color: rgba(255,255,255,.10);
4355
+ }
4317
4356
 
4318
4357
  /* ── D19: Hide lh-run button from default learnings head — only show when pending ── */
4319
4358
  /* The JS always renders it; suppress via CSS for default display */
@@ -4822,9 +4861,29 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
4822
4861
  .prt-hire-btn { font-size:11px; font-weight:700; color:#fff; background:var(--accent,#0071e3); border:none; border-radius:6px; padding:4px 12px; cursor:pointer; margin-top:2px; }
4823
4862
  .prt-hire-btn:hover { background:var(--accent-hover,#005bbf); }
4824
4863
  .prt-price { font-size:10px; color:var(--sub); margin-top:1px; }
4825
- .manager-no-team-msg { font-size:13px; color:var(--sub); margin:0 0 10px; }
4826
- .manager-go-company-btn { font-size:12px; font-weight:600; color:var(--accent,#0071e3); background:var(--accent-soft,rgba(0,113,227,.08)); border:1px solid var(--accent,#0071e3); border-radius:6px; padding:5px 13px; cursor:pointer; }
4827
- .manager-go-company-btn:hover { background:var(--accent-soft,rgba(0,113,227,.15)); }
4864
+ .manager-no-team-msg { font-size:13px; color:var(--sub); margin:0 0 10px; }
4865
+ .manager-go-company-btn { font-size:12px; font-weight:600; color:var(--accent,#0071e3); background:var(--accent-soft,rgba(0,113,227,.08)); border:1px solid var(--accent,#0071e3); border-radius:6px; padding:5px 13px; cursor:pointer; }
4866
+ .manager-go-company-btn:hover { background:var(--accent-soft,rgba(0,113,227,.15)); }
4867
+ :root[data-theme="dark"] .manager-no-team-msg,
4868
+ :root[data-theme="dark"] .learn-empty,
4869
+ :root[data-theme="dark"] .le-count {
4870
+ color: var(--text);
4871
+ background: #2a2a2a;
4872
+ border: 1px solid rgba(255,255,255,.12);
4873
+ border-radius: 10px;
4874
+ }
4875
+ :root[data-theme="dark"] .le-sub,
4876
+ :root[data-theme="dark"] .manager-no-team-msg {
4877
+ color: var(--muted);
4878
+ }
4879
+ :root[data-theme="dark"] .manager-go-company-btn {
4880
+ color: #fff;
4881
+ background: var(--accent);
4882
+ border-color: var(--accent);
4883
+ }
4884
+ :root[data-theme="dark"] .manager-go-company-btn:hover {
4885
+ background: var(--accent-strong);
4886
+ }
4828
4887
 
4829
4888
  /* ── Issue #540: AI Hub hiring surfaces ── */
4830
4889
 
@@ -5125,13 +5184,40 @@ img.eh-av { object-fit: cover; background: var(--surface); }
5125
5184
  justify-content: flex-end;
5126
5185
  }
5127
5186
 
5128
- .configured-agent-card {
5129
- border: 1px solid var(--line);
5130
- border-radius: 8px;
5131
- background: var(--surface);
5132
- padding: 10px 12px;
5133
- min-width: 0;
5134
- }
5187
+ .configured-agent-card {
5188
+ border: 1px solid var(--line);
5189
+ border-radius: 8px;
5190
+ background: var(--surface);
5191
+ padding: 10px 12px;
5192
+ min-width: 0;
5193
+ }
5194
+ :root[data-theme="dark"] .configured-agent-card,
5195
+ :root[data-theme="dark"] .configured-agent-form,
5196
+ :root[data-theme="dark"] .learn-card,
5197
+ :root[data-theme="dark"] .learn-prop,
5198
+ :root[data-theme="dark"] .team-row,
5199
+ :root[data-theme="dark"] .persona-card,
5200
+ :root[data-theme="dark"] .persona-roster-tile {
5201
+ background: #2a2a2a;
5202
+ border-color: rgba(255,255,255,.12);
5203
+ }
5204
+ :root[data-theme="dark"] .configured-agent-action,
5205
+ :root[data-theme="dark"] .configured-agent-icon-action {
5206
+ background: #323232;
5207
+ border-color: rgba(255,255,255,.14);
5208
+ color: var(--text);
5209
+ }
5210
+ :root[data-theme="dark"] .configured-agent-action.primary {
5211
+ background: var(--accent);
5212
+ border-color: var(--accent);
5213
+ color: #fff;
5214
+ }
5215
+ :root[data-theme="dark"] .configured-agent-status.ok {
5216
+ background: rgba(92,184,92,.10);
5217
+ }
5218
+ :root[data-theme="dark"] .configured-agent-status.warn {
5219
+ background: rgba(212,160,78,.10);
5220
+ }
5135
5221
 
5136
5222
  .configured-agent-head {
5137
5223
  display: flex;