beast-agent 2.38.4 → 2.39.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.
@@ -211,6 +211,11 @@ const els = {
211
211
  finSymAdd: $('#finSymAdd'),
212
212
  finSymOverlay: $('#finSymOverlay'),
213
213
  finSymClose: $('#finSymClose'),
214
+ finTeamOverlay: $('#finTeamOverlay'),
215
+ finTeamClose: $('#finTeamClose'),
216
+ finTeamPick: $('#finTeamPick'),
217
+ finTeamCount: $('#finTeamCount'),
218
+ finSetupBtn: $('#finSetupBtn'),
214
219
  finSkillsBtn: $('#finSkillsBtn'),
215
220
  finSkillsOverlay: $('#finSkillsOverlay'),
216
221
  finSkillsClose: $('#finSkillsClose'),
@@ -9357,15 +9362,31 @@ function finTraderInputsSet(cfg) {
9357
9362
  if (els.finTraderModel && ae !== els.finTraderModel && cfg.traderSel) els.finTraderModel.value = cfg.traderSel;
9358
9363
  }
9359
9364
 
9360
- /* ANALİZ EKİBİ: SADECE SAYI seçilir — rolleri sistem otomatik atar
9361
- (FIN_ROLES_AUTO sırası: Teknik → Risk → Haber). Elle rol kutucukları
9362
- kaldırıldı; analysisAuto sunucuda daima açık. Katalog sunucudan gelir. */
9365
+ /* ANALİZ EKİBİ: tek satır çoklu seçim picker'ı — hangi uzman ajanların
9366
+ koşacağını seçersin (Risk / Teknik / Haber / Görsel); sayaç rozeti seçili
9367
+ ajan sayısını gösterir. Katalog sunucudan gelir (finance:state roles). */
9368
+ /* Ekip düğmesi ikonu: emoji yerine çizgi SVG (beyin) — tema rengiyle uyumlu */
9369
+ const FIN_TEAM_SVG =
9370
+ '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px">' +
9371
+ '<path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/>' +
9372
+ '<path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/>' +
9373
+ '<path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/>' +
9374
+ '<path d="M17.599 6.5a3 3 0 0 0 .399-1.375"/>' +
9375
+ '<path d="M6.003 5.125A3 3 0 0 0 6.401 6.5"/>' +
9376
+ '<path d="M3.477 10.896a4 4 0 0 1 .585-.396"/>' +
9377
+ '<path d="M19.938 10.5a4 4 0 0 1 .585.396"/>' +
9378
+ '<path d="M6 18a4 4 0 0 1-1.967-.516"/>' +
9379
+ '<path d="M19.967 17.484A4 4 0 0 1 18 18"/></svg>';
9380
+ function finTeamBtnPaint(btn, n) {
9381
+ if (btn) btn.innerHTML = FIN_TEAM_SVG + '<span>Ekip: ' + n + ' ajan</span>';
9382
+ }
9363
9383
  let finRolesCatalog = [
9364
9384
  { id: 'risk', label: 'Risk Ajanı', desc: 'marj/kaldıraç/SL disiplini, exposure ve günlük kayıp hızı denetimi' },
9365
9385
  { id: 'technic', label: 'Teknik Analiz', desc: 'trend/yapı/destek-direnç/momentum okuma, AL-SAT-BEKLE önerileri' },
9366
9386
  { id: 'macro', label: 'Haber / Makro', desc: 'haber akışı + ekonomik takvim, DXY/emtia bağıntıları, yön eğilimi' },
9387
+ { id: 'visual', label: 'Görsel Ajan', desc: 'MT5 grafiği/ekran görüntüsü — trend, formasyon, seviye ve mum yapısını görsel doğrulama' },
9367
9388
  ];
9368
- let finRolesAuto = ['technic', 'risk', 'macro'];
9389
+ let finRolesAuto = ['technic', 'risk', 'macro', 'visual'];
9369
9390
  let finRolesDirty = false; /* tık→kaydet arası snapshot ezmesin */
9370
9391
  let finRolesSyncTimer = null;
9371
9392
 
@@ -9374,45 +9395,93 @@ function finRoleLabel(id) {
9374
9395
  return d ? d.label : String(id || '');
9375
9396
  }
9376
9397
 
9398
+ /* Etkin ekip listesi: oto modda ilk N rol, elle modda seçilen roller */
9399
+ function finTeamSelectedIds(cfg) {
9400
+ const c = cfg || finCfgCache || {};
9401
+ if (c.analysisAuto !== false) {
9402
+ const n = Math.max(0, Math.min((finRolesAuto || []).length || 4, Math.round(Number(c.analysisCount) || 0)));
9403
+ return (finRolesAuto || []).slice(0, n);
9404
+ }
9405
+ return (Array.isArray(c.analysisTeam) ? c.analysisTeam : []).filter((id) =>
9406
+ (finRolesCatalog || []).some((d) => d.id === id)
9407
+ );
9408
+ }
9409
+
9410
+ /* tek satır: buton (seçili sayı) + seçili rol adları özeti */
9377
9411
  function finRenderRoles(cfg) {
9378
9412
  const box = els.finRoles;
9379
9413
  if (!box) return;
9380
9414
  if (finRolesDirty) return; /* bekleyen kullanıcı değişikliği korunur */
9381
- const max = Math.max(1, (finRolesAuto || []).length || 3);
9382
- const count = Math.max(0, Math.min(max, Math.round(Number(cfg && cfg.analysisCount) || 0)));
9415
+ const selected = finTeamSelectedIds(cfg);
9383
9416
  box.innerHTML = '';
9384
9417
  const wrap = document.createElement('div');
9385
9418
  wrap.className = 'fin-team';
9386
- const cnt = document.createElement('input');
9387
- cnt.type = 'number';
9388
- cnt.className = 'fin-role-count';
9389
- cnt.min = '0';
9390
- cnt.max = String(max);
9391
- cnt.step = '1';
9392
- cnt.value = String(count);
9393
- cnt.title = 'Kaç uzman ajan koşacak (0 = ekip yok, en fazla ' + max + '). Roller otomatik atanır.';
9419
+ const btn = document.createElement('button');
9420
+ btn.type = 'button';
9421
+ btn.className = 'fin-sym-select fin-team-btn';
9422
+ finTeamBtnPaint(btn, selected.length);
9423
+ btn.title = 'Uzman ajanları çoktan seç — seçilen her rol AYRI sürekli ajan olarak koşar (işlem açmaz)';
9394
9424
  const hint = document.createElement('span');
9395
9425
  hint.className = 'fin-team-hint';
9396
- const names = (n) => finRolesAuto.slice(0, n).map(finRoleLabel);
9397
- const paint = (n) => {
9398
- hint.textContent = n > 0 ? 'otomatik: ' + names(n).join(' · ') : 'ekip kapalı — sadece trader koşar';
9399
- };
9400
- cnt.addEventListener('change', () => {
9401
- const n = Math.max(0, Math.min(max, Math.round(Number(cnt.value) || 0)));
9402
- cnt.value = String(n);
9403
- finRolesDirty = true;
9404
- finSaveCfg({ analysisAuto: true, analysisCount: n });
9405
- paint(n);
9406
- toast(n ? 'Analiz ekibi: ' + n + ' ajan — ' + names(n).join(', ') : 'Analiz ekibi kapatıldı');
9407
- clearTimeout(finRolesSyncTimer);
9408
- finRolesSyncTimer = setTimeout(() => { finRolesDirty = false; finSnapshot(); }, 900);
9409
- });
9410
- paint(count);
9411
- wrap.appendChild(cnt);
9426
+ hint.textContent = selected.length
9427
+ ? ((cfg && cfg.analysisAuto !== false) ? 'oto: ' : '') + selected.map(finRoleLabel).join(', ')
9428
+ : 'ekip kapalı — sadece trader koşar';
9429
+ btn.addEventListener('click', finTeamPickerOpen);
9430
+ wrap.appendChild(btn);
9412
9431
  wrap.appendChild(hint);
9413
9432
  box.appendChild(wrap);
9414
9433
  }
9415
9434
 
9435
+ /* picker modalı: çoklu checkbox listesi — her değişiklik ANINDA kaydedilir */
9436
+ function finTeamPickerPaint() {
9437
+ const pick = els.finTeamPick;
9438
+ if (!pick) return;
9439
+ const sel = new Set(finTeamSelectedIds());
9440
+ if (els.finTeamCount) els.finTeamCount.textContent = sel.size ? sel.size + ' seçili' : 'kapalı';
9441
+ pick.innerHTML = '';
9442
+ for (const d of finRolesCatalog || []) {
9443
+ const row = document.createElement('label');
9444
+ row.className = 'fin-team-item';
9445
+ row.title = d.desc || '';
9446
+ const cb = document.createElement('input');
9447
+ cb.type = 'checkbox';
9448
+ cb.checked = sel.has(d.id);
9449
+ cb.dataset.role = d.id;
9450
+ cb.addEventListener('change', () => {
9451
+ const ids = [...pick.querySelectorAll('input[data-role]')].filter((x) => x.checked).map((x) => x.dataset.role);
9452
+ finRolesDirty = true;
9453
+ finCfgCache = finCfgCache || {};
9454
+ finCfgCache.analysisAuto = false;
9455
+ finCfgCache.analysisTeam = ids;
9456
+ finSaveCfg({ analysisAuto: false, analysisTeam: ids });
9457
+ if (els.finTeamCount) els.finTeamCount.textContent = ids.length ? ids.length + ' seçili' : 'kapalı';
9458
+ const btn = els.finRoles && els.finRoles.querySelector('.fin-team-btn');
9459
+ const hint = els.finRoles && els.finRoles.querySelector('.fin-team-hint');
9460
+ finTeamBtnPaint(btn, ids.length);
9461
+ if (hint) hint.textContent = ids.length ? ids.map(finRoleLabel).join(', ') : 'ekip kapalı — sadece trader koşar';
9462
+ toast(ids.length ? 'Analiz ekibi: ' + ids.length + ' ajan — ' + ids.map(finRoleLabel).join(', ') : 'Analiz ekibi kapatıldı');
9463
+ clearTimeout(finRolesSyncTimer);
9464
+ finRolesSyncTimer = setTimeout(() => { finRolesDirty = false; finSnapshot(); }, 900);
9465
+ });
9466
+ const txt = document.createElement('span');
9467
+ txt.className = 'fin-team-txt';
9468
+ txt.innerHTML = '<b>' + escapeHtml(d.label) + '</b><i>' + escapeHtml(d.desc || '') + '</i>';
9469
+ row.appendChild(cb);
9470
+ row.appendChild(txt);
9471
+ pick.appendChild(row);
9472
+ }
9473
+ }
9474
+
9475
+ function finTeamPickerOpen() {
9476
+ if (!els.finTeamOverlay) return;
9477
+ finTeamPickerPaint();
9478
+ els.finTeamOverlay.hidden = false;
9479
+ }
9480
+
9481
+ function finTeamPickerClose() {
9482
+ if (els.finTeamOverlay) els.finTeamOverlay.hidden = true;
9483
+ }
9484
+
9416
9485
  function finRenderTrader(trader, cfg) {
9417
9486
  if (!els.finTraderBtn) return;
9418
9487
  const on = !!(trader && trader.on);
@@ -9966,8 +10035,11 @@ function finAdvPaint() {
9966
10035
  const on = (() => { try { return localStorage.getItem(finAdvKey) === '1'; } catch { return false; } })();
9967
10036
  if (els.finAdvWrap) els.finAdvWrap.hidden = !on;
9968
10037
  if (els.finAdvToggle) {
9969
- els.finAdvToggle.textContent = (on ? '\u25BE' : '\u25B8') + ' Gelişmiş';
10038
+ els.finAdvToggle.classList.toggle('on', on);
9970
10039
  els.finAdvToggle.setAttribute('aria-expanded', on ? 'true' : 'false');
10040
+ els.finAdvToggle.title = on
10041
+ ? 'Gelişmiş açık — disiplin kuralları + shadow mod (kapat)'
10042
+ : 'Gelişmiş — disiplin kuralları + shadow mod';
9971
10043
  }
9972
10044
  }
9973
10045
  if (els.finAdvToggle) {
@@ -10049,6 +10121,20 @@ if (els.finModelRefreshBtn) {
10049
10121
  }
10050
10122
  });
10051
10123
  }
10124
+ if (els.finSetupBtn) {
10125
+ els.finSetupBtn.addEventListener('click', async () => {
10126
+ els.finSetupBtn.disabled = true;
10127
+ const r = await beast.financeMt5Setup().catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
10128
+ els.finSetupBtn.disabled = false;
10129
+ if (r && r.ok) {
10130
+ toast(r.changed
10131
+ ? 'MT5 kurulumu uygulandı' + (r.restartRequired ? ' — MT5 yeniden başlatılınca etkin' : '')
10132
+ : 'MT5 kurulumu zaten güncel');
10133
+ } else {
10134
+ toast('MT5 kurulumu: ' + ((r && r.error) || 'başarısız'));
10135
+ }
10136
+ });
10137
+ }
10052
10138
  if (els.finTraderBtn) {
10053
10139
  els.finTraderBtn.addEventListener('click', async () => {
10054
10140
  if (els.finTraderBtn.classList.contains('stop')) {
@@ -10060,8 +10146,12 @@ if (els.finTraderBtn) {
10060
10146
  else if (r && r.ok) {
10061
10147
  const cfg = (await beast.financeState().catch(() => null));
10062
10148
  const c = (cfg && cfg.cfg) || {};
10063
- const team = Math.round(Number(c.analysisCount) || 0);
10149
+ const team = c.analysisAuto === false
10150
+ ? (Array.isArray(c.analysisTeam) ? c.analysisTeam.length : 0)
10151
+ : Math.round(Number(c.analysisCount) || 0);
10064
10152
  toast(team ? 'Trade ajanı + analiz ekibi (' + team + ' uzman) başladı — turlar panelde izlenir' : 'Trade ajanı başladı — turlar panelde izlenir');
10153
+ /* ajanlar arası konuşma için AJAN DM konsolu da açılır */
10154
+ try { toggleDmRail(false); } catch {}
10065
10155
  }
10066
10156
  }
10067
10157
  finSnapshot();
@@ -10228,7 +10318,7 @@ function finRenderSkills() {
10228
10318
  const map = cfg.roleSkills && typeof cfg.roleSkills === 'object' ? cfg.roleSkills : {};
10229
10319
  /* ANA KARAR VERİCİ (trader) da bir satır: playbook skill'i zorunlu tek seçim */
10230
10320
  const roles = [
10231
- { id: 'trader', label: 'TRADER (Ana Karar Verici)', desc: 'playbook: hangi setup\'lar serbest, giriş/çıkış/iptal kuralları, seans ve risk disiplini — asıl karar vericinin zorunlu skill\'i' },
10321
+ { id: 'trader', label: 'TRADER (Ana Karar Verici)', desc: 'playbook: hangi setup\'lar serbest, giriş/çıkış/iptal kuralları, seans ve risk disiplini — asıl karar vericinin skill\'i (boş = ajan kendi seçer)' },
10232
10322
  ].concat(Array.isArray(finRolesCatalog) ? finRolesCatalog : []);
10233
10323
  box.innerHTML = '';
10234
10324
  if (!roles.length) {
@@ -10249,10 +10339,34 @@ function finRenderSkills() {
10249
10339
  '<span>' + escapeHtml(String(r.desc || '').slice(0, 110)) + '</span>';
10250
10340
  const cur = Array.isArray(map[r.id]) ? map[r.id].map((x) => String(x || '').trim()).filter(Boolean) : [];
10251
10341
  const active = cur.length ? cur[0] : '';
10342
+ /* ÇÖP: rolün skill atamasını kaldır — boş bırakmak da geçerli bir seçim
10343
+ (o zaman ajan skill'i göreve göre SKILLS kataloğundan kendi seçer) */
10344
+ const clearBtn = document.createElement('button');
10345
+ clearBtn.type = 'button';
10346
+ clearBtn.className = 'fin-skill-clear';
10347
+ clearBtn.title = active
10348
+ ? 'Skill atamasını kaldır (' + active + ') — boş kalırsa ajan göreve göre kendi seçer'
10349
+ : 'Atama yok — boş bırakılabilir';
10350
+ clearBtn.innerHTML =
10351
+ '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>';
10352
+ clearBtn.addEventListener('click', (e) => {
10353
+ e.preventDefault();
10354
+ e.stopPropagation();
10355
+ const was = active;
10356
+ finCfgCache = finCfgCache || {};
10357
+ finCfgCache.roleSkills = finCfgCache.roleSkills || {};
10358
+ finCfgCache.roleSkills[r.id] = [];
10359
+ finSaveCfg({ roleSkills: { [r.id]: [] } });
10360
+ toast(was
10361
+ ? (r.label || r.id) + ' → ' + was + ' ataması kaldırıldı — ajan göreve göre kendi seçer'
10362
+ : (r.label || r.id) + ' → atama zaten boş');
10363
+ finRenderSkills();
10364
+ });
10365
+ head.appendChild(clearBtn);
10252
10366
  if (!active) {
10253
10367
  const warn = document.createElement('span');
10254
10368
  warn.className = 'fin-skill-req';
10255
- warn.textContent = 'ZORUNLU — skill seçilmedi';
10369
+ warn.textContent = 'atama yok — ajan göreve göre kendi seçer';
10256
10370
  head.appendChild(warn);
10257
10371
  }
10258
10372
  row.appendChild(head);
@@ -10267,7 +10381,7 @@ function finRenderSkills() {
10267
10381
  cb.type = 'radio';
10268
10382
  cb.name = 'fin-skill-role-' + r.id;
10269
10383
  cb.checked = on;
10270
- /* TEK + ZORUNLU: yeni skill seçilir; mevcut seçim kaldırılamaz */
10384
+ /* TEK seçim: yeni skill seçilir; kaldırmak için çöp ikonu kullanılır */
10271
10385
  cb.addEventListener('change', () => {
10272
10386
  if (!cb.checked) return;
10273
10387
  const next = [s.name];
@@ -10280,7 +10394,7 @@ function finRenderSkills() {
10280
10394
  const w = head.querySelector('.fin-skill-req');
10281
10395
  if (w) w.remove();
10282
10396
  finSaveCfg({ roleSkills: { [r.id]: next } });
10283
- toast((r.label || r.id) + ' → ' + s.name + ' (zorunlu tek skill)');
10397
+ toast((r.label || r.id) + ' → ' + s.name + ' (tek skill)');
10284
10398
  });
10285
10399
  chip.appendChild(cb);
10286
10400
  chip.appendChild(document.createTextNode(s.name));
@@ -10335,6 +10449,15 @@ if (els.finSymOverlay) {
10335
10449
  if (e.key === 'Escape') { e.stopPropagation(); finSymPickerClose(); }
10336
10450
  });
10337
10451
  }
10452
+ if (els.finTeamClose) els.finTeamClose.addEventListener('click', finTeamPickerClose);
10453
+ if (els.finTeamOverlay) {
10454
+ els.finTeamOverlay.addEventListener('click', (e) => {
10455
+ if (e.target === els.finTeamOverlay) finTeamPickerClose();
10456
+ });
10457
+ els.finTeamOverlay.addEventListener('keydown', (e) => {
10458
+ if (e.key === 'Escape') { e.stopPropagation(); finTeamPickerClose(); }
10459
+ });
10460
+ }
10338
10461
  if (els.finSymSearch) {
10339
10462
  els.finSymSearch.addEventListener('input', () => {
10340
10463
  clearTimeout(finSymSearchTimer);
@@ -4875,20 +4875,6 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
4875
4875
  .fin-field input:focus, .fin-field select:focus, .fin-field textarea:focus { border-color: var(--accent); outline: none; }
4876
4876
  .fin-time-row { display: flex; gap: 6px; }
4877
4877
  .fin-time-row input { flex: 1; min-width: 0; }
4878
- .fin-adv-toggle {
4879
- display: block;
4880
- width: 100%;
4881
- text-align: left;
4882
- background: none;
4883
- border: none;
4884
- color: var(--muted);
4885
- font-size: 10px;
4886
- font-weight: 800;
4887
- letter-spacing: 0.6px;
4888
- padding: 2px 0 8px;
4889
- cursor: pointer;
4890
- }
4891
- .fin-adv-toggle:hover { color: var(--accent); }
4892
4878
  /* Ajan talimatı: çok satırlı not alanı (dikey büyütülebilir) */
4893
4879
  .fin-field textarea {
4894
4880
  resize: vertical;
@@ -4926,6 +4912,17 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
4926
4912
  .fin-alert .fa-note { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4927
4913
  /* ekib sayısı + otomatik atama özeti */
4928
4914
  .fin-team { display: flex; align-items: center; gap: 8px; min-width: 0; }
4915
+ .fin-team-btn { font-weight: 600; display: inline-flex; align-items: center; gap: 5px; }
4916
+ .fin-team-item {
4917
+ display: flex; align-items: flex-start; gap: 8px;
4918
+ padding: 6px 8px; border-radius: 6px;
4919
+ cursor: pointer;
4920
+ }
4921
+ .fin-team-item:hover { background: var(--panel2); }
4922
+ .fin-team-item input { flex: none; width: auto; margin: 2px 0 0 0; }
4923
+ .fin-team-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
4924
+ .fin-team-txt b { font-size: 12px; color: var(--text); }
4925
+ .fin-team-txt i { font-size: 10.5px; font-style: normal; color: var(--muted); }
4929
4926
  .fin-team-hint {
4930
4927
  flex: 1;
4931
4928
  min-width: 0;
@@ -5030,10 +5027,11 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5030
5027
  .fin-start:hover { filter: brightness(1.08); box-shadow: 0 1px 6px rgba(0, 0, 0, 0.22); }
5031
5028
  .fin-start:active { transform: translateY(1px); filter: brightness(0.96); }
5032
5029
  .fin-start.stop {
5033
- background: #ef4444;
5034
- border-color: #ef4444;
5030
+ background: #b91c1c;
5031
+ border-color: #b91c1c;
5035
5032
  color: #fff; /* kırmızı zeminde beyaz her iki temada da okunur */
5036
5033
  }
5034
+ .fin-start.stop:hover { background: #991b1b; border-color: #991b1b; }
5037
5035
 
5038
5036
  /* TRADE AJANI kartı — vurgulu görünüm (accent çerçeve + yumuşak zemin) */
5039
5037
  .fin-card-trader {
@@ -5148,6 +5146,7 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5148
5146
  border-radius: 5px;
5149
5147
  }
5150
5148
  .fin-card-title button:hover { background: var(--accent-dim); color: var(--accent); }
5149
+ .fin-card-title button.on { background: var(--accent-dim); color: var(--accent); }
5151
5150
 
5152
5151
  /* MT5 sembol seçici modalı */
5153
5152
  .fin-sym-dialog { width: 460px; max-width: calc(100vw - 40px); }
@@ -5233,6 +5232,7 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5233
5232
  gap: 10px;
5234
5233
  }
5235
5234
  .fin-skill-role {
5235
+ position: relative;
5236
5236
  border: 1px solid var(--border);
5237
5237
  border-radius: 8px;
5238
5238
  padding: 8px 9px;
@@ -5241,13 +5241,26 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5241
5241
  .fin-skill-role-head { display: flex; flex-direction: column; gap: 1px; margin-bottom: 7px; }
5242
5242
  .fin-skill-role-head b { font-size: 11.5px; color: var(--text); }
5243
5243
  .fin-skill-role-head span { font-size: 10px; color: var(--muted); }
5244
+ .fin-skill-clear {
5245
+ position: absolute;
5246
+ top: 6px;
5247
+ right: 6px;
5248
+ background: none;
5249
+ border: none;
5250
+ color: var(--muted);
5251
+ line-height: 0;
5252
+ padding: 3px 5px;
5253
+ border-radius: 6px;
5254
+ cursor: pointer;
5255
+ }
5256
+ .fin-skill-clear:hover { color: #ef4444; background: var(--accent-dim); }
5244
5257
  .fin-skill-req {
5245
5258
  align-self: flex-start;
5246
5259
  margin-top: 2px;
5247
5260
  font-size: 9.5px;
5248
5261
  font-weight: 800;
5249
5262
  letter-spacing: 0.5px;
5250
- color: #ef4444;
5263
+ color: var(--muted);
5251
5264
  }
5252
5265
  .fin-skill-chips { display: flex; flex-wrap: wrap; gap: 4px; }
5253
5266
  .fin-skill-chip {