@leon___/dsh-client-liang-intensity-skin 0.1.10 → 0.1.11

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/README.md CHANGED
@@ -56,20 +56,21 @@ dsh plugin --profile web add 'github:kingOfSoySauce/dsh-liang-skin'
56
56
 
57
57
  ## 外观开关
58
58
 
59
- 入口位于 `设置 → 通用设置 → 外观皮肤`:
59
+ 入口位于 `设置 → 通用设置 → 外观`:
60
60
 
61
61
  - `滑动变祖`:显示滑块并启用人物、背景和自适应配色。
62
- - `原生`:移除背景层、皮肤变量和滑块,恢复 Harness 原生界面。
62
+ - 点击原生的 `浅色`、`深色` 或 `跟随系统`:移除背景层、皮肤变量和滑块,切回对应的 Harness 原生外观。
63
+ - `滑动变祖绑定思考等级`:使用 DSH 原生开关,关闭后滑块只切换人物和配色,不修改模型的推理等级;仅点击开关切换,标题文字不触发切换。
63
64
 
64
65
  皮肤保持启用时,人物与背景配色由滑块档位决定;切换 DSH 原生深浅主题不会改变当前档位的背景。
65
66
 
66
- 选择保存在当前浏览器本地,不会改动模型配置。
67
+ 绑定开关保存在当前浏览器本地。切回原生外观只对本次客户端激活有效;刷新页面或重新激活插件后默认开启皮肤。外观选择的跨刷新记忆暂未实现。绑定开启时,滑块会提交模型的推理档位;关闭绑定后只改变外观。
67
68
 
68
69
  <a id="cli-install"></a>
69
70
 
70
71
  ## 命令安装
71
72
 
72
- 需要先安装 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness);当前版本已在 `0.1.0-rc.6` 上验证。安装本身可以在 DSH 运行时执行(只改动磁盘配置),重启后生效。三种方式任选其一:
73
+ 需要先安装 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness);本轮已在 DSH Web `0.1.7-rc.2` 检查原生控件,macOS Desktop 由用户试用;Windows Desktop 仍需更新后的实机反馈。安装本身可以在 DSH 运行时执行(只改动磁盘配置),重启后生效。三种方式任选其一:
73
74
 
74
75
  > 安装前请确保已关闭其他皮肤插件,避免冲突。
75
76
 
@@ -82,10 +83,10 @@ dsh --profile web --dump-config | grep -B1 -A2 liang-intensity
82
83
 
83
84
  ### 方式二:从 GitHub Release tarball 安装
84
85
 
85
- 从本仓库 [Releases](https://github.com/kingOfSoySauce/dsh-liang-skin/releases) 页面下载 `dsh-client-liang-intensity-skin-0.1.9.tgz`(包内已包含构建好的 `lib/client.js`,安装时不需要执行任何 prepare 脚本),然后:
86
+ 从本仓库 [Releases](https://github.com/kingOfSoySauce/dsh-liang-skin/releases) 页面下载 `leon___-dsh-client-liang-intensity-skin-0.1.11.tgz`(包内已包含构建好的 `lib/client.js`,安装时不需要执行任何 prepare 脚本),然后:
86
87
 
87
88
  ```sh
88
- dsh plugin --profile web add ./dsh-client-liang-intensity-skin-0.1.9.tgz
89
+ dsh plugin --profile web add ./leon___-dsh-client-liang-intensity-skin-0.1.11.tgz
89
90
  ```
90
91
 
91
92
 
@@ -116,7 +117,7 @@ dsh plugin --profile web add .
116
117
  ### 卸载
117
118
 
118
119
  ```sh
119
- dsh plugin --profile web remove dsh-client-liang-intensity-skin
120
+ dsh plugin --profile web remove @leon___/dsh-client-liang-intensity-skin
120
121
  ```
121
122
 
122
123
  `remove` 会自动把插件从 `dsh.profile.bundles` 中摘除;重启后设置入口完全移除。
@@ -134,10 +135,13 @@ dsh plugin --profile web remove dsh-client-liang-intensity-skin
134
135
  npm install
135
136
  npm test
136
137
  npm run build
138
+ npm run test:compatibility
137
139
  ```
138
140
 
139
141
  修改 client 源码后需要运行 `npm run build`,并一起提交更新后的 `lib/client.js` 和 source map。
140
142
 
143
+ 浏览器兼容性回归使用本机 Chrome / Chromium;可通过 `CHROME_PATH` 指定浏览器可执行文件,不会自动下载浏览器。测试使用宿主布局夹具,不能代替官方 Desktop 真机验收。本轮兼容性修复的验证步骤见 [兼容性验证说明](docs/compatibility-validation.md)。
144
+
141
145
  ## 灵感与素材来源
142
146
 
143
147
  本插件的“滑动变祖”视觉概念与人物图片素材源自
package/lib/client.js CHANGED
@@ -25,11 +25,12 @@ __export(index_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
27
  var import_react = require("react");
28
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
28
29
 
29
30
  // src/client/skin.css
30
31
  var skin_default = `.liang-skin-backdrop {
31
32
  position: fixed;
32
- z-index: 0;
33
+ z-index: -1;
33
34
  inset: 0;
34
35
  overflow: hidden;
35
36
  pointer-events: none;
@@ -48,7 +49,7 @@ body[data-liang-skin="on"] .liang-skin-backdrop {
48
49
  right: 0;
49
50
  display: block;
50
51
  width: min(42vw, 720px);
51
- height: 100vh;
52
+ height: 100%;
52
53
  object-fit: cover;
53
54
  object-position: 50% 42%;
54
55
  opacity: var(--liang-portrait-opacity, 0.45);
@@ -75,11 +76,16 @@ body[data-liang-skin="on"] .liang-skin-backdrop {
75
76
  position: absolute;
76
77
  inset: 0;
77
78
  content: "";
78
- background: linear-gradient(90deg, var(--liang-page, transparent) 0 28%, transparent 57% 100%);
79
+ background:
80
+ linear-gradient(90deg, var(--liang-page, transparent) 0 28%, transparent 57% 100%),
81
+ linear-gradient(var(--liang-bg-base, transparent), var(--liang-bg-base, transparent));
79
82
  }
80
83
 
81
84
  body[data-liang-skin="on"] {
82
- --dsw-alias-bg-base: var(--liang-bg-base) !important;
85
+ /* Keep the backdrop above the canvas but below content and native portals.
86
+ The host owns root positioning, dimensions, and its own stacking order. */
87
+ isolation: isolate;
88
+ --dsw-alias-bg-base: transparent !important;
83
89
  --dsw-alias-bg-layer-1: var(--liang-layer-1) !important;
84
90
  --dsw-alias-bg-layer-2: var(--liang-layer-2) !important;
85
91
  --dsw-alias-bg-layer-3: var(--liang-layer-3) !important;
@@ -239,11 +245,16 @@ body[data-liang-skin="on"]:is(
239
245
  }
240
246
 
241
247
  body[data-liang-skin="on"] > #root {
242
- position: relative;
243
- z-index: 1;
244
248
  background: transparent !important;
245
249
  }
246
250
 
251
+ body[data-liang-skin="on"]:is(
252
+ [data-dsh-desktop-mode="compatibility"],
253
+ [data-dsh-desktop-mode="extended"]
254
+ ) .liang-skin-backdrop {
255
+ top: var(--dsh-desktop-frame-height, 0px);
256
+ }
257
+
247
258
  /* Windows paints the sidebar fill across the host frame, covering the portrait.
248
259
  Match macOS's transparent frame while keeping the sidebar, caption, and
249
260
  conversation surfaces painted by their own host rules. */
@@ -480,7 +491,7 @@ body[data-liang-skin="on"] .liang-effort-control__range::-webkit-slider-thumb {
480
491
  display: flex;
481
492
  }
482
493
 
483
- [class*="_8HJdBW_cubeRow"]:has(.liang-appearance-choice) {
494
+ [class*="_cubeRow"]:has(.liang-appearance-choice) {
484
495
  display: grid;
485
496
  grid-template-columns: repeat(4, minmax(0, 1fr));
486
497
  }
@@ -516,90 +527,14 @@ body[data-liang-skin="on"] .liang-effort-control__range::-webkit-slider-thumb {
516
527
  }
517
528
 
518
529
  .liang-appearance-binding {
519
- box-sizing: border-box;
520
530
  display: flex;
521
- width: 100%;
522
- min-height: 28px;
523
531
  align-items: center;
524
532
  justify-content: space-between;
525
- gap: 16px;
526
- padding: 4px 0 0;
527
- color: var(--dsw-alias-label-primary);
528
- font: inherit;
533
+ gap: 24px;
534
+ padding: 16px 0;
535
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
529
536
  font-size: 14px;
530
- line-height: 22px;
531
- cursor: pointer;
532
- }
533
-
534
- .liang-appearance-binding__label {
535
- display: block;
536
- min-width: 0;
537
- overflow: hidden;
538
- text-overflow: ellipsis;
539
- white-space: nowrap;
540
- }
541
-
542
- .liang-appearance-binding__copy {
543
- display: flex;
544
- min-width: 0;
545
- flex-direction: column;
546
- gap: 1px;
547
- }
548
-
549
- .liang-appearance-binding__description {
550
- display: block;
551
- overflow: hidden;
552
- color: var(--dsw-alias-label-secondary);
553
- font-size: 12px;
554
- line-height: 18px;
555
- text-overflow: ellipsis;
556
- white-space: nowrap;
557
- }
558
-
559
- .liang-appearance-binding__input {
560
- position: relative;
561
- flex: 0 0 36px;
562
- width: 36px;
563
- height: 20px;
564
- margin: 0;
565
- border: 1px solid var(--dsw-alias-border-l2);
566
- border-radius: 999px;
567
- outline: none;
568
- cursor: pointer;
569
- appearance: none;
570
- background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-module-platform));
571
- }
572
-
573
- .liang-appearance-binding__input::before {
574
- position: absolute;
575
- top: 2px;
576
- left: 2px;
577
- width: 14px;
578
- height: 14px;
579
- border-radius: 50%;
580
- content: "";
581
- background: var(--dsw-alias-label-primary);
582
- box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
583
- transition: transform 160ms ease, background-color 160ms ease;
584
- }
585
-
586
- .liang-appearance-binding__input:checked {
587
- border-color: var(--dsw-static-neutral-bluish-400);
588
- background: var(--dsw-static-neutral-bluish-400);
589
- }
590
-
591
- .liang-appearance-binding__input:checked::before {
592
- background: var(--dsw-alias-bg-layer-1, #fff);
593
- transform: translateX(16px);
594
- }
595
-
596
- .liang-appearance-binding__input:focus-visible {
597
- box-shadow: 0 0 0 2px var(--dsw-alias-interactive-bg-hover);
598
- }
599
-
600
- .liang-appearance-binding__input:disabled {
601
- cursor: progress;
602
- opacity: 0.7;
537
+ line-height: 20px;
603
538
  }
604
539
 
605
540
  @media (max-width: 760px) {
@@ -626,6 +561,278 @@ body[data-liang-skin="on"] .liang-effort-control__range::-webkit-slider-thumb {
626
561
  }
627
562
  `;
628
563
 
564
+ // src/client/appearance.ts
565
+ var NATIVE_APPEARANCE_ROW = '[class*="_cubeRow"]';
566
+ var LIANG_APPEARANCE_BUTTON = "liang-appearance-choice";
567
+ function hasClassSuffix(node, suffix) {
568
+ return [...node.classList].some((name) => name.endsWith(suffix));
569
+ }
570
+ function findAppearanceRow() {
571
+ for (const row of document.querySelectorAll(NATIVE_APPEARANCE_ROW)) {
572
+ if (!hasClassSuffix(row, "_cubeRow")) continue;
573
+ const nativeButtons = [...row.children].filter(
574
+ (node) => node instanceof HTMLButtonElement && hasClassSuffix(node, "_themeCube")
575
+ );
576
+ if (nativeButtons.length < 3) continue;
577
+ let group = row.parentElement;
578
+ while (group !== null && !hasClassSuffix(group, "_group")) {
579
+ group = group.parentElement;
580
+ }
581
+ group ??= row.parentElement;
582
+ if (group !== null) return { row, group, nativeButtons };
583
+ }
584
+ return null;
585
+ }
586
+ function installLiangAppearanceButton(scope, presenter, packageId) {
587
+ let pending = false;
588
+ let disposed = false;
589
+ let mounted = null;
590
+ const nativeClickHandlers = /* @__PURE__ */ new Map();
591
+ const unmount = () => {
592
+ for (const [button, handler] of nativeClickHandlers) {
593
+ button.removeEventListener("click", handler, { capture: true });
594
+ }
595
+ nativeClickHandlers.clear();
596
+ if (mounted === null) return;
597
+ mounted.button.removeEventListener("click", mounted.handleCustomClick);
598
+ mounted.button.remove();
599
+ mounted = null;
600
+ };
601
+ const choose = async (enabled) => {
602
+ if (disposed || pending || scope.getSnapshot().enabled === enabled) return;
603
+ pending = true;
604
+ sync();
605
+ try {
606
+ await presenter.choose(enabled);
607
+ } catch {
608
+ } finally {
609
+ pending = false;
610
+ if (!disposed) sync();
611
+ }
612
+ };
613
+ const createMount = (row, group) => {
614
+ const english = document.documentElement.lang.toLowerCase().startsWith("en");
615
+ const button = document.createElement("button");
616
+ button.className = LIANG_APPEARANCE_BUTTON;
617
+ button.type = "button";
618
+ button.dataset.plugin = packageId;
619
+ button.setAttribute("aria-label", "\u6ED1\u52A8\u53D8\u7956");
620
+ const icon = document.createElement("span");
621
+ icon.className = "liang-appearance-choice__icon";
622
+ icon.setAttribute("aria-hidden", "true");
623
+ icon.textContent = "\u25C8";
624
+ const label = document.createElement("span");
625
+ label.className = "liang-appearance-choice__label";
626
+ label.textContent = english ? "Slider" : "\u6ED1\u52A8\u53D8\u7956";
627
+ button.append(icon, label);
628
+ const handleCustomClick = () => {
629
+ void choose(true);
630
+ };
631
+ button.addEventListener("click", handleCustomClick);
632
+ return { row, group, button, handleCustomClick };
633
+ };
634
+ const sync = () => {
635
+ if (disposed) return;
636
+ const target = findAppearanceRow();
637
+ if (target === null) {
638
+ unmount();
639
+ return;
640
+ }
641
+ if (mounted !== null && (mounted.row !== target.row || mounted.group !== target.group)) {
642
+ unmount();
643
+ }
644
+ mounted ??= createMount(target.row, target.group);
645
+ const { row, button } = mounted;
646
+ if (button.parentElement !== row) row.append(button);
647
+ const snapshot = scope.getSnapshot();
648
+ button.disabled = pending;
649
+ button.setAttribute("aria-pressed", String(snapshot.enabled));
650
+ for (const [nativeButton, handler] of nativeClickHandlers) {
651
+ if (target.nativeButtons.includes(nativeButton)) continue;
652
+ nativeButton.removeEventListener("click", handler, { capture: true });
653
+ nativeClickHandlers.delete(nativeButton);
654
+ }
655
+ for (const nativeButton of target.nativeButtons) {
656
+ if (nativeClickHandlers.has(nativeButton)) continue;
657
+ const handleNativeClick = () => {
658
+ void choose(false);
659
+ };
660
+ nativeClickHandlers.set(nativeButton, handleNativeClick);
661
+ nativeButton.addEventListener("click", handleNativeClick, { capture: true });
662
+ }
663
+ };
664
+ const observer = new MutationObserver(sync);
665
+ observer.observe(document.body, { childList: true, subtree: true });
666
+ const unsubscribe = scope.subscribe(sync);
667
+ sync();
668
+ return () => {
669
+ if (disposed) return;
670
+ disposed = true;
671
+ observer.disconnect();
672
+ unsubscribe();
673
+ unmount();
674
+ };
675
+ }
676
+
677
+ // src/client/portrait-loader.ts
678
+ var RETRY_DELAYS = [500, 1500, 3e3];
679
+ function retryUrl(source, retry) {
680
+ if (retry === 0) return source;
681
+ const hashIndex = source.indexOf("#");
682
+ const hash = hashIndex < 0 ? "" : source.slice(hashIndex);
683
+ const base = hashIndex < 0 ? source : source.slice(0, hashIndex);
684
+ const queryIndex = base.indexOf("?");
685
+ const path = queryIndex < 0 ? base : base.slice(0, queryIndex);
686
+ const query = new URLSearchParams(queryIndex < 0 ? "" : base.slice(queryIndex + 1));
687
+ query.set("retry", String(retry));
688
+ return `${path}?${query}${hash}`;
689
+ }
690
+ function createPortraitLoader(options) {
691
+ const sources = options.sources.map((source) => ({ ...source }));
692
+ const assets = /* @__PURE__ */ new Map();
693
+ for (const { url } of sources) {
694
+ if (!assets.has(url)) {
695
+ assets.set(url, {
696
+ url,
697
+ status: "idle",
698
+ loadedUrl: null,
699
+ retries: 0,
700
+ image: null,
701
+ timer: null,
702
+ detach: null
703
+ });
704
+ }
705
+ }
706
+ const createImage = options.createImage ?? (() => new Image());
707
+ let onChange = options.onChange;
708
+ let active = false;
709
+ let disposed = false;
710
+ let generation = 0;
711
+ let targetLevel = sources[0]?.level ?? 0;
712
+ let displayedIndex = null;
713
+ let lastState = null;
714
+ const isCurrent = (run) => active && !disposed && generation === run;
715
+ const nearestIndex = (available) => {
716
+ let nearest = null;
717
+ for (let index = 0; index < sources.length; index += 1) {
718
+ if (!available(index)) continue;
719
+ const distance = Math.abs(sources[index].level - targetLevel);
720
+ const previous = nearest === null ? Infinity : Math.abs(sources[nearest].level - targetLevel);
721
+ if (nearest === null || distance < previous || distance === previous && sources[index].level > sources[nearest].level) {
722
+ nearest = index;
723
+ }
724
+ }
725
+ return nearest;
726
+ };
727
+ const isReady = (index) => assets.get(sources[index].url)?.status === "ready";
728
+ const emit = (state) => {
729
+ if (lastState?.index === state.index && lastState.url === state.url && lastState.status === state.status) return;
730
+ lastState = state;
731
+ onChange?.(state);
732
+ };
733
+ const reconcile = () => {
734
+ if (!active || disposed) return;
735
+ const target = nearestIndex(() => true);
736
+ if (target !== null && isReady(target)) displayedIndex = target;
737
+ else if (displayedIndex === null) displayedIndex = nearestIndex(isReady);
738
+ if (displayedIndex !== null) {
739
+ const asset = assets.get(sources[displayedIndex].url);
740
+ emit({ index: displayedIndex, url: asset.loadedUrl, image: asset.image, status: "ready" });
741
+ } else {
742
+ const exhausted = [...assets.values()].every((asset) => asset.status === "failed");
743
+ emit({ index: null, url: null, image: null, status: exhausted ? "failed" : "loading" });
744
+ }
745
+ };
746
+ const request = (asset, run) => {
747
+ if (!isCurrent(run)) return;
748
+ asset.status = "loading";
749
+ const image = createImage();
750
+ asset.image = image;
751
+ image.loading = "eager";
752
+ image.decoding = "async";
753
+ const url = retryUrl(asset.url, asset.retries);
754
+ let settled = false;
755
+ let decoding = false;
756
+ const current = () => !settled && isCurrent(run) && asset.image === image;
757
+ const detach = () => {
758
+ image.removeEventListener("load", handleLoad);
759
+ image.removeEventListener("error", handleError);
760
+ asset.detach = null;
761
+ };
762
+ const handleError = () => {
763
+ if (!current()) return;
764
+ settled = true;
765
+ detach();
766
+ image.removeAttribute("src");
767
+ asset.image = null;
768
+ if (asset.retries < RETRY_DELAYS.length) {
769
+ const delay = RETRY_DELAYS[asset.retries];
770
+ asset.retries += 1;
771
+ asset.timer = setTimeout(() => {
772
+ if (!isCurrent(run)) return;
773
+ asset.timer = null;
774
+ request(asset, run);
775
+ }, delay);
776
+ } else {
777
+ asset.status = "failed";
778
+ reconcile();
779
+ }
780
+ };
781
+ const handleLoad = () => {
782
+ if (!current() || decoding) return;
783
+ decoding = true;
784
+ void image.decode().then(() => {
785
+ if (!current()) return;
786
+ settled = true;
787
+ detach();
788
+ asset.loadedUrl = url;
789
+ asset.status = "ready";
790
+ reconcile();
791
+ }, handleError);
792
+ };
793
+ asset.detach = detach;
794
+ image.addEventListener("load", handleLoad);
795
+ image.addEventListener("error", handleError);
796
+ image.src = url;
797
+ };
798
+ const stop = () => {
799
+ active = false;
800
+ generation += 1;
801
+ for (const asset of assets.values()) {
802
+ if (asset.timer !== null) clearTimeout(asset.timer);
803
+ asset.timer = null;
804
+ asset.detach?.();
805
+ asset.image?.removeAttribute("src");
806
+ asset.image = null;
807
+ asset.status = "idle";
808
+ asset.loadedUrl = null;
809
+ asset.retries = 0;
810
+ }
811
+ displayedIndex = null;
812
+ lastState = null;
813
+ };
814
+ return {
815
+ start() {
816
+ if (disposed || active) return;
817
+ active = true;
818
+ const run = ++generation;
819
+ reconcile();
820
+ for (const asset of assets.values()) request(asset, run);
821
+ },
822
+ select(level) {
823
+ if (disposed || !Number.isFinite(level)) return;
824
+ targetLevel = level;
825
+ reconcile();
826
+ },
827
+ stop,
828
+ dispose() {
829
+ stop();
830
+ disposed = true;
831
+ onChange = null;
832
+ }
833
+ };
834
+ }
835
+
629
836
  // src/client/logic.ts
630
837
  var PREVIEW_MAX_FRAME = 240;
631
838
  var MAX_LEVEL = 30;
@@ -665,19 +872,6 @@ function selectedEffortIndex(efforts, selectedId, defaultId) {
665
872
  const id = selectedId ?? defaultId;
666
873
  return id === void 0 ? -1 : efforts.findIndex((effort) => effort.id === id);
667
874
  }
668
- function portraitBlendForLevel(level, anchors) {
669
- if (anchors.length === 0) return { lowerIndex: -1, upperIndex: -1, mix: 0 };
670
- const safeLevel = Number.isFinite(level) ? Math.min(anchors[anchors.length - 1], Math.max(anchors[0], level)) : anchors[0];
671
- let upperIndex = anchors.findIndex((anchor) => anchor >= safeLevel);
672
- if (upperIndex < 0) upperIndex = anchors.length - 1;
673
- const lowerIndex = Math.max(0, upperIndex - (anchors[upperIndex] > safeLevel ? 1 : 0));
674
- const span = anchors[upperIndex] - anchors[lowerIndex];
675
- return {
676
- lowerIndex,
677
- upperIndex,
678
- mix: span === 0 ? 0 : (safeLevel - anchors[lowerIndex]) / span
679
- };
680
- }
681
875
  function liangRankForFrame(rawFrame) {
682
876
  const level = clampFrame(rawFrame) / PREVIEW_MAX_FRAME * MAX_LEVEL;
683
877
  const index = level >= MAX_LEVEL ? LIANG_RANKS.length - 1 : Math.floor(level / 6);
@@ -750,7 +944,6 @@ var import_jsx_runtime = require("react/jsx-runtime");
750
944
  var PACKAGE_ID = "dsh-client-liang-intensity-skin";
751
945
  var LOCALE_NAMESPACE = "liang.skin";
752
946
  var ASSET_PREFIX = `/plugins/${PACKAGE_ID}/assets`;
753
- var FIRST_PORTRAIT_FILE = "portrait-source-v2/stage-00.webp";
754
947
  var BIND_EFFORT_KEY = "dsh-liang-intensity-skin.bind-effort";
755
948
  var PORTRAIT_ANCHORS = [
756
949
  { level: 0, file: "stage-00.webp" },
@@ -778,7 +971,6 @@ var PORTRAIT_ANCHORS = [
778
971
  { level: 29, file: "level-29.webp" },
779
972
  { level: 30, file: "stage-30.webp" }
780
973
  ];
781
- var ANCHOR_LEVELS = PORTRAIT_ANCHORS.map((anchor) => anchor.level);
782
974
  var cssVariables = [
783
975
  "--liang-strength",
784
976
  "--liang-page",
@@ -800,9 +992,7 @@ var SkinPresenter = class {
800
992
  scope;
801
993
  theme;
802
994
  root;
803
- portrait;
804
- preloads;
805
- portraitReady = false;
995
+ portraits;
806
996
  enabled = true;
807
997
  // Default to the max frame so the first paint after load is the dark shell;
808
998
  // starting at 0 flashed the light palette before the directory resolved.
@@ -817,46 +1007,31 @@ var SkinPresenter = class {
817
1007
  this.root = document.createElement("div");
818
1008
  this.root.className = "liang-skin-backdrop";
819
1009
  this.root.dataset.plugin = PACKAGE_ID;
820
- this.root.dataset.media = "sequence";
1010
+ this.root.dataset.media = "color";
821
1011
  this.root.setAttribute("aria-hidden", "true");
822
- this.portrait = document.createElement("img");
823
- this.portrait.className = "liang-skin-sequence-frame";
824
- this.portrait.alt = "";
825
- this.portrait.draggable = false;
826
- this.portrait.decoding = "async";
827
- this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;
828
- this.portrait.addEventListener("error", this.handleSequenceError);
829
- this.preloads = PORTRAIT_ANCHORS.map(({ file }) => {
830
- const image = new Image();
831
- image.loading = "eager";
832
- image.decoding = "async";
833
- image.src = `${ASSET_PREFIX}/portrait-source-v2/${file}`;
834
- return image;
835
- });
836
- void Promise.all(this.preloads.map((image) => image.decode())).then(
837
- () => {
838
- if (this.disposed) return;
839
- this.portraitReady = true;
1012
+ this.portraits = createPortraitLoader({
1013
+ sources: PORTRAIT_ANCHORS.map(({ level, file }) => ({
1014
+ level,
1015
+ url: `${ASSET_PREFIX}/portrait-source-v2/${file}`
1016
+ })),
1017
+ onChange: ({ image }) => {
1018
+ if (this.disposed || !this.enabled) return;
1019
+ if (image === null) {
1020
+ this.root.dataset.media = "color";
1021
+ this.root.replaceChildren();
1022
+ return;
1023
+ }
1024
+ const portrait = image;
1025
+ portrait.className = "liang-skin-sequence-frame";
1026
+ portrait.alt = "";
1027
+ portrait.draggable = false;
1028
+ if (this.root.firstChild !== portrait) this.root.replaceChildren(portrait);
840
1029
  this.root.dataset.media = "sequence";
841
- this.updatePortrait(paletteForFrame(this.frame).level);
842
- },
843
- () => {
844
1030
  }
845
- );
846
- this.root.append(this.portrait);
847
- document.body.prepend(this.root);
1031
+ });
848
1032
  this.unsubscribe = scope.subscribe(() => this.syncSettings());
849
1033
  this.syncSettings();
850
1034
  }
851
- handleSequenceError = () => {
852
- if (this.portrait.src.endsWith(FIRST_PORTRAIT_FILE)) {
853
- this.root.dataset.media = "color";
854
- return;
855
- }
856
- this.portraitReady = false;
857
- this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;
858
- this.root.dataset.media = "sequence";
859
- };
860
1035
  syncSettings() {
861
1036
  this.setEnabled(this.scope.getSnapshot().enabled);
862
1037
  }
@@ -867,19 +1042,27 @@ var SkinPresenter = class {
867
1042
  return this.frame;
868
1043
  }
869
1044
  setEnabled(enabled) {
1045
+ if (this.disposed) return;
870
1046
  this.enabled = enabled;
871
1047
  if (enabled) {
872
1048
  if (!this.root.isConnected) document.body.prepend(this.root);
873
1049
  document.body.dataset.liangSkin = "on";
874
1050
  this.applyFrame();
1051
+ this.portraits.start();
875
1052
  } else {
1053
+ if (this.raf !== 0) cancelAnimationFrame(this.raf);
1054
+ this.raf = 0;
876
1055
  this.root.remove();
1056
+ this.portraits.stop();
1057
+ this.root.replaceChildren();
1058
+ this.root.dataset.media = "color";
877
1059
  delete document.body.dataset.liangSkin;
878
1060
  delete document.body.dataset.liangStage;
879
1061
  for (const name of cssVariables) document.body.style.removeProperty(name);
880
1062
  }
881
1063
  }
882
1064
  setFrame(frame) {
1065
+ if (this.disposed) return;
883
1066
  this.pendingFrame = Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(frame)));
884
1067
  this.frame = this.pendingFrame;
885
1068
  if (!this.enabled) return;
@@ -891,6 +1074,7 @@ var SkinPresenter = class {
891
1074
  });
892
1075
  }
893
1076
  applyFrame() {
1077
+ if (this.disposed || !this.enabled) return;
894
1078
  const palette = paletteForFrame(this.frame);
895
1079
  const body = document.body;
896
1080
  this.syncNativeTheme(palette.stage === 5 ? "dark" : "light");
@@ -917,16 +1101,7 @@ var SkinPresenter = class {
917
1101
  this.theme.setTheme(theme);
918
1102
  }
919
1103
  updatePortrait(level) {
920
- if (!this.portraitReady) return;
921
- const { lowerIndex, upperIndex, mix: mix2 } = portraitBlendForLevel(
922
- level,
923
- ANCHOR_LEVELS
924
- );
925
- const lower = PORTRAIT_ANCHORS[lowerIndex];
926
- const upper = PORTRAIT_ANCHORS[upperIndex];
927
- const selected = mix2 >= 0.5 ? upper : lower;
928
- const source = `${ASSET_PREFIX}/portrait-source-v2/${selected.file}`;
929
- if (this.portrait.getAttribute("src") !== source) this.portrait.src = source;
1104
+ this.portraits.select(level);
930
1105
  }
931
1106
  async choose(enabled) {
932
1107
  this.setEnabled(enabled);
@@ -942,8 +1117,7 @@ var SkinPresenter = class {
942
1117
  this.disposed = true;
943
1118
  this.unsubscribe();
944
1119
  if (this.raf !== 0) cancelAnimationFrame(this.raf);
945
- this.portrait.removeEventListener("error", this.handleSequenceError);
946
- for (const image of this.preloads) image.src = "";
1120
+ this.portraits.dispose();
947
1121
  this.root.remove();
948
1122
  document.body.removeAttribute("data-liang-skin");
949
1123
  delete document.body.dataset.liangStage;
@@ -1110,116 +1284,29 @@ function LiangEffortSlider({ directory, load, select, presenter, scope }) {
1110
1284
  }
1111
1285
  );
1112
1286
  }
1113
- var NATIVE_APPEARANCE_GROUP = '[class*="_8HJdBW_group"]';
1114
- var NATIVE_APPEARANCE_ROW = '[class*="_8HJdBW_cubeRow"]';
1115
- var LIANG_APPEARANCE_BUTTON = "liang-appearance-choice";
1116
- var LIANG_BINDING_CONTROL = "liang-appearance-binding";
1117
- var LIANG_BINDING_INPUT = "liang-appearance-binding__input";
1118
- function installLiangAppearanceButton(scope, presenter) {
1119
- let pending = false;
1120
- const hookedNativeButtons = /* @__PURE__ */ new Set();
1121
- const nativeClickHandlers = /* @__PURE__ */ new Map();
1122
- const sync = () => {
1123
- const group = [...document.querySelectorAll(NATIVE_APPEARANCE_GROUP)].find((node) => node.querySelector('[class*="_8HJdBW_themeCube"]'));
1124
- const row = group?.querySelector(NATIVE_APPEARANCE_ROW);
1125
- if (row === void 0 || row === null) return;
1126
- let customButton = row.querySelector(`.${LIANG_APPEARANCE_BUTTON}`);
1127
- if (customButton === null) {
1128
- customButton = document.createElement("button");
1129
- customButton.className = LIANG_APPEARANCE_BUTTON;
1130
- customButton.type = "button";
1131
- customButton.dataset.plugin = PACKAGE_ID;
1132
- customButton.setAttribute("aria-label", "\u6ED1\u52A8\u53D8\u7956");
1133
- const icon = document.createElement("span");
1134
- icon.className = "liang-appearance-choice__icon";
1135
- icon.setAttribute("aria-hidden", "true");
1136
- icon.textContent = "\u25C8";
1137
- const label = document.createElement("span");
1138
- label.className = "liang-appearance-choice__label";
1139
- label.textContent = document.documentElement.lang.toLowerCase().startsWith("en") ? "Slider" : "\u6ED1\u52A8\u53D8\u7956";
1140
- customButton.append(icon, label);
1141
- customButton.addEventListener("click", () => {
1142
- if (pending || scope.getSnapshot().enabled) return;
1143
- pending = true;
1144
- sync();
1145
- void presenter.choose(true).finally(() => {
1146
- pending = false;
1147
- sync();
1148
- });
1149
- });
1150
- }
1151
- if (customButton.parentElement !== row) row.append(customButton);
1152
- const snapshot = scope.getSnapshot();
1153
- customButton.disabled = pending;
1154
- customButton.setAttribute("aria-pressed", String(snapshot.enabled));
1155
- let bindingControl = group.querySelector(`.${LIANG_BINDING_CONTROL}`);
1156
- if (!snapshot.enabled) {
1157
- bindingControl?.remove();
1158
- bindingControl = null;
1159
- } else if (bindingControl === null) {
1160
- bindingControl = document.createElement("label");
1161
- bindingControl.className = LIANG_BINDING_CONTROL;
1162
- bindingControl.dataset.plugin = PACKAGE_ID;
1163
- const bindingCopy = document.createElement("span");
1164
- bindingCopy.className = "liang-appearance-binding__copy";
1165
- const bindingLabel = document.createElement("span");
1166
- bindingLabel.className = "liang-appearance-binding__label";
1167
- const bindingText = document.documentElement.lang.toLowerCase().startsWith("en") ? "Bind slider to reasoning level" : "\u6ED1\u52A8\u53D8\u7956\u7ED1\u5B9A\u601D\u8003\u7B49\u7EA7";
1168
- bindingLabel.textContent = bindingText;
1169
- const bindingDescription = document.createElement("span");
1170
- bindingDescription.className = "liang-appearance-binding__description";
1171
- bindingDescription.id = "liang-appearance-binding-description";
1172
- bindingDescription.textContent = document.documentElement.lang.toLowerCase().startsWith("en") ? "When off, the slider does not change the reasoning level." : "\u5173\u95ED\u4E4B\u540E\u6ED1\u5757\u4E0D\u8054\u52A8\u601D\u8003\u7B49\u7EA7";
1173
- bindingCopy.append(bindingLabel, bindingDescription);
1174
- const bindingInput = document.createElement("input");
1175
- bindingInput.className = LIANG_BINDING_INPUT;
1176
- bindingInput.type = "checkbox";
1177
- bindingInput.setAttribute("role", "switch");
1178
- bindingInput.setAttribute("aria-label", bindingText);
1179
- bindingInput.setAttribute("aria-describedby", bindingDescription.id);
1180
- bindingInput.addEventListener("change", () => {
1181
- void scope.setBindEffort(bindingInput.checked).catch(() => sync());
1182
- });
1183
- bindingControl.append(bindingCopy, bindingInput);
1184
- group.append(bindingControl);
1185
- }
1186
- if (bindingControl !== null) {
1187
- const bindingInput = bindingControl.querySelector(`.${LIANG_BINDING_INPUT}`);
1188
- if (bindingInput !== null) {
1189
- bindingInput.checked = snapshot.bindEffort;
1190
- bindingInput.setAttribute("aria-checked", String(snapshot.bindEffort));
1191
- bindingInput.disabled = pending;
1287
+ function EffortBindingRow({ scope, t }) {
1288
+ const snapshot = (0, import_react.useSyncExternalStore)(
1289
+ (listener) => scope.subscribe(listener),
1290
+ () => scope.getSnapshot()
1291
+ );
1292
+ const [pending, setPending] = (0, import_react.useState)(false);
1293
+ if (!snapshot.enabled) return null;
1294
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "liang-appearance-binding", "data-plugin": PACKAGE_ID, children: [
1295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("effort.binding") }),
1296
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1297
+ import_dsh_client_ui_primitives.Switch,
1298
+ {
1299
+ checked: snapshot.bindEffort,
1300
+ disabled: pending,
1301
+ label: t("effort.binding"),
1302
+ onChange: (next) => {
1303
+ if (pending) return;
1304
+ setPending(true);
1305
+ void scope.setBindEffort(next).catch(() => void 0).finally(() => setPending(false));
1306
+ }
1192
1307
  }
1193
- }
1194
- for (const nativeButton of row.querySelectorAll('[class*="_8HJdBW_themeCube"]')) {
1195
- if (hookedNativeButtons.has(nativeButton)) continue;
1196
- hookedNativeButtons.add(nativeButton);
1197
- const handleNativeClick = () => {
1198
- if (pending || !scope.getSnapshot().enabled) return;
1199
- pending = true;
1200
- sync();
1201
- void presenter.choose(false).finally(() => {
1202
- pending = false;
1203
- sync();
1204
- });
1205
- };
1206
- nativeClickHandlers.set(nativeButton, handleNativeClick);
1207
- nativeButton.addEventListener("click", handleNativeClick, { capture: true });
1208
- }
1209
- };
1210
- const observer = new MutationObserver(sync);
1211
- observer.observe(document.body, { childList: true, subtree: true });
1212
- const unsubscribe = scope.subscribe(sync);
1213
- sync();
1214
- return () => {
1215
- observer.disconnect();
1216
- unsubscribe();
1217
- for (const [nativeButton, handleNativeClick] of nativeClickHandlers) {
1218
- nativeButton.removeEventListener("click", handleNativeClick, { capture: true });
1219
- }
1220
- document.querySelectorAll(`.${LIANG_APPEARANCE_BUTTON}`).forEach((button) => button.remove());
1221
- document.querySelectorAll(`.${LIANG_BINDING_CONTROL}`).forEach((control) => control.remove());
1222
- };
1308
+ )
1309
+ ] });
1223
1310
  }
1224
1311
  var inject = [
1225
1312
  "slots",
@@ -1284,28 +1371,23 @@ function apply(ctx) {
1284
1371
  const presenter = new SkinPresenter(scope, theme);
1285
1372
  ctx.effect(() => () => presenter.dispose(), "liang-intensity-skin: backdrop presenter");
1286
1373
  ctx.effect(
1287
- () => installLiangAppearanceButton(scope, presenter),
1374
+ () => installLiangAppearanceButton(scope, presenter, PACKAGE_ID),
1288
1375
  "liang-intensity-skin: native appearance extension"
1289
1376
  );
1290
1377
  ctx.effect(
1291
1378
  () => ctx.locale.register(LOCALE_NAMESPACE, {
1292
- zh: {
1293
- "appearance.title": "\u5916\u89C2",
1294
- "appearance.light": "\u6D45\u8272",
1295
- "appearance.dark": "\u6DF1\u8272",
1296
- "appearance.system": "\u8DDF\u968F\u7CFB\u7EDF",
1297
- "appearance.liang": "\u6ED1\u52A8\u53D8\u7956"
1298
- },
1299
- en: {
1300
- "appearance.title": "Appearance",
1301
- "appearance.light": "Light",
1302
- "appearance.dark": "Dark",
1303
- "appearance.system": "System",
1304
- "appearance.liang": "Slider"
1305
- }
1379
+ zh: { "effort.binding": "\u6ED1\u52A8\u53D8\u7956\u7ED1\u5B9A\u601D\u8003\u7B49\u7EA7" },
1380
+ en: { "effort.binding": "Bind slider to reasoning level" }
1306
1381
  }),
1307
1382
  "liang-intensity-skin: settings locale"
1308
1383
  );
1384
+ ctx.slots.inject("settings.general.item", () => ctx.slots.register({
1385
+ name: "settings.general.item",
1386
+ id: "liang-effort-binding",
1387
+ order: 10.5,
1388
+ locale: LOCALE_NAMESPACE,
1389
+ inject: () => ({ scope })
1390
+ }, EffortBindingRow));
1309
1391
  ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
1310
1392
  name: "conversation.input.right",
1311
1393
  id: "liang-intensity-control",
package/lib/client.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/client/index.tsx", "../src/client/skin.css", "../src/client/logic.ts"],
4
- "sourcesContent": ["import {\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport type { Context as ClientContext } from \"@deepseek-ai/cordis\";\nimport type { SnapshotStore } from \"@deepseek-ai/dsh-client-store\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-settings/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-model-selection/client\";\nimport styles from \"./skin.css\";\nimport {\n PREVIEW_MAX_FRAME,\n frameForEffort,\n indicatorLabel,\n nearestEffortIndex,\n paletteForFrame,\n portraitBlendForLevel,\n selectedEffortIndex,\n type EffortLike,\n} from \"./logic\";\n\nconst PACKAGE_ID = \"dsh-client-liang-intensity-skin\";\nconst LOCALE_NAMESPACE = \"liang.skin\";\nconst ASSET_PREFIX = `/plugins/${PACKAGE_ID}/assets`;\nconst FIRST_PORTRAIT_FILE = \"portrait-source-v2/stage-00.webp\";\nconst BIND_EFFORT_KEY = \"dsh-liang-intensity-skin.bind-effort\";\n\nconst PORTRAIT_ANCHORS = [\n { level: 0, file: \"stage-00.webp\" },\n { level: 1, file: \"level-01.webp\" },\n { level: 3, file: \"level-03.webp\" },\n { level: 4, file: \"level-04.webp\" },\n { level: 6, file: \"stage-06.webp\" },\n { level: 7, file: \"level-07.webp\" },\n { level: 9, file: \"level-09.webp\" },\n { level: 10, file: \"level-10.webp\" },\n { level: 12, file: \"stage-12.webp\" },\n { level: 13, file: \"level-13.webp\" },\n { level: 14, file: \"level-14.webp\" },\n { level: 15, file: \"bridge-15.webp\" },\n { level: 16, file: \"level-16.webp\" },\n { level: 17, file: \"level-17.webp\" },\n { level: 18, file: \"stage-18.webp\" },\n { level: 19, file: \"level-19.webp\" },\n { level: 21, file: \"level-21.webp\" },\n { level: 22, file: \"level-22.webp\" },\n { level: 24, file: \"stage-24.webp\" },\n { level: 25, file: \"level-25.webp\" },\n { level: 27, file: \"bridge-27.webp\" },\n { level: 28, file: \"level-28.webp\" },\n { level: 29, file: \"level-29.webp\" },\n { level: 30, file: \"stage-30.webp\" },\n] as const;\n\nconst ANCHOR_LEVELS = PORTRAIT_ANCHORS.map((anchor) => anchor.level);\n\ninterface SkinSettings {\n enabled: boolean;\n bindEffort: boolean;\n}\n\ninterface PreferenceStore {\n getSnapshot(): SkinSettings;\n subscribe(listener: () => void): () => void;\n set(enabled: boolean): Promise<void>;\n setBindEffort(enabled: boolean): Promise<void>;\n dispose(): void;\n}\n\ntype NativeThemeId = \"light\" | \"dark\";\n\ninterface ThemeService {\n getTheme(): { preference: string };\n setTheme(id: NativeThemeId | \"system\"): void;\n}\n\ninterface ModelSelection {\n provider: string;\n model: string;\n reasoningEffort?: string;\n}\n\ninterface CatalogModel {\n id: string;\n reasoning?: {\n efforts: EffortLike[];\n defaultEffort?: string;\n };\n}\n\ninterface ModelDirectoryState {\n current: ModelSelection | null;\n groups: readonly { id: string; models: CatalogModel[] }[];\n status: \"idle\" | \"loading\" | \"ready\" | \"selecting\" | \"error\";\n error: string | null;\n}\n\ninterface ModelDirectory {\n store: SnapshotStore<ModelDirectoryState>;\n load(): Promise<unknown>;\n select(selection: ModelSelection): Promise<{ ok: boolean }>;\n}\n\ninterface SliderProps {\n directory: SnapshotStore<ModelDirectoryState>;\n load: () => void;\n select: (selection: ModelSelection) => Promise<boolean>;\n presenter: SkinPresenter;\n scope: PreferenceStore;\n}\n\ninterface SettingsRowProps {\n scope: PreferenceStore;\n presenter: SkinPresenter;\n theme: ThemeService;\n subscribeTheme: (listener: () => void) => () => void;\n t: (key: string) => string;\n}\n\nconst cssVariables = [\n \"--liang-strength\",\n \"--liang-page\",\n \"--liang-bg-base\",\n \"--liang-layer-1\",\n \"--liang-layer-2\",\n \"--liang-layer-3\",\n \"--liang-sidebar\",\n \"--liang-ink\",\n \"--liang-secondary\",\n \"--liang-tertiary\",\n \"--liang-border\",\n \"--liang-accent\",\n \"--liang-accent-hover\",\n \"--liang-hover\",\n \"--liang-portrait-opacity\",\n] as const;\n\nclass SkinPresenter {\n private readonly scope: PreferenceStore;\n private readonly theme: ThemeService;\n private readonly root: HTMLDivElement;\n private readonly portrait: HTMLImageElement;\n private readonly preloads: HTMLImageElement[];\n private portraitReady = false;\n private enabled = true;\n // Default to the max frame so the first paint after load is the dark shell;\n // starting at 0 flashed the light palette before the directory resolved.\n private frame = PREVIEW_MAX_FRAME;\n private pendingFrame = PREVIEW_MAX_FRAME;\n private raf = 0;\n private disposed = false;\n private unsubscribe: () => void;\n\n constructor(scope: PreferenceStore, theme: ThemeService) {\n this.scope = scope;\n this.theme = theme;\n this.root = document.createElement(\"div\");\n this.root.className = \"liang-skin-backdrop\";\n this.root.dataset.plugin = PACKAGE_ID;\n // Show the first half-body frame immediately while the remaining frames\n // are fetched and decoded. A request being complete does not mean the\n // bitmap is ready for a tear-free first swap.\n this.root.dataset.media = \"sequence\";\n this.root.setAttribute(\"aria-hidden\", \"true\");\n\n this.portrait = document.createElement(\"img\");\n this.portrait.className = \"liang-skin-sequence-frame\";\n this.portrait.alt = \"\";\n this.portrait.draggable = false;\n this.portrait.decoding = \"async\";\n this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;\n this.portrait.addEventListener(\"error\", this.handleSequenceError);\n\n this.preloads = PORTRAIT_ANCHORS.map(({ file }) => {\n const image = new Image();\n image.loading = \"eager\";\n image.decoding = \"async\";\n image.src = `${ASSET_PREFIX}/portrait-source-v2/${file}`;\n return image;\n });\n\n // `new Image()` starts the requests, but the browser may still defer\n // decoding until the image is attached to the document. Wait for all\n // frames up front so the first slider interaction never reveals a blank\n // or half-painted frame.\n void Promise.all(this.preloads.map((image) => image.decode())).then(\n () => {\n if (this.disposed) return;\n this.portraitReady = true;\n this.root.dataset.media = \"sequence\";\n this.updatePortrait(paletteForFrame(this.frame).level);\n },\n () => {\n // Keep the already-visible first half-body frame if another optional\n // frame cannot be decoded. It is still a valid skin fallback.\n },\n );\n\n this.root.append(this.portrait);\n document.body.prepend(this.root);\n\n this.unsubscribe = scope.subscribe(() => this.syncSettings());\n this.syncSettings();\n }\n\n private readonly handleSequenceError = () => {\n if (this.portrait.src.endsWith(FIRST_PORTRAIT_FILE)) {\n this.root.dataset.media = \"color\";\n return;\n }\n this.portraitReady = false;\n this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;\n this.root.dataset.media = \"sequence\";\n };\n\n private syncSettings() {\n this.setEnabled(this.scope.getSnapshot().enabled);\n }\n\n isEnabled() {\n return this.enabled;\n }\n\n getFrame() {\n return this.frame;\n }\n\n setEnabled(enabled: boolean) {\n this.enabled = enabled;\n if (enabled) {\n if (!this.root.isConnected) document.body.prepend(this.root);\n document.body.dataset.liangSkin = \"on\";\n this.applyFrame();\n } else {\n this.root.remove();\n delete document.body.dataset.liangSkin;\n delete document.body.dataset.liangStage;\n for (const name of cssVariables) document.body.style.removeProperty(name);\n }\n }\n\n setFrame(frame: number) {\n this.pendingFrame = Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(frame)));\n this.frame = this.pendingFrame;\n if (!this.enabled) return;\n if (this.raf !== 0) return;\n this.raf = requestAnimationFrame(() => {\n this.raf = 0;\n this.frame = this.pendingFrame;\n this.applyFrame();\n });\n }\n\n private applyFrame() {\n const palette = paletteForFrame(this.frame);\n const body = document.body;\n this.syncNativeTheme(palette.stage === 5 ? \"dark\" : \"light\");\n body.dataset.liangStage = String(palette.stage);\n body.style.setProperty(\"--liang-strength\", String(palette.strength));\n body.style.setProperty(\"--liang-page\", palette.page);\n body.style.setProperty(\"--liang-bg-base\", palette.base);\n body.style.setProperty(\"--liang-layer-1\", palette.layer1);\n body.style.setProperty(\"--liang-layer-2\", palette.layer2);\n body.style.setProperty(\"--liang-layer-3\", palette.layer3);\n body.style.setProperty(\"--liang-sidebar\", palette.sidebar);\n body.style.setProperty(\"--liang-ink\", palette.ink);\n body.style.setProperty(\"--liang-secondary\", palette.secondary);\n body.style.setProperty(\"--liang-tertiary\", palette.tertiary);\n body.style.setProperty(\"--liang-border\", palette.border);\n body.style.setProperty(\"--liang-accent\", palette.accent);\n body.style.setProperty(\"--liang-accent-hover\", palette.accentHover);\n body.style.setProperty(\"--liang-hover\", palette.hover);\n body.style.setProperty(\"--liang-portrait-opacity\", palette.portraitOpacity);\n this.updatePortrait(palette.level);\n }\n\n syncNativeTheme(theme: NativeThemeId = paletteForFrame(this.frame).stage === 5 ? \"dark\" : \"light\") {\n if (!this.enabled || this.theme.getTheme().preference === theme) return;\n this.theme.setTheme(theme);\n }\n\n private updatePortrait(level: number) {\n if (!this.portraitReady) return;\n const { lowerIndex, upperIndex, mix } = portraitBlendForLevel(\n level,\n ANCHOR_LEVELS,\n );\n const lower = PORTRAIT_ANCHORS[lowerIndex];\n const upper = PORTRAIT_ANCHORS[upperIndex];\n const selected = mix >= 0.5 ? upper : lower;\n const source = `${ASSET_PREFIX}/portrait-source-v2/${selected.file}`;\n if (this.portrait.getAttribute(\"src\") !== source) this.portrait.src = source;\n }\n\n async choose(enabled: boolean) {\n this.setEnabled(enabled);\n try {\n await this.scope.set(enabled);\n } catch (error) {\n this.syncSettings();\n throw error;\n }\n }\n\n dispose() {\n if (this.disposed) return;\n this.disposed = true;\n this.unsubscribe();\n if (this.raf !== 0) cancelAnimationFrame(this.raf);\n this.portrait.removeEventListener(\"error\", this.handleSequenceError);\n for (const image of this.preloads) image.src = \"\";\n this.root.remove();\n document.body.removeAttribute(\"data-liang-skin\");\n delete document.body.dataset.liangStage;\n for (const name of cssVariables) document.body.style.removeProperty(name);\n }\n}\n\nfunction modelReasoning(state: ModelDirectoryState) {\n const current = state.current;\n if (current === null) return null;\n const group = state.groups.find((item) => item.id === current.provider);\n const model = group?.models.find((item) => item.id === current.model);\n if (model?.reasoning === undefined) return null;\n return {\n selection: current,\n efforts: model.reasoning.efforts,\n defaultEffort: model.reasoning.defaultEffort,\n };\n}\n\nfunction LiangEffortSlider({ directory, load, select, presenter, scope }: SliderProps) {\n const state = useSyncExternalStore(\n (listener) => directory.subscribe(listener),\n () => directory.getSnapshot(),\n );\n const skin = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n );\n const reasoning = useMemo(() => modelReasoning(state), [state]);\n const efforts = reasoning?.efforts ?? [];\n const committedIndex = selectedEffortIndex(\n efforts,\n reasoning?.selection.reasoningEffort,\n reasoning?.defaultEffort,\n );\n // An unknown committed effort defaults to the max frame: a fresh\n // conversation paints the dark shell immediately instead of flashing the\n // light palette until the directory load resolves the real effort.\n const committedFrame = committedIndex < 0\n ? PREVIEW_MAX_FRAME\n : frameForEffort(committedIndex, efforts.length);\n const bindEffort = skin.bindEffort;\n const [frame, setFrame] = useState(() => bindEffort ? committedFrame : presenter.getFrame());\n const [pending, setPending] = useState(false);\n const [failed, setFailed] = useState(false);\n const [interacting, setInteracting] = useState(false);\n const dragging = useRef(false);\n const dragStartFrame = useRef(frame);\n const enabled = skin.enabled;\n\n useEffect(() => {\n if (enabled) load();\n }, [enabled, load]);\n\n useEffect(() => {\n if (!bindEffort || dragging.current || pending) return;\n setFrame(committedFrame);\n presenter.setFrame(committedFrame);\n }, [bindEffort, committedFrame, pending, presenter]);\n\n if (!enabled) return null;\n if (bindEffort && (reasoning === null || efforts.length < 2)) return null;\n\n const previewIndex = nearestEffortIndex(frame, efforts);\n const previewEffort = efforts[previewIndex];\n const progressRatio = frame / PREVIEW_MAX_FRAME;\n const tooltipLabel = indicatorLabel(frame, bindEffort ? efforts : []);\n\n const commit = async (rawFrame: number) => {\n if (!bindEffort) {\n dragging.current = false;\n setFrame(rawFrame);\n presenter.setFrame(rawFrame);\n return;\n }\n const targetIndex = nearestEffortIndex(rawFrame, efforts);\n const target = efforts[targetIndex];\n if (target === undefined) return;\n const targetFrame = frameForEffort(targetIndex, efforts.length);\n dragging.current = false;\n setFrame(targetFrame);\n presenter.setFrame(targetFrame);\n if (targetIndex === committedIndex || pending) return;\n setPending(true);\n setFailed(false);\n const accepted = await select({\n provider: reasoning.selection.provider,\n model: reasoning.selection.model,\n reasoningEffort: target.id,\n });\n setPending(false);\n if (!accepted) {\n setFailed(true);\n setFrame(committedFrame);\n presenter.setFrame(committedFrame);\n }\n };\n\n return (\n <div\n className=\"liang-effort-control\"\n data-plugin={PACKAGE_ID}\n data-state={failed ? \"error\" : pending ? \"pending\" : \"ready\"}\n title={bindEffort ? previewEffort?.name : undefined}\n >\n {interacting && (\n <output\n className=\"liang-effort-control__tooltip\"\n style={{ \"--liang-slider-ratio\": progressRatio } as React.CSSProperties}\n >\n {tooltipLabel}\n </output>\n )}\n <div className=\"liang-effort-control__ticks\" aria-hidden=\"true\">\n {efforts.map((effort, index) => (\n <i\n className=\"liang-effort-control__tick\"\n key={effort.id}\n style={{ left: `${(frameForEffort(index, efforts.length) / PREVIEW_MAX_FRAME) * 100}%` }}\n />\n ))}\n </div>\n <input\n className=\"liang-effort-control__range\"\n type=\"range\"\n min={0}\n max={PREVIEW_MAX_FRAME}\n step={1}\n value={frame}\n disabled={pending || state.status === \"selecting\"}\n aria-label={bindEffort ? \"\u601D\u8003\u7B49\u7EA7\" : \"\u76AE\u80A4\u8FDB\u5EA6\"}\n aria-valuetext={bindEffort ? previewEffort?.name ?? \"\" : tooltipLabel}\n onPointerDown={() => {\n dragging.current = true;\n dragStartFrame.current = frame;\n setInteracting(true);\n }}\n onInput={(event) => {\n dragging.current = true;\n const next = Number(event.currentTarget.value);\n setFrame(next);\n presenter.setFrame(next);\n }}\n onPointerUp={(event) => {\n setInteracting(false);\n void commit(Number(event.currentTarget.value));\n }}\n onPointerCancel={() => {\n setInteracting(false);\n dragging.current = false;\n setFrame(dragStartFrame.current);\n presenter.setFrame(dragStartFrame.current);\n }}\n onKeyUp={(event) => {\n setInteracting(false);\n if (event.key !== \"Escape\") void commit(Number(event.currentTarget.value));\n }}\n onBlur={(event) => {\n setInteracting(false);\n if (dragging.current) void commit(Number(event.currentTarget.value));\n }}\n onKeyDown={(event) => {\n setInteracting(true);\n if (event.key === \"Escape\" && !pending) {\n setInteracting(false);\n dragging.current = false;\n setFrame(dragStartFrame.current);\n presenter.setFrame(dragStartFrame.current);\n }\n }}\n />\n </div>\n );\n}\n\ntype AppearanceChoice = NativeThemeId | \"system\" | \"liang\";\n\nconst APPEARANCE_CHOICES: readonly { id: AppearanceChoice; labelKey: string }[] = [\n { id: \"light\", labelKey: \"appearance.light\" },\n { id: \"dark\", labelKey: \"appearance.dark\" },\n { id: \"system\", labelKey: \"appearance.system\" },\n { id: \"liang\", labelKey: \"appearance.liang\" },\n];\n\nfunction NativeAppearanceIcon({ id }: { id: Exclude<AppearanceChoice, \"liang\"> }) {\n if (id === \"light\") {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M11.3496 8C11.3496 6.14985 9.85015 4.65039 8 4.65039C6.14985 4.65039 4.65039 6.14985 4.65039 8C4.65039 9.85015 6.14985 11.3496 8 11.3496C9.85015 11.3496 11.3496 9.85015 11.3496 8ZM12.6504 8C12.6504 10.5681 10.5681 12.6504 8 12.6504C5.43188 12.6504 3.34961 10.5681 3.34961 8C3.34961 5.43188 5.43188 3.34961 8 3.34961C10.5681 3.34961 12.6504 5.43188 12.6504 8Z\" fill=\"currentColor\" />\n <path d=\"M8.65039 0.5V2.5H7.34961V0.5H8.65039Z\" fill=\"currentColor\" />\n <path d=\"M8.65039 13.5V15.5H7.34961V13.5H8.65039Z\" fill=\"currentColor\" />\n <path d=\"M3.15808 2.24035L4.57229 3.65456L3.6525 4.57435L2.23829 3.16014L3.15808 2.24035Z\" fill=\"currentColor\" />\n <path d=\"M12.3505 11.4327L13.7647 12.8469L12.8449 13.7667L11.4307 12.3525L12.3505 11.4327Z\" fill=\"currentColor\" />\n <path d=\"M2.24537 12.8469L3.65958 11.4327L4.57937 12.3525L3.16516 13.7667L2.24537 12.8469Z\" fill=\"currentColor\" />\n <path d=\"M11.4377 3.65455L12.852 2.24033L13.7718 3.16012L12.3575 4.57434L11.4377 3.65455Z\" fill=\"currentColor\" />\n <path d=\"M0.5 7.35461H2.5V8.6554H0.5L0.5 7.35461Z\" fill=\"currentColor\" />\n <path d=\"M13.5 7.35461H15.5V8.6554H13.5V7.35461Z\" fill=\"currentColor\" />\n </svg>\n );\n }\n\n if (id === \"dark\") {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M13.2764 9.52324C12.5607 9.97754 11.7177 10.242 10.7812 10.242C8.11386 10.2419 5.95042 8.07997 5.9502 5.41289C5.9502 4.48128 6.21453 3.61071 6.67188 2.87285C4.30332 3.4658 2.54992 5.60845 2.5498 8.16093C2.5498 11.1712 4.99103 13.6102 8 13.6102C10.5383 13.6102 12.6709 11.8724 13.2764 9.52324ZM7.05078 5.41289C7.051 7.47224 8.72116 9.1423 10.7812 9.14238C11.9248 9.14238 12.887 8.63397 13.5781 7.8084C13.7266 7.63106 13.9701 7.56547 14.1875 7.64433C14.4049 7.72329 14.5497 7.9297 14.5498 8.16093C14.5498 11.7766 11.6161 14.7098 8 14.7098C4.38402 14.7098 1.4502 11.7792 1.4502 8.16093C1.45033 4.54322 4.3812 1.61015 8 1.61015C8.23027 1.61015 8.43585 1.75352 8.51562 1.96953C8.59536 2.18554 8.53241 2.42829 8.35742 2.57793C7.55573 3.26311 7.05078 4.27876 7.05078 5.41289Z\" fill=\"currentColor\" />\n </svg>\n );\n }\n\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.1665 13.5811V14.7803H3.66651V13.5811H12.1665Z\" fill=\"currentColor\" />\n <path d=\"M13.4453 7.02379C13.4453 6.04702 13.4452 5.3616 13.3887 4.83434C13.3333 4.31828 13.2302 4.02378 13.0723 3.80309C12.9446 3.62475 12.7877 3.46883 12.6094 3.34117C12.3887 3.18328 12.0942 3.08007 11.5781 3.02477C11.0508 2.96829 10.3655 2.96715 9.38867 2.96715H6.61035C5.63359 2.96715 4.94816 2.96827 4.4209 3.02477C3.90486 3.0801 3.61034 3.18321 3.38965 3.34117C3.21143 3.46878 3.05534 3.62487 2.92774 3.80309C2.76977 4.02377 2.66667 4.3183 2.61133 4.83434C2.55483 5.3616 2.55371 6.04702 2.55371 7.02379C2.55371 8.0006 2.55485 8.68596 2.61133 9.21324C2.66663 9.72936 2.76983 10.0238 2.92774 10.2445C3.0554 10.4228 3.21131 10.5797 3.38965 10.7074C3.61034 10.8654 3.90484 10.9685 4.4209 11.0238C4.94816 11.0803 5.63359 11.0804 6.61035 11.0804H9.38867C10.3654 11.0804 11.0508 11.0803 11.5781 11.0238C12.0941 10.9685 12.3887 10.8652 12.6094 10.7074C12.7877 10.5797 12.9446 10.4229 13.0723 10.2445C13.2301 10.0238 13.3334 9.72927 13.3887 9.21324C13.4452 8.68596 13.4453 8.00058 13.4453 7.02379ZM14.6455 7.02379C14.6455 7.97428 14.646 8.73509 14.5811 9.34117C14.5149 9.95828 14.3756 10.4858 14.0479 10.9437C13.8436 11.229 13.5938 11.4788 13.3086 11.683C12.8507 12.0108 12.3232 12.15 11.7061 12.2162C11.1 12.2811 10.3391 12.2806 9.38867 12.2806H6.61035C5.66018 12.2806 4.89991 12.2811 4.29395 12.2162C3.67684 12.15 3.14935 12.0108 2.69141 11.683C2.40613 11.4788 2.15639 11.229 1.95215 10.9437C1.62436 10.4858 1.4841 9.95828 1.41797 9.34117C1.35305 8.73511 1.35449 7.97424 1.35449 7.02379C1.35449 6.07366 1.35308 5.31333 1.41797 4.70738C1.4841 4.09028 1.62436 3.56279 1.95215 3.10485C2.15638 2.81956 2.40613 2.56982 2.69141 2.36559C3.14935 2.03779 3.67684 1.89753 4.29395 1.83141C4.8999 1.76652 5.66022 1.76793 6.61035 1.76793H9.38867C10.3391 1.76793 11.1 1.76649 11.7061 1.83141C12.3232 1.89753 12.8507 2.03779 13.3086 2.36559C13.5939 2.56982 13.8436 2.81957 14.0479 3.10485C14.3756 3.56279 14.5149 4.09028 14.5811 4.70738C14.646 5.31335 14.6455 6.07362 14.6455 7.02379Z\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nfunction AppearanceSkinRow({ scope, presenter, theme, subscribeTheme, t }: SettingsRowProps) {\n const snapshot = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n );\n const preference = useSyncExternalStore(\n subscribeTheme,\n () => theme.getTheme().preference,\n );\n const selected = snapshot.enabled\n ? \"liang\"\n : preference === \"light\" || preference === \"dark\" || preference === \"system\"\n ? preference\n : \"system\";\n const [pending, setPending] = useState(false);\n\n const choose = async (next: AppearanceChoice) => {\n if (next === selected || pending) return;\n setPending(true);\n try {\n if (next === \"liang\") {\n await presenter.choose(true);\n } else {\n // Disable the custom skin first. This is intentionally unconditional:\n // it makes the native choice the only writer after this click, even if\n // the external preference store is one render behind.\n await presenter.choose(false);\n theme.setTheme(next);\n }\n } finally {\n setPending(false);\n }\n };\n\n return (\n <div className=\"liang-settings-row\" data-plugin={PACKAGE_ID}>\n <span className=\"liang-settings-row__title\">{t(\"appearance.title\")}</span>\n <div className=\"liang-settings-row__choices\">\n {APPEARANCE_CHOICES.map(({ id, labelKey }) => (\n <button\n className={`liang-settings-row__choice${id === \"liang\" ? \" liang-settings-row__choice--liang\" : \"\"}`}\n type=\"button\"\n aria-pressed={selected === id}\n disabled={pending}\n onClick={() => void choose(id)}\n key={id}\n >\n {id === \"liang\" ? (\n <span className=\"liang-settings-row__liang-icon\" aria-hidden=\"true\">\u25C8</span>\n ) : (\n <NativeAppearanceIcon id={id} />\n )}\n {t(labelKey)}\n </button>\n ))}\n </div>\n </div>\n );\n}\n\nconst NATIVE_APPEARANCE_GROUP = '[class*=\"_8HJdBW_group\"]';\nconst NATIVE_APPEARANCE_ROW = '[class*=\"_8HJdBW_cubeRow\"]';\nconst LIANG_APPEARANCE_BUTTON = \"liang-appearance-choice\";\nconst LIANG_BINDING_CONTROL = \"liang-appearance-binding\";\nconst LIANG_BINDING_INPUT = \"liang-appearance-binding__input\";\n\nfunction installLiangAppearanceButton(scope: PreferenceStore, presenter: SkinPresenter) {\n let pending = false;\n const hookedNativeButtons = new Set<HTMLButtonElement>();\n const nativeClickHandlers = new Map<HTMLButtonElement, () => void>();\n\n const sync = () => {\n const group = [...document.querySelectorAll<HTMLElement>(NATIVE_APPEARANCE_GROUP)]\n .find((node) => node.querySelector('[class*=\"_8HJdBW_themeCube\"]'));\n const row = group?.querySelector<HTMLElement>(NATIVE_APPEARANCE_ROW);\n if (row === undefined || row === null) return;\n\n let customButton = row.querySelector<HTMLButtonElement>(`.${LIANG_APPEARANCE_BUTTON}`);\n if (customButton === null) {\n customButton = document.createElement(\"button\");\n customButton.className = LIANG_APPEARANCE_BUTTON;\n customButton.type = \"button\";\n customButton.dataset.plugin = PACKAGE_ID;\n customButton.setAttribute(\"aria-label\", \"\u6ED1\u52A8\u53D8\u7956\");\n\n const icon = document.createElement(\"span\");\n icon.className = \"liang-appearance-choice__icon\";\n icon.setAttribute(\"aria-hidden\", \"true\");\n icon.textContent = \"\u25C8\";\n\n const label = document.createElement(\"span\");\n label.className = \"liang-appearance-choice__label\";\n label.textContent = document.documentElement.lang.toLowerCase().startsWith(\"en\")\n ? \"Slider\"\n : \"\u6ED1\u52A8\u53D8\u7956\";\n customButton.append(icon, label);\n customButton.addEventListener(\"click\", () => {\n if (pending || scope.getSnapshot().enabled) return;\n pending = true;\n sync();\n void presenter.choose(true).finally(() => {\n pending = false;\n sync();\n });\n });\n }\n\n if (customButton.parentElement !== row) row.append(customButton);\n const snapshot = scope.getSnapshot();\n customButton.disabled = pending;\n customButton.setAttribute(\"aria-pressed\", String(snapshot.enabled));\n\n let bindingControl = group.querySelector<HTMLElement>(`.${LIANG_BINDING_CONTROL}`);\n if (!snapshot.enabled) {\n bindingControl?.remove();\n bindingControl = null;\n } else if (bindingControl === null) {\n bindingControl = document.createElement(\"label\");\n bindingControl.className = LIANG_BINDING_CONTROL;\n bindingControl.dataset.plugin = PACKAGE_ID;\n\n const bindingCopy = document.createElement(\"span\");\n bindingCopy.className = \"liang-appearance-binding__copy\";\n\n const bindingLabel = document.createElement(\"span\");\n bindingLabel.className = \"liang-appearance-binding__label\";\n const bindingText = document.documentElement.lang.toLowerCase().startsWith(\"en\")\n ? \"Bind slider to reasoning level\"\n : \"\u6ED1\u52A8\u53D8\u7956\u7ED1\u5B9A\u601D\u8003\u7B49\u7EA7\";\n bindingLabel.textContent = bindingText;\n\n const bindingDescription = document.createElement(\"span\");\n bindingDescription.className = \"liang-appearance-binding__description\";\n bindingDescription.id = \"liang-appearance-binding-description\";\n bindingDescription.textContent = document.documentElement.lang.toLowerCase().startsWith(\"en\")\n ? \"When off, the slider does not change the reasoning level.\"\n : \"\u5173\u95ED\u4E4B\u540E\u6ED1\u5757\u4E0D\u8054\u52A8\u601D\u8003\u7B49\u7EA7\";\n bindingCopy.append(bindingLabel, bindingDescription);\n\n const bindingInput = document.createElement(\"input\");\n bindingInput.className = LIANG_BINDING_INPUT;\n bindingInput.type = \"checkbox\";\n bindingInput.setAttribute(\"role\", \"switch\");\n bindingInput.setAttribute(\"aria-label\", bindingText);\n bindingInput.setAttribute(\"aria-describedby\", bindingDescription.id);\n bindingInput.addEventListener(\"change\", () => {\n void scope.setBindEffort(bindingInput.checked).catch(() => sync());\n });\n\n bindingControl.append(bindingCopy, bindingInput);\n group.append(bindingControl);\n }\n\n if (bindingControl !== null) {\n const bindingInput = bindingControl.querySelector<HTMLInputElement>(`.${LIANG_BINDING_INPUT}`);\n if (bindingInput !== null) {\n bindingInput.checked = snapshot.bindEffort;\n bindingInput.setAttribute(\"aria-checked\", String(snapshot.bindEffort));\n bindingInput.disabled = pending;\n }\n }\n\n for (const nativeButton of row.querySelectorAll<HTMLButtonElement>('[class*=\"_8HJdBW_themeCube\"]')) {\n if (hookedNativeButtons.has(nativeButton)) continue;\n hookedNativeButtons.add(nativeButton);\n const handleNativeClick = () => {\n if (pending || !scope.getSnapshot().enabled) return;\n pending = true;\n sync();\n void presenter.choose(false).finally(() => {\n pending = false;\n sync();\n });\n };\n nativeClickHandlers.set(nativeButton, handleNativeClick);\n nativeButton.addEventListener(\"click\", handleNativeClick, { capture: true });\n }\n };\n\n const observer = new MutationObserver(sync);\n observer.observe(document.body, { childList: true, subtree: true });\n const unsubscribe = scope.subscribe(sync);\n sync();\n\n return () => {\n observer.disconnect();\n unsubscribe();\n for (const [nativeButton, handleNativeClick] of nativeClickHandlers) {\n nativeButton.removeEventListener(\"click\", handleNativeClick, { capture: true });\n }\n document.querySelectorAll(`.${LIANG_APPEARANCE_BUTTON}`).forEach((button) => button.remove());\n document.querySelectorAll(`.${LIANG_BINDING_CONTROL}`).forEach((control) => control.remove());\n };\n}\n\nexport const inject = [\n \"slots\",\n \"sessions\",\n \"modelDirectories\",\n \"locale\",\n \"theme\",\n];\n\nfunction createPreferenceStore(): PreferenceStore {\n // The market's active skin is the source of truth for whether this client\n // should be visible. The appearance switch is therefore scoped to this\n // client activation and must not survive switching away and back.\n try {\n localStorage.removeItem(\"dsh-liang-intensity-skin.enabled\");\n } catch {\n // Storage may be unavailable; the in-memory default still enables Liang.\n }\n let snapshot: SkinSettings = {\n enabled: true,\n bindEffort: localStorage.getItem(BIND_EFFORT_KEY) !== \"0\",\n };\n const listeners = new Set<() => void>();\n const onStorage = (event: StorageEvent) => {\n if (event.key !== BIND_EFFORT_KEY) return;\n const next = {\n enabled: snapshot.enabled,\n bindEffort: event.newValue !== \"0\",\n };\n if (next.enabled === snapshot.enabled && next.bindEffort === snapshot.bindEffort) return;\n snapshot = next;\n for (const listener of listeners) listener();\n };\n window.addEventListener(\"storage\", onStorage);\n return {\n getSnapshot: () => snapshot,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n async set(enabled) {\n if (enabled === snapshot.enabled) return;\n snapshot = { ...snapshot, enabled };\n for (const listener of listeners) listener();\n },\n async setBindEffort(bindEffort) {\n if (bindEffort === snapshot.bindEffort) return;\n localStorage.setItem(BIND_EFFORT_KEY, bindEffort ? \"1\" : \"0\");\n snapshot = { ...snapshot, bindEffort };\n for (const listener of listeners) listener();\n },\n dispose() {\n window.removeEventListener(\"storage\", onStorage);\n listeners.clear();\n },\n };\n}\n\nexport function apply(ctx: ClientContext) {\n const style = document.createElement(\"style\");\n style.dataset.plugin = PACKAGE_ID;\n style.textContent = styles;\n document.head.append(style);\n ctx.effect(() => () => style.remove(), \"liang-intensity-skin: scoped styles\");\n\n const scope = createPreferenceStore();\n ctx.effect(() => () => scope.dispose(), \"liang-intensity-skin: appearance preference\");\n const theme = ctx.get(\"theme\") as ThemeService;\n const presenter = new SkinPresenter(scope, theme);\n ctx.effect(() => () => presenter.dispose(), \"liang-intensity-skin: backdrop presenter\");\n ctx.effect(\n () => installLiangAppearanceButton(scope, presenter),\n \"liang-intensity-skin: native appearance extension\",\n );\n ctx.effect(\n () => ctx.locale.register(LOCALE_NAMESPACE, {\n zh: {\n \"appearance.title\": \"\u5916\u89C2\",\n \"appearance.light\": \"\u6D45\u8272\",\n \"appearance.dark\": \"\u6DF1\u8272\",\n \"appearance.system\": \"\u8DDF\u968F\u7CFB\u7EDF\",\n \"appearance.liang\": \"\u6ED1\u52A8\u53D8\u7956\",\n },\n en: {\n \"appearance.title\": \"Appearance\",\n \"appearance.light\": \"Light\",\n \"appearance.dark\": \"Dark\",\n \"appearance.system\": \"System\",\n \"appearance.liang\": \"Slider\",\n },\n }), \"liang-intensity-skin: settings locale\");\n\n ctx.slots.inject(\"conversation.input.right\", () => ctx.slots.register({\n name: \"conversation.input.right\",\n id: \"liang-intensity-control\",\n order: 10,\n inject: (sessionId: string) => {\n const available = ctx.sessions.subagentAddress(sessionId) === undefined;\n const directory = ctx.modelDirectories.directoryFor(sessionId) as ModelDirectory;\n return {\n directory: directory.store,\n presenter,\n scope,\n load: () => {\n if (available) void directory.load().catch(() => undefined);\n },\n select: (selection: ModelSelection) => available\n ? directory.select(selection).then((result) => result.ok, () => false)\n : Promise.resolve(false),\n };\n },\n }, LiangEffortSlider));\n}\n", ".liang-skin-backdrop {\n position: fixed;\n z-index: 0;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n background: var(--liang-page, transparent);\n opacity: 0;\n transition: opacity 220ms ease, background-color 180ms linear;\n}\n\nbody[data-liang-skin=\"on\"] .liang-skin-backdrop {\n opacity: 1;\n}\n\n.liang-skin-backdrop img {\n position: absolute;\n top: 50%;\n right: 0;\n display: block;\n width: min(42vw, 720px);\n height: 100vh;\n object-fit: cover;\n object-position: 50% 42%;\n opacity: var(--liang-portrait-opacity, 0.45);\n transform: translateY(-50%);\n filter: none;\n mask-image: linear-gradient(90deg, transparent 0%, rgb(0 0 0 / 20%) 10%, black 30%, black 100%);\n transition: filter 180ms linear;\n}\n\n.liang-skin-backdrop img {\n display: none;\n}\n\n.liang-skin-backdrop[data-media=\"sequence\"] .liang-skin-sequence-frame {\n display: block;\n opacity: var(--liang-portrait-opacity, 0.82);\n}\n\n.liang-skin-backdrop[data-media=\"color\"] img {\n display: none;\n}\n\n.liang-skin-backdrop::after {\n position: absolute;\n inset: 0;\n content: \"\";\n background: linear-gradient(90deg, var(--liang-page, transparent) 0 28%, transparent 57% 100%);\n}\n\nbody[data-liang-skin=\"on\"] {\n --dsw-alias-bg-base: var(--liang-bg-base) !important;\n --dsw-alias-bg-layer-1: var(--liang-layer-1) !important;\n --dsw-alias-bg-layer-2: var(--liang-layer-2) !important;\n --dsw-alias-bg-layer-3: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-fill: var(--liang-sidebar) !important;\n --dsw-alias-label-primary: var(--liang-ink) !important;\n --dsw-alias-label-primary-dimmed: var(--liang-ink) !important;\n --dsw-alias-label-secondary: var(--liang-secondary) !important;\n --dsw-alias-label-tertiary: var(--liang-tertiary) !important;\n --dsw-alias-label-caption: var(--liang-tertiary) !important;\n --dsw-alias-border-l1: var(--liang-border) !important;\n --dsw-alias-border-l2-darkmode-thin: var(--liang-border) !important;\n --dsw-alias-border-l2: var(--liang-border) !important;\n --dsw-alias-border-l3: var(--liang-border) !important;\n --dsw-alias-button-primary-fill: var(--liang-accent) !important;\n --dsw-alias-button-primary-hover: var(--liang-accent-hover) !important;\n --dsw-alias-button-info-fill: var(--liang-accent) !important;\n --dsw-alias-button-info-hover: var(--liang-accent-hover) !important;\n --dsw-alias-state-business-primary: var(--liang-accent) !important;\n --dsw-alias-interactive-bg-hover: var(--liang-hover) !important;\n --dsw-alias-interactive-bg-active: var(--liang-hover) !important;\n --dsw-alias-button-elevated-fill: var(--liang-layer-1) !important;\n --dsw-alias-button-floating-fill: var(--liang-layer-2) !important;\n --dsw-alias-button-floating-hover: var(--liang-layer-3) !important;\n --dsw-alias-interactive-bg-hover-solid: var(--liang-layer-2) !important;\n --dsw-specific-bubble: var(--liang-layer-2) !important;\n --dsw-specific-input-major: var(--liang-layer-1) !important;\n --dsw-specific-menu: var(--liang-layer-3) !important;\n --dsw-specific-selector: var(--liang-layer-2) !important;\n --dsw-alias-markdown-citation: var(--liang-layer-2) !important;\n --dsw-alias-markdown-code-block-banner: var(--liang-layer-1) !important;\n --dsw-alias-markdown-code-block: var(--liang-layer-1) !important;\n --dsw-alias-markdown-code-segment-selected: var(--liang-layer-2) !important;\n --dsw-alias-markdown-code-segment-unselected: var(--liang-layer-1) !important;\n --dsw-alias-markdown-inline-code: var(--liang-layer-2) !important;\n --dsw-alias-markdown-placeholder: var(--liang-layer-1) !important;\n --dsw-alias-markdown-tag: var(--liang-layer-2) !important;\n background: var(--liang-page) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) {\n --dsw-alias-brand-primary-new-colorprimary-new-color: rgb(65 118 230) !important;\n --dsw-alias-brand-primary: rgb(15 17 21) !important;\n --dsw-alias-brand-text: rgb(15 17 21) !important;\n --dsw-alias-button-primary-fill: rgb(15 17 21) !important;\n --dsw-alias-button-primary-hover: rgb(53 54 56) !important;\n --dsw-alias-button-info-fill: rgb(65 118 230) !important;\n --dsw-alias-button-info-hover: rgb(103 158 254) !important;\n --dsw-alias-state-business-primary: rgb(65 118 230) !important;\n --dsw-alias-label-primary-inverted: rgb(249 250 251) !important;\n --dsw-alias-button-elevated-fill: rgb(255 255 255) !important;\n --dsw-alias-button-floating-fill: rgb(255 255 255) !important;\n --dsw-alias-button-floating-hover: rgb(241 243 245) !important;\n --dsw-alias-interactive-bg-hover-solid: rgb(241 243 245) !important;\n --dsw-specific-bubble: rgb(237 243 254) !important;\n --dsw-specific-input-major: rgb(255 255 255) !important;\n --dsw-specific-menu: rgb(255 255 255) !important;\n --dsw-specific-selector: rgb(245 246 247) !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] {\n --dsw-alias-brand-primary-new-colorprimary-new-color: #c19a49 !important;\n --dsw-alias-brand-primary: #c19a49 !important;\n --dsw-alias-brand-text: #d5b56e !important;\n --dsw-alias-button-info-fill: #c19a49 !important;\n --dsw-alias-button-info-hover: #d5b56e !important;\n --dsw-alias-state-business-primary: #c19a49 !important;\n --dsw-alias-bg-module-platform: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-nav-item-active: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-nav-item-hover: var(--liang-hover) !important;\n}\n\n/* The host renders the running-turn label as a clipped blue text gradient.\n Retarget only that gradient's color tokens in the custom dark skin; keep\n the host's text clipping and shimmer behavior, and leave light mode alone. */\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"_turnStatus\"] {\n --dsw-static-deepseek-500: #c19a49 !important;\n --dsw-static-deepseek-200: #d5b56e !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"_turnStatusClock\"] {\n color: #c19a49 !important;\n -webkit-text-fill-color: #c19a49 !important;\n}\n\n/* Preserve the wordmark badge contrast in the low-intensity shell. */\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > rect[width=\"52\"] {\n fill: rgb(15 17 21) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > g[clip-path*=\"badge\"] path {\n fill: rgb(249 250 251) !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > rect[width=\"52\"] {\n fill: #c19a49 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > g[clip-path*=\"badge\"] path {\n fill: #171816 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [aria-label^=\"\u9009\u62E9\u6A21\u578B\"] > span:nth-of-type(2) {\n color: #d5b56e !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"heroGlow\"] ellipse {\n fill: #c19a49 !important;\n fill-opacity: 0.16 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] span[class*=\"_previewBadge\"] {\n color: #171816 !important;\n background: #c19a49 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u53D1\u9001\u6D88\u606F\"] {\n color: #171816 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u53D1\u9001\u6D88\u606F\"]:disabled {\n opacity: 0.62;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u53D1\u9001\u6D88\u606F\"] {\n color: #fff !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u53D1\u9001\u6D88\u606F\"]:disabled {\n color: rgb(255 255 255 / 92%) !important;\n background: rgb(65 118 230 / 42%) !important;\n opacity: 1;\n}\n\nbody[data-liang-skin=\"on\"] > #root {\n position: relative;\n z-index: 1;\n background: transparent !important;\n}\n\n/* Windows paints the sidebar fill across the host frame, covering the portrait.\n Match macOS's transparent frame while keeping the sidebar, caption, and\n conversation surfaces painted by their own host rules. */\nhtml[data-windows-titlebar] body[data-liang-skin=\"on\"] #root [class*=\"_frame\"]:has(> [class*=\"_centerCol\"]) {\n background: transparent !important;\n}\n\n/* macOS adds different translucent sidebar materials for native light/dark.\n While Liang is active, the effort palette owns the sidebar fill. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_frame\"]:has(> [class*=\"_centerCol\"]) > [class*=\"_sidebarCol\"] {\n background: var(--liang-sidebar) !important;\n}\n\n/* Keep the host's expanded new-session surface on the same palette. The\n collapsed icon keeps its native transparent surface and hover behavior. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"]:has(> [class*=\"_logoRow\"]):not([class*=\"_collapsed\"]) button[class*=\"_newSession\"] {\n background: var(--dsw-alias-button-elevated-fill) !important;\n}\n\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"]:has(> [class*=\"_logoRow\"]):not([class*=\"_collapsed\"]) button[class*=\"_newSession\"]:hover {\n background: var(--dsw-alias-button-floating-hover) !important;\n}\n\n/* The native dark rule also outranks the collapsed icon's transparent fill. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"][class*=\"_collapsed\"]:has(> [class*=\"_logoRow\"]) button[class*=\"_newSession\"] {\n background: transparent !important;\n}\n\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"][class*=\"_collapsed\"]:has(> [class*=\"_logoRow\"]) button[class*=\"_newSession\"]:hover {\n background: var(--dsw-alias-interactive-bg-hover) !important;\n}\n\nbody[data-liang-skin=\"on\"] button,\nbody[data-liang-skin=\"on\"] input,\nbody[data-liang-skin=\"on\"] textarea {\n transition: color 160ms linear, background-color 160ms linear, border-color 160ms linear;\n}\n\n/* The composer card has a native theme-mode fill, so keep its surface and\n readable ink aligned with the active Liang palette. */\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] {\n border-color: var(--liang-border) !important;\n color: var(--liang-ink) !important;\n background: var(--liang-layer-1) !important;\n box-shadow: 0 8px 28px rgb(20 22 20 / 8%);\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] :is(textarea, button, [data-input-mirror=\"true\"]) {\n color: var(--liang-ink) !important;\n caret-color: var(--liang-accent) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] textarea::placeholder {\n color: var(--liang-tertiary) !important;\n opacity: 1;\n}\n\n.liang-effort-control {\n --liang-control-accent: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n --liang-control-rail: var(--dsw-alias-border-l3, rgb(0 0 0 / 16%));\n position: relative;\n display: flex;\n width: 124px;\n height: 28px;\n align-items: center;\n margin: 0 3px;\n overflow: visible;\n}\n\nbody[data-liang-skin=\"on\"] .liang-effort-control {\n --liang-control-accent: var(--liang-secondary);\n --liang-control-rail: color-mix(in srgb, var(--liang-secondary) 28%, transparent);\n}\n\n.liang-effort-control__ticks {\n position: absolute;\n z-index: 0;\n inset: 0 10px;\n pointer-events: none;\n}\n\n.liang-effort-control__ticks::before {\n position: absolute;\n top: 50%;\n right: 0;\n left: 0;\n height: 1px;\n content: \"\";\n background: var(--liang-control-rail);\n transform: translateY(-50%);\n}\n\n.liang-effort-control__tooltip {\n position: absolute;\n z-index: 4;\n bottom: calc(100% + 7px);\n left: calc(10px + (100% - 20px) * var(--liang-slider-ratio));\n min-width: max-content;\n padding: 5px 8px;\n border: 1px solid var(--liang-border, rgb(0 0 0 / 12%));\n border-radius: 7px;\n color: var(--liang-ink, #171816);\n background: var(--liang-layer-1, #fff);\n box-shadow: 0 5px 16px rgb(0 0 0 / 16%);\n font-size: 11px;\n font-weight: 600;\n line-height: 16px;\n letter-spacing: 0.01em;\n pointer-events: none;\n transform: translateX(-50%);\n white-space: nowrap;\n}\n\n.liang-effort-control__tooltip::after {\n position: absolute;\n top: 100%;\n left: 50%;\n width: 7px;\n height: 7px;\n content: \"\";\n background: inherit;\n transform: translate(-50%, -4px) rotate(45deg);\n}\n\n.liang-effort-control__tick {\n position: absolute;\n top: 50%;\n width: 1px;\n height: 7px;\n background: var(--liang-control-accent);\n opacity: 0.42;\n transform: translate(-50%, -50%);\n}\n\n.liang-effort-control__range {\n position: relative;\n z-index: 1;\n width: calc(100% - 7px);\n height: 28px;\n margin: 0 3.5px;\n cursor: ew-resize;\n appearance: none;\n background: transparent;\n touch-action: pan-y;\n}\n\n.liang-effort-control__range:disabled {\n cursor: progress;\n opacity: 0.58;\n}\n\n.liang-effort-control__range::-webkit-slider-runnable-track {\n height: 1px;\n border-radius: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-webkit-slider-thumb {\n width: 13px;\n height: 13px;\n margin-top: -6px;\n border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n border-radius: 50%;\n appearance: none;\n background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--dsw-alias-bg-layer-1, #fff)) 2.5px);\n box-shadow: 0 1px 4px rgb(0 0 0 / 14%);\n}\n\nbody[data-liang-skin=\"on\"] .liang-effort-control__range::-webkit-slider-thumb {\n width: 13px;\n height: 13px;\n margin-top: -6px;\n border-color: color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--liang-layer-1)) 2.5px);\n}\n\n.liang-effort-control__range::-moz-range-track {\n height: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-moz-range-progress {\n height: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-moz-range-thumb {\n width: 11px;\n height: 11px;\n border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n border-radius: 50%;\n background: color-mix(in srgb, var(--liang-control-accent) 24%, var(--dsw-alias-bg-layer-1, #fff));\n}\n\n.liang-effort-control__range:focus-visible {\n outline: none;\n}\n\n.liang-effort-control[data-state=\"error\"] {\n --liang-control-accent: var(--dsw-alias-state-error-primary, #e43c3c);\n}\n\n.liang-appearance-choice {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n flex: 180px;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 4px;\n padding: 20px 32px;\n border-radius: 16px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n background: transparent;\n font-size: 14px;\n line-height: 22px;\n display: flex;\n}\n\n[class*=\"_8HJdBW_cubeRow\"]:has(.liang-appearance-choice) {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n}\n\n.liang-appearance-choice:hover:not([aria-pressed=\"true\"]) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.liang-appearance-choice[aria-pressed=\"true\"] {\n border-color: var(--dsw-static-neutral-bluish-400);\n background: var(--dsw-alias-bg-module-platform);\n}\n\n.liang-appearance-choice__icon {\n display: block;\n flex: 0 0 16px;\n width: 16px;\n height: 16px;\n color: currentColor;\n font-size: 16px;\n line-height: 16px;\n}\n\n.liang-appearance-choice__label {\n display: block;\n}\n\n/* Keep the host's three theme cubes untouched. These rules only style the\n fourth button that is appended to the host cube row. */\n.liang-appearance-choice:disabled {\n cursor: progress;\n opacity: 0.7;\n}\n\n.liang-appearance-binding {\n box-sizing: border-box;\n display: flex;\n width: 100%;\n min-height: 28px;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 4px 0 0;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n}\n\n.liang-appearance-binding__label {\n display: block;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.liang-appearance-binding__copy {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: 1px;\n}\n\n.liang-appearance-binding__description {\n display: block;\n overflow: hidden;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 18px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.liang-appearance-binding__input {\n position: relative;\n flex: 0 0 36px;\n width: 36px;\n height: 20px;\n margin: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n outline: none;\n cursor: pointer;\n appearance: none;\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-module-platform));\n}\n\n.liang-appearance-binding__input::before {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n content: \"\";\n background: var(--dsw-alias-label-primary);\n box-shadow: 0 1px 3px rgb(0 0 0 / 18%);\n transition: transform 160ms ease, background-color 160ms ease;\n}\n\n.liang-appearance-binding__input:checked {\n border-color: var(--dsw-static-neutral-bluish-400);\n background: var(--dsw-static-neutral-bluish-400);\n}\n\n.liang-appearance-binding__input:checked::before {\n background: var(--dsw-alias-bg-layer-1, #fff);\n transform: translateX(16px);\n}\n\n.liang-appearance-binding__input:focus-visible {\n box-shadow: 0 0 0 2px var(--dsw-alias-interactive-bg-hover);\n}\n\n.liang-appearance-binding__input:disabled {\n cursor: progress;\n opacity: 0.7;\n}\n\n@media (max-width: 760px) {\n .liang-effort-control {\n width: 92px;\n }\n\n .liang-skin-backdrop img {\n right: -18vw;\n width: 92vw;\n opacity: calc(var(--liang-portrait-opacity, 0.45) * 0.72);\n }\n\n}\n\n@media (prefers-reduced-motion: reduce) {\n .liang-skin-backdrop,\n .liang-skin-backdrop img,\n body[data-liang-skin=\"on\"] button,\n body[data-liang-skin=\"on\"] input,\n body[data-liang-skin=\"on\"] textarea {\n transition: none;\n }\n}\n", "export const PREVIEW_MAX_FRAME = 240;\nexport const MAX_LEVEL = 30;\n\nconst LIANG_RANKS = [\"\u5C0F\u96BE\u6881\", \"\u7262\u6881\", \"\u6881\u5B50\", \"\u6881\u5723\", \"\u6881\u795E\", \"\u6881\u7956\"] as const;\n\nexport interface EffortLike {\n id: string;\n name: string;\n description?: string;\n}\n\nexport interface Palette {\n level: number;\n stage: number;\n strength: number;\n page: string;\n base: string;\n layer1: string;\n layer2: string;\n layer3: string;\n sidebar: string;\n ink: string;\n secondary: string;\n tertiary: string;\n border: string;\n accent: string;\n accentHover: string;\n hover: string;\n portraitOpacity: string;\n}\n\ntype Rgb = readonly [number, number, number];\n\ninterface PaletteStop {\n at: number;\n page: Rgb;\n surface: Rgb;\n surface2: Rgb;\n ink: Rgb;\n secondary: Rgb;\n accent: Rgb;\n portraitOpacity: number;\n}\n\n// These are the original calibrator's six stage anchors: pale neutral at the\n// low end, progressively smoked surfaces, then charcoal and antique gold.\nconst STOPS: readonly PaletteStop[] = [\n { at: 0, page: [232, 233, 229], surface: [248, 248, 245], surface2: [238, 239, 235], ink: [23, 24, 22], secondary: [112, 116, 111], accent: [181, 43, 36], portraitOpacity: 0.92 },\n { at: 6, page: [211, 211, 206], surface: [239, 239, 234], surface2: [224, 224, 218], ink: [26, 26, 24], secondary: [101, 101, 96], accent: [181, 43, 36], portraitOpacity: 0.93 },\n { at: 12, page: [171, 168, 162], surface: [211, 208, 201], surface2: [190, 186, 179], ink: [27, 26, 24], secondary: [83, 79, 74], accent: [166, 54, 42], portraitOpacity: 0.94 },\n { at: 18, page: [117, 112, 106], surface: [154, 148, 140], surface2: [128, 122, 115], ink: [24, 22, 20], secondary: [65, 61, 56], accent: [154, 56, 42], portraitOpacity: 0.94 },\n { at: 24, page: [43, 39, 37], surface: [48, 43, 40], surface2: [58, 51, 46], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [181, 92, 54], portraitOpacity: 0.94 },\n { at: 30, page: [17, 17, 17], surface: [30, 27, 25], surface2: [41, 35, 30], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [193, 154, 73], portraitOpacity: 0.94 },\n];\n\nexport function clampFrame(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(value)));\n}\n\nexport function frameForEffort(index: number, count: number): number {\n if (count <= 1 || !Number.isFinite(index)) return 0;\n const safe = Math.min(count - 1, Math.max(0, Math.round(index)));\n return Math.round((safe / (count - 1)) * PREVIEW_MAX_FRAME);\n}\n\nexport function nearestEffortIndex(frame: number, efforts: readonly EffortLike[]): number {\n if (efforts.length === 0) return -1;\n const safe = clampFrame(frame);\n let best = 0;\n let distance = Math.abs(safe - frameForEffort(0, efforts.length));\n for (let index = 1; index < efforts.length; index += 1) {\n const next = Math.abs(safe - frameForEffort(index, efforts.length));\n if (next < distance) {\n best = index;\n distance = next;\n }\n }\n return best;\n}\n\nexport function selectedEffortIndex(\n efforts: readonly EffortLike[],\n selectedId?: string,\n defaultId?: string,\n): number {\n const id = selectedId ?? defaultId;\n return id === undefined ? -1 : efforts.findIndex((effort) => effort.id === id);\n}\n\nexport function portraitBlendForLevel(level: number, anchors: readonly number[]) {\n if (anchors.length === 0) return { lowerIndex: -1, upperIndex: -1, mix: 0 };\n const safeLevel = Number.isFinite(level)\n ? Math.min(anchors[anchors.length - 1], Math.max(anchors[0], level))\n : anchors[0];\n let upperIndex = anchors.findIndex((anchor) => anchor >= safeLevel);\n if (upperIndex < 0) upperIndex = anchors.length - 1;\n const lowerIndex = Math.max(0, upperIndex - (anchors[upperIndex] > safeLevel ? 1 : 0));\n const span = anchors[upperIndex] - anchors[lowerIndex];\n return {\n lowerIndex,\n upperIndex,\n mix: span === 0 ? 0 : (safeLevel - anchors[lowerIndex]) / span,\n };\n}\n\nexport function liangRankForFrame(rawFrame: number): string {\n const level = (clampFrame(rawFrame) / PREVIEW_MAX_FRAME) * MAX_LEVEL;\n const index = level >= MAX_LEVEL ? LIANG_RANKS.length - 1 : Math.floor(level / 6);\n return LIANG_RANKS[Math.min(LIANG_RANKS.length - 1, Math.max(0, index))];\n}\n\nexport function indicatorLabel(rawFrame: number, efforts: readonly EffortLike[]): string {\n const effort = efforts[nearestEffortIndex(rawFrame, efforts)];\n return effort === undefined\n ? liangRankForFrame(rawFrame)\n : `${liangRankForFrame(rawFrame)} \u00B7 ${effort.name}`;\n}\n\nfunction lerp(a: number, b: number, amount: number): number {\n return a + (b - a) * amount;\n}\n\nfunction mix(a: Rgb, b: Rgb, amount: number): Rgb {\n return [\n Math.round(lerp(a[0], b[0], amount)),\n Math.round(lerp(a[1], b[1], amount)),\n Math.round(lerp(a[2], b[2], amount)),\n ];\n}\n\nfunction rgb(value: Rgb, alpha = 1): string {\n return alpha === 1\n ? `rgb(${value[0]} ${value[1]} ${value[2]})`\n : `rgb(${value[0]} ${value[1]} ${value[2]} / ${alpha})`;\n}\n\nexport function paletteForFrame(rawFrame: number): Palette {\n const frame = clampFrame(rawFrame);\n const level = (frame / PREVIEW_MAX_FRAME) * MAX_LEVEL;\n const portraitStage = Math.min(5, Math.floor(level / 6));\n const portraitFrom = STOPS[portraitStage];\n const portraitTo = STOPS[Math.min(5, portraitStage + 1)];\n const portraitAmount = portraitFrom === portraitTo\n ? 0\n : (level - portraitFrom.at) / (portraitTo.at - portraitFrom.at);\n\n // The UI itself is intentionally binary: levels 0\u201323 keep the native light\n // shell; entering the original \u6881\u795E/\u6881\u7956 region at level 24 switches black/gold.\n const dark = level >= 24;\n const stage = dark ? 5 : 0;\n const ui = dark ? STOPS[5] : STOPS[0];\n const page = ui.page;\n const surface = ui.surface;\n const surface2 = ui.surface2;\n const sidebar = mix(page, surface2, 0.25);\n const ink = ui.ink;\n const secondary = ui.secondary;\n // Keep Harness' native blue in the light shell. The original calibrator's\n // antique gold only becomes the product accent once the dark region begins.\n const accent: Rgb = dark ? [193, 154, 73] : [65, 118, 230];\n const accentHover = mix(accent, ink, 0.13);\n\n return {\n level,\n stage,\n strength: level / MAX_LEVEL,\n page: rgb(page),\n // Keep the shell readable while allowing the right-side portrait to remain\n // visibly present. Dense controls use the opaque layer tokens below.\n base: rgb(page, dark ? 0.42 : 0.28),\n layer1: rgb(surface, 0.94),\n layer2: rgb(surface2, 0.96),\n layer3: rgb(surface2, 0.99),\n sidebar: rgb(sidebar, 0.96),\n ink: rgb(ink),\n secondary: rgb(secondary),\n tertiary: rgb(mix(secondary, page, 0.28)),\n border: rgb(ink, dark ? 0.15 : 0.12),\n accent: rgb(accent),\n accentHover: rgb(accentHover),\n hover: rgb(ink, dark ? 0.09 : 0.07),\n portraitOpacity: String(lerp(\n portraitFrom.portraitOpacity,\n portraitTo.portraitOpacity,\n portraitAmount,\n )),\n };\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMO;;;ACNP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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",
6
- "names": ["mix"]
3
+ "sources": ["../src/client/index.tsx", "../src/client/skin.css", "../src/client/appearance.ts", "../src/client/portrait-loader.ts", "../src/client/logic.ts"],
4
+ "sourcesContent": ["import {\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { Switch } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { Context as ClientContext } from \"@deepseek-ai/cordis\";\nimport type { SnapshotStore } from \"@deepseek-ai/dsh-client-store\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-settings/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-model-selection/client\";\nimport styles from \"./skin.css\";\nimport { installLiangAppearanceButton } from \"./appearance\";\nimport { createPortraitLoader } from \"./portrait-loader\";\nimport {\n PREVIEW_MAX_FRAME,\n frameForEffort,\n indicatorLabel,\n nearestEffortIndex,\n paletteForFrame,\n selectedEffortIndex,\n type EffortLike,\n} from \"./logic\";\n\nconst PACKAGE_ID = \"dsh-client-liang-intensity-skin\";\nconst LOCALE_NAMESPACE = \"liang.skin\";\nconst ASSET_PREFIX = `/plugins/${PACKAGE_ID}/assets`;\nconst BIND_EFFORT_KEY = \"dsh-liang-intensity-skin.bind-effort\";\n\nconst PORTRAIT_ANCHORS = [\n { level: 0, file: \"stage-00.webp\" },\n { level: 1, file: \"level-01.webp\" },\n { level: 3, file: \"level-03.webp\" },\n { level: 4, file: \"level-04.webp\" },\n { level: 6, file: \"stage-06.webp\" },\n { level: 7, file: \"level-07.webp\" },\n { level: 9, file: \"level-09.webp\" },\n { level: 10, file: \"level-10.webp\" },\n { level: 12, file: \"stage-12.webp\" },\n { level: 13, file: \"level-13.webp\" },\n { level: 14, file: \"level-14.webp\" },\n { level: 15, file: \"bridge-15.webp\" },\n { level: 16, file: \"level-16.webp\" },\n { level: 17, file: \"level-17.webp\" },\n { level: 18, file: \"stage-18.webp\" },\n { level: 19, file: \"level-19.webp\" },\n { level: 21, file: \"level-21.webp\" },\n { level: 22, file: \"level-22.webp\" },\n { level: 24, file: \"stage-24.webp\" },\n { level: 25, file: \"level-25.webp\" },\n { level: 27, file: \"bridge-27.webp\" },\n { level: 28, file: \"level-28.webp\" },\n { level: 29, file: \"level-29.webp\" },\n { level: 30, file: \"stage-30.webp\" },\n] as const;\n\ninterface SkinSettings {\n enabled: boolean;\n bindEffort: boolean;\n}\n\ninterface PreferenceStore {\n getSnapshot(): SkinSettings;\n subscribe(listener: () => void): () => void;\n set(enabled: boolean): Promise<void>;\n setBindEffort(enabled: boolean): Promise<void>;\n dispose(): void;\n}\n\ntype NativeThemeId = \"light\" | \"dark\";\n\ninterface ThemeService {\n getTheme(): { preference: string };\n setTheme(id: NativeThemeId | \"system\"): void;\n}\n\ninterface ModelSelection {\n provider: string;\n model: string;\n reasoningEffort?: string;\n}\n\ninterface CatalogModel {\n id: string;\n reasoning?: {\n efforts: EffortLike[];\n defaultEffort?: string;\n };\n}\n\ninterface ModelDirectoryState {\n current: ModelSelection | null;\n groups: readonly { id: string; models: CatalogModel[] }[];\n status: \"idle\" | \"loading\" | \"ready\" | \"selecting\" | \"error\";\n error: string | null;\n}\n\ninterface ModelDirectory {\n store: SnapshotStore<ModelDirectoryState>;\n load(): Promise<unknown>;\n select(selection: ModelSelection): Promise<{ ok: boolean }>;\n}\n\ninterface SliderProps {\n directory: SnapshotStore<ModelDirectoryState>;\n load: () => void;\n select: (selection: ModelSelection) => Promise<boolean>;\n presenter: SkinPresenter;\n scope: PreferenceStore;\n}\n\ninterface EffortBindingRowProps {\n scope: PreferenceStore;\n t: (key: string) => string;\n}\n\nconst cssVariables = [\n \"--liang-strength\",\n \"--liang-page\",\n \"--liang-bg-base\",\n \"--liang-layer-1\",\n \"--liang-layer-2\",\n \"--liang-layer-3\",\n \"--liang-sidebar\",\n \"--liang-ink\",\n \"--liang-secondary\",\n \"--liang-tertiary\",\n \"--liang-border\",\n \"--liang-accent\",\n \"--liang-accent-hover\",\n \"--liang-hover\",\n \"--liang-portrait-opacity\",\n] as const;\n\nclass SkinPresenter {\n private readonly scope: PreferenceStore;\n private readonly theme: ThemeService;\n private readonly root: HTMLDivElement;\n private readonly portraits: ReturnType<typeof createPortraitLoader>;\n private enabled = true;\n // Default to the max frame so the first paint after load is the dark shell;\n // starting at 0 flashed the light palette before the directory resolved.\n private frame = PREVIEW_MAX_FRAME;\n private pendingFrame = PREVIEW_MAX_FRAME;\n private raf = 0;\n private disposed = false;\n private unsubscribe: () => void;\n\n constructor(scope: PreferenceStore, theme: ThemeService) {\n this.scope = scope;\n this.theme = theme;\n this.root = document.createElement(\"div\");\n this.root.className = \"liang-skin-backdrop\";\n this.root.dataset.plugin = PACKAGE_ID;\n this.root.dataset.media = \"color\";\n this.root.setAttribute(\"aria-hidden\", \"true\");\n this.portraits = createPortraitLoader({\n sources: PORTRAIT_ANCHORS.map(({ level, file }) => ({\n level,\n url: `${ASSET_PREFIX}/portrait-source-v2/${file}`,\n })),\n onChange: ({ image }) => {\n if (this.disposed || !this.enabled) return;\n if (image === null) {\n this.root.dataset.media = \"color\";\n this.root.replaceChildren();\n return;\n }\n // Reuse the decoded node so a frame swap cannot start a second fetch.\n const portrait = image as HTMLImageElement;\n portrait.className = \"liang-skin-sequence-frame\";\n portrait.alt = \"\";\n portrait.draggable = false;\n if (this.root.firstChild !== portrait) this.root.replaceChildren(portrait);\n this.root.dataset.media = \"sequence\";\n },\n });\n\n this.unsubscribe = scope.subscribe(() => this.syncSettings());\n this.syncSettings();\n }\n\n private syncSettings() {\n this.setEnabled(this.scope.getSnapshot().enabled);\n }\n\n isEnabled() {\n return this.enabled;\n }\n\n getFrame() {\n return this.frame;\n }\n\n setEnabled(enabled: boolean) {\n if (this.disposed) return;\n this.enabled = enabled;\n if (enabled) {\n if (!this.root.isConnected) document.body.prepend(this.root);\n document.body.dataset.liangSkin = \"on\";\n this.applyFrame();\n this.portraits.start();\n } else {\n if (this.raf !== 0) cancelAnimationFrame(this.raf);\n this.raf = 0;\n this.root.remove();\n this.portraits.stop();\n this.root.replaceChildren();\n this.root.dataset.media = \"color\";\n delete document.body.dataset.liangSkin;\n delete document.body.dataset.liangStage;\n for (const name of cssVariables) document.body.style.removeProperty(name);\n }\n }\n\n setFrame(frame: number) {\n if (this.disposed) return;\n this.pendingFrame = Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(frame)));\n this.frame = this.pendingFrame;\n if (!this.enabled) return;\n if (this.raf !== 0) return;\n this.raf = requestAnimationFrame(() => {\n this.raf = 0;\n this.frame = this.pendingFrame;\n this.applyFrame();\n });\n }\n\n private applyFrame() {\n if (this.disposed || !this.enabled) return;\n const palette = paletteForFrame(this.frame);\n const body = document.body;\n this.syncNativeTheme(palette.stage === 5 ? \"dark\" : \"light\");\n body.dataset.liangStage = String(palette.stage);\n body.style.setProperty(\"--liang-strength\", String(palette.strength));\n body.style.setProperty(\"--liang-page\", palette.page);\n body.style.setProperty(\"--liang-bg-base\", palette.base);\n body.style.setProperty(\"--liang-layer-1\", palette.layer1);\n body.style.setProperty(\"--liang-layer-2\", palette.layer2);\n body.style.setProperty(\"--liang-layer-3\", palette.layer3);\n body.style.setProperty(\"--liang-sidebar\", palette.sidebar);\n body.style.setProperty(\"--liang-ink\", palette.ink);\n body.style.setProperty(\"--liang-secondary\", palette.secondary);\n body.style.setProperty(\"--liang-tertiary\", palette.tertiary);\n body.style.setProperty(\"--liang-border\", palette.border);\n body.style.setProperty(\"--liang-accent\", palette.accent);\n body.style.setProperty(\"--liang-accent-hover\", palette.accentHover);\n body.style.setProperty(\"--liang-hover\", palette.hover);\n body.style.setProperty(\"--liang-portrait-opacity\", palette.portraitOpacity);\n this.updatePortrait(palette.level);\n }\n\n syncNativeTheme(theme: NativeThemeId = paletteForFrame(this.frame).stage === 5 ? \"dark\" : \"light\") {\n if (!this.enabled || this.theme.getTheme().preference === theme) return;\n this.theme.setTheme(theme);\n }\n\n private updatePortrait(level: number) {\n this.portraits.select(level);\n }\n\n async choose(enabled: boolean) {\n this.setEnabled(enabled);\n try {\n await this.scope.set(enabled);\n } catch (error) {\n this.syncSettings();\n throw error;\n }\n }\n\n dispose() {\n if (this.disposed) return;\n this.disposed = true;\n this.unsubscribe();\n if (this.raf !== 0) cancelAnimationFrame(this.raf);\n this.portraits.dispose();\n this.root.remove();\n document.body.removeAttribute(\"data-liang-skin\");\n delete document.body.dataset.liangStage;\n for (const name of cssVariables) document.body.style.removeProperty(name);\n }\n}\n\nfunction modelReasoning(state: ModelDirectoryState) {\n const current = state.current;\n if (current === null) return null;\n const group = state.groups.find((item) => item.id === current.provider);\n const model = group?.models.find((item) => item.id === current.model);\n if (model?.reasoning === undefined) return null;\n return {\n selection: current,\n efforts: model.reasoning.efforts,\n defaultEffort: model.reasoning.defaultEffort,\n };\n}\n\nfunction LiangEffortSlider({ directory, load, select, presenter, scope }: SliderProps) {\n const state = useSyncExternalStore(\n (listener) => directory.subscribe(listener),\n () => directory.getSnapshot(),\n );\n const skin = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n );\n const reasoning = useMemo(() => modelReasoning(state), [state]);\n const efforts = reasoning?.efforts ?? [];\n const committedIndex = selectedEffortIndex(\n efforts,\n reasoning?.selection.reasoningEffort,\n reasoning?.defaultEffort,\n );\n // An unknown committed effort defaults to the max frame: a fresh\n // conversation paints the dark shell immediately instead of flashing the\n // light palette until the directory load resolves the real effort.\n const committedFrame = committedIndex < 0\n ? PREVIEW_MAX_FRAME\n : frameForEffort(committedIndex, efforts.length);\n const bindEffort = skin.bindEffort;\n const [frame, setFrame] = useState(() => bindEffort ? committedFrame : presenter.getFrame());\n const [pending, setPending] = useState(false);\n const [failed, setFailed] = useState(false);\n const [interacting, setInteracting] = useState(false);\n const dragging = useRef(false);\n const dragStartFrame = useRef(frame);\n const enabled = skin.enabled;\n\n useEffect(() => {\n if (enabled) load();\n }, [enabled, load]);\n\n useEffect(() => {\n if (!bindEffort || dragging.current || pending) return;\n setFrame(committedFrame);\n presenter.setFrame(committedFrame);\n }, [bindEffort, committedFrame, pending, presenter]);\n\n if (!enabled) return null;\n if (bindEffort && (reasoning === null || efforts.length < 2)) return null;\n\n const previewIndex = nearestEffortIndex(frame, efforts);\n const previewEffort = efforts[previewIndex];\n const progressRatio = frame / PREVIEW_MAX_FRAME;\n const tooltipLabel = indicatorLabel(frame, bindEffort ? efforts : []);\n\n const commit = async (rawFrame: number) => {\n if (!bindEffort) {\n dragging.current = false;\n setFrame(rawFrame);\n presenter.setFrame(rawFrame);\n return;\n }\n const targetIndex = nearestEffortIndex(rawFrame, efforts);\n const target = efforts[targetIndex];\n if (target === undefined) return;\n const targetFrame = frameForEffort(targetIndex, efforts.length);\n dragging.current = false;\n setFrame(targetFrame);\n presenter.setFrame(targetFrame);\n if (targetIndex === committedIndex || pending) return;\n setPending(true);\n setFailed(false);\n const accepted = await select({\n provider: reasoning.selection.provider,\n model: reasoning.selection.model,\n reasoningEffort: target.id,\n });\n setPending(false);\n if (!accepted) {\n setFailed(true);\n setFrame(committedFrame);\n presenter.setFrame(committedFrame);\n }\n };\n\n return (\n <div\n className=\"liang-effort-control\"\n data-plugin={PACKAGE_ID}\n data-state={failed ? \"error\" : pending ? \"pending\" : \"ready\"}\n title={bindEffort ? previewEffort?.name : undefined}\n >\n {interacting && (\n <output\n className=\"liang-effort-control__tooltip\"\n style={{ \"--liang-slider-ratio\": progressRatio } as React.CSSProperties}\n >\n {tooltipLabel}\n </output>\n )}\n <div className=\"liang-effort-control__ticks\" aria-hidden=\"true\">\n {efforts.map((effort, index) => (\n <i\n className=\"liang-effort-control__tick\"\n key={effort.id}\n style={{ left: `${(frameForEffort(index, efforts.length) / PREVIEW_MAX_FRAME) * 100}%` }}\n />\n ))}\n </div>\n <input\n className=\"liang-effort-control__range\"\n type=\"range\"\n min={0}\n max={PREVIEW_MAX_FRAME}\n step={1}\n value={frame}\n disabled={pending || state.status === \"selecting\"}\n aria-label={bindEffort ? \"\u601D\u8003\u7B49\u7EA7\" : \"\u76AE\u80A4\u8FDB\u5EA6\"}\n aria-valuetext={bindEffort ? previewEffort?.name ?? \"\" : tooltipLabel}\n onPointerDown={() => {\n dragging.current = true;\n dragStartFrame.current = frame;\n setInteracting(true);\n }}\n onInput={(event) => {\n dragging.current = true;\n const next = Number(event.currentTarget.value);\n setFrame(next);\n presenter.setFrame(next);\n }}\n onPointerUp={(event) => {\n setInteracting(false);\n void commit(Number(event.currentTarget.value));\n }}\n onPointerCancel={() => {\n setInteracting(false);\n dragging.current = false;\n setFrame(dragStartFrame.current);\n presenter.setFrame(dragStartFrame.current);\n }}\n onKeyUp={(event) => {\n setInteracting(false);\n if (event.key !== \"Escape\") void commit(Number(event.currentTarget.value));\n }}\n onBlur={(event) => {\n setInteracting(false);\n if (dragging.current) void commit(Number(event.currentTarget.value));\n }}\n onKeyDown={(event) => {\n setInteracting(true);\n if (event.key === \"Escape\" && !pending) {\n setInteracting(false);\n dragging.current = false;\n setFrame(dragStartFrame.current);\n presenter.setFrame(dragStartFrame.current);\n }\n }}\n />\n </div>\n );\n}\n\nfunction EffortBindingRow({ scope, t }: EffortBindingRowProps) {\n const snapshot = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n );\n const [pending, setPending] = useState(false);\n if (!snapshot.enabled) return null;\n\n return (\n <div className=\"liang-appearance-binding\" data-plugin={PACKAGE_ID}>\n <span>{t(\"effort.binding\")}</span>\n <Switch\n checked={snapshot.bindEffort}\n disabled={pending}\n label={t(\"effort.binding\")}\n onChange={(next) => {\n if (pending) return;\n setPending(true);\n void scope.setBindEffort(next).catch(() => undefined).finally(() => setPending(false));\n }}\n />\n </div>\n );\n}\n\nexport const inject = [\n \"slots\",\n \"sessions\",\n \"modelDirectories\",\n \"locale\",\n \"theme\",\n];\n\nfunction createPreferenceStore(): PreferenceStore {\n // The market's active skin is the source of truth for whether this client\n // should be visible. The appearance switch is therefore scoped to this\n // client activation and must not survive switching away and back.\n try {\n localStorage.removeItem(\"dsh-liang-intensity-skin.enabled\");\n } catch {\n // Storage may be unavailable; the in-memory default still enables Liang.\n }\n let snapshot: SkinSettings = {\n enabled: true,\n bindEffort: localStorage.getItem(BIND_EFFORT_KEY) !== \"0\",\n };\n const listeners = new Set<() => void>();\n const onStorage = (event: StorageEvent) => {\n if (event.key !== BIND_EFFORT_KEY) return;\n const next = {\n enabled: snapshot.enabled,\n bindEffort: event.newValue !== \"0\",\n };\n if (next.enabled === snapshot.enabled && next.bindEffort === snapshot.bindEffort) return;\n snapshot = next;\n for (const listener of listeners) listener();\n };\n window.addEventListener(\"storage\", onStorage);\n return {\n getSnapshot: () => snapshot,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n async set(enabled) {\n if (enabled === snapshot.enabled) return;\n snapshot = { ...snapshot, enabled };\n for (const listener of listeners) listener();\n },\n async setBindEffort(bindEffort) {\n if (bindEffort === snapshot.bindEffort) return;\n localStorage.setItem(BIND_EFFORT_KEY, bindEffort ? \"1\" : \"0\");\n snapshot = { ...snapshot, bindEffort };\n for (const listener of listeners) listener();\n },\n dispose() {\n window.removeEventListener(\"storage\", onStorage);\n listeners.clear();\n },\n };\n}\n\nexport function apply(ctx: ClientContext) {\n const style = document.createElement(\"style\");\n style.dataset.plugin = PACKAGE_ID;\n style.textContent = styles;\n document.head.append(style);\n ctx.effect(() => () => style.remove(), \"liang-intensity-skin: scoped styles\");\n\n const scope = createPreferenceStore();\n ctx.effect(() => () => scope.dispose(), \"liang-intensity-skin: appearance preference\");\n const theme = ctx.get(\"theme\") as ThemeService;\n const presenter = new SkinPresenter(scope, theme);\n ctx.effect(() => () => presenter.dispose(), \"liang-intensity-skin: backdrop presenter\");\n ctx.effect(\n () => installLiangAppearanceButton(scope, presenter, PACKAGE_ID),\n \"liang-intensity-skin: native appearance extension\",\n );\n ctx.effect(\n () => ctx.locale.register(LOCALE_NAMESPACE, {\n zh: { \"effort.binding\": \"\u6ED1\u52A8\u53D8\u7956\u7ED1\u5B9A\u601D\u8003\u7B49\u7EA7\" },\n en: { \"effort.binding\": \"Bind slider to reasoning level\" },\n }), \"liang-intensity-skin: settings locale\");\n\n ctx.slots.inject(\"settings.general.item\", () => ctx.slots.register({\n name: \"settings.general.item\",\n id: \"liang-effort-binding\",\n order: 10.5,\n locale: LOCALE_NAMESPACE,\n inject: () => ({ scope }),\n }, EffortBindingRow));\n\n ctx.slots.inject(\"conversation.input.right\", () => ctx.slots.register({\n name: \"conversation.input.right\",\n id: \"liang-intensity-control\",\n order: 10,\n inject: (sessionId: string) => {\n const available = ctx.sessions.subagentAddress(sessionId) === undefined;\n const directory = ctx.modelDirectories.directoryFor(sessionId) as ModelDirectory;\n return {\n directory: directory.store,\n presenter,\n scope,\n load: () => {\n if (available) void directory.load().catch(() => undefined);\n },\n select: (selection: ModelSelection) => available\n ? directory.select(selection).then((result) => result.ok, () => false)\n : Promise.resolve(false),\n };\n },\n }, LiangEffortSlider));\n}\n", ".liang-skin-backdrop {\n position: fixed;\n z-index: -1;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n background: var(--liang-page, transparent);\n opacity: 0;\n transition: opacity 220ms ease, background-color 180ms linear;\n}\n\nbody[data-liang-skin=\"on\"] .liang-skin-backdrop {\n opacity: 1;\n}\n\n.liang-skin-backdrop img {\n position: absolute;\n top: 50%;\n right: 0;\n display: block;\n width: min(42vw, 720px);\n height: 100%;\n object-fit: cover;\n object-position: 50% 42%;\n opacity: var(--liang-portrait-opacity, 0.45);\n transform: translateY(-50%);\n filter: none;\n mask-image: linear-gradient(90deg, transparent 0%, rgb(0 0 0 / 20%) 10%, black 30%, black 100%);\n transition: filter 180ms linear;\n}\n\n.liang-skin-backdrop img {\n display: none;\n}\n\n.liang-skin-backdrop[data-media=\"sequence\"] .liang-skin-sequence-frame {\n display: block;\n opacity: var(--liang-portrait-opacity, 0.82);\n}\n\n.liang-skin-backdrop[data-media=\"color\"] img {\n display: none;\n}\n\n.liang-skin-backdrop::after {\n position: absolute;\n inset: 0;\n content: \"\";\n background:\n linear-gradient(90deg, var(--liang-page, transparent) 0 28%, transparent 57% 100%),\n linear-gradient(var(--liang-bg-base, transparent), var(--liang-bg-base, transparent));\n}\n\nbody[data-liang-skin=\"on\"] {\n /* Keep the backdrop above the canvas but below content and native portals.\n The host owns root positioning, dimensions, and its own stacking order. */\n isolation: isolate;\n --dsw-alias-bg-base: transparent !important;\n --dsw-alias-bg-layer-1: var(--liang-layer-1) !important;\n --dsw-alias-bg-layer-2: var(--liang-layer-2) !important;\n --dsw-alias-bg-layer-3: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-fill: var(--liang-sidebar) !important;\n --dsw-alias-label-primary: var(--liang-ink) !important;\n --dsw-alias-label-primary-dimmed: var(--liang-ink) !important;\n --dsw-alias-label-secondary: var(--liang-secondary) !important;\n --dsw-alias-label-tertiary: var(--liang-tertiary) !important;\n --dsw-alias-label-caption: var(--liang-tertiary) !important;\n --dsw-alias-border-l1: var(--liang-border) !important;\n --dsw-alias-border-l2-darkmode-thin: var(--liang-border) !important;\n --dsw-alias-border-l2: var(--liang-border) !important;\n --dsw-alias-border-l3: var(--liang-border) !important;\n --dsw-alias-button-primary-fill: var(--liang-accent) !important;\n --dsw-alias-button-primary-hover: var(--liang-accent-hover) !important;\n --dsw-alias-button-info-fill: var(--liang-accent) !important;\n --dsw-alias-button-info-hover: var(--liang-accent-hover) !important;\n --dsw-alias-state-business-primary: var(--liang-accent) !important;\n --dsw-alias-interactive-bg-hover: var(--liang-hover) !important;\n --dsw-alias-interactive-bg-active: var(--liang-hover) !important;\n --dsw-alias-button-elevated-fill: var(--liang-layer-1) !important;\n --dsw-alias-button-floating-fill: var(--liang-layer-2) !important;\n --dsw-alias-button-floating-hover: var(--liang-layer-3) !important;\n --dsw-alias-interactive-bg-hover-solid: var(--liang-layer-2) !important;\n --dsw-specific-bubble: var(--liang-layer-2) !important;\n --dsw-specific-input-major: var(--liang-layer-1) !important;\n --dsw-specific-menu: var(--liang-layer-3) !important;\n --dsw-specific-selector: var(--liang-layer-2) !important;\n --dsw-alias-markdown-citation: var(--liang-layer-2) !important;\n --dsw-alias-markdown-code-block-banner: var(--liang-layer-1) !important;\n --dsw-alias-markdown-code-block: var(--liang-layer-1) !important;\n --dsw-alias-markdown-code-segment-selected: var(--liang-layer-2) !important;\n --dsw-alias-markdown-code-segment-unselected: var(--liang-layer-1) !important;\n --dsw-alias-markdown-inline-code: var(--liang-layer-2) !important;\n --dsw-alias-markdown-placeholder: var(--liang-layer-1) !important;\n --dsw-alias-markdown-tag: var(--liang-layer-2) !important;\n background: var(--liang-page) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) {\n --dsw-alias-brand-primary-new-colorprimary-new-color: rgb(65 118 230) !important;\n --dsw-alias-brand-primary: rgb(15 17 21) !important;\n --dsw-alias-brand-text: rgb(15 17 21) !important;\n --dsw-alias-button-primary-fill: rgb(15 17 21) !important;\n --dsw-alias-button-primary-hover: rgb(53 54 56) !important;\n --dsw-alias-button-info-fill: rgb(65 118 230) !important;\n --dsw-alias-button-info-hover: rgb(103 158 254) !important;\n --dsw-alias-state-business-primary: rgb(65 118 230) !important;\n --dsw-alias-label-primary-inverted: rgb(249 250 251) !important;\n --dsw-alias-button-elevated-fill: rgb(255 255 255) !important;\n --dsw-alias-button-floating-fill: rgb(255 255 255) !important;\n --dsw-alias-button-floating-hover: rgb(241 243 245) !important;\n --dsw-alias-interactive-bg-hover-solid: rgb(241 243 245) !important;\n --dsw-specific-bubble: rgb(237 243 254) !important;\n --dsw-specific-input-major: rgb(255 255 255) !important;\n --dsw-specific-menu: rgb(255 255 255) !important;\n --dsw-specific-selector: rgb(245 246 247) !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] {\n --dsw-alias-brand-primary-new-colorprimary-new-color: #c19a49 !important;\n --dsw-alias-brand-primary: #c19a49 !important;\n --dsw-alias-brand-text: #d5b56e !important;\n --dsw-alias-button-info-fill: #c19a49 !important;\n --dsw-alias-button-info-hover: #d5b56e !important;\n --dsw-alias-state-business-primary: #c19a49 !important;\n --dsw-alias-bg-module-platform: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-nav-item-active: var(--liang-layer-3) !important;\n --dsw-specific-sidebar-nav-item-hover: var(--liang-hover) !important;\n}\n\n/* The host renders the running-turn label as a clipped blue text gradient.\n Retarget only that gradient's color tokens in the custom dark skin; keep\n the host's text clipping and shimmer behavior, and leave light mode alone. */\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"_turnStatus\"] {\n --dsw-static-deepseek-500: #c19a49 !important;\n --dsw-static-deepseek-200: #d5b56e !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"_turnStatusClock\"] {\n color: #c19a49 !important;\n -webkit-text-fill-color: #c19a49 !important;\n}\n\n/* Preserve the wordmark badge contrast in the low-intensity shell. */\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > rect[width=\"52\"] {\n fill: rgb(15 17 21) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > g[clip-path*=\"badge\"] path {\n fill: rgb(249 250 251) !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > rect[width=\"52\"] {\n fill: #c19a49 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u65B0\u5EFA\u4F1A\u8BDD\"] svg[viewBox=\"0 0 182 24\"] > g[clip-path*=\"badge\"] path {\n fill: #171816 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [aria-label^=\"\u9009\u62E9\u6A21\u578B\"] > span:nth-of-type(2) {\n color: #d5b56e !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] [class*=\"heroGlow\"] ellipse {\n fill: #c19a49 !important;\n fill-opacity: 0.16 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] span[class*=\"_previewBadge\"] {\n color: #171816 !important;\n background: #c19a49 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u53D1\u9001\u6D88\u606F\"] {\n color: #171816 !important;\n}\n\nbody[data-liang-skin=\"on\"][data-liang-stage=\"5\"] button[aria-label=\"\u53D1\u9001\u6D88\u606F\"]:disabled {\n opacity: 0.62;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u53D1\u9001\u6D88\u606F\"] {\n color: #fff !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) button[aria-label=\"\u53D1\u9001\u6D88\u606F\"]:disabled {\n color: rgb(255 255 255 / 92%) !important;\n background: rgb(65 118 230 / 42%) !important;\n opacity: 1;\n}\n\nbody[data-liang-skin=\"on\"] > #root {\n background: transparent !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-dsh-desktop-mode=\"compatibility\"],\n [data-dsh-desktop-mode=\"extended\"]\n) .liang-skin-backdrop {\n top: var(--dsh-desktop-frame-height, 0px);\n}\n\n/* Windows paints the sidebar fill across the host frame, covering the portrait.\n Match macOS's transparent frame while keeping the sidebar, caption, and\n conversation surfaces painted by their own host rules. */\nhtml[data-windows-titlebar] body[data-liang-skin=\"on\"] #root [class*=\"_frame\"]:has(> [class*=\"_centerCol\"]) {\n background: transparent !important;\n}\n\n/* macOS adds different translucent sidebar materials for native light/dark.\n While Liang is active, the effort palette owns the sidebar fill. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_frame\"]:has(> [class*=\"_centerCol\"]) > [class*=\"_sidebarCol\"] {\n background: var(--liang-sidebar) !important;\n}\n\n/* Keep the host's expanded new-session surface on the same palette. The\n collapsed icon keeps its native transparent surface and hover behavior. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"]:has(> [class*=\"_logoRow\"]):not([class*=\"_collapsed\"]) button[class*=\"_newSession\"] {\n background: var(--dsw-alias-button-elevated-fill) !important;\n}\n\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"]:has(> [class*=\"_logoRow\"]):not([class*=\"_collapsed\"]) button[class*=\"_newSession\"]:hover {\n background: var(--dsw-alias-button-floating-hover) !important;\n}\n\n/* The native dark rule also outranks the collapsed icon's transparent fill. */\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"][class*=\"_collapsed\"]:has(> [class*=\"_logoRow\"]) button[class*=\"_newSession\"] {\n background: transparent !important;\n}\n\nhtml[data-platform=\"darwin\"] body[data-liang-skin=\"on\"] #root [class*=\"_sidebarCol\"] [class*=\"_root\"][class*=\"_collapsed\"]:has(> [class*=\"_logoRow\"]) button[class*=\"_newSession\"]:hover {\n background: var(--dsw-alias-interactive-bg-hover) !important;\n}\n\nbody[data-liang-skin=\"on\"] button,\nbody[data-liang-skin=\"on\"] input,\nbody[data-liang-skin=\"on\"] textarea {\n transition: color 160ms linear, background-color 160ms linear, border-color 160ms linear;\n}\n\n/* The composer card has a native theme-mode fill, so keep its surface and\n readable ink aligned with the active Liang palette. */\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] {\n border-color: var(--liang-border) !important;\n color: var(--liang-ink) !important;\n background: var(--liang-layer-1) !important;\n box-shadow: 0 8px 28px rgb(20 22 20 / 8%);\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] :is(textarea, button, [data-input-mirror=\"true\"]) {\n color: var(--liang-ink) !important;\n caret-color: var(--liang-accent) !important;\n}\n\nbody[data-liang-skin=\"on\"]:is(\n [data-liang-stage=\"0\"],\n [data-liang-stage=\"1\"],\n [data-liang-stage=\"2\"],\n [data-liang-stage=\"3\"]\n) [data-composer-card=\"true\"] textarea::placeholder {\n color: var(--liang-tertiary) !important;\n opacity: 1;\n}\n\n.liang-effort-control {\n --liang-control-accent: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n --liang-control-rail: var(--dsw-alias-border-l3, rgb(0 0 0 / 16%));\n position: relative;\n display: flex;\n width: 124px;\n height: 28px;\n align-items: center;\n margin: 0 3px;\n overflow: visible;\n}\n\nbody[data-liang-skin=\"on\"] .liang-effort-control {\n --liang-control-accent: var(--liang-secondary);\n --liang-control-rail: color-mix(in srgb, var(--liang-secondary) 28%, transparent);\n}\n\n.liang-effort-control__ticks {\n position: absolute;\n z-index: 0;\n inset: 0 10px;\n pointer-events: none;\n}\n\n.liang-effort-control__ticks::before {\n position: absolute;\n top: 50%;\n right: 0;\n left: 0;\n height: 1px;\n content: \"\";\n background: var(--liang-control-rail);\n transform: translateY(-50%);\n}\n\n.liang-effort-control__tooltip {\n position: absolute;\n z-index: 4;\n bottom: calc(100% + 7px);\n left: calc(10px + (100% - 20px) * var(--liang-slider-ratio));\n min-width: max-content;\n padding: 5px 8px;\n border: 1px solid var(--liang-border, rgb(0 0 0 / 12%));\n border-radius: 7px;\n color: var(--liang-ink, #171816);\n background: var(--liang-layer-1, #fff);\n box-shadow: 0 5px 16px rgb(0 0 0 / 16%);\n font-size: 11px;\n font-weight: 600;\n line-height: 16px;\n letter-spacing: 0.01em;\n pointer-events: none;\n transform: translateX(-50%);\n white-space: nowrap;\n}\n\n.liang-effort-control__tooltip::after {\n position: absolute;\n top: 100%;\n left: 50%;\n width: 7px;\n height: 7px;\n content: \"\";\n background: inherit;\n transform: translate(-50%, -4px) rotate(45deg);\n}\n\n.liang-effort-control__tick {\n position: absolute;\n top: 50%;\n width: 1px;\n height: 7px;\n background: var(--liang-control-accent);\n opacity: 0.42;\n transform: translate(-50%, -50%);\n}\n\n.liang-effort-control__range {\n position: relative;\n z-index: 1;\n width: calc(100% - 7px);\n height: 28px;\n margin: 0 3.5px;\n cursor: ew-resize;\n appearance: none;\n background: transparent;\n touch-action: pan-y;\n}\n\n.liang-effort-control__range:disabled {\n cursor: progress;\n opacity: 0.58;\n}\n\n.liang-effort-control__range::-webkit-slider-runnable-track {\n height: 1px;\n border-radius: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-webkit-slider-thumb {\n width: 13px;\n height: 13px;\n margin-top: -6px;\n border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n border-radius: 50%;\n appearance: none;\n background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--dsw-alias-bg-layer-1, #fff)) 2.5px);\n box-shadow: 0 1px 4px rgb(0 0 0 / 14%);\n}\n\nbody[data-liang-skin=\"on\"] .liang-effort-control__range::-webkit-slider-thumb {\n width: 13px;\n height: 13px;\n margin-top: -6px;\n border-color: color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--liang-layer-1)) 2.5px);\n}\n\n.liang-effort-control__range::-moz-range-track {\n height: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-moz-range-progress {\n height: 1px;\n background: transparent;\n}\n\n.liang-effort-control__range::-moz-range-thumb {\n width: 11px;\n height: 11px;\n border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);\n border-radius: 50%;\n background: color-mix(in srgb, var(--liang-control-accent) 24%, var(--dsw-alias-bg-layer-1, #fff));\n}\n\n.liang-effort-control__range:focus-visible {\n outline: none;\n}\n\n.liang-effort-control[data-state=\"error\"] {\n --liang-control-accent: var(--dsw-alias-state-error-primary, #e43c3c);\n}\n\n.liang-appearance-choice {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n flex: 180px;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 4px;\n padding: 20px 32px;\n border-radius: 16px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n background: transparent;\n font-size: 14px;\n line-height: 22px;\n display: flex;\n}\n\n[class*=\"_cubeRow\"]:has(.liang-appearance-choice) {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n}\n\n.liang-appearance-choice:hover:not([aria-pressed=\"true\"]) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.liang-appearance-choice[aria-pressed=\"true\"] {\n border-color: var(--dsw-static-neutral-bluish-400);\n background: var(--dsw-alias-bg-module-platform);\n}\n\n.liang-appearance-choice__icon {\n display: block;\n flex: 0 0 16px;\n width: 16px;\n height: 16px;\n color: currentColor;\n font-size: 16px;\n line-height: 16px;\n}\n\n.liang-appearance-choice__label {\n display: block;\n}\n\n/* Keep the host's three theme cubes untouched. These rules only style the\n fourth button that is appended to the host cube row. */\n.liang-appearance-choice:disabled {\n cursor: progress;\n opacity: 0.7;\n}\n\n.liang-appearance-binding {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 24px;\n padding: 16px 0;\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n font-size: 14px;\n line-height: 20px;\n}\n\n@media (max-width: 760px) {\n .liang-effort-control {\n width: 92px;\n }\n\n .liang-skin-backdrop img {\n right: -18vw;\n width: 92vw;\n opacity: calc(var(--liang-portrait-opacity, 0.45) * 0.72);\n }\n\n}\n\n@media (prefers-reduced-motion: reduce) {\n .liang-skin-backdrop,\n .liang-skin-backdrop img,\n body[data-liang-skin=\"on\"] button,\n body[data-liang-skin=\"on\"] input,\n body[data-liang-skin=\"on\"] textarea {\n transition: none;\n }\n}\n", "export interface AppearanceSnapshot {\n enabled: boolean;\n}\n\nexport interface AppearanceScope {\n getSnapshot(): AppearanceSnapshot;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface AppearancePresenter {\n choose(enabled: boolean): Promise<void>;\n}\n\nconst NATIVE_APPEARANCE_ROW = '[class*=\"_cubeRow\"]';\nconst LIANG_APPEARANCE_BUTTON = \"liang-appearance-choice\";\n\nfunction hasClassSuffix(node: Element, suffix: string) {\n return [...node.classList].some((name) => name.endsWith(suffix));\n}\n\nfunction findAppearanceRow() {\n for (const row of document.querySelectorAll<HTMLElement>(NATIVE_APPEARANCE_ROW)) {\n if (!hasClassSuffix(row, \"_cubeRow\")) continue;\n // All three native appearance choices are direct button children. Validate\n // the structure as well as the suffix so unrelated cube rows stay alone.\n const nativeButtons = [...row.children].filter(\n (node): node is HTMLButtonElement => node instanceof HTMLButtonElement\n && hasClassSuffix(node, \"_themeCube\"),\n );\n if (nativeButtons.length < 3) continue;\n\n let group = row.parentElement;\n while (group !== null && !hasClassSuffix(group, \"_group\")) {\n group = group.parentElement;\n }\n group ??= row.parentElement;\n if (group !== null) return { row, group, nativeButtons };\n }\n return null;\n}\n\ninterface MountedAppearance {\n row: HTMLElement;\n group: HTMLElement;\n button: HTMLButtonElement;\n handleCustomClick: () => void;\n}\n\nexport function installLiangAppearanceButton(\n scope: AppearanceScope,\n presenter: AppearancePresenter,\n packageId: string,\n): () => void {\n let pending = false;\n let disposed = false;\n let mounted: MountedAppearance | null = null;\n const nativeClickHandlers = new Map<HTMLButtonElement, () => void>();\n\n const unmount = () => {\n for (const [button, handler] of nativeClickHandlers) {\n button.removeEventListener(\"click\", handler, { capture: true });\n }\n nativeClickHandlers.clear();\n if (mounted === null) return;\n mounted.button.removeEventListener(\"click\", mounted.handleCustomClick);\n mounted.button.remove();\n mounted = null;\n };\n\n const choose = async (enabled: boolean) => {\n if (disposed || pending || scope.getSnapshot().enabled === enabled) return;\n pending = true;\n sync();\n try {\n await presenter.choose(enabled);\n } catch {\n // The preference store remains the source of truth after a failed choice.\n } finally {\n pending = false;\n if (!disposed) sync();\n }\n };\n\n const createMount = (row: HTMLElement, group: HTMLElement): MountedAppearance => {\n const english = document.documentElement.lang.toLowerCase().startsWith(\"en\");\n const button = document.createElement(\"button\");\n button.className = LIANG_APPEARANCE_BUTTON;\n button.type = \"button\";\n button.dataset.plugin = packageId;\n button.setAttribute(\"aria-label\", \"\u6ED1\u52A8\u53D8\u7956\");\n\n const icon = document.createElement(\"span\");\n icon.className = \"liang-appearance-choice__icon\";\n icon.setAttribute(\"aria-hidden\", \"true\");\n icon.textContent = \"\u25C8\";\n\n const label = document.createElement(\"span\");\n label.className = \"liang-appearance-choice__label\";\n label.textContent = english ? \"Slider\" : \"\u6ED1\u52A8\u53D8\u7956\";\n button.append(icon, label);\n const handleCustomClick = () => { void choose(true); };\n button.addEventListener(\"click\", handleCustomClick);\n\n return { row, group, button, handleCustomClick };\n };\n\n const sync = () => {\n if (disposed) return;\n const target = findAppearanceRow();\n if (target === null) {\n unmount();\n return;\n }\n if (mounted !== null && (mounted.row !== target.row || mounted.group !== target.group)) {\n unmount();\n }\n mounted ??= createMount(target.row, target.group);\n const { row, button } = mounted;\n if (button.parentElement !== row) row.append(button);\n\n const snapshot = scope.getSnapshot();\n button.disabled = pending;\n button.setAttribute(\"aria-pressed\", String(snapshot.enabled));\n\n for (const [nativeButton, handler] of nativeClickHandlers) {\n if (target.nativeButtons.includes(nativeButton)) continue;\n nativeButton.removeEventListener(\"click\", handler, { capture: true });\n nativeClickHandlers.delete(nativeButton);\n }\n for (const nativeButton of target.nativeButtons) {\n if (nativeClickHandlers.has(nativeButton)) continue;\n const handleNativeClick = () => { void choose(false); };\n nativeClickHandlers.set(nativeButton, handleNativeClick);\n nativeButton.addEventListener(\"click\", handleNativeClick, { capture: true });\n }\n };\n\n const observer = new MutationObserver(sync);\n observer.observe(document.body, { childList: true, subtree: true });\n const unsubscribe = scope.subscribe(sync);\n sync();\n\n return () => {\n if (disposed) return;\n // Mark disposal first: outstanding choices and queued observer callbacks\n // must never attach new controls after the client has been deactivated.\n disposed = true;\n observer.disconnect();\n unsubscribe();\n unmount();\n };\n}\n", "export interface PortraitSource {\n level: number;\n url: string;\n}\n\nexport interface PortraitState {\n index: number | null;\n url: string | null;\n status: \"loading\" | \"ready\" | \"failed\";\n image: PortraitImage | null;\n}\n\nexport interface PortraitImage {\n src: string;\n loading: \"eager\" | \"lazy\";\n decoding: \"async\" | \"sync\" | \"auto\";\n decode(): Promise<void>;\n addEventListener(type: \"load\" | \"error\", listener: () => void): void;\n removeEventListener(type: \"load\" | \"error\", listener: () => void): void;\n removeAttribute(name: string): void;\n}\n\nexport interface PortraitLoaderOptions {\n sources: readonly PortraitSource[];\n onChange: (state: PortraitState) => void;\n createImage?: () => PortraitImage;\n}\n\ninterface Asset {\n url: string;\n status: \"idle\" | \"loading\" | \"ready\" | \"failed\";\n loadedUrl: string | null;\n retries: number;\n image: PortraitImage | null;\n timer: ReturnType<typeof setTimeout> | null;\n detach: (() => void) | null;\n}\n\nconst RETRY_DELAYS = [500, 1500, 3000] as const;\n\nfunction retryUrl(source: string, retry: number) {\n if (retry === 0) return source;\n const hashIndex = source.indexOf(\"#\");\n const hash = hashIndex < 0 ? \"\" : source.slice(hashIndex);\n const base = hashIndex < 0 ? source : source.slice(0, hashIndex);\n const queryIndex = base.indexOf(\"?\");\n const path = queryIndex < 0 ? base : base.slice(0, queryIndex);\n const query = new URLSearchParams(queryIndex < 0 ? \"\" : base.slice(queryIndex + 1));\n query.set(\"retry\", String(retry));\n return `${path}?${query}${hash}`;\n}\n\n/**\n * Decode frames independently and return the decoded image itself for display.\n * start() resumes after stop(); stop() silently releases every request/image.\n * dispose() is permanent. select() also accepts a target before start().\n */\nexport function createPortraitLoader(options: PortraitLoaderOptions) {\n const sources = options.sources.map((source) => ({ ...source }));\n const assets = new Map<string, Asset>();\n for (const { url } of sources) {\n if (!assets.has(url)) {\n assets.set(url, {\n url, status: \"idle\", loadedUrl: null, retries: 0,\n image: null, timer: null, detach: null,\n });\n }\n }\n const createImage = options.createImage ?? (() => new Image());\n let onChange: PortraitLoaderOptions[\"onChange\"] | null = options.onChange;\n let active = false;\n let disposed = false;\n let generation = 0;\n let targetLevel = sources[0]?.level ?? 0;\n let displayedIndex: number | null = null;\n let lastState: PortraitState | null = null;\n\n const isCurrent = (run: number) => active && !disposed && generation === run;\n const nearestIndex = (available: (index: number) => boolean) => {\n let nearest: number | null = null;\n for (let index = 0; index < sources.length; index += 1) {\n if (!available(index)) continue;\n const distance = Math.abs(sources[index].level - targetLevel);\n const previous = nearest === null ? Infinity : Math.abs(sources[nearest].level - targetLevel);\n if (nearest === null || distance < previous || (distance === previous && sources[index].level > sources[nearest].level)) {\n nearest = index;\n }\n }\n return nearest;\n };\n const isReady = (index: number) => assets.get(sources[index].url)?.status === \"ready\";\n const emit = (state: PortraitState) => {\n if (lastState?.index === state.index && lastState.url === state.url && lastState.status === state.status) return;\n lastState = state;\n onChange?.(state);\n };\n const reconcile = () => {\n if (!active || disposed) return;\n const target = nearestIndex(() => true);\n if (target !== null && isReady(target)) displayedIndex = target;\n else if (displayedIndex === null) displayedIndex = nearestIndex(isReady);\n if (displayedIndex !== null) {\n const asset = assets.get(sources[displayedIndex].url)!;\n emit({ index: displayedIndex, url: asset.loadedUrl, image: asset.image, status: \"ready\" });\n } else {\n const exhausted = [...assets.values()].every((asset) => asset.status === \"failed\");\n emit({ index: null, url: null, image: null, status: exhausted ? \"failed\" : \"loading\" });\n }\n };\n\n const request = (asset: Asset, run: number) => {\n if (!isCurrent(run)) return;\n asset.status = \"loading\";\n const image = createImage();\n asset.image = image;\n image.loading = \"eager\";\n image.decoding = \"async\";\n const url = retryUrl(asset.url, asset.retries);\n let settled = false;\n let decoding = false;\n const current = () => !settled && isCurrent(run) && asset.image === image;\n const detach = () => {\n image.removeEventListener(\"load\", handleLoad);\n image.removeEventListener(\"error\", handleError);\n asset.detach = null;\n };\n const handleError = () => {\n if (!current()) return;\n settled = true;\n detach();\n image.removeAttribute(\"src\");\n asset.image = null;\n if (asset.retries < RETRY_DELAYS.length) {\n const delay = RETRY_DELAYS[asset.retries];\n asset.retries += 1;\n asset.timer = setTimeout(() => {\n if (!isCurrent(run)) return;\n asset.timer = null;\n request(asset, run);\n }, delay);\n } else {\n asset.status = \"failed\";\n reconcile();\n }\n };\n const handleLoad = () => {\n if (!current() || decoding) return;\n decoding = true;\n void image.decode().then(() => {\n if (!current()) return;\n settled = true;\n detach();\n asset.loadedUrl = url;\n asset.status = \"ready\";\n reconcile();\n }, handleError);\n };\n asset.detach = detach;\n image.addEventListener(\"load\", handleLoad);\n image.addEventListener(\"error\", handleError);\n image.src = url;\n };\n\n const stop = () => {\n active = false;\n generation += 1;\n for (const asset of assets.values()) {\n if (asset.timer !== null) clearTimeout(asset.timer);\n asset.timer = null;\n asset.detach?.();\n asset.image?.removeAttribute(\"src\");\n asset.image = null;\n asset.status = \"idle\";\n asset.loadedUrl = null;\n asset.retries = 0;\n }\n displayedIndex = null;\n lastState = null;\n };\n\n return {\n start() {\n if (disposed || active) return;\n active = true;\n const run = ++generation;\n reconcile();\n for (const asset of assets.values()) request(asset, run);\n },\n select(level: number) {\n if (disposed || !Number.isFinite(level)) return;\n targetLevel = level;\n reconcile();\n },\n stop,\n dispose() {\n stop();\n disposed = true;\n onChange = null;\n },\n };\n}\n", "export const PREVIEW_MAX_FRAME = 240;\nexport const MAX_LEVEL = 30;\n\nconst LIANG_RANKS = [\"\u5C0F\u96BE\u6881\", \"\u7262\u6881\", \"\u6881\u5B50\", \"\u6881\u5723\", \"\u6881\u795E\", \"\u6881\u7956\"] as const;\n\nexport interface EffortLike {\n id: string;\n name: string;\n description?: string;\n}\n\nexport interface Palette {\n level: number;\n stage: number;\n strength: number;\n page: string;\n base: string;\n layer1: string;\n layer2: string;\n layer3: string;\n sidebar: string;\n ink: string;\n secondary: string;\n tertiary: string;\n border: string;\n accent: string;\n accentHover: string;\n hover: string;\n portraitOpacity: string;\n}\n\ntype Rgb = readonly [number, number, number];\n\ninterface PaletteStop {\n at: number;\n page: Rgb;\n surface: Rgb;\n surface2: Rgb;\n ink: Rgb;\n secondary: Rgb;\n accent: Rgb;\n portraitOpacity: number;\n}\n\n// These are the original calibrator's six stage anchors: pale neutral at the\n// low end, progressively smoked surfaces, then charcoal and antique gold.\nconst STOPS: readonly PaletteStop[] = [\n { at: 0, page: [232, 233, 229], surface: [248, 248, 245], surface2: [238, 239, 235], ink: [23, 24, 22], secondary: [112, 116, 111], accent: [181, 43, 36], portraitOpacity: 0.92 },\n { at: 6, page: [211, 211, 206], surface: [239, 239, 234], surface2: [224, 224, 218], ink: [26, 26, 24], secondary: [101, 101, 96], accent: [181, 43, 36], portraitOpacity: 0.93 },\n { at: 12, page: [171, 168, 162], surface: [211, 208, 201], surface2: [190, 186, 179], ink: [27, 26, 24], secondary: [83, 79, 74], accent: [166, 54, 42], portraitOpacity: 0.94 },\n { at: 18, page: [117, 112, 106], surface: [154, 148, 140], surface2: [128, 122, 115], ink: [24, 22, 20], secondary: [65, 61, 56], accent: [154, 56, 42], portraitOpacity: 0.94 },\n { at: 24, page: [43, 39, 37], surface: [48, 43, 40], surface2: [58, 51, 46], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [181, 92, 54], portraitOpacity: 0.94 },\n { at: 30, page: [17, 17, 17], surface: [30, 27, 25], surface2: [41, 35, 30], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [193, 154, 73], portraitOpacity: 0.94 },\n];\n\nexport function clampFrame(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(value)));\n}\n\nexport function frameForEffort(index: number, count: number): number {\n if (count <= 1 || !Number.isFinite(index)) return 0;\n const safe = Math.min(count - 1, Math.max(0, Math.round(index)));\n return Math.round((safe / (count - 1)) * PREVIEW_MAX_FRAME);\n}\n\nexport function nearestEffortIndex(frame: number, efforts: readonly EffortLike[]): number {\n if (efforts.length === 0) return -1;\n const safe = clampFrame(frame);\n let best = 0;\n let distance = Math.abs(safe - frameForEffort(0, efforts.length));\n for (let index = 1; index < efforts.length; index += 1) {\n const next = Math.abs(safe - frameForEffort(index, efforts.length));\n if (next < distance) {\n best = index;\n distance = next;\n }\n }\n return best;\n}\n\nexport function selectedEffortIndex(\n efforts: readonly EffortLike[],\n selectedId?: string,\n defaultId?: string,\n): number {\n const id = selectedId ?? defaultId;\n return id === undefined ? -1 : efforts.findIndex((effort) => effort.id === id);\n}\n\nexport function portraitBlendForLevel(level: number, anchors: readonly number[]) {\n if (anchors.length === 0) return { lowerIndex: -1, upperIndex: -1, mix: 0 };\n const safeLevel = Number.isFinite(level)\n ? Math.min(anchors[anchors.length - 1], Math.max(anchors[0], level))\n : anchors[0];\n let upperIndex = anchors.findIndex((anchor) => anchor >= safeLevel);\n if (upperIndex < 0) upperIndex = anchors.length - 1;\n const lowerIndex = Math.max(0, upperIndex - (anchors[upperIndex] > safeLevel ? 1 : 0));\n const span = anchors[upperIndex] - anchors[lowerIndex];\n return {\n lowerIndex,\n upperIndex,\n mix: span === 0 ? 0 : (safeLevel - anchors[lowerIndex]) / span,\n };\n}\n\nexport function liangRankForFrame(rawFrame: number): string {\n const level = (clampFrame(rawFrame) / PREVIEW_MAX_FRAME) * MAX_LEVEL;\n const index = level >= MAX_LEVEL ? LIANG_RANKS.length - 1 : Math.floor(level / 6);\n return LIANG_RANKS[Math.min(LIANG_RANKS.length - 1, Math.max(0, index))];\n}\n\nexport function indicatorLabel(rawFrame: number, efforts: readonly EffortLike[]): string {\n const effort = efforts[nearestEffortIndex(rawFrame, efforts)];\n return effort === undefined\n ? liangRankForFrame(rawFrame)\n : `${liangRankForFrame(rawFrame)} \u00B7 ${effort.name}`;\n}\n\nfunction lerp(a: number, b: number, amount: number): number {\n return a + (b - a) * amount;\n}\n\nfunction mix(a: Rgb, b: Rgb, amount: number): Rgb {\n return [\n Math.round(lerp(a[0], b[0], amount)),\n Math.round(lerp(a[1], b[1], amount)),\n Math.round(lerp(a[2], b[2], amount)),\n ];\n}\n\nfunction rgb(value: Rgb, alpha = 1): string {\n return alpha === 1\n ? `rgb(${value[0]} ${value[1]} ${value[2]})`\n : `rgb(${value[0]} ${value[1]} ${value[2]} / ${alpha})`;\n}\n\nexport function paletteForFrame(rawFrame: number): Palette {\n const frame = clampFrame(rawFrame);\n const level = (frame / PREVIEW_MAX_FRAME) * MAX_LEVEL;\n const portraitStage = Math.min(5, Math.floor(level / 6));\n const portraitFrom = STOPS[portraitStage];\n const portraitTo = STOPS[Math.min(5, portraitStage + 1)];\n const portraitAmount = portraitFrom === portraitTo\n ? 0\n : (level - portraitFrom.at) / (portraitTo.at - portraitFrom.at);\n\n // The UI itself is intentionally binary: levels 0\u201323 keep the native light\n // shell; entering the original \u6881\u795E/\u6881\u7956 region at level 24 switches black/gold.\n const dark = level >= 24;\n const stage = dark ? 5 : 0;\n const ui = dark ? STOPS[5] : STOPS[0];\n const page = ui.page;\n const surface = ui.surface;\n const surface2 = ui.surface2;\n const sidebar = mix(page, surface2, 0.25);\n const ink = ui.ink;\n const secondary = ui.secondary;\n // Keep Harness' native blue in the light shell. The original calibrator's\n // antique gold only becomes the product accent once the dark region begins.\n const accent: Rgb = dark ? [193, 154, 73] : [65, 118, 230];\n const accentHover = mix(accent, ink, 0.13);\n\n return {\n level,\n stage,\n strength: level / MAX_LEVEL,\n page: rgb(page),\n // Keep the shell readable while allowing the right-side portrait to remain\n // visibly present. Dense controls use the opaque layer tokens below.\n base: rgb(page, dark ? 0.42 : 0.28),\n layer1: rgb(surface, 0.94),\n layer2: rgb(surface2, 0.96),\n layer3: rgb(surface2, 0.99),\n sidebar: rgb(sidebar, 0.96),\n ink: rgb(ink),\n secondary: rgb(secondary),\n tertiary: rgb(mix(secondary, page, 0.28)),\n border: rgb(ink, dark ? 0.15 : 0.12),\n accent: rgb(accent),\n accentHover: rgb(accentHover),\n hover: rgb(ink, dark ? 0.09 : 0.07),\n portraitOpacity: String(lerp(\n portraitFrom.portraitOpacity,\n portraitTo.portraitOpacity,\n portraitAmount,\n )),\n };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMO;AACP,sCAAuB;;;ACPvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAEhC,SAAS,eAAe,MAAe,QAAgB;AACrD,SAAO,CAAC,GAAG,KAAK,SAAS,EAAE,KAAK,CAAC,SAAS,KAAK,SAAS,MAAM,CAAC;AACjE;AAEA,SAAS,oBAAoB;AAC3B,aAAW,OAAO,SAAS,iBAA8B,qBAAqB,GAAG;AAC/E,QAAI,CAAC,eAAe,KAAK,UAAU,EAAG;AAGtC,UAAM,gBAAgB,CAAC,GAAG,IAAI,QAAQ,EAAE;AAAA,MACtC,CAAC,SAAoC,gBAAgB,qBAChD,eAAe,MAAM,YAAY;AAAA,IACxC;AACA,QAAI,cAAc,SAAS,EAAG;AAE9B,QAAI,QAAQ,IAAI;AAChB,WAAO,UAAU,QAAQ,CAAC,eAAe,OAAO,QAAQ,GAAG;AACzD,cAAQ,MAAM;AAAA,IAChB;AACA,cAAU,IAAI;AACd,QAAI,UAAU,KAAM,QAAO,EAAE,KAAK,OAAO,cAAc;AAAA,EACzD;AACA,SAAO;AACT;AASO,SAAS,6BACd,OACA,WACA,WACY;AACZ,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,UAAoC;AACxC,QAAM,sBAAsB,oBAAI,IAAmC;AAEnE,QAAM,UAAU,MAAM;AACpB,eAAW,CAAC,QAAQ,OAAO,KAAK,qBAAqB;AACnD,aAAO,oBAAoB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;AAAA,IAChE;AACA,wBAAoB,MAAM;AAC1B,QAAI,YAAY,KAAM;AACtB,YAAQ,OAAO,oBAAoB,SAAS,QAAQ,iBAAiB;AACrE,YAAQ,OAAO,OAAO;AACtB,cAAU;AAAA,EACZ;AAEA,QAAM,SAAS,OAAO,YAAqB;AACzC,QAAI,YAAY,WAAW,MAAM,YAAY,EAAE,YAAY,QAAS;AACpE,cAAU;AACV,SAAK;AACL,QAAI;AACF,YAAM,UAAU,OAAO,OAAO;AAAA,IAChC,QAAQ;AAAA,IAER,UAAE;AACA,gBAAU;AACV,UAAI,CAAC,SAAU,MAAK;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,cAAc,CAAC,KAAkB,UAA0C;AAC/E,UAAM,UAAU,SAAS,gBAAgB,KAAK,YAAY,EAAE,WAAW,IAAI;AAC3E,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,YAAY;AACnB,WAAO,OAAO;AACd,WAAO,QAAQ,SAAS;AACxB,WAAO,aAAa,cAAc,0BAAM;AAExC,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,YAAY;AACjB,SAAK,aAAa,eAAe,MAAM;AACvC,SAAK,cAAc;AAEnB,UAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,UAAM,YAAY;AAClB,UAAM,cAAc,UAAU,WAAW;AACzC,WAAO,OAAO,MAAM,KAAK;AACzB,UAAM,oBAAoB,MAAM;AAAE,WAAK,OAAO,IAAI;AAAA,IAAG;AACrD,WAAO,iBAAiB,SAAS,iBAAiB;AAElD,WAAO,EAAE,KAAK,OAAO,QAAQ,kBAAkB;AAAA,EACjD;AAEA,QAAM,OAAO,MAAM;AACjB,QAAI,SAAU;AACd,UAAM,SAAS,kBAAkB;AACjC,QAAI,WAAW,MAAM;AACnB,cAAQ;AACR;AAAA,IACF;AACA,QAAI,YAAY,SAAS,QAAQ,QAAQ,OAAO,OAAO,QAAQ,UAAU,OAAO,QAAQ;AACtF,cAAQ;AAAA,IACV;AACA,gBAAY,YAAY,OAAO,KAAK,OAAO,KAAK;AAChD,UAAM,EAAE,KAAK,OAAO,IAAI;AACxB,QAAI,OAAO,kBAAkB,IAAK,KAAI,OAAO,MAAM;AAEnD,UAAM,WAAW,MAAM,YAAY;AACnC,WAAO,WAAW;AAClB,WAAO,aAAa,gBAAgB,OAAO,SAAS,OAAO,CAAC;AAE5D,eAAW,CAAC,cAAc,OAAO,KAAK,qBAAqB;AACzD,UAAI,OAAO,cAAc,SAAS,YAAY,EAAG;AACjD,mBAAa,oBAAoB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;AACpE,0BAAoB,OAAO,YAAY;AAAA,IACzC;AACA,eAAW,gBAAgB,OAAO,eAAe;AAC/C,UAAI,oBAAoB,IAAI,YAAY,EAAG;AAC3C,YAAM,oBAAoB,MAAM;AAAE,aAAK,OAAO,KAAK;AAAA,MAAG;AACtD,0BAAoB,IAAI,cAAc,iBAAiB;AACvD,mBAAa,iBAAiB,SAAS,mBAAmB,EAAE,SAAS,KAAK,CAAC;AAAA,IAC7E;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,iBAAiB,IAAI;AAC1C,WAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAClE,QAAM,cAAc,MAAM,UAAU,IAAI;AACxC,OAAK;AAEL,SAAO,MAAM;AACX,QAAI,SAAU;AAGd,eAAW;AACX,aAAS,WAAW;AACpB,gBAAY;AACZ,YAAQ;AAAA,EACV;AACF;;;ACjHA,IAAM,eAAe,CAAC,KAAK,MAAM,GAAI;AAErC,SAAS,SAAS,QAAgB,OAAe;AAC/C,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,YAAY,OAAO,QAAQ,GAAG;AACpC,QAAM,OAAO,YAAY,IAAI,KAAK,OAAO,MAAM,SAAS;AACxD,QAAM,OAAO,YAAY,IAAI,SAAS,OAAO,MAAM,GAAG,SAAS;AAC/D,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,QAAM,OAAO,aAAa,IAAI,OAAO,KAAK,MAAM,GAAG,UAAU;AAC7D,QAAM,QAAQ,IAAI,gBAAgB,aAAa,IAAI,KAAK,KAAK,MAAM,aAAa,CAAC,CAAC;AAClF,QAAM,IAAI,SAAS,OAAO,KAAK,CAAC;AAChC,SAAO,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI;AAChC;AAOO,SAAS,qBAAqB,SAAgC;AACnE,QAAM,UAAU,QAAQ,QAAQ,IAAI,CAAC,YAAY,EAAE,GAAG,OAAO,EAAE;AAC/D,QAAM,SAAS,oBAAI,IAAmB;AACtC,aAAW,EAAE,IAAI,KAAK,SAAS;AAC7B,QAAI,CAAC,OAAO,IAAI,GAAG,GAAG;AACpB,aAAO,IAAI,KAAK;AAAA,QACd;AAAA,QAAK,QAAQ;AAAA,QAAQ,WAAW;AAAA,QAAM,SAAS;AAAA,QAC/C,OAAO;AAAA,QAAM,OAAO;AAAA,QAAM,QAAQ;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,cAAc,QAAQ,gBAAgB,MAAM,IAAI,MAAM;AAC5D,MAAI,WAAqD,QAAQ;AACjE,MAAI,SAAS;AACb,MAAI,WAAW;AACf,MAAI,aAAa;AACjB,MAAI,cAAc,QAAQ,CAAC,GAAG,SAAS;AACvC,MAAI,iBAAgC;AACpC,MAAI,YAAkC;AAEtC,QAAM,YAAY,CAAC,QAAgB,UAAU,CAAC,YAAY,eAAe;AACzE,QAAM,eAAe,CAAC,cAA0C;AAC9D,QAAI,UAAyB;AAC7B,aAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAI,CAAC,UAAU,KAAK,EAAG;AACvB,YAAM,WAAW,KAAK,IAAI,QAAQ,KAAK,EAAE,QAAQ,WAAW;AAC5D,YAAM,WAAW,YAAY,OAAO,WAAW,KAAK,IAAI,QAAQ,OAAO,EAAE,QAAQ,WAAW;AAC5F,UAAI,YAAY,QAAQ,WAAW,YAAa,aAAa,YAAY,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,EAAE,OAAQ;AACvH,kBAAU;AAAA,MACZ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,CAAC,UAAkB,OAAO,IAAI,QAAQ,KAAK,EAAE,GAAG,GAAG,WAAW;AAC9E,QAAM,OAAO,CAAC,UAAyB;AACrC,QAAI,WAAW,UAAU,MAAM,SAAS,UAAU,QAAQ,MAAM,OAAO,UAAU,WAAW,MAAM,OAAQ;AAC1G,gBAAY;AACZ,eAAW,KAAK;AAAA,EAClB;AACA,QAAM,YAAY,MAAM;AACtB,QAAI,CAAC,UAAU,SAAU;AACzB,UAAM,SAAS,aAAa,MAAM,IAAI;AACtC,QAAI,WAAW,QAAQ,QAAQ,MAAM,EAAG,kBAAiB;AAAA,aAChD,mBAAmB,KAAM,kBAAiB,aAAa,OAAO;AACvE,QAAI,mBAAmB,MAAM;AAC3B,YAAM,QAAQ,OAAO,IAAI,QAAQ,cAAc,EAAE,GAAG;AACpD,WAAK,EAAE,OAAO,gBAAgB,KAAK,MAAM,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ,CAAC;AAAA,IAC3F,OAAO;AACL,YAAM,YAAY,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,MAAM,WAAW,QAAQ;AACjF,WAAK,EAAE,OAAO,MAAM,KAAK,MAAM,OAAO,MAAM,QAAQ,YAAY,WAAW,UAAU,CAAC;AAAA,IACxF;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,OAAc,QAAgB;AAC7C,QAAI,CAAC,UAAU,GAAG,EAAG;AACrB,UAAM,SAAS;AACf,UAAM,QAAQ,YAAY;AAC1B,UAAM,QAAQ;AACd,UAAM,UAAU;AAChB,UAAM,WAAW;AACjB,UAAM,MAAM,SAAS,MAAM,KAAK,MAAM,OAAO;AAC7C,QAAI,UAAU;AACd,QAAI,WAAW;AACf,UAAM,UAAU,MAAM,CAAC,WAAW,UAAU,GAAG,KAAK,MAAM,UAAU;AACpE,UAAM,SAAS,MAAM;AACnB,YAAM,oBAAoB,QAAQ,UAAU;AAC5C,YAAM,oBAAoB,SAAS,WAAW;AAC9C,YAAM,SAAS;AAAA,IACjB;AACA,UAAM,cAAc,MAAM;AACxB,UAAI,CAAC,QAAQ,EAAG;AAChB,gBAAU;AACV,aAAO;AACP,YAAM,gBAAgB,KAAK;AAC3B,YAAM,QAAQ;AACd,UAAI,MAAM,UAAU,aAAa,QAAQ;AACvC,cAAM,QAAQ,aAAa,MAAM,OAAO;AACxC,cAAM,WAAW;AACjB,cAAM,QAAQ,WAAW,MAAM;AAC7B,cAAI,CAAC,UAAU,GAAG,EAAG;AACrB,gBAAM,QAAQ;AACd,kBAAQ,OAAO,GAAG;AAAA,QACpB,GAAG,KAAK;AAAA,MACV,OAAO;AACL,cAAM,SAAS;AACf,kBAAU;AAAA,MACZ;AAAA,IACF;AACA,UAAM,aAAa,MAAM;AACvB,UAAI,CAAC,QAAQ,KAAK,SAAU;AAC5B,iBAAW;AACX,WAAK,MAAM,OAAO,EAAE,KAAK,MAAM;AAC7B,YAAI,CAAC,QAAQ,EAAG;AAChB,kBAAU;AACV,eAAO;AACP,cAAM,YAAY;AAClB,cAAM,SAAS;AACf,kBAAU;AAAA,MACZ,GAAG,WAAW;AAAA,IAChB;AACA,UAAM,SAAS;AACf,UAAM,iBAAiB,QAAQ,UAAU;AACzC,UAAM,iBAAiB,SAAS,WAAW;AAC3C,UAAM,MAAM;AAAA,EACd;AAEA,QAAM,OAAO,MAAM;AACjB,aAAS;AACT,kBAAc;AACd,eAAW,SAAS,OAAO,OAAO,GAAG;AACnC,UAAI,MAAM,UAAU,KAAM,cAAa,MAAM,KAAK;AAClD,YAAM,QAAQ;AACd,YAAM,SAAS;AACf,YAAM,OAAO,gBAAgB,KAAK;AAClC,YAAM,QAAQ;AACd,YAAM,SAAS;AACf,YAAM,YAAY;AAClB,YAAM,UAAU;AAAA,IAClB;AACA,qBAAiB;AACjB,gBAAY;AAAA,EACd;AAEA,SAAO;AAAA,IACL,QAAQ;AACN,UAAI,YAAY,OAAQ;AACxB,eAAS;AACT,YAAM,MAAM,EAAE;AACd,gBAAU;AACV,iBAAW,SAAS,OAAO,OAAO,EAAG,SAAQ,OAAO,GAAG;AAAA,IACzD;AAAA,IACA,OAAO,OAAe;AACpB,UAAI,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG;AACzC,oBAAc;AACd,gBAAU;AAAA,IACZ;AAAA,IACA;AAAA,IACA,UAAU;AACR,WAAK;AACL,iBAAW;AACX,iBAAW;AAAA,IACb;AAAA,EACF;AACF;;;ACxMO,IAAM,oBAAoB;AAC1B,IAAM,YAAY;AAEzB,IAAM,cAAc,CAAC,sBAAO,gBAAM,gBAAM,gBAAM,gBAAM,cAAI;AA2CxD,IAAM,QAAgC;AAAA,EACpC,EAAE,IAAI,GAAG,MAAM,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,GAAG,WAAW,CAAC,KAAK,KAAK,GAAG,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,iBAAiB,KAAK;AAAA,EACjL,EAAE,IAAI,GAAG,MAAM,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,GAAG,WAAW,CAAC,KAAK,KAAK,EAAE,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,iBAAiB,KAAK;AAAA,EAChL,EAAE,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,iBAAiB,KAAK;AAAA,EAC/K,EAAE,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,iBAAiB,KAAK;AAAA,EAC/K,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,WAAW,CAAC,KAAK,KAAK,GAAG,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,iBAAiB,KAAK;AAAA,EAC5K,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,WAAW,CAAC,KAAK,KAAK,GAAG,GAAG,QAAQ,CAAC,KAAK,KAAK,EAAE,GAAG,iBAAiB,KAAK;AAC/K;AAEO,SAAS,WAAW,OAAuB;AAChD,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,SAAO,KAAK,IAAI,mBAAmB,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AACnE;AAEO,SAAS,eAAe,OAAe,OAAuB;AACnE,MAAI,SAAS,KAAK,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AAClD,QAAM,OAAO,KAAK,IAAI,QAAQ,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AAC/D,SAAO,KAAK,MAAO,QAAQ,QAAQ,KAAM,iBAAiB;AAC5D;AAEO,SAAS,mBAAmB,OAAe,SAAwC;AACxF,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,OAAO,WAAW,KAAK;AAC7B,MAAI,OAAO;AACX,MAAI,WAAW,KAAK,IAAI,OAAO,eAAe,GAAG,QAAQ,MAAM,CAAC;AAChE,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,OAAO,KAAK,IAAI,OAAO,eAAe,OAAO,QAAQ,MAAM,CAAC;AAClE,QAAI,OAAO,UAAU;AACnB,aAAO;AACP,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,oBACd,SACA,YACA,WACQ;AACR,QAAM,KAAK,cAAc;AACzB,SAAO,OAAO,SAAY,KAAK,QAAQ,UAAU,CAAC,WAAW,OAAO,OAAO,EAAE;AAC/E;AAkBO,SAAS,kBAAkB,UAA0B;AAC1D,QAAM,QAAS,WAAW,QAAQ,IAAI,oBAAqB;AAC3D,QAAM,QAAQ,SAAS,YAAY,YAAY,SAAS,IAAI,KAAK,MAAM,QAAQ,CAAC;AAChF,SAAO,YAAY,KAAK,IAAI,YAAY,SAAS,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC;AACzE;AAEO,SAAS,eAAe,UAAkB,SAAwC;AACvF,QAAM,SAAS,QAAQ,mBAAmB,UAAU,OAAO,CAAC;AAC5D,SAAO,WAAW,SACd,kBAAkB,QAAQ,IAC1B,GAAG,kBAAkB,QAAQ,CAAC,SAAM,OAAO,IAAI;AACrD;AAEA,SAAS,KAAK,GAAW,GAAW,QAAwB;AAC1D,SAAO,KAAK,IAAI,KAAK;AACvB;AAEA,SAAS,IAAI,GAAQ,GAAQ,QAAqB;AAChD,SAAO;AAAA,IACL,KAAK,MAAM,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;AAAA,IACnC,KAAK,MAAM,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;AAAA,IACnC,KAAK,MAAM,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;AAAA,EACrC;AACF;AAEA,SAAS,IAAI,OAAY,QAAQ,GAAW;AAC1C,SAAO,UAAU,IACb,OAAO,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MACvC,OAAO,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,KAAK;AACxD;AAEO,SAAS,gBAAgB,UAA2B;AACzD,QAAM,QAAQ,WAAW,QAAQ;AACjC,QAAM,QAAS,QAAQ,oBAAqB;AAC5C,QAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC;AACvD,QAAM,eAAe,MAAM,aAAa;AACxC,QAAM,aAAa,MAAM,KAAK,IAAI,GAAG,gBAAgB,CAAC,CAAC;AACvD,QAAM,iBAAiB,iBAAiB,aACpC,KACC,QAAQ,aAAa,OAAO,WAAW,KAAK,aAAa;AAI9D,QAAM,OAAO,SAAS;AACtB,QAAM,QAAQ,OAAO,IAAI;AACzB,QAAM,KAAK,OAAO,MAAM,CAAC,IAAI,MAAM,CAAC;AACpC,QAAM,OAAO,GAAG;AAChB,QAAM,UAAU,GAAG;AACnB,QAAM,WAAW,GAAG;AACpB,QAAM,UAAU,IAAI,MAAM,UAAU,IAAI;AACxC,QAAM,MAAM,GAAG;AACf,QAAM,YAAY,GAAG;AAGrB,QAAM,SAAc,OAAO,CAAC,KAAK,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,GAAG;AACzD,QAAM,cAAc,IAAI,QAAQ,KAAK,IAAI;AAEzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,MAAM,IAAI,IAAI;AAAA;AAAA;AAAA,IAGd,MAAM,IAAI,MAAM,OAAO,OAAO,IAAI;AAAA,IAClC,QAAQ,IAAI,SAAS,IAAI;AAAA,IACzB,QAAQ,IAAI,UAAU,IAAI;AAAA,IAC1B,QAAQ,IAAI,UAAU,IAAI;AAAA,IAC1B,SAAS,IAAI,SAAS,IAAI;AAAA,IAC1B,KAAK,IAAI,GAAG;AAAA,IACZ,WAAW,IAAI,SAAS;AAAA,IACxB,UAAU,IAAI,IAAI,WAAW,MAAM,IAAI,CAAC;AAAA,IACxC,QAAQ,IAAI,KAAK,OAAO,OAAO,IAAI;AAAA,IACnC,QAAQ,IAAI,MAAM;AAAA,IAClB,aAAa,IAAI,WAAW;AAAA,IAC5B,OAAO,IAAI,KAAK,OAAO,OAAO,IAAI;AAAA,IAClC,iBAAiB,OAAO;AAAA,MACtB,aAAa;AAAA,MACb,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AJ+LI;AAjWJ,IAAM,aAAa;AACnB,IAAM,mBAAmB;AACzB,IAAM,eAAe,YAAY,UAAU;AAC3C,IAAM,kBAAkB;AAExB,IAAM,mBAAmB;AAAA,EACvB,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,GAAG,MAAM,gBAAgB;AAAA,EAClC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,iBAAiB;AAAA,EACpC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,iBAAiB;AAAA,EACpC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AAAA,EACnC,EAAE,OAAO,IAAI,MAAM,gBAAgB;AACrC;AA8DA,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,gBAAN,MAAoB;AAAA,EACD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,UAAU;AAAA;AAAA;AAAA,EAGV,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,MAAM;AAAA,EACN,WAAW;AAAA,EACX;AAAA,EAER,YAAY,OAAwB,OAAqB;AACvD,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,KAAK,YAAY;AACtB,SAAK,KAAK,QAAQ,SAAS;AAC3B,SAAK,KAAK,QAAQ,QAAQ;AAC1B,SAAK,KAAK,aAAa,eAAe,MAAM;AAC5C,SAAK,YAAY,qBAAqB;AAAA,MACpC,SAAS,iBAAiB,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO;AAAA,QAClD;AAAA,QACA,KAAK,GAAG,YAAY,uBAAuB,IAAI;AAAA,MACjD,EAAE;AAAA,MACF,UAAU,CAAC,EAAE,MAAM,MAAM;AACvB,YAAI,KAAK,YAAY,CAAC,KAAK,QAAS;AACpC,YAAI,UAAU,MAAM;AAClB,eAAK,KAAK,QAAQ,QAAQ;AAC1B,eAAK,KAAK,gBAAgB;AAC1B;AAAA,QACF;AAEA,cAAM,WAAW;AACjB,iBAAS,YAAY;AACrB,iBAAS,MAAM;AACf,iBAAS,YAAY;AACrB,YAAI,KAAK,KAAK,eAAe,SAAU,MAAK,KAAK,gBAAgB,QAAQ;AACzE,aAAK,KAAK,QAAQ,QAAQ;AAAA,MAC5B;AAAA,IACF,CAAC;AAED,SAAK,cAAc,MAAM,UAAU,MAAM,KAAK,aAAa,CAAC;AAC5D,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,eAAe;AACrB,SAAK,WAAW,KAAK,MAAM,YAAY,EAAE,OAAO;AAAA,EAClD;AAAA,EAEA,YAAY;AACV,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW;AACT,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,SAAkB;AAC3B,QAAI,KAAK,SAAU;AACnB,SAAK,UAAU;AACf,QAAI,SAAS;AACX,UAAI,CAAC,KAAK,KAAK,YAAa,UAAS,KAAK,QAAQ,KAAK,IAAI;AAC3D,eAAS,KAAK,QAAQ,YAAY;AAClC,WAAK,WAAW;AAChB,WAAK,UAAU,MAAM;AAAA,IACvB,OAAO;AACL,UAAI,KAAK,QAAQ,EAAG,sBAAqB,KAAK,GAAG;AACjD,WAAK,MAAM;AACX,WAAK,KAAK,OAAO;AACjB,WAAK,UAAU,KAAK;AACpB,WAAK,KAAK,gBAAgB;AAC1B,WAAK,KAAK,QAAQ,QAAQ;AAC1B,aAAO,SAAS,KAAK,QAAQ;AAC7B,aAAO,SAAS,KAAK,QAAQ;AAC7B,iBAAW,QAAQ,aAAc,UAAS,KAAK,MAAM,eAAe,IAAI;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,SAAS,OAAe;AACtB,QAAI,KAAK,SAAU;AACnB,SAAK,eAAe,KAAK,IAAI,mBAAmB,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AAC9E,SAAK,QAAQ,KAAK;AAClB,QAAI,CAAC,KAAK,QAAS;AACnB,QAAI,KAAK,QAAQ,EAAG;AACpB,SAAK,MAAM,sBAAsB,MAAM;AACrC,WAAK,MAAM;AACX,WAAK,QAAQ,KAAK;AAClB,WAAK,WAAW;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEQ,aAAa;AACnB,QAAI,KAAK,YAAY,CAAC,KAAK,QAAS;AACpC,UAAM,UAAU,gBAAgB,KAAK,KAAK;AAC1C,UAAM,OAAO,SAAS;AACtB,SAAK,gBAAgB,QAAQ,UAAU,IAAI,SAAS,OAAO;AAC3D,SAAK,QAAQ,aAAa,OAAO,QAAQ,KAAK;AAC9C,SAAK,MAAM,YAAY,oBAAoB,OAAO,QAAQ,QAAQ,CAAC;AACnE,SAAK,MAAM,YAAY,gBAAgB,QAAQ,IAAI;AACnD,SAAK,MAAM,YAAY,mBAAmB,QAAQ,IAAI;AACtD,SAAK,MAAM,YAAY,mBAAmB,QAAQ,MAAM;AACxD,SAAK,MAAM,YAAY,mBAAmB,QAAQ,MAAM;AACxD,SAAK,MAAM,YAAY,mBAAmB,QAAQ,MAAM;AACxD,SAAK,MAAM,YAAY,mBAAmB,QAAQ,OAAO;AACzD,SAAK,MAAM,YAAY,eAAe,QAAQ,GAAG;AACjD,SAAK,MAAM,YAAY,qBAAqB,QAAQ,SAAS;AAC7D,SAAK,MAAM,YAAY,oBAAoB,QAAQ,QAAQ;AAC3D,SAAK,MAAM,YAAY,kBAAkB,QAAQ,MAAM;AACvD,SAAK,MAAM,YAAY,kBAAkB,QAAQ,MAAM;AACvD,SAAK,MAAM,YAAY,wBAAwB,QAAQ,WAAW;AAClE,SAAK,MAAM,YAAY,iBAAiB,QAAQ,KAAK;AACrD,SAAK,MAAM,YAAY,4BAA4B,QAAQ,eAAe;AAC1E,SAAK,eAAe,QAAQ,KAAK;AAAA,EACnC;AAAA,EAEA,gBAAgB,QAAuB,gBAAgB,KAAK,KAAK,EAAE,UAAU,IAAI,SAAS,SAAS;AACjG,QAAI,CAAC,KAAK,WAAW,KAAK,MAAM,SAAS,EAAE,eAAe,MAAO;AACjE,SAAK,MAAM,SAAS,KAAK;AAAA,EAC3B;AAAA,EAEQ,eAAe,OAAe;AACpC,SAAK,UAAU,OAAO,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAM,OAAO,SAAkB;AAC7B,SAAK,WAAW,OAAO;AACvB,QAAI;AACF,YAAM,KAAK,MAAM,IAAI,OAAO;AAAA,IAC9B,SAAS,OAAO;AACd,WAAK,aAAa;AAClB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,QAAI,KAAK,QAAQ,EAAG,sBAAqB,KAAK,GAAG;AACjD,SAAK,UAAU,QAAQ;AACvB,SAAK,KAAK,OAAO;AACjB,aAAS,KAAK,gBAAgB,iBAAiB;AAC/C,WAAO,SAAS,KAAK,QAAQ;AAC7B,eAAW,QAAQ,aAAc,UAAS,KAAK,MAAM,eAAe,IAAI;AAAA,EAC1E;AACF;AAEA,SAAS,eAAe,OAA4B;AAClD,QAAM,UAAU,MAAM;AACtB,MAAI,YAAY,KAAM,QAAO;AAC7B,QAAM,QAAQ,MAAM,OAAO,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ,QAAQ;AACtE,QAAM,QAAQ,OAAO,OAAO,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ,KAAK;AACpE,MAAI,OAAO,cAAc,OAAW,QAAO;AAC3C,SAAO;AAAA,IACL,WAAW;AAAA,IACX,SAAS,MAAM,UAAU;AAAA,IACzB,eAAe,MAAM,UAAU;AAAA,EACjC;AACF;AAEA,SAAS,kBAAkB,EAAE,WAAW,MAAM,QAAQ,WAAW,MAAM,GAAgB;AACrF,QAAM,YAAQ;AAAA,IACZ,CAAC,aAAa,UAAU,UAAU,QAAQ;AAAA,IAC1C,MAAM,UAAU,YAAY;AAAA,EAC9B;AACA,QAAM,WAAO;AAAA,IACX,CAAC,aAAa,MAAM,UAAU,QAAQ;AAAA,IACtC,MAAM,MAAM,YAAY;AAAA,EAC1B;AACA,QAAM,gBAAY,sBAAQ,MAAM,eAAe,KAAK,GAAG,CAAC,KAAK,CAAC;AAC9D,QAAM,UAAU,WAAW,WAAW,CAAC;AACvC,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,WAAW,UAAU;AAAA,IACrB,WAAW;AAAA,EACb;AAIA,QAAM,iBAAiB,iBAAiB,IACpC,oBACA,eAAe,gBAAgB,QAAQ,MAAM;AACjD,QAAM,aAAa,KAAK;AACxB,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,MAAM,aAAa,iBAAiB,UAAU,SAAS,CAAC;AAC3F,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,eAAW,qBAAO,KAAK;AAC7B,QAAM,qBAAiB,qBAAO,KAAK;AACnC,QAAM,UAAU,KAAK;AAErB,8BAAU,MAAM;AACd,QAAI,QAAS,MAAK;AAAA,EACpB,GAAG,CAAC,SAAS,IAAI,CAAC;AAElB,8BAAU,MAAM;AACd,QAAI,CAAC,cAAc,SAAS,WAAW,QAAS;AAChD,aAAS,cAAc;AACvB,cAAU,SAAS,cAAc;AAAA,EACnC,GAAG,CAAC,YAAY,gBAAgB,SAAS,SAAS,CAAC;AAEnD,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,eAAe,cAAc,QAAQ,QAAQ,SAAS,GAAI,QAAO;AAErE,QAAM,eAAe,mBAAmB,OAAO,OAAO;AACtD,QAAM,gBAAgB,QAAQ,YAAY;AAC1C,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,eAAe,eAAe,OAAO,aAAa,UAAU,CAAC,CAAC;AAEpE,QAAM,SAAS,OAAO,aAAqB;AACzC,QAAI,CAAC,YAAY;AACf,eAAS,UAAU;AACnB,eAAS,QAAQ;AACjB,gBAAU,SAAS,QAAQ;AAC3B;AAAA,IACF;AACA,UAAM,cAAc,mBAAmB,UAAU,OAAO;AACxD,UAAM,SAAS,QAAQ,WAAW;AAClC,QAAI,WAAW,OAAW;AAC1B,UAAM,cAAc,eAAe,aAAa,QAAQ,MAAM;AAC9D,aAAS,UAAU;AACnB,aAAS,WAAW;AACpB,cAAU,SAAS,WAAW;AAC9B,QAAI,gBAAgB,kBAAkB,QAAS;AAC/C,eAAW,IAAI;AACf,cAAU,KAAK;AACf,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,UAAU,UAAU,UAAU;AAAA,MAC9B,OAAO,UAAU,UAAU;AAAA,MAC3B,iBAAiB,OAAO;AAAA,IAC1B,CAAC;AACD,eAAW,KAAK;AAChB,QAAI,CAAC,UAAU;AACb,gBAAU,IAAI;AACd,eAAS,cAAc;AACvB,gBAAU,SAAS,cAAc;AAAA,IACnC;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAa;AAAA,MACb,cAAY,SAAS,UAAU,UAAU,YAAY;AAAA,MACrD,OAAO,aAAa,eAAe,OAAO;AAAA,MAEzC;AAAA,uBACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,wBAAwB,cAAc;AAAA,YAE9C;AAAA;AAAA,QACH;AAAA,QAEF,4CAAC,SAAI,WAAU,+BAA8B,eAAY,QACtD,kBAAQ,IAAI,CAAC,QAAQ,UACpB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YAEV,OAAO,EAAE,MAAM,GAAI,eAAe,OAAO,QAAQ,MAAM,IAAI,oBAAqB,GAAG,IAAI;AAAA;AAAA,UADlF,OAAO;AAAA,QAEd,CACD,GACH;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AAAA,YACL,MAAM;AAAA,YACN,OAAO;AAAA,YACP,UAAU,WAAW,MAAM,WAAW;AAAA,YACtC,cAAY,aAAa,6BAAS;AAAA,YAClC,kBAAgB,aAAa,eAAe,QAAQ,KAAK;AAAA,YACzD,eAAe,MAAM;AACnB,uBAAS,UAAU;AACnB,6BAAe,UAAU;AACzB,6BAAe,IAAI;AAAA,YACrB;AAAA,YACA,SAAS,CAAC,UAAU;AAClB,uBAAS,UAAU;AACnB,oBAAM,OAAO,OAAO,MAAM,cAAc,KAAK;AAC7C,uBAAS,IAAI;AACb,wBAAU,SAAS,IAAI;AAAA,YACzB;AAAA,YACA,aAAa,CAAC,UAAU;AACtB,6BAAe,KAAK;AACpB,mBAAK,OAAO,OAAO,MAAM,cAAc,KAAK,CAAC;AAAA,YAC/C;AAAA,YACA,iBAAiB,MAAM;AACrB,6BAAe,KAAK;AACpB,uBAAS,UAAU;AACnB,uBAAS,eAAe,OAAO;AAC/B,wBAAU,SAAS,eAAe,OAAO;AAAA,YAC3C;AAAA,YACA,SAAS,CAAC,UAAU;AAClB,6BAAe,KAAK;AACpB,kBAAI,MAAM,QAAQ,SAAU,MAAK,OAAO,OAAO,MAAM,cAAc,KAAK,CAAC;AAAA,YAC3E;AAAA,YACA,QAAQ,CAAC,UAAU;AACjB,6BAAe,KAAK;AACpB,kBAAI,SAAS,QAAS,MAAK,OAAO,OAAO,MAAM,cAAc,KAAK,CAAC;AAAA,YACrE;AAAA,YACA,WAAW,CAAC,UAAU;AACpB,6BAAe,IAAI;AACnB,kBAAI,MAAM,QAAQ,YAAY,CAAC,SAAS;AACtC,+BAAe,KAAK;AACpB,yBAAS,UAAU;AACnB,yBAAS,eAAe,OAAO;AAC/B,0BAAU,SAAS,eAAe,OAAO;AAAA,cAC3C;AAAA,YACF;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,iBAAiB,EAAE,OAAO,EAAE,GAA0B;AAC7D,QAAM,eAAW;AAAA,IACf,CAAC,aAAa,MAAM,UAAU,QAAQ;AAAA,IACtC,MAAM,MAAM,YAAY;AAAA,EAC1B;AACA,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,MAAI,CAAC,SAAS,QAAS,QAAO;AAE9B,SACE,6CAAC,SAAI,WAAU,4BAA2B,eAAa,YACrD;AAAA,gDAAC,UAAM,YAAE,gBAAgB,GAAE;AAAA,IAC3B;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,SAAS;AAAA,QAClB,UAAU;AAAA,QACV,OAAO,EAAE,gBAAgB;AAAA,QACzB,UAAU,CAAC,SAAS;AAClB,cAAI,QAAS;AACb,qBAAW,IAAI;AACf,eAAK,MAAM,cAAc,IAAI,EAAE,MAAM,MAAM,MAAS,EAAE,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,QACvF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEO,IAAM,SAAS;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,wBAAyC;AAIhD,MAAI;AACF,iBAAa,WAAW,kCAAkC;AAAA,EAC5D,QAAQ;AAAA,EAER;AACA,MAAI,WAAyB;AAAA,IAC3B,SAAS;AAAA,IACT,YAAY,aAAa,QAAQ,eAAe,MAAM;AAAA,EACxD;AACA,QAAM,YAAY,oBAAI,IAAgB;AACtC,QAAM,YAAY,CAAC,UAAwB;AACzC,QAAI,MAAM,QAAQ,gBAAiB;AACnC,UAAM,OAAO;AAAA,MACX,SAAS,SAAS;AAAA,MAClB,YAAY,MAAM,aAAa;AAAA,IACjC;AACA,QAAI,KAAK,YAAY,SAAS,WAAW,KAAK,eAAe,SAAS,WAAY;AAClF,eAAW;AACX,eAAW,YAAY,UAAW,UAAS;AAAA,EAC7C;AACA,SAAO,iBAAiB,WAAW,SAAS;AAC5C,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,UAAU,UAAU;AAClB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,IACA,MAAM,IAAI,SAAS;AACjB,UAAI,YAAY,SAAS,QAAS;AAClC,iBAAW,EAAE,GAAG,UAAU,QAAQ;AAClC,iBAAW,YAAY,UAAW,UAAS;AAAA,IAC7C;AAAA,IACA,MAAM,cAAc,YAAY;AAC9B,UAAI,eAAe,SAAS,WAAY;AACxC,mBAAa,QAAQ,iBAAiB,aAAa,MAAM,GAAG;AAC5D,iBAAW,EAAE,GAAG,UAAU,WAAW;AACrC,iBAAW,YAAY,UAAW,UAAS;AAAA,IAC7C;AAAA,IACA,UAAU;AACR,aAAO,oBAAoB,WAAW,SAAS;AAC/C,gBAAU,MAAM;AAAA,IAClB;AAAA,EACF;AACF;AAEO,SAAS,MAAM,KAAoB;AACxC,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,QAAQ,SAAS;AACvB,QAAM,cAAc;AACpB,WAAS,KAAK,OAAO,KAAK;AAC1B,MAAI,OAAO,MAAM,MAAM,MAAM,OAAO,GAAG,qCAAqC;AAE5E,QAAM,QAAQ,sBAAsB;AACpC,MAAI,OAAO,MAAM,MAAM,MAAM,QAAQ,GAAG,6CAA6C;AACrF,QAAM,QAAQ,IAAI,IAAI,OAAO;AAC7B,QAAM,YAAY,IAAI,cAAc,OAAO,KAAK;AAChD,MAAI,OAAO,MAAM,MAAM,UAAU,QAAQ,GAAG,0CAA0C;AACtF,MAAI;AAAA,IACF,MAAM,6BAA6B,OAAO,WAAW,UAAU;AAAA,IAC/D;AAAA,EACF;AACA,MAAI;AAAA,IACF,MAAM,IAAI,OAAO,SAAS,kBAAkB;AAAA,MAC1C,IAAI,EAAE,kBAAkB,+DAAa;AAAA,MACrC,IAAI,EAAE,kBAAkB,iCAAiC;AAAA,IAC3D,CAAC;AAAA,IAAG;AAAA,EAAuC;AAE7C,MAAI,MAAM,OAAO,yBAAyB,MAAM,IAAI,MAAM,SAAS;AAAA,IACjE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,OAAO,EAAE,MAAM;AAAA,EACzB,GAAG,gBAAgB,CAAC;AAEpB,MAAI,MAAM,OAAO,4BAA4B,MAAM,IAAI,MAAM,SAAS;AAAA,IACpE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ,CAAC,cAAsB;AAC7B,YAAM,YAAY,IAAI,SAAS,gBAAgB,SAAS,MAAM;AAC9D,YAAM,YAAY,IAAI,iBAAiB,aAAa,SAAS;AAC7D,aAAO;AAAA,QACL,WAAW,UAAU;AAAA,QACrB;AAAA,QACA;AAAA,QACA,MAAM,MAAM;AACV,cAAI,UAAW,MAAK,UAAU,KAAK,EAAE,MAAM,MAAM,MAAS;AAAA,QAC5D;AAAA,QACA,QAAQ,CAAC,cAA8B,YACnC,UAAU,OAAO,SAAS,EAAE,KAAK,CAAC,WAAW,OAAO,IAAI,MAAM,KAAK,IACnE,QAAQ,QAAQ,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,GAAG,iBAAiB,CAAC;AACvB;",
6
+ "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leon___/dsh-client-liang-intensity-skin",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "滑动变祖:an opt-in adaptive reasoning slider skin for DeepSeek Harness",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,7 +48,8 @@
48
48
  ],
49
49
  "scripts": {
50
50
  "build": "node ./scripts/build-client.mjs",
51
- "test": "vitest run"
51
+ "test": "vitest run",
52
+ "test:compatibility": "npm run build && node ./scripts/test-client-compatibility.mjs && node ./scripts/test-client-runtime.mjs"
52
53
  },
53
54
  "dsh": {
54
55
  "bundle": {
@@ -62,6 +63,7 @@
62
63
  "@deepseek-ai/dsh-client-ui-settings",
63
64
  "@deepseek-ai/dsh-client-ui-theme",
64
65
  "@deepseek-ai/dsh-client-ui-settings-general",
66
+ "@deepseek-ai/dsh-client-ui-primitives",
65
67
  "@deepseek-ai/dsh-client-locale",
66
68
  "@deepseek-ai/dsh-api-remotes"
67
69
  ]
@@ -70,6 +72,7 @@
70
72
  "devDependencies": {
71
73
  "@types/react": "~18.3.1",
72
74
  "esbuild": "^0.25.0",
75
+ "playwright-core": "^1.64.1",
73
76
  "vitest": "^4.1.10"
74
77
  }
75
78
  }