cicy-desktop 2.1.44 → 2.1.46

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.
@@ -1 +1 @@
1
- *{box-sizing:border-box}html,body,#root{margin:0;height:100%}body{font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Segoe UI,Roboto,Helvetica Neue,sans-serif;background:#07080c;color:#e5e7eb;-webkit-font-smoothing:antialiased}.shell{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-app-region:drag}.shell--app{align-items:stretch;justify-content:stretch;flex-direction:row;background:linear-gradient(180deg,#0b0d13,#07080c);overflow:hidden;-webkit-app-region:no-drag}.shell__left{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;overflow:auto}.helper-aside{flex:0 0 auto;position:relative;background:#0f1115;border-left:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;min-width:320px;z-index:1}.helper-aside,.helper-aside *,.shell--app .main{-webkit-app-region:no-drag}.shell--app .topbar{-webkit-app-region:drag}.shell--app .topbar .user-chip,.shell--app .topbar .user-chip *,.shell--app .topbar .btn-ghost{-webkit-app-region:no-drag}.glow{position:absolute;top:-40%;right:-40%;bottom:-40%;left:-40%;z-index:0;pointer-events:none;background:radial-gradient(closest-side,rgba(91,141,247,.2),transparent 60%),radial-gradient(closest-side at 30% 70%,rgba(167,139,250,.13),transparent 65%);filter:blur(30px)}.card{-webkit-app-region:no-drag;position:relative;z-index:1;width:380px;padding:36px 36px 28px;background:linear-gradient(180deg,#141820d9,#0d1016d9);border:1px solid rgba(255,255,255,.06);border-radius:16px;box-shadow:0 1px #ffffff0a inset,0 30px 60px #0006;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);display:flex;flex-direction:column;align-items:center;gap:18px}.brand{display:flex;align-items:center;gap:12px;align-self:stretch}.brand-mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);box-shadow:0 8px 20px #5b8df759}.brand-mark.sm{width:28px;height:28px;border-radius:8px;box-shadow:none}.brand-mark.sm svg{width:16px;height:16px}.brand-text{line-height:1.2}.brand-name{font-weight:600;font-size:15px}.brand-sub{font-size:12px;color:#9ca3af;margin-top:2px}.tagline{margin:4px 0 0;color:#c7cdd6;font-size:13.5px;text-align:center;line-height:1.55}.btn-primary{-webkit-app-region:no-drag;margin-top:4px;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:42px;display:inline-flex;align-items:center;justify-content:center;gap:8px;background:linear-gradient(180deg,#5b8df7,#4570d8);color:#fff;border:0;border-radius:10px;font-size:14px;font-weight:500;letter-spacing:.2px;cursor:pointer;box-shadow:0 1px #ffffff2e inset,0 -1px #0000002e inset,0 10px 22px #5b8df747;transition:transform 80ms ease,filter .12s ease}.btn-primary:hover{filter:brightness(1.08)}.btn-primary:active{transform:translateY(1px)}.btn-primary:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.btn-ghost{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:6px 14px;font-size:12.5px;cursor:pointer;transition:color .12s ease,border-color .12s ease,background .12s ease}.btn-ghost.sm{padding:4px 10px;font-size:11.5px}.btn-ghost:hover{color:#e5e7eb;background:#ffffff0a;border-color:#ffffff24}.btn-ghost:disabled{opacity:.4;cursor:default}.hint{margin:0;font-size:11.5px;color:#6b7280}.spinner-row{display:inline-flex;align-items:center;gap:8px;color:#c7cdd6;font-size:13px}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{width:100%;font-size:12px;color:#fca5a5;background:#ef444414;border:1px solid rgba(239,68,68,.18);padding:8px 12px;border-radius:8px;text-align:center;line-height:1.5}.topbar{-webkit-app-region:drag;position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;padding:14px 24px 12px;background:#08090e99;border-bottom:1px solid rgba(255,255,255,.05);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}[data-platform=darwin][data-fullscreen="0"] .topbar{padding-left:84px}.brand-mini{display:inline-flex;align-items:center;gap:10px}.brand-mini .brand-name{font-size:14px}.user-chip{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:10px}.welcome{font-size:12px;color:#34d399;padding:4px 10px;border-radius:999px;background:#10b9811a;border:1px solid rgba(16,185,129,.25);animation:fadein .2s ease}@keyframes fadein{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}.avatar{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);font-size:12px;font-weight:600;color:#fff}.user-name{font-size:13px;color:#c7cdd6}.glow--app{inset:-10% -10% auto -10%;height:50vh;background:radial-gradient(closest-side at 75% 0%,rgba(91,141,247,.18),transparent 65%),radial-gradient(closest-side at 20% 10%,rgba(167,139,250,.1),transparent 60%);filter:blur(40px)}.main{position:relative;z-index:1;padding:22px 32px 48px;width:100%;display:flex;flex-direction:column;gap:16px}.app__tabs{display:inline-flex;align-items:center;gap:4px;padding:4px;background:#1418208c;border:1px solid rgba(255,255,255,.06);border-radius:10px;align-self:flex-start;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.app__tab{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:0;border-radius:7px;padding:6px 14px;font-size:12.5px;font-weight:500;letter-spacing:.15px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:color .12s ease,background .12s ease}.app__tab:hover{color:#e5e7eb;background:#ffffff0a}.app__tab.is-active{color:#fff;background:#5b8df72e;box-shadow:0 0 0 1px #5b8df74d inset}.app__tab-count{font-size:10.5px;color:#9ca3af;background:#ffffff0f;padding:1px 6px;border-radius:999px;min-width:18px;text-align:center}.app__tab.is-active .app__tab-count{background:#5b8df74d;color:#fff}.app__grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.add-card{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:200px;height:200px;background:transparent;border:1.5px dashed rgba(255,255,255,.12);border-radius:14px;color:#9ca3af;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;transition:border-color .16s ease,color .16s ease,background .16s ease}.add-card:hover{border-color:#5b8df780;color:#e5e7eb;background:#5b8df70d}.add-card__plus{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;background:#ffffff0a;font-size:22px;font-weight:300;color:inherit}.add-card__label{font-size:13px;font-weight:500}.bcard--helper{background:linear-gradient(160deg,#5b8df729,#a78bfa24 60%,#1418208c);border-color:#a78bfa40}.bcard--helper .bcard__accent{background:linear-gradient(90deg,#5b8df7,#a78bfa);opacity:1}.bcard--helper:hover{border-color:#a78bfa73}.bcard__pill--helper{background:#a78bfa2e;border-color:#a78bfa4d;color:#c4b5fd;font-size:11px;font-weight:600;letter-spacing:.2px}.bcard__helper-icon{font-size:12px;filter:grayscale(.2)}.bcard__badge--free{background:#34d39926;color:#34d399;border:1px solid rgba(52,211,153,.3)}.bcard__badge--trial{background:#fbbf2426;color:#fcd34d;border:1px solid rgba(251,191,36,.3);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard__badge--local{background:#5b8df72e;color:#a5c4ff;border:1px solid rgba(91,141,247,.35);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard--helper .bcard__name{color:#f3f4f6}.bcard__desc{margin:4px 0 0;font-size:11.5px;line-height:1.5;color:#c7cdd6;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.bcard__fineprint{margin:4px 0 0;font-size:10.5px;color:#9ca3af;opacity:.8}.bcard__cta--helper{background:linear-gradient(90deg,#5b8df7,#a78bfa);box-shadow:0 6px 18px -4px #a78bfa73}.bcard__cta--helper:hover{filter:brightness(1.1)}.helper-aside__top{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid rgba(255,255,255,.05)}.helper-aside__title{font-size:12.5px;font-weight:600;color:#c7cdd6}.helper-aside__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:#6b7280;font-size:20px;line-height:1;width:26px;height:26px;border-radius:6px;cursor:pointer;transition:color .12s ease,background .12s ease}.helper-aside__close:hover{color:#e5e7eb;background:#ffffff0f}.helper-modal__backdrop{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:transparent;z-index:20;animation:fadein .14s ease;padding:16px;pointer-events:auto}.helper-modal{width:min(360px,100%);background:linear-gradient(180deg,#1f2733,#1a2029);border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:20px 22px 16px;color:#e5e7eb;box-shadow:0 24px 48px -12px #0009,0 1px #ffffff14 inset;animation:fadein .18s ease}.helper-modal__title{font-size:14px;font-weight:600;color:#f3f4f6;margin-bottom:8px}.helper-modal__desc{font-size:12.5px;line-height:1.6;color:#b6bcc6;margin-bottom:18px}.helper-modal__desc code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11.5px;padding:1px 6px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);border-radius:4px;color:#e7eaef}.helper-modal__actions{display:flex;align-items:center;justify-content:flex-end;gap:8px}.helper-modal__btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#ffffff0f;color:#d2d6dd;border:1px solid rgba(255,255,255,.1);border-radius:7px;padding:7px 14px;font-size:12.5px;font-weight:500;cursor:pointer;transition:background .12s ease,color .12s ease,transform 80ms ease}.helper-modal__btn:hover{background:#ffffff1a;color:#fff}.helper-modal__btn:active{transform:translateY(1px)}.helper-modal__btn--ghost{background:transparent;border-color:transparent;color:#ffffff8c;margin-right:auto;padding-left:4px;padding-right:4px}.helper-modal__btn--ghost:hover{background:transparent;color:#ffffffd9}.helper-modal__btn--primary{background:linear-gradient(180deg,#5b8df7,#4570d8);border-color:#ffffff2e;color:#fff}.helper-modal__btn--primary:hover{background:linear-gradient(180deg,#6c9af9,#5a82e0)}.helper-modal__btn:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.helper-placeholder{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 40px;text-align:center;color:#9ca3af}.helper-placeholder__mark{font-size:48px;line-height:1;filter:grayscale(.2);opacity:.85}.helper-placeholder__title{margin:0;font-size:16px;font-weight:600;color:#e5e7eb}.helper-placeholder__sub{margin:0;font-size:12.5px;line-height:1.6;color:#9ca3af;max-width:320px}.helper-placeholder__note{margin-top:8px;font-size:11px;color:#6b7280;padding:4px 10px;background:#ffffff08;border:1px solid rgba(255,255,255,.06);border-radius:999px}.helper-placeholder__note code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#c7cdd6}.section{background:linear-gradient(180deg,#141820b8,#0d1016b8);border:1px solid rgba(255,255,255,.06);border-radius:14px;box-shadow:0 1px #ffffff0a inset,0 14px 30px #00000052;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);padding:18px 18px 16px}.section-head{display:flex;align-items:center;gap:8px;padding:0 4px 14px;border-bottom:1px solid rgba(255,255,255,.04);margin-bottom:14px}.section-icon{font-size:14px;opacity:.8}.section-head h2{margin:0;font-size:13.5px;font-weight:600;color:#e5e7eb;letter-spacing:.2px}.section-sub{font-size:12px;color:#6b7280}.section-body{display:flex;flex-direction:column;gap:10px}.grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.bcard{position:relative;width:200px;height:200px;background:#1418208c;border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:16px;display:flex;flex-direction:column;overflow:hidden;transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease;--brand: #5b8df7;--accent-cloud: #f59e0b}.bcard:hover{transform:translateY(-2px);border-color:#ffffff24;box-shadow:0 12px 32px -10px #00000073,0 1px #ffffff0a inset}.bcard__accent{position:absolute;top:0;left:0;right:0;height:3px;background:var(--brand);opacity:.9}.bcard--cloud .bcard__accent{background:var(--accent-cloud)}.bcard--online:before{content:"";position:absolute;bottom:-40%;right:-20%;width:140%;height:100%;background:radial-gradient(circle at center,rgba(91,141,247,.22) 0%,transparent 60%);pointer-events:none;opacity:.55}.bcard--cloud.bcard--online:before{background:radial-gradient(circle at center,rgba(245,158,11,.22) 0%,transparent 60%)}.bcard__top{display:flex;align-items:center;justify-content:space-between;position:relative;z-index:1}.bcard__pill{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:#08090eb3;border:1px solid rgba(255,255,255,.07);border-radius:999px;color:#9ca3af}.bcard__pill svg{display:block}.bcard__dot{width:7px;height:7px;border-radius:50%;background:#6b7280;flex-shrink:0}.bcard__dot[data-tone=ok]{background:#34d399;box-shadow:0 0 0 2px #34d39940}.bcard__dot[data-tone=off]{background:#6b7280}.bcard__dot[data-tone=warn]{background:#fbbf24;box-shadow:0 0 0 2px #fbbf2440}.bcard__dot[data-tone=err]{background:#f87171;box-shadow:0 0 0 2px #f8717140}.bcard__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:#fbbf241f;color:#fbbf24;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.bcard__body{flex:1;display:flex;flex-direction:column;gap:4px;padding-top:12px;padding-bottom:12px;position:relative;z-index:1;min-width:0}.bcard__name{margin:0;font-size:17px;font-weight:700;color:#e5e7eb;letter-spacing:-.015em;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__host{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#9ca3af;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.bcard__chip{font-size:10.5px;color:#9ca3af;background:#ffffff08;border:1px solid rgba(255,255,255,.06);padding:2px 7px;border-radius:999px}.bcard__cta{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;height:38px;border:0;border-radius:9px;background:var(--brand);color:#fff;font-size:13px;font-weight:600;letter-spacing:.1px;cursor:pointer;transition:transform 80ms ease,background .16s ease,box-shadow .16s ease,filter .16s ease;box-shadow:0 4px 12px -2px #5b8df773}.bcard--cloud .bcard__cta{background:var(--accent-cloud);box-shadow:0 4px 12px -2px #f59e0b73}.bcard__cta:hover{filter:brightness(1.08)}.bcard__cta:active{transform:translateY(1px)}.bcard__cta:disabled{background:#ffffff08;color:#6b7280;cursor:not-allowed;box-shadow:none;border:1px solid rgba(255,255,255,.06)}.empty{font-size:12.5px;color:#6b7280;padding:14px 16px;background:#ffffff05;border:1px dashed rgba(255,255,255,.08);border-radius:10px}
1
+ *{box-sizing:border-box}html,body,#root{margin:0;height:100%}body{font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Segoe UI,Roboto,Helvetica Neue,sans-serif;background:#07080c;color:#e5e7eb;-webkit-font-smoothing:antialiased}.shell{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-app-region:drag}.shell--app{align-items:stretch;justify-content:stretch;flex-direction:row;background:linear-gradient(180deg,#0b0d13,#07080c);overflow:hidden;-webkit-app-region:no-drag}.shell__left{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;overflow:auto}.helper-aside{flex:0 0 auto;position:relative;background:#0f1115;border-left:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;min-width:320px;z-index:1}.helper-aside,.helper-aside *,.shell--app .main{-webkit-app-region:no-drag}.shell--app .topbar{-webkit-app-region:drag}.shell--app .topbar .user-chip,.shell--app .topbar .user-chip *,.shell--app .topbar .btn-ghost{-webkit-app-region:no-drag}.glow{position:absolute;top:-40%;right:-40%;bottom:-40%;left:-40%;z-index:0;pointer-events:none;background:radial-gradient(closest-side,rgba(91,141,247,.2),transparent 60%),radial-gradient(closest-side at 30% 70%,rgba(167,139,250,.13),transparent 65%);filter:blur(30px)}.card{-webkit-app-region:no-drag;position:relative;z-index:1;width:380px;padding:36px 36px 28px;background:linear-gradient(180deg,#141820d9,#0d1016d9);border:1px solid rgba(255,255,255,.06);border-radius:16px;box-shadow:0 1px #ffffff0a inset,0 30px 60px #0006;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);display:flex;flex-direction:column;align-items:center;gap:18px}.brand{display:flex;align-items:center;gap:12px;align-self:stretch}.brand-mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);box-shadow:0 8px 20px #5b8df759}.brand-mark.sm{width:28px;height:28px;border-radius:8px;box-shadow:none}.brand-mark.sm svg{width:16px;height:16px}.brand-text{line-height:1.2}.brand-name{font-weight:600;font-size:15px}.brand-sub{font-size:12px;color:#9ca3af;margin-top:2px}.tagline{margin:4px 0 0;color:#c7cdd6;font-size:13.5px;text-align:center;line-height:1.55}.btn-primary{-webkit-app-region:no-drag;margin-top:4px;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:42px;display:inline-flex;align-items:center;justify-content:center;gap:8px;background:linear-gradient(180deg,#5b8df7,#4570d8);color:#fff;border:0;border-radius:10px;font-size:14px;font-weight:500;letter-spacing:.2px;cursor:pointer;box-shadow:0 1px #ffffff2e inset,0 -1px #0000002e inset,0 10px 22px #5b8df747;transition:transform 80ms ease,filter .12s ease}.btn-primary:hover{filter:brightness(1.08)}.btn-primary:active{transform:translateY(1px)}.btn-primary:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.btn-ghost{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:6px 14px;font-size:12.5px;cursor:pointer;transition:color .12s ease,border-color .12s ease,background .12s ease}.btn-ghost.sm{padding:4px 10px;font-size:11.5px}.btn-ghost:hover{color:#e5e7eb;background:#ffffff0a;border-color:#ffffff24}.btn-ghost:disabled{opacity:.4;cursor:default}.hint{margin:0;font-size:11.5px;color:#6b7280}.spinner-row{display:inline-flex;align-items:center;gap:8px;color:#c7cdd6;font-size:13px}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{width:100%;font-size:12px;color:#fca5a5;background:#ef444414;border:1px solid rgba(239,68,68,.18);padding:8px 12px;border-radius:8px;text-align:center;line-height:1.5}.topbar{-webkit-app-region:drag;position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;padding:14px 24px 12px;background:#08090e99;border-bottom:1px solid rgba(255,255,255,.05);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}[data-platform=darwin][data-fullscreen="0"] .topbar{padding-left:84px}.brand-mini{display:inline-flex;align-items:center;gap:10px}.brand-mini .brand-name{font-size:14px}.user-chip{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:10px}.welcome{font-size:12px;color:#34d399;padding:4px 10px;border-radius:999px;background:#10b9811a;border:1px solid rgba(16,185,129,.25);animation:fadein .2s ease}@keyframes fadein{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}.avatar{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);font-size:12px;font-weight:600;color:#fff}.user-name{font-size:13px;color:#c7cdd6}.glow--app{inset:-10% -10% auto -10%;height:50vh;background:radial-gradient(closest-side at 75% 0%,rgba(91,141,247,.18),transparent 65%),radial-gradient(closest-side at 20% 10%,rgba(167,139,250,.1),transparent 60%);filter:blur(40px)}.main{position:relative;z-index:1;padding:22px 32px 48px;width:100%;display:flex;flex-direction:column;gap:16px}.app__tabs{display:inline-flex;align-items:center;gap:4px;padding:4px;background:#1418208c;border:1px solid rgba(255,255,255,.06);border-radius:10px;align-self:flex-start;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.app__tab{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:0;border-radius:7px;padding:6px 14px;font-size:12.5px;font-weight:500;letter-spacing:.15px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:color .12s ease,background .12s ease}.app__tab:hover{color:#e5e7eb;background:#ffffff0a}.app__tab.is-active{color:#fff;background:#5b8df72e;box-shadow:0 0 0 1px #5b8df74d inset}.app__tab-count{font-size:10.5px;color:#9ca3af;background:#ffffff0f;padding:1px 6px;border-radius:999px;min-width:18px;text-align:center}.app__tab.is-active .app__tab-count{background:#5b8df74d;color:#fff}.app__grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.add-card{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:200px;height:200px;background:transparent;border:1.5px dashed rgba(255,255,255,.12);border-radius:14px;color:#9ca3af;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;transition:border-color .16s ease,color .16s ease,background .16s ease}.add-card:hover{border-color:#5b8df780;color:#e5e7eb;background:#5b8df70d}.add-card__plus{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;background:#ffffff0a;font-size:22px;font-weight:300;color:inherit}.add-card__label{font-size:13px;font-weight:500}.bcard--helper{background:linear-gradient(160deg,#5b8df729,#a78bfa24 60%,#1418208c);border-color:#a78bfa40}.bcard--helper .bcard__accent{background:linear-gradient(90deg,#5b8df7,#a78bfa);opacity:1}.bcard--helper:hover{border-color:#a78bfa73}.bcard__pill--helper{background:#a78bfa2e;border-color:#a78bfa4d;color:#c4b5fd;font-size:11px;font-weight:600;letter-spacing:.2px}.bcard__helper-icon{font-size:12px;filter:grayscale(.2)}.bcard__badge--free{background:#34d39926;color:#34d399;border:1px solid rgba(52,211,153,.3)}.bcard__badge--trial{background:#fbbf2426;color:#fcd34d;border:1px solid rgba(251,191,36,.3);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard__badge--local{background:#5b8df72e;color:#a5c4ff;border:1px solid rgba(91,141,247,.35);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard--helper .bcard__name{color:#f3f4f6}.bcard__desc{margin:4px 0 0;font-size:11.5px;line-height:1.5;color:#c7cdd6;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.bcard__fineprint{margin:4px 0 0;font-size:10.5px;color:#9ca3af;opacity:.8}.bcard__cta--helper{background:linear-gradient(90deg,#5b8df7,#a78bfa);box-shadow:0 6px 18px -4px #a78bfa73}.bcard__cta--helper:hover{filter:brightness(1.1)}.helper-aside__top{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid rgba(255,255,255,.05)}.helper-aside__title{font-size:12.5px;font-weight:600;color:#c7cdd6}.helper-aside__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:#6b7280;font-size:20px;line-height:1;width:26px;height:26px;border-radius:6px;cursor:pointer;transition:color .12s ease,background .12s ease}.helper-aside__close:hover{color:#e5e7eb;background:#ffffff0f}.helper-modal__backdrop{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:transparent;z-index:20;animation:fadein .14s ease;padding:16px;pointer-events:auto}.helper-modal{width:min(360px,100%);background:linear-gradient(180deg,#1f2733,#1a2029);border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:20px 22px 16px;color:#e5e7eb;box-shadow:0 24px 48px -12px #0009,0 1px #ffffff14 inset;animation:fadein .18s ease}.helper-modal__title{font-size:14px;font-weight:600;color:#f3f4f6;margin-bottom:8px}.helper-modal__desc{font-size:12.5px;line-height:1.6;color:#b6bcc6;margin-bottom:18px}.helper-modal__desc code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11.5px;padding:1px 6px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);border-radius:4px;color:#e7eaef}.helper-modal__actions{display:flex;align-items:center;justify-content:flex-end;gap:8px}.helper-modal__btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#ffffff0f;color:#d2d6dd;border:1px solid rgba(255,255,255,.1);border-radius:7px;padding:7px 14px;font-size:12.5px;font-weight:500;cursor:pointer;transition:background .12s ease,color .12s ease,transform 80ms ease}.helper-modal__btn:hover{background:#ffffff1a;color:#fff}.helper-modal__btn:active{transform:translateY(1px)}.helper-modal__btn--ghost{background:transparent;border-color:transparent;color:#ffffff8c;margin-right:auto;padding-left:4px;padding-right:4px}.helper-modal__btn--ghost:hover{background:transparent;color:#ffffffd9}.helper-modal__btn--primary{background:linear-gradient(180deg,#5b8df7,#4570d8);border-color:#ffffff2e;color:#fff}.helper-modal__btn--primary:hover{background:linear-gradient(180deg,#6c9af9,#5a82e0)}.helper-modal__btn:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.helper-placeholder{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 40px;text-align:center;color:#9ca3af}.helper-placeholder__mark{font-size:48px;line-height:1;filter:grayscale(.2);opacity:.85}.helper-placeholder__title{margin:0;font-size:16px;font-weight:600;color:#e5e7eb}.helper-placeholder__sub{margin:0;font-size:12.5px;line-height:1.6;color:#9ca3af;max-width:320px}.helper-placeholder__note{margin-top:8px;font-size:11px;color:#6b7280;padding:4px 10px;background:#ffffff08;border:1px solid rgba(255,255,255,.06);border-radius:999px}.helper-placeholder__note code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#c7cdd6}.section{background:linear-gradient(180deg,#141820b8,#0d1016b8);border:1px solid rgba(255,255,255,.06);border-radius:14px;box-shadow:0 1px #ffffff0a inset,0 14px 30px #00000052;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);padding:18px 18px 16px}.section-head{display:flex;align-items:center;gap:8px;padding:0 4px 14px;border-bottom:1px solid rgba(255,255,255,.04);margin-bottom:14px}.section-icon{font-size:14px;opacity:.8}.section-head h2{margin:0;font-size:13.5px;font-weight:600;color:#e5e7eb;letter-spacing:.2px}.section-sub{font-size:12px;color:#6b7280}.section-body{display:flex;flex-direction:column;gap:10px}.grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.bcard{position:relative;width:200px;height:200px;background:#1418208c;border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:16px;display:flex;flex-direction:column;overflow:hidden;transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease;--brand: #5b8df7;--accent-cloud: #f59e0b}.bcard:hover{transform:translateY(-2px);border-color:#ffffff24;box-shadow:0 12px 32px -10px #00000073,0 1px #ffffff0a inset}.bcard__accent{position:absolute;top:0;left:0;right:0;height:3px;background:var(--brand);opacity:.9}.bcard--cloud .bcard__accent{background:var(--accent-cloud)}.bcard--online:before{content:"";position:absolute;bottom:-40%;right:-20%;width:140%;height:100%;background:radial-gradient(circle at center,rgba(91,141,247,.22) 0%,transparent 60%);pointer-events:none;opacity:.55}.bcard--cloud.bcard--online:before{background:radial-gradient(circle at center,rgba(245,158,11,.22) 0%,transparent 60%)}.bcard__top{display:flex;align-items:center;justify-content:space-between;position:relative;z-index:1}.bcard__pill{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:#08090eb3;border:1px solid rgba(255,255,255,.07);border-radius:999px;color:#9ca3af}.bcard__pill svg{display:block}.bcard__dot{width:7px;height:7px;border-radius:50%;background:#6b7280;flex-shrink:0}.bcard__dot[data-tone=ok]{background:#34d399;box-shadow:0 0 0 2px #34d39940}.bcard__dot[data-tone=off]{background:#6b7280}.bcard__dot[data-tone=warn]{background:#fbbf24;box-shadow:0 0 0 2px #fbbf2440}.bcard__dot[data-tone=err]{background:#f87171;box-shadow:0 0 0 2px #f8717140}.bcard__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:#fbbf241f;color:#fbbf24;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.bcard__body{flex:1;display:flex;flex-direction:column;gap:4px;padding-top:12px;padding-bottom:12px;position:relative;z-index:1;min-width:0}.bcard__name{margin:0;font-size:17px;font-weight:700;color:#e5e7eb;letter-spacing:-.015em;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__host{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#9ca3af;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.bcard__chip{font-size:10.5px;color:#9ca3af;background:#ffffff08;border:1px solid rgba(255,255,255,.06);padding:2px 7px;border-radius:999px}.bcard__cta{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;height:38px;border:0;border-radius:9px;background:var(--brand);color:#fff;font-size:13px;font-weight:600;letter-spacing:.1px;cursor:pointer;transition:transform 80ms ease,background .16s ease,box-shadow .16s ease,filter .16s ease;box-shadow:0 4px 12px -2px #5b8df773}.bcard--cloud .bcard__cta{background:var(--accent-cloud);box-shadow:0 4px 12px -2px #f59e0b73}.bcard__cta:hover{filter:brightness(1.08)}.bcard__cta:active{transform:translateY(1px)}.bcard__cta:disabled{background:#ffffff08;color:#6b7280;cursor:not-allowed;box-shadow:none;border:1px solid rgba(255,255,255,.06)}.empty{font-size:12.5px;color:#6b7280;padding:14px 16px;background:#ffffff05;border:1px dashed rgba(255,255,255,.08);border-radius:10px}.bcard__ops{display:flex;gap:6px;margin-top:10px}.bcard__op{display:inline-flex;align-items:center;gap:5px;flex:1;justify-content:center;border:1px solid rgba(255,255,255,.12);background:#ffffff08;color:#d1d5db;border-radius:7px;padding:5px 8px;font-size:11.5px;cursor:pointer;transition:.15s}.bcard__op:hover:not(:disabled){color:#fff;background:#ffffff0f;border-color:#fff3}.bcard__op:disabled{opacity:.4;cursor:default}.bcard__op--danger{color:#f7a3a3;border-color:#ef444440}.bcard__op--danger:hover:not(:disabled){color:#fff;background:#ef44442e;border-color:#ef444480}.bcard__opmsg{margin-top:8px;font-size:11px;color:#9ca3af;word-break:break-word}
@@ -4,8 +4,8 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>CiCy Desktop</title>
7
- <script type="module" crossorigin src="./assets/index-BqRSij9W.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-CNVsvsZX.css">
7
+ <script type="module" crossorigin src="./assets/index-CoLaJ3o7.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-UOwEuHCy.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -3,8 +3,11 @@
3
3
  // cicy-code is no longer downloaded by an in-app installer — the sidecar runs
4
4
  // it via `npx cicy-code` (mac/linux) or Docker (Windows); see
5
5
  // src/sidecar/cicy-code.js. So this surface is just lifecycle + status:
6
- // sidecar:status → { running } — is something answering on :8008?
7
- // sidecar:start → { ok, ... } — start (or reuse) the daemon
6
+ // sidecar:status → { running } — is something answering on :8008?
7
+ // sidecar:start → { ok, ... } — start (or reuse) the daemon
8
+ // sidecar:stop → { ok } — stop the daemon we spawned
9
+ // sidecar:restart → { ok, ... } — stop + fresh spawn (same version)
10
+ // sidecar:update → { ok, ... } — stop + spawn cicy-code@latest
8
11
  //
9
12
  // (Removed: sidecar:check-latest / install / cancel / wsl-status / wsl-install,
10
13
  // along with src/sidecar/installer.js and src/sidecar/wsl.js.)
@@ -41,6 +44,48 @@ function register({ sidecarLogPath } = {}) {
41
44
  return { ok: false, error: e.message };
42
45
  }
43
46
  });
47
+
48
+ // Stop the daemon we spawned. (A user-run / external instance we only
49
+ // probed can't be killed from here — stop() no-ops when we hold no child.)
50
+ ipcMain.handle("sidecar:stop", async () => {
51
+ try {
52
+ await sidecar.stop();
53
+ return { ok: true };
54
+ } catch (e) {
55
+ return { ok: false, error: e.message };
56
+ }
57
+ });
58
+
59
+ // Restart: stop + fresh spawn (same cached version). Wait for :8008 to
60
+ // come back so the homepage poll flips to "running".
61
+ ipcMain.handle("sidecar:restart", async () => {
62
+ try {
63
+ const child = await sidecar.restart({ logPath: sidecarLogPath });
64
+ for (let i = 0; i < 20; i++) {
65
+ if (await sidecar.probeExisting(PORT)) return { ok: true, pid: child?.pid || null };
66
+ await new Promise((r) => setTimeout(r, 250));
67
+ }
68
+ return { ok: true, pid: child?.pid || null, warning: "restarted but did not bind :8008 within 5s" };
69
+ } catch (e) {
70
+ return { ok: false, error: e.message };
71
+ }
72
+ });
73
+
74
+ // Update: stop + spawn cicy-code@latest (or reload the Docker image on
75
+ // win32). The npx re-resolve / image pull can take a while on a cold cache,
76
+ // so allow a longer window for :8008 to come back.
77
+ ipcMain.handle("sidecar:update", async () => {
78
+ try {
79
+ const child = await sidecar.update({ logPath: sidecarLogPath });
80
+ for (let i = 0; i < 240; i++) {
81
+ if (await sidecar.probeExisting(PORT)) return { ok: true, pid: child?.pid || null };
82
+ await new Promise((r) => setTimeout(r, 250));
83
+ }
84
+ return { ok: true, pid: child?.pid || null, warning: "updated but did not bind :8008 within 60s" };
85
+ } catch (e) {
86
+ return { ok: false, error: e.message };
87
+ }
88
+ });
44
89
  }
45
90
 
46
91
  module.exports = { register };
@@ -14,9 +14,10 @@
14
14
  // there on win32. (The old WSL path was retired.)
15
15
 
16
16
  const fs = require("fs");
17
+ const os = require("os");
17
18
  const http = require("http");
18
19
  const path = require("path");
19
- const { spawn } = require("child_process");
20
+ const { spawn, execFileSync } = require("child_process");
20
21
 
21
22
  const DEFAULT_PORT = Number(process.env.CICY_CODE_PORT || 8008);
22
23
 
@@ -36,7 +37,7 @@ function probeExisting(port = DEFAULT_PORT, timeoutMs = 500) {
36
37
 
37
38
  let child = null;
38
39
 
39
- async function start({ logPath, port = DEFAULT_PORT, force = false } = {}) {
40
+ async function start({ logPath, port = DEFAULT_PORT, force = false, version = null } = {}) {
40
41
  if (child && !force) return child;
41
42
 
42
43
  if (!force && await probeExisting(port)) {
@@ -85,9 +86,11 @@ async function start({ logPath, port = DEFAULT_PORT, force = false } = {}) {
85
86
  npm_config_registry: registry,
86
87
  };
87
88
  const npxBin = process.platform === "win32" ? "npx.cmd" : "npx";
88
- const spec = process.env.CICY_CODE_VERSION
89
- ? `cicy-code@${process.env.CICY_CODE_VERSION}`
90
- : "cicy-code";
89
+ // version arg (e.g. "latest" from update()) wins over the env pin; explicit
90
+ // `cicy-code@latest` makes npx re-resolve against the registry so an update
91
+ // actually pulls a newer build even when an older one is cached/global.
92
+ const pin = version || process.env.CICY_CODE_VERSION;
93
+ const spec = pin ? `cicy-code@${pin}` : "cicy-code";
91
94
  child = spawn(npxBin, ["-y", spec], { stdio, detached: false, env });
92
95
  console.log(`[cicy-code-sidecar] spawned npx ${spec} pid=${child.pid} port=${port} registry=${registry} log=${logPath || "(none)"}`);
93
96
 
@@ -98,23 +101,114 @@ async function start({ logPath, port = DEFAULT_PORT, force = false } = {}) {
98
101
  return child;
99
102
  }
100
103
 
101
- async function stop({ timeoutMs = 5000 } = {}) {
102
- if (!child) return;
103
- const p = child;
104
- child = null;
105
- // Docker-launched (win32): not a real ChildProcess — remove the container.
106
- if (p && p.docker) {
107
- try { await require("./docker").stop(); } catch {}
108
- return;
104
+ // PIDs currently LISTENing on `port`, via lsof. Tries a few common paths
105
+ // because the GUI-launched Electron process often has a minimal PATH. Returns
106
+ // [] when lsof is missing or nothing is listening.
107
+ const LSOF_CANDIDATES = ["/usr/sbin/lsof", "/usr/bin/lsof", "lsof"];
108
+ function listPortPids(port) {
109
+ for (const bin of LSOF_CANDIDATES) {
110
+ try {
111
+ const out = execFileSync(bin, ["-nP", `-tiTCP:${port}`, "-sTCP:LISTEN"], {
112
+ encoding: "utf8",
113
+ stdio: ["ignore", "pipe", "ignore"],
114
+ });
115
+ return [...new Set(out.split(/\s+/).map(s => parseInt(s, 10)).filter(n => n > 0))];
116
+ } catch (e) {
117
+ if (e && e.code === "ENOENT") continue; // wrong path → try next candidate
118
+ return []; // lsof ran but matched nothing (non-zero exit)
119
+ }
120
+ }
121
+ return [];
122
+ }
123
+
124
+ // Kill whatever is LISTENing on `port` — even a detached/orphan (PPID=1)
125
+ // cicy-code from a prior launch that we never tracked as a child. SIGTERM,
126
+ // wait for the port to free, then SIGKILL the stragglers.
127
+ async function killPortListeners(port = DEFAULT_PORT, timeoutMs = 5000) {
128
+ const pids = listPortPids(port);
129
+ if (!pids.length) return 0;
130
+ for (const pid of pids) { try { process.kill(pid, "SIGTERM"); } catch {} }
131
+ const t0 = Date.now();
132
+ while (Date.now() - t0 < timeoutMs) {
133
+ if (!listPortPids(port).length) return pids.length;
134
+ await new Promise(r => setTimeout(r, 150));
109
135
  }
110
- try { p.kill("SIGTERM"); } catch {}
111
- const start = Date.now();
112
- while (p.exitCode === null && Date.now() - start < timeoutMs) {
113
- await new Promise(r => setTimeout(r, 100));
136
+ for (const pid of listPortPids(port)) { try { process.kill(pid, "SIGKILL"); } catch {} }
137
+ return pids.length;
138
+ }
139
+
140
+ async function stop({ timeoutMs = 5000, port = DEFAULT_PORT } = {}) {
141
+ // 1) The child we spawned this session (npx) or the Docker container.
142
+ if (child) {
143
+ const p = child;
144
+ child = null;
145
+ if (p.docker) {
146
+ try { await require("./docker").stop(); } catch {}
147
+ return;
148
+ }
149
+ try { p.kill("SIGTERM"); } catch {}
150
+ const t0 = Date.now();
151
+ while (p.exitCode === null && Date.now() - t0 < timeoutMs) {
152
+ await new Promise(r => setTimeout(r, 100));
153
+ }
154
+ if (p.exitCode === null) { try { p.kill("SIGKILL"); } catch {} }
114
155
  }
115
- if (p.exitCode === null) {
116
- try { p.kill("SIGKILL"); } catch {}
156
+
157
+ // 2) Anything STILL on :port we didn't spawn — a detached npx from a prior
158
+ // launch, a user-run daemon, a PPID=1 orphan. The homepage 停止/重启 must
159
+ // act on the REAL listener; otherwise (no tracked child) it would no-op.
160
+ // Docker (win32) owns its own lifecycle, so skip the port-kill there.
161
+ if (process.platform !== "win32") {
162
+ await killPortListeners(port, timeoutMs);
163
+ }
164
+ }
165
+
166
+ // Remove npx's cached cicy-code installs so the next spawn re-fetches from the
167
+ // registry. npx keys each temp install by a hash under ~/.npm/_npx; we only
168
+ // nuke entries that actually contain cicy-code (leaving other npx packages
169
+ // alone). Best-effort: missing dir / perms just yield 0 removed.
170
+ function clearNpxCache() {
171
+ const npxRoot = path.join(os.homedir(), ".npm", "_npx");
172
+ let removed = 0;
173
+ try {
174
+ for (const ent of fs.readdirSync(npxRoot)) {
175
+ const cc = path.join(npxRoot, ent, "node_modules", "cicy-code");
176
+ if (fs.existsSync(cc)) {
177
+ try {
178
+ fs.rmSync(path.join(npxRoot, ent), { recursive: true, force: true });
179
+ removed++;
180
+ } catch {}
181
+ }
182
+ }
183
+ } catch {}
184
+ console.log(`[cicy-code-sidecar] cleared ${removed} npx cache entr${removed === 1 ? "y" : "ies"} for cicy-code`);
185
+ return removed;
186
+ }
187
+
188
+ // Restart: stop the running daemon, let :8008 free, then force a fresh spawn
189
+ // (reusing the same cached version — no registry round-trip).
190
+ async function restart({ logPath, port = DEFAULT_PORT } = {}) {
191
+ await stop({ port });
192
+ await new Promise(r => setTimeout(r, 300));
193
+ return start({ logPath, port, force: true });
194
+ }
195
+
196
+ // Update: stop, then start the LATEST build.
197
+ // win32 → reload the Docker image (from R2) and re-run the container.
198
+ // else → clear the npx cache + spawn `cicy-code@latest` so npx re-resolves
199
+ // against the registry (npmmirror for CN) and pulls a newer build.
200
+ async function update({ logPath, port = DEFAULT_PORT } = {}) {
201
+ await stop({ port });
202
+ if (process.platform === "win32") {
203
+ try { await require("./docker").loadImage(); } catch (e) {
204
+ console.warn(`[cicy-code-sidecar] docker image reload failed: ${e.message}`);
205
+ }
206
+ await new Promise(r => setTimeout(r, 300));
207
+ return start({ logPath, port, force: true });
117
208
  }
209
+ clearNpxCache();
210
+ await new Promise(r => setTimeout(r, 300));
211
+ return start({ logPath, port, force: true, version: "latest" });
118
212
  }
119
213
 
120
- module.exports = { start, stop, probeExisting };
214
+ module.exports = { start, stop, restart, update, probeExisting, clearNpxCache };
@@ -629,3 +629,32 @@ body {
629
629
  border: 1px dashed rgba(255,255,255,.08);
630
630
  border-radius: 10px;
631
631
  }
632
+
633
+ /* ---- 本地团队卡片上的 cicy-code 守护进程控制 (重启/更新/停止) ---- */
634
+ .bcard__ops {
635
+ display: flex;
636
+ gap: 6px;
637
+ margin-top: 10px;
638
+ }
639
+ .bcard__op {
640
+ display: inline-flex; align-items: center; gap: 5px;
641
+ flex: 1;
642
+ justify-content: center;
643
+ border: 1px solid rgba(255,255,255,.12);
644
+ background: rgba(255,255,255,.03); color: #d1d5db;
645
+ border-radius: 7px; padding: 5px 8px; font-size: 11.5px;
646
+ cursor: pointer; transition: .15s;
647
+ }
648
+ .bcard__op:hover:not(:disabled) {
649
+ color: #fff; background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.2);
650
+ }
651
+ .bcard__op:disabled { opacity: .4; cursor: default; }
652
+ .bcard__op--danger { color: #f7a3a3; border-color: rgba(239,68,68,.25); }
653
+ .bcard__op--danger:hover:not(:disabled) {
654
+ color: #fff; background: rgba(239,68,68,.18); border-color: rgba(239,68,68,.5);
655
+ }
656
+ .bcard__opmsg {
657
+ margin-top: 8px;
658
+ font-size: 11px; color: #9ca3af;
659
+ word-break: break-word;
660
+ }