dsh-smooth-stream 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -10,40 +10,40 @@ window.__ModuleLoader__.load({
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
11
11
  let react_dom = require("react-dom");
12
12
  //#region \0dsh-css:/Users/dzlin/work/project/dsh-smooth-stream/src/client/TypewriterAssistantNodeView.module.css.mjs
13
- const css$3 = ".I17U7q_root{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:16px;line-height:28px;display:flex}.I17U7q_body{flex-direction:column;gap:16px;min-width:0;display:flex}.I17U7q_think{flex-direction:column;display:flex}.I17U7q_thinkRow{position:relative;overflow:hidden}.I17U7q_think[data-state=running] .I17U7q_thinkRow:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite I17U7q_dsh-smooth-stream-think-sweep;position:absolute;left:0}@keyframes I17U7q_dsh-smooth-stream-think-sweep{0%{left:-300px}90%,to{left:100%}}.I17U7q_thinkLeading{flex-shrink:0}.I17U7q_thinkChevron{color:var(--dsw-alias-label-secondary)}.I17U7q_thinkTitle{font-weight:400}.I17U7q_thinkSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.I17U7q_thinkSummary{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:14px;line-height:24px;overflow:hidden}.I17U7q_thinkSummary[data-follow-end]{text-overflow:clip}.I17U7q_thinkBody{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word;padding:4px 0 4px 22px;font-size:14px;line-height:24px}.I17U7q_disclosureRoot{flex-direction:column;width:100%;min-width:0;display:flex}.I17U7q_disclosureRow{cursor:pointer;align-items:center;min-width:0;height:24px;display:flex;position:relative;overflow:hidden}.I17U7q_disclosureLeading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.I17U7q_disclosureIconIdle{opacity:1;transition:opacity .1s;display:inline-flex}.I17U7q_disclosureChevronHover{opacity:0;margin:auto;transition:opacity .1s;position:absolute;inset:0}.I17U7q_disclosureRow:hover .I17U7q_disclosureIconIdle{opacity:0}.I17U7q_disclosureRow:hover .I17U7q_disclosureChevronHover{opacity:1}.I17U7q_disclosureTitle{color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px}.I17U7q_disclosureContent{visibility:visible;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s;grid-template-rows:1fr;display:grid}.I17U7q_disclosureContent[data-collapsed]{visibility:hidden;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s var(--ds-transition-duration,.2s);grid-template-rows:0fr}.I17U7q_disclosureContent[data-no-transition]{transition:none}.I17U7q_disclosureContent>*{min-height:0;overflow:hidden}@media (prefers-reduced-motion:reduce){.I17U7q_think[data-state=running] .I17U7q_thinkRow:after{animation:none}.I17U7q_disclosureContent,.I17U7q_disclosureContent[data-collapsed]{transition:none}}.I17U7q_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;padding:0 6px;font-size:11px;line-height:18px}.I17U7q_visuallyHidden{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.I17U7q_follow{contain:layout style;min-width:0}.I17U7q_root :not(pre)>code{line-height:inherit;white-space:normal;overflow-wrap:anywhere;vertical-align:baseline;display:inline}@supports (text-box-trim:trim-both){.I17U7q_root :is(p,h1,h2,h3,h4,h5,h6,blockquote){text-box-trim:trim-both;text-box-edge:text}}";
14
- const tagId$3 = "dsh-smooth-stream/TypewriterAssistantNodeView.module.css";
13
+ const css$4 = ".I17U7q_root{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:16px;line-height:28px;display:flex}.I17U7q_body{flex-direction:column;gap:16px;min-width:0;display:flex}.I17U7q_think{flex-direction:column;display:flex}.I17U7q_thinkRow{position:relative;overflow:hidden}.I17U7q_think[data-state=running] .I17U7q_thinkRow:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite I17U7q_dsh-smooth-stream-think-sweep;position:absolute;left:0}@keyframes I17U7q_dsh-smooth-stream-think-sweep{0%{left:-300px}90%,to{left:100%}}.I17U7q_thinkLeading{flex-shrink:0}.I17U7q_thinkChevron{color:var(--dsw-alias-label-secondary)}.I17U7q_thinkTitle{font-weight:400}.I17U7q_thinkSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.I17U7q_thinkSummary{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:14px;line-height:24px;overflow:hidden}.I17U7q_thinkSummary[data-follow-end]{text-overflow:clip}.I17U7q_thinkBody{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word;padding:4px 0 4px 22px;font-size:14px;line-height:24px}.I17U7q_disclosureRoot{flex-direction:column;width:100%;min-width:0;display:flex}.I17U7q_disclosureRow{cursor:pointer;align-items:center;min-width:0;height:24px;display:flex;position:relative;overflow:hidden}.I17U7q_disclosureLeading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.I17U7q_disclosureIconIdle{opacity:1;transition:opacity .1s;display:inline-flex}.I17U7q_disclosureChevronHover{opacity:0;margin:auto;transition:opacity .1s;position:absolute;inset:0}.I17U7q_disclosureRow:hover .I17U7q_disclosureIconIdle{opacity:0}.I17U7q_disclosureRow:hover .I17U7q_disclosureChevronHover{opacity:1}.I17U7q_disclosureTitle{color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px}.I17U7q_disclosureContent{visibility:visible;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s;grid-template-rows:1fr;display:grid}.I17U7q_disclosureContent[data-collapsed]{visibility:hidden;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s var(--ds-transition-duration,.2s);grid-template-rows:0fr}.I17U7q_disclosureContent[data-no-transition]{transition:none}.I17U7q_disclosureContent>*{min-height:0;overflow:hidden}@media (prefers-reduced-motion:reduce){.I17U7q_think[data-state=running] .I17U7q_thinkRow:after{animation:none}.I17U7q_disclosureContent,.I17U7q_disclosureContent[data-collapsed]{transition:none}}.I17U7q_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;padding:0 6px;font-size:11px;line-height:18px}.I17U7q_visuallyHidden{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.I17U7q_follow{contain:layout style;min-width:0}.I17U7q_root :not(pre)>code{line-height:inherit;white-space:normal;overflow-wrap:anywhere;vertical-align:baseline;display:inline}@supports (text-box-trim:trim-both){.I17U7q_root :is(p,h1,h2,h3,h4,h5,h6,blockquote){text-box-trim:trim-both;text-box-edge:text}}";
14
+ const tagId$4 = "dsh-smooth-stream/TypewriterAssistantNodeView.module.css";
15
15
  if (typeof document !== "undefined") {
16
- let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]");
16
+ let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]");
17
17
  if (tag === null) {
18
18
  tag = document.createElement("style");
19
19
  tag.dataset.plugin = "dsh-smooth-stream";
20
- tag.dataset.pluginCss = tagId$3;
20
+ tag.dataset.pluginCss = tagId$4;
21
21
  document.head.appendChild(tag);
22
22
  }
23
- tag.textContent = css$3;
23
+ tag.textContent = css$4;
24
24
  }
25
25
  var TypewriterAssistantNodeView_module_css_default = {
26
- "disclosureIconIdle": "I17U7q_disclosureIconIdle",
27
- "disclosureTitle": "I17U7q_disclosureTitle",
26
+ "thinkTitle": "I17U7q_thinkTitle",
27
+ "disclosureContent": "I17U7q_disclosureContent",
28
+ "disclosureLeading": "I17U7q_disclosureLeading",
29
+ "thinkSummary": "I17U7q_thinkSummary",
28
30
  "thinkRow": "I17U7q_thinkRow",
29
- "thinkChevron": "I17U7q_thinkChevron",
30
- "root": "I17U7q_root",
31
- "body": "I17U7q_body",
32
- "disclosureRow": "I17U7q_disclosureRow",
33
- "stopped": "I17U7q_stopped",
34
31
  "visuallyHidden": "I17U7q_visuallyHidden",
35
- "thinkSeparator": "I17U7q_thinkSeparator",
36
- "thinkSummary": "I17U7q_thinkSummary",
37
- "think": "I17U7q_think",
32
+ "disclosureRoot": "I17U7q_disclosureRoot",
33
+ "body": "I17U7q_body",
38
34
  "dsh-smooth-stream-think-sweep": "I17U7q_dsh-smooth-stream-think-sweep",
35
+ "disclosureIconIdle": "I17U7q_disclosureIconIdle",
36
+ "root": "I17U7q_root",
39
37
  "disclosureChevronHover": "I17U7q_disclosureChevronHover",
40
- "thinkLeading": "I17U7q_thinkLeading",
41
- "disclosureContent": "I17U7q_disclosureContent",
38
+ "stopped": "I17U7q_stopped",
39
+ "think": "I17U7q_think",
40
+ "thinkChevron": "I17U7q_thinkChevron",
41
+ "thinkBody": "I17U7q_thinkBody",
42
42
  "follow": "I17U7q_follow",
43
- "disclosureLeading": "I17U7q_disclosureLeading",
44
- "thinkTitle": "I17U7q_thinkTitle",
45
- "disclosureRoot": "I17U7q_disclosureRoot",
46
- "thinkBody": "I17U7q_thinkBody"
43
+ "thinkSeparator": "I17U7q_thinkSeparator",
44
+ "thinkLeading": "I17U7q_thinkLeading",
45
+ "disclosureRow": "I17U7q_disclosureRow",
46
+ "disclosureTitle": "I17U7q_disclosureTitle"
47
47
  };
48
48
  //#endregion
49
49
  //#region src/client/AnimatedDisclosure.tsx
@@ -126,7 +126,9 @@ window.__ModuleLoader__.load({
126
126
  const DEFAULT_STREAM_SETTINGS = {
127
127
  enabled: true,
128
128
  controlScroll: true,
129
+ motionPreference: "auto",
129
130
  thinkAutoExpand: true,
131
+ logarithmicFade: true,
130
132
  debugEnabled: false,
131
133
  debugTuning: DEFAULT_STREAM_DEBUG_TUNING
132
134
  };
@@ -857,7 +859,8 @@ window.__ModuleLoader__.load({
857
859
  });
858
860
  return null;
859
861
  }
860
- const delta = top - stored.top - (shift - stored.shift) + (pad - stored.pad);
862
+ const scrollDelta = scrollTop - stored.scrollTop;
863
+ const delta = top - stored.top + scrollDelta - (shift - stored.shift) + (pad - stored.pad);
861
864
  if (stored.element === anchor) {
862
865
  followGuardAnchors.set(port, {
863
866
  element: anchor,
@@ -1934,18 +1937,18 @@ window.__ModuleLoader__.load({
1934
1937
  }
1935
1938
  let settleQuietMs = 0;
1936
1939
  let settleSig = "";
1937
- const lagBeforeCompletionPaint = Math.max(0, host.scrollHeight - animatedH - runwayOffsetOf(host));
1938
- const currentRunway = runwayOffsetOf(host);
1939
- const currentShift = Math.abs(currentShiftOf(shiftSurfacesOf(host).at(-1) ?? host));
1940
- if (!activeRef.current && lagBeforeCompletionPaint <= 25 && currentRunway <= .25 && currentShift <= .25 && flowPadOf(host) <= .25) {
1940
+ if (!activeRef.current) {
1941
1941
  followTraceUntilMs = Math.max(followTraceUntilMs, performance.now() + 1e4);
1942
1942
  followTrace("fast-gate", {
1943
1943
  sh: host.scrollHeight,
1944
1944
  st: Math.round(host.scrollTop),
1945
1945
  pad: Math.round(flowPadOf(host))
1946
1946
  });
1947
- finishAtNaturalFloor(host, !startedAsEntrance);
1947
+ restoreRunway(host);
1948
+ setFlowPad(host, 0);
1949
+ finishAtNaturalFloor(host, !startedAsEntrance, true);
1948
1950
  followLeaders.delete(host);
1951
+ followCompletionSettle.delete(host);
1949
1952
  releaseRevealScale();
1950
1953
  debugRuntime.reportFollow(host, null);
1951
1954
  return;
@@ -2604,6 +2607,293 @@ window.__ModuleLoader__.load({
2604
2607
  };
2605
2608
  }
2606
2609
  //#endregion
2610
+ //#region \0dsh-css:/Users/dzlin/work/project/dsh-smooth-stream/src/client/LogarithmicFade.module.css.mjs
2611
+ const css$3 = ".g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-0),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-0){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 0.0%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-1),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-1){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 3.22581%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-2),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-2){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 6.45161%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-3),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-3){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 9.67742%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-4),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-4){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 12.9032%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-5),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-5){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 16.129%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-6),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-6){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 19.3548%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-7),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-7){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 22.5807%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-8),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-8){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 25.8065%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-9),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-9){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 29.0323%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-10),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-10){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 32.2581%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-11),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-11){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 35.4839%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-12),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-12){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 38.7097%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-13),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-13){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 41.9355%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-14),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-14){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 45.1613%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-15),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-15){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 48.3871%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-16),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-16){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 51.6129%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-17),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-17){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 54.8387%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-18),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-18){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 58.0645%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-19),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-19){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 61.2903%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-20),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-20){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 64.5161%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-21),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-21){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 67.7419%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-22),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-22){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 70.9677%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-23),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-23){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 74.1936%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-24),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-24){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 77.4194%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-25),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-25){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 80.6452%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-26),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-26){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 83.871%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-27),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-27){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 87.0968%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-28),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-28){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 90.3226%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-29),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-29){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 93.5484%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-30),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-30){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 96.7742%, transparent)}.g268Pa_scope::highlight(g268Pa_dsh-smooth-stream-log-fade-31),.g268Pa_scope ::highlight(g268Pa_dsh-smooth-stream-log-fade-31){color:color-mix(in srgb, var(--dsh-smooth-stream-fade-color,currentColor) 100.0%, transparent)}";
2612
+ const tagId$3 = "dsh-smooth-stream/LogarithmicFade.module.css";
2613
+ if (typeof document !== "undefined") {
2614
+ let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]");
2615
+ if (tag === null) {
2616
+ tag = document.createElement("style");
2617
+ tag.dataset.plugin = "dsh-smooth-stream";
2618
+ tag.dataset.pluginCss = tagId$3;
2619
+ document.head.appendChild(tag);
2620
+ }
2621
+ tag.textContent = css$3;
2622
+ }
2623
+ var LogarithmicFade_module_css_default = {
2624
+ "dsh-smooth-stream-log-fade-0": "g268Pa_dsh-smooth-stream-log-fade-0",
2625
+ "dsh-smooth-stream-log-fade-30": "g268Pa_dsh-smooth-stream-log-fade-30",
2626
+ "dsh-smooth-stream-log-fade-4": "g268Pa_dsh-smooth-stream-log-fade-4",
2627
+ "dsh-smooth-stream-log-fade-31": "g268Pa_dsh-smooth-stream-log-fade-31",
2628
+ "dsh-smooth-stream-log-fade-9": "g268Pa_dsh-smooth-stream-log-fade-9",
2629
+ "dsh-smooth-stream-log-fade-17": "g268Pa_dsh-smooth-stream-log-fade-17",
2630
+ "dsh-smooth-stream-log-fade-18": "g268Pa_dsh-smooth-stream-log-fade-18",
2631
+ "dsh-smooth-stream-log-fade-19": "g268Pa_dsh-smooth-stream-log-fade-19",
2632
+ "dsh-smooth-stream-log-fade-21": "g268Pa_dsh-smooth-stream-log-fade-21",
2633
+ "dsh-smooth-stream-log-fade-12": "g268Pa_dsh-smooth-stream-log-fade-12",
2634
+ "dsh-smooth-stream-log-fade-8": "g268Pa_dsh-smooth-stream-log-fade-8",
2635
+ "dsh-smooth-stream-log-fade-22": "g268Pa_dsh-smooth-stream-log-fade-22",
2636
+ "dsh-smooth-stream-log-fade-29": "g268Pa_dsh-smooth-stream-log-fade-29",
2637
+ "dsh-smooth-stream-log-fade-1": "g268Pa_dsh-smooth-stream-log-fade-1",
2638
+ "dsh-smooth-stream-log-fade-25": "g268Pa_dsh-smooth-stream-log-fade-25",
2639
+ "dsh-smooth-stream-log-fade-23": "g268Pa_dsh-smooth-stream-log-fade-23",
2640
+ "dsh-smooth-stream-log-fade-26": "g268Pa_dsh-smooth-stream-log-fade-26",
2641
+ "dsh-smooth-stream-log-fade-28": "g268Pa_dsh-smooth-stream-log-fade-28",
2642
+ "dsh-smooth-stream-log-fade-6": "g268Pa_dsh-smooth-stream-log-fade-6",
2643
+ "dsh-smooth-stream-log-fade-20": "g268Pa_dsh-smooth-stream-log-fade-20",
2644
+ "dsh-smooth-stream-log-fade-10": "g268Pa_dsh-smooth-stream-log-fade-10",
2645
+ "dsh-smooth-stream-log-fade-14": "g268Pa_dsh-smooth-stream-log-fade-14",
2646
+ "dsh-smooth-stream-log-fade-24": "g268Pa_dsh-smooth-stream-log-fade-24",
2647
+ "dsh-smooth-stream-log-fade-2": "g268Pa_dsh-smooth-stream-log-fade-2",
2648
+ "dsh-smooth-stream-log-fade-13": "g268Pa_dsh-smooth-stream-log-fade-13",
2649
+ "dsh-smooth-stream-log-fade-16": "g268Pa_dsh-smooth-stream-log-fade-16",
2650
+ "dsh-smooth-stream-log-fade-5": "g268Pa_dsh-smooth-stream-log-fade-5",
2651
+ "dsh-smooth-stream-log-fade-27": "g268Pa_dsh-smooth-stream-log-fade-27",
2652
+ "scope": "g268Pa_scope",
2653
+ "dsh-smooth-stream-log-fade-7": "g268Pa_dsh-smooth-stream-log-fade-7",
2654
+ "dsh-smooth-stream-log-fade-15": "g268Pa_dsh-smooth-stream-log-fade-15",
2655
+ "dsh-smooth-stream-log-fade-3": "g268Pa_dsh-smooth-stream-log-fade-3",
2656
+ "dsh-smooth-stream-log-fade-11": "g268Pa_dsh-smooth-stream-log-fade-11"
2657
+ };
2658
+ const FADE_STEPS = 32;
2659
+ const PREFIX = "dsh-smooth-stream-log-fade-";
2660
+ const COLOR_PROPERTY = "--dsh-smooth-stream-fade-color";
2661
+ const highlightName = (index) => LogarithmicFade_module_css_default[`${PREFIX}${index}`] ?? `${PREFIX}${index}`;
2662
+ const EXCLUDED = "pre,code,math,.katex,.katex-display,mjx-container,svg,script,style,textarea,input,button,select,[role=\"button\"],[contenteditable],[hidden],[aria-hidden=\"true\"],[aria-live]";
2663
+ function logarithmicOpacity(progress) {
2664
+ return 0 + 1 * (1 - Math.log1p(5 * (1 - (Number.isFinite(progress) ? Math.max(0, Math.min(1, progress)) : 1))) / Math.log(6));
2665
+ }
2666
+ function fadeTailSize(speedCps) {
2667
+ return Math.min(160, Math.max(24, Math.ceil((Number.isFinite(speedCps) ? Math.max(0, speedCps) : 0) * 240 / 1e3)));
2668
+ }
2669
+ const schedulers = /* @__PURE__ */ new WeakMap();
2670
+ const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
2671
+ function schedule(scheduler) {
2672
+ if (scheduler.frame !== 0 || scheduler.pending.size === 0) return;
2673
+ scheduler.frame = scheduler.window.requestAnimationFrame((now) => {
2674
+ scheduler.frame = 0;
2675
+ for (const client of scheduler.pending) if (!client.paint(now)) scheduler.pending.delete(client);
2676
+ schedule(scheduler);
2677
+ });
2678
+ }
2679
+ function schedulerFor(root) {
2680
+ const doc = root.ownerDocument;
2681
+ const win = doc.defaultView;
2682
+ if (win === null) return null;
2683
+ const realm = win;
2684
+ if (typeof realm.Highlight !== "function" || !realm.CSS?.highlights || !realm.CSS.supports("color", "color-mix(in srgb, currentColor 15%, transparent)")) return null;
2685
+ let scheduler = schedulers.get(doc);
2686
+ if (scheduler === void 0) {
2687
+ const highlights = Array.from({ length: FADE_STEPS }, () => new realm.Highlight());
2688
+ for (const [index, highlight] of highlights.entries()) realm.CSS.highlights.set(highlightName(index), highlight);
2689
+ scheduler = {
2690
+ highlights,
2691
+ clients: /* @__PURE__ */ new Set(),
2692
+ pending: /* @__PURE__ */ new Set(),
2693
+ frame: 0,
2694
+ registry: realm.CSS.highlights,
2695
+ window: win
2696
+ };
2697
+ schedulers.set(doc, scheduler);
2698
+ }
2699
+ return scheduler;
2700
+ }
2701
+ /** Owns ranges only: React retains ownership of every element and Text node. */
2702
+ var LogarithmicFadeController = class LogarithmicFadeController {
2703
+ root;
2704
+ scheduler;
2705
+ previous = "";
2706
+ characters = [];
2707
+ colors = /* @__PURE__ */ new Map();
2708
+ enabled = false;
2709
+ active = false;
2710
+ speedCps = 100;
2711
+ pausedAt = null;
2712
+ disposed = false;
2713
+ observer;
2714
+ constructor(root, scheduler) {
2715
+ this.root = root;
2716
+ this.scheduler = scheduler;
2717
+ scheduler.clients.add(this);
2718
+ const win = root.ownerDocument.defaultView;
2719
+ this.observer = new win.MutationObserver(() => {
2720
+ this.reconcile();
2721
+ });
2722
+ this.observer.observe(root, {
2723
+ subtree: true,
2724
+ childList: true,
2725
+ characterData: true
2726
+ });
2727
+ }
2728
+ static create(root) {
2729
+ const scheduler = schedulerFor(root);
2730
+ return scheduler === null ? null : new LogarithmicFadeController(root, scheduler);
2731
+ }
2732
+ update(enabled, active, speedCps = 100, paused = false) {
2733
+ const now = this.scheduler.window.performance.now();
2734
+ if (paused && this.pausedAt === null) this.pausedAt = now;
2735
+ if (!paused && this.pausedAt !== null) {
2736
+ const pauseDuration = now - this.pausedAt;
2737
+ for (const character of this.characters) character.born += pauseDuration;
2738
+ this.pausedAt = null;
2739
+ }
2740
+ this.enabled = enabled;
2741
+ this.active = active;
2742
+ this.speedCps = speedCps;
2743
+ this.reconcile();
2744
+ }
2745
+ clearRanges() {
2746
+ for (const character of this.characters) this.scheduler.highlights[character.bucket]?.delete(character.range);
2747
+ this.characters = [];
2748
+ this.restoreColors();
2749
+ }
2750
+ restoreColors() {
2751
+ for (const [element, original] of this.colors) if (original.value === "") element.style.removeProperty(COLOR_PROPERTY);
2752
+ else element.style.setProperty(COLOR_PROPERTY, original.value, original.priority);
2753
+ this.colors.clear();
2754
+ }
2755
+ preserveColor(element) {
2756
+ if (this.colors.has(element)) return;
2757
+ const color = this.scheduler.window.getComputedStyle(element).color;
2758
+ this.colors.set(element, {
2759
+ value: element.style.getPropertyValue(COLOR_PROPERTY),
2760
+ priority: element.style.getPropertyPriority(COLOR_PROPERTY)
2761
+ });
2762
+ element.style.setProperty(COLOR_PROPERTY, color);
2763
+ }
2764
+ reconcile() {
2765
+ if (this.disposed) return;
2766
+ const text = this.root.textContent ?? "";
2767
+ const previous = this.previous;
2768
+ this.previous = text;
2769
+ const old = this.characters;
2770
+ this.clearRanges();
2771
+ if (!this.enabled) {
2772
+ this.root.classList.remove(LogarithmicFade_module_css_default.scope);
2773
+ this.scheduler.pending.delete(this);
2774
+ this.stopIfIdle();
2775
+ return;
2776
+ }
2777
+ this.root.classList.add(LogarithmicFade_module_css_default.scope);
2778
+ const now = this.pausedAt ?? this.scheduler.window.performance.now();
2779
+ let prefix = 0;
2780
+ while (prefix < previous.length && prefix < text.length && previous[prefix] === text[prefix]) prefix += 1;
2781
+ const appended = text.startsWith(previous);
2782
+ const nodes = [];
2783
+ const walker = this.root.ownerDocument.createTreeWalker(this.root, NodeFilter.SHOW_TEXT);
2784
+ let offset = 0;
2785
+ for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
2786
+ const end = offset + (node.textContent?.length ?? 0);
2787
+ nodes.push({
2788
+ node,
2789
+ start: offset,
2790
+ end,
2791
+ eligible: node.parentElement?.closest(EXCLUDED) === null
2792
+ });
2793
+ offset = end;
2794
+ }
2795
+ const segments = segmenter.segment(text);
2796
+ const tailSize = fadeTailSize(this.speedCps);
2797
+ const oldestLiveStart = old.reduce((start, character) => now - character.born < 240 && character.end <= prefix ? Math.min(start, character.start) : start, Infinity);
2798
+ let end = text.length;
2799
+ for (let count = 0; count < 160 && end > 0 && (count < tailSize || end > oldestLiveStart); count += 1) {
2800
+ const segment = segments.containing(end - 1);
2801
+ if (segment === void 0) break;
2802
+ const start = segment.index;
2803
+ const parts = nodes.filter((node) => node.end > start && node.start < end);
2804
+ const born = old.find((character) => character.start === start && character.end === end && end <= prefix)?.born ?? (this.active && appended && start >= previous.length ? now : null);
2805
+ if (born !== null && now - born < 240 && segment.segment.trim() !== "" && parts.length > 0 && parts.every((part) => part.eligible)) {
2806
+ const first = parts[0];
2807
+ const last = parts[parts.length - 1];
2808
+ const range = this.root.ownerDocument.createRange();
2809
+ range.setStart(first.node, start - first.start);
2810
+ range.setEnd(last.node, end - last.start);
2811
+ for (const part of parts) this.preserveColor(part.node.parentElement);
2812
+ this.characters.push({
2813
+ start,
2814
+ end,
2815
+ born,
2816
+ range,
2817
+ bucket: -1
2818
+ });
2819
+ }
2820
+ end = start;
2821
+ }
2822
+ if (this.paint(now)) {
2823
+ if (this.pausedAt === null) {
2824
+ this.scheduler.pending.add(this);
2825
+ schedule(this.scheduler);
2826
+ } else {
2827
+ this.scheduler.pending.delete(this);
2828
+ this.stopIfIdle();
2829
+ }
2830
+ } else {
2831
+ this.scheduler.pending.delete(this);
2832
+ this.stopIfIdle();
2833
+ }
2834
+ }
2835
+ paint(now) {
2836
+ this.characters = this.characters.filter((character) => {
2837
+ const progress = (now - character.born) / 240;
2838
+ if (progress >= 1 || !this.root.isConnected || !this.root.contains(character.range.startContainer)) {
2839
+ this.scheduler.highlights[character.bucket]?.delete(character.range);
2840
+ return false;
2841
+ }
2842
+ const bucket = Math.min(31, Math.round((logarithmicOpacity(progress) - 0) / 1 * 31));
2843
+ if (bucket !== character.bucket) {
2844
+ this.scheduler.highlights[character.bucket]?.delete(character.range);
2845
+ this.scheduler.highlights[bucket].add(character.range);
2846
+ character.bucket = bucket;
2847
+ }
2848
+ return true;
2849
+ });
2850
+ if (this.characters.length === 0) this.restoreColors();
2851
+ return this.characters.length > 0;
2852
+ }
2853
+ stopIfIdle() {
2854
+ if (this.scheduler.pending.size !== 0) return;
2855
+ this.scheduler.window.cancelAnimationFrame(this.scheduler.frame);
2856
+ this.scheduler.frame = 0;
2857
+ }
2858
+ dispose() {
2859
+ if (this.disposed) return;
2860
+ this.disposed = true;
2861
+ this.observer.disconnect();
2862
+ this.clearRanges();
2863
+ this.root.classList.remove(LogarithmicFade_module_css_default.scope);
2864
+ this.scheduler.pending.delete(this);
2865
+ this.scheduler.clients.delete(this);
2866
+ this.stopIfIdle();
2867
+ if (this.scheduler.clients.size === 0) {
2868
+ for (const [index, highlight] of this.scheduler.highlights.entries()) {
2869
+ const name = highlightName(index);
2870
+ if (this.scheduler.registry.get(name) === highlight) this.scheduler.registry.delete(name);
2871
+ }
2872
+ schedulers.delete(this.root.ownerDocument);
2873
+ }
2874
+ }
2875
+ };
2876
+ /** active admits new characters; enabled=false also cancels completion linger. */
2877
+ function useLogarithmicFade(rootRef, enabled, active, speedCpsRef, paused = false) {
2878
+ const controller = (0, react.useRef)(null);
2879
+ const committed = (0, react.useRef)(false);
2880
+ (0, react.useLayoutEffect)(() => {
2881
+ return () => {
2882
+ controller.current?.dispose();
2883
+ controller.current = null;
2884
+ };
2885
+ }, [rootRef]);
2886
+ (0, react.useLayoutEffect)(() => {
2887
+ const root = rootRef.current;
2888
+ if (controller.current === null && root !== null && enabled && active) {
2889
+ controller.current = LogarithmicFadeController.create(root);
2890
+ if (committed.current) controller.current?.update(false, false);
2891
+ }
2892
+ controller.current?.update(enabled, active, speedCpsRef?.current, paused);
2893
+ committed.current = true;
2894
+ });
2895
+ }
2896
+ //#endregion
2607
2897
  //#region src/client/FollowHost.tsx
2608
2898
  /**
2609
2899
  * Document-flow host that owns conversation-port follow while `active`.
@@ -2681,6 +2971,20 @@ window.__ModuleLoader__.load({
2681
2971
  }, []);
2682
2972
  return reduced;
2683
2973
  }
2974
+ /**
2975
+ * Resolve whether the reveal engine should stay off for this view. The OS
2976
+ * preference wins only in `auto` mode: `force-smooth` keeps the engine on
2977
+ * machines where a system-wide reduce-motion switch (or a forced browser
2978
+ * flag) would otherwise silently bypass smoothing, and `force-reduced`
2979
+ * disables it even when the OS asks for motion. Credit: three-state design
2980
+ * proposed by @Zn-Dk in #21/#22.
2981
+ */
2982
+ function useMotionReduced(preference) {
2983
+ const system = usePrefersReducedMotion();
2984
+ if (preference === "force-smooth") return false;
2985
+ if (preference === "force-reduced") return true;
2986
+ return system;
2987
+ }
2684
2988
  /** Conservative fallback before the streaming Markdown tail has geometry. */
2685
2989
  const PREDICTIVE_WRAP_FALLBACK_CHARS = 32;
2686
2990
  const STREAM_ANNOUNCEMENT_INTERVAL_MS = 800;
@@ -2886,8 +3190,8 @@ window.__ModuleLoader__.load({
2886
3190
  * drains, the settled full parse (KaTeX math, fence highlighting, file
2887
3191
  * mentions) swaps in exactly once.
2888
3192
  */
2889
- function AnimatedMarkdownText({ text, labels, fileMentions, streaming, ownFollow, followSpeedCpsRef, followRevealedCharsRef, followRevealScaleRef, onPredictiveChange, preset, shouldHoldBack, controlScroll = true }) {
2890
- const reduced = usePrefersReducedMotion();
3193
+ function AnimatedMarkdownText({ text, labels, fileMentions, streaming, logarithmicFade, motionReduced, ownFollow, followSpeedCpsRef, followRevealedCharsRef, followRevealScaleRef, onPredictiveChange, preset, shouldHoldBack, controlScroll = true }) {
3194
+ const reduced = motionReduced;
2891
3195
  const [typing, setTyping] = (0, react.useState)(streaming);
2892
3196
  const localSpeedCpsRef = (0, react.useRef)(35);
2893
3197
  const followRootRef = (0, react.useRef)(null);
@@ -2909,6 +3213,7 @@ window.__ModuleLoader__.load({
2909
3213
  });
2910
3214
  const shown = reduced ? text : displayed;
2911
3215
  const live = typing && !reduced;
3216
+ useLogarithmicFade(followRootRef, logarithmicFade && !reduced, live, speedCpsRef);
2912
3217
  (0, react.useEffect)(() => {
2913
3218
  const root = followRootRef.current;
2914
3219
  if (root === null || typeof ResizeObserver === "undefined") return;
@@ -2943,6 +3248,9 @@ window.__ModuleLoader__.load({
2943
3248
  text,
2944
3249
  typing
2945
3250
  ]);
3251
+ (0, react.useEffect)(() => {
3252
+ if (streaming) setTyping(true);
3253
+ }, [streaming]);
2946
3254
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FollowHost, {
2947
3255
  active: live && ownFollow,
2948
3256
  speedCpsRef,
@@ -2972,6 +3280,50 @@ window.__ModuleLoader__.load({
2972
3280
  }
2973
3281
  };
2974
3282
  }
3283
+ /**
3284
+ * Apply searchable hidden state without unmounting a stable subtree — the
3285
+ * Host's completion fold hides the answer-inline reasoning this way, so the
3286
+ * takeover renderer must reproduce it to stay inside the contract: the row
3287
+ * disappears into the Host's process summary and comes back on find-in-page.
3288
+ * (Mirrors the Harness chat kit's `useSearchableHidden`.)
3289
+ */
3290
+ function useSearchableHidden(hidden, reveal) {
3291
+ const ref = (0, react.useRef)(null);
3292
+ (0, react.useLayoutEffect)(() => {
3293
+ const element = ref.current;
3294
+ if (element === null) return;
3295
+ if (hidden && element.contains(element.ownerDocument.activeElement)) {
3296
+ reveal();
3297
+ return;
3298
+ }
3299
+ if (hidden) element.setAttribute("hidden", "until-found");
3300
+ else element.removeAttribute("hidden");
3301
+ }, [hidden, reveal]);
3302
+ (0, react.useEffect)(() => {
3303
+ const element = ref.current;
3304
+ if (element === null) return;
3305
+ element.addEventListener("beforematch", reveal);
3306
+ return () => {
3307
+ element.removeEventListener("beforematch", reveal);
3308
+ };
3309
+ }, [reveal]);
3310
+ return ref;
3311
+ }
3312
+ /**
3313
+ * One answer-inline reasoning block wrapped in the Host's fold contract. The
3314
+ * Host computes the fold decision (turn closed, compact transcript, this node
3315
+ * is the answer) and delivers it through the `turnProcess` owner prop; when
3316
+ * folded the block hides into the Host's "thought" summary row instead of
3317
+ * staying mounted above the answer.
3318
+ */
3319
+ function FoldableReasoning({ hidden, reveal, children }) {
3320
+ const ref = useSearchableHidden(hidden, reveal);
3321
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3322
+ ref,
3323
+ "data-turn-process-inline": hidden || void 0,
3324
+ children
3325
+ });
3326
+ }
2975
3327
  function firstLine(text) {
2976
3328
  const newline = text.indexOf("\n");
2977
3329
  return newline === -1 ? text : text.slice(0, newline);
@@ -2990,17 +3342,20 @@ window.__ModuleLoader__.load({
2990
3342
  * or the assistant node settling — not when the rest of the reply is
2991
3343
  * still streaming.
2992
3344
  */
2993
- function AnimatedReasoning({ text, running, preset, thinkAutoExpand, shouldHoldBack, followSpeedCpsRef, followRevealScaleRef, t }) {
2994
- const reduced = usePrefersReducedMotion();
3345
+ function AnimatedReasoning({ text, running, preset, thinkAutoExpand, motionReduced, logarithmicFade, shouldHoldBack, followSpeedCpsRef, followRevealScaleRef, t }) {
3346
+ const reduced = motionReduced;
2995
3347
  const [expanded, setExpanded] = (0, react.useState)(running && thinkAutoExpand);
2996
3348
  const [autoClosed, setAutoClosed] = (0, react.useState)(false);
2997
3349
  const summaryRef = (0, react.useRef)(null);
3350
+ const fadeRootRef = (0, react.useRef)(null);
3351
+ const localFadeSpeedRef = (0, react.useRef)(35);
3352
+ const fadeSpeedRef = followSpeedCpsRef ?? localFadeSpeedRef;
2998
3353
  const commitAnchorRef = (0, react.useRef)(null);
2999
3354
  const displayed = useSmoothStreamContent(text, {
3000
3355
  enabled: running && !reduced,
3001
3356
  preset,
3002
3357
  shouldHoldBack,
3003
- speedCpsRef: followSpeedCpsRef,
3358
+ speedCpsRef: fadeSpeedRef,
3004
3359
  revealScaleRef: followRevealScaleRef,
3005
3360
  onRevealCommit: () => {
3006
3361
  notifyFollowCommit(commitAnchorRef.current);
@@ -3008,6 +3363,7 @@ window.__ModuleLoader__.load({
3008
3363
  });
3009
3364
  const shown = running && !reduced ? displayed : text;
3010
3365
  const summary = running ? latestLine(shown) : firstLine(text);
3366
+ useLogarithmicFade(fadeRootRef, logarithmicFade && !reduced && expanded, running, fadeSpeedRef);
3011
3367
  (0, react.useLayoutEffect)(() => {
3012
3368
  if (thinkAutoExpand) {
3013
3369
  setExpanded(running);
@@ -3053,6 +3409,7 @@ window.__ModuleLoader__.load({
3053
3409
  children: summary
3054
3410
  })] }),
3055
3411
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3412
+ ref: fadeRootRef,
3056
3413
  className: TypewriterAssistantNodeView_module_css_default.thinkBody,
3057
3414
  children: shown
3058
3415
  })
@@ -3070,10 +3427,14 @@ window.__ModuleLoader__.load({
3070
3427
  * holds offscreen reveals when the frame rate is degraded. Settled text
3071
3428
  * renders with the full Markdown pipeline.
3072
3429
  */
3073
- const TypewriterAssistantNodeView = (0, react.memo)(function TypewriterAssistantNodeView({ mode: _mode = DEFAULT_STREAM_CONFIG.mode, preset = DEFAULT_STREAM_CONFIG.preset, revealCharsPerSec: _revealCharsPerSec = DEFAULT_STREAM_CONFIG.revealCharsPerSec, scrollSpeedPxPerSec: _scrollSpeedPxPerSec = DEFAULT_STREAM_CONFIG.scrollSpeedPxPerSec, maxScrollSpeedPxPerSec: _maxScrollSpeedPxPerSec = DEFAULT_STREAM_CONFIG.maxScrollSpeedPxPerSec, thinkAutoExpand = DEFAULT_STREAM_SETTINGS.thinkAutoExpand, controlScroll = true, node, useTurnData, openFile, loadImage, fileMentions, t }) {
3430
+ const TypewriterAssistantNodeView = (0, react.memo)(function TypewriterAssistantNodeView({ mode: _mode = DEFAULT_STREAM_CONFIG.mode, preset = DEFAULT_STREAM_CONFIG.preset, revealCharsPerSec: _revealCharsPerSec = DEFAULT_STREAM_CONFIG.revealCharsPerSec, scrollSpeedPxPerSec: _scrollSpeedPxPerSec = DEFAULT_STREAM_CONFIG.scrollSpeedPxPerSec, maxScrollSpeedPxPerSec: _maxScrollSpeedPxPerSec = DEFAULT_STREAM_CONFIG.maxScrollSpeedPxPerSec, thinkAutoExpand = DEFAULT_STREAM_SETTINGS.thinkAutoExpand, logarithmicFade = DEFAULT_STREAM_SETTINGS.logarithmicFade, controlScroll = true, motionPreference = DEFAULT_STREAM_SETTINGS.motionPreference, node, useTurnData, openFile, loadImage, fileMentions, turnProcess, t }) {
3074
3431
  const data = node.data;
3075
3432
  const streaming = data.status === "running";
3076
- const reduced = usePrefersReducedMotion();
3433
+ const reduced = useMotionReduced(motionPreference);
3434
+ const reasoningHidden = turnProcess !== void 0 && turnProcess.foldable && turnProcess.spec.answerStep === data.step && turnProcess.spec.inlineReasoning && !turnProcess.open;
3435
+ const revealProcess = (0, react.useCallback)(() => {
3436
+ turnProcess?.setOpen(true);
3437
+ }, [turnProcess]);
3077
3438
  const { ref: guardRef, shouldHoldBack } = useFpsGuard(streaming);
3078
3439
  const rootSpeedRef = (0, react.useRef)(35);
3079
3440
  const rootRevealedCharsRef = (0, react.useRef)(0);
@@ -3136,6 +3497,8 @@ window.__ModuleLoader__.load({
3136
3497
  labels: markdownLabels,
3137
3498
  fileMentions: mentions,
3138
3499
  streaming,
3500
+ logarithmicFade: logarithmicFade && data.status !== "interrupted",
3501
+ motionReduced: reduced,
3139
3502
  ownFollow: !streaming && index === lastFollow,
3140
3503
  followSpeedCpsRef: index === lastFollow ? rootSpeedRef : void 0,
3141
3504
  followRevealedCharsRef: index === lastFollow ? rootRevealedCharsRef : void 0,
@@ -3147,15 +3510,21 @@ window.__ModuleLoader__.load({
3147
3510
  }, index));
3148
3511
  break;
3149
3512
  case "reasoning":
3150
- rendered.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedReasoning, {
3151
- text: block.text,
3152
- running: streaming && index === last,
3153
- preset,
3154
- thinkAutoExpand,
3155
- shouldHoldBack,
3156
- followSpeedCpsRef: reasoningOwnsSpeed && index === last ? rootSpeedRef : void 0,
3157
- followRevealScaleRef: reasoningOwnsSpeed && index === last ? rootRevealScaleRef : void 0,
3158
- t
3513
+ rendered.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldableReasoning, {
3514
+ hidden: reasoningHidden,
3515
+ reveal: revealProcess,
3516
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedReasoning, {
3517
+ text: block.text,
3518
+ running: streaming && index === last,
3519
+ preset,
3520
+ thinkAutoExpand,
3521
+ logarithmicFade: logarithmicFade && data.status !== "interrupted",
3522
+ motionReduced: reduced,
3523
+ shouldHoldBack,
3524
+ followSpeedCpsRef: reasoningOwnsSpeed && index === last ? rootSpeedRef : void 0,
3525
+ followRevealScaleRef: reasoningOwnsSpeed && index === last ? rootRevealScaleRef : void 0,
3526
+ t
3527
+ })
3159
3528
  }, index));
3160
3529
  break;
3161
3530
  case "image": {
@@ -3482,8 +3851,8 @@ window.__ModuleLoader__.load({
3482
3851
  tag.textContent = css$2;
3483
3852
  }
3484
3853
  var AgentRowEntrance_module_css_default = {
3485
- "surface": "_7P9_Ta_surface",
3486
- "dsh-smooth-stream-agent-row-in": "_7P9_Ta_dsh-smooth-stream-agent-row-in"
3854
+ "dsh-smooth-stream-agent-row-in": "_7P9_Ta_dsh-smooth-stream-agent-row-in",
3855
+ "surface": "_7P9_Ta_surface"
3487
3856
  };
3488
3857
  //#endregion
3489
3858
  //#region src/client/TypewriterToolNodeView.tsx
@@ -3662,7 +4031,7 @@ window.__ModuleLoader__.load({
3662
4031
  }
3663
4032
  //#endregion
3664
4033
  //#region \0dsh-css:/Users/dzlin/work/project/dsh-smooth-stream/src/client/SmoothStreamCard.module.css.mjs
3665
- const css$1 = ".XNGeRG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;list-style:none;transition:border-color .16s,background .16s;display:flex}.XNGeRG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.XNGeRG_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.XNGeRG_header{appearance:none;cursor:pointer;text-align:left;width:100%;font:inherit;color:inherit;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.XNGeRG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.XNGeRG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.XNGeRG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.XNGeRG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.XNGeRG_version{text-overflow:ellipsis;white-space:nowrap;max-width:16rem;color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:1.5;overflow:hidden}.XNGeRG_pending{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.XNGeRG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.XNGeRG_chevronOpen{transform:rotate(180deg)}.XNGeRG_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;margin:0 16px;padding-bottom:8px;display:flex}.XNGeRG_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.XNGeRG_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.XNGeRG_field+.XNGeRG_field{border-top:1px solid var(--dsw-alias-border-l2)}.XNGeRG_fieldDisabled{opacity:.5}.XNGeRG_fieldHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.XNGeRG_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.XNGeRG_toggle{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XNGeRG_toggle:disabled{cursor:default}.XNGeRG_toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.XNGeRG_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.XNGeRG_failure{justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XNGeRG_updateRow{border-top:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XNGeRG_updateCopy{flex-direction:column;gap:4px;min-width:0;display:flex}.XNGeRG_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.XNGeRG_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.XNGeRG_save,.XNGeRG_discard,.XNGeRG_update{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.XNGeRG_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.XNGeRG_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.XNGeRG_discard:hover:not(:disabled),.XNGeRG_update:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.XNGeRG_update{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;flex:none;align-items:center;gap:6px;display:inline-flex}.XNGeRG_discard:disabled,.XNGeRG_save:disabled,.XNGeRG_update:disabled{opacity:.4;cursor:default}.XNGeRG_discard:focus-visible,.XNGeRG_save:focus-visible,.XNGeRG_update:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
4034
+ const css$1 = ".XNGeRG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;list-style:none;transition:border-color .16s,background .16s;display:flex}.XNGeRG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.XNGeRG_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.XNGeRG_header{appearance:none;cursor:pointer;text-align:left;width:100%;font:inherit;color:inherit;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.XNGeRG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.XNGeRG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.XNGeRG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.XNGeRG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.XNGeRG_version{text-overflow:ellipsis;white-space:nowrap;max-width:16rem;color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:1.5;overflow:hidden}.XNGeRG_pending{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.XNGeRG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.XNGeRG_chevronOpen{transform:rotate(180deg)}.XNGeRG_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;margin:0 16px;padding-bottom:8px;display:flex}.XNGeRG_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.XNGeRG_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.XNGeRG_field+.XNGeRG_field{border-top:1px solid var(--dsw-alias-border-l2)}.XNGeRG_fieldDisabled{opacity:.5}.XNGeRG_fieldHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.XNGeRG_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.XNGeRG_toggle{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XNGeRG_toggle:disabled{cursor:default}.XNGeRG_toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.XNGeRG_choiceRow{flex-wrap:wrap;gap:6px 14px;margin:2px 0 0;padding:0;display:flex}.XNGeRG_choice{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:5px;font-size:12px;line-height:1.5;display:flex}.XNGeRG_choiceInput{width:14px;height:14px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XNGeRG_choice:has(.XNGeRG_choiceInput:disabled){cursor:default;opacity:.55}.XNGeRG_choiceInput:disabled{cursor:default}.XNGeRG_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.XNGeRG_failure{justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XNGeRG_updateRow{border-top:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XNGeRG_updateCopy{flex-direction:column;gap:4px;min-width:0;display:flex}.XNGeRG_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.XNGeRG_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.XNGeRG_save,.XNGeRG_discard,.XNGeRG_update{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.XNGeRG_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.XNGeRG_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.XNGeRG_discard:hover:not(:disabled),.XNGeRG_update:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.XNGeRG_update{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;flex:none;align-items:center;gap:6px;display:inline-flex}.XNGeRG_discard:disabled,.XNGeRG_save:disabled,.XNGeRG_update:disabled{opacity:.4;cursor:default}.XNGeRG_discard:focus-visible,.XNGeRG_save:focus-visible,.XNGeRG_update:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
3666
4035
  const tagId$1 = "dsh-smooth-stream/SmoothStreamCard.module.css";
3667
4036
  if (typeof document !== "undefined") {
3668
4037
  let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]");
@@ -3675,32 +4044,35 @@ window.__ModuleLoader__.load({
3675
4044
  tag.textContent = css$1;
3676
4045
  }
3677
4046
  var SmoothStreamCard_module_css_default = {
4047
+ "save": "XNGeRG_save",
3678
4048
  "updateCopy": "XNGeRG_updateCopy",
3679
- "footer": "XNGeRG_footer",
3680
- "name": "XNGeRG_name",
4049
+ "hint": "XNGeRG_hint",
4050
+ "version": "XNGeRG_version",
3681
4051
  "update": "XNGeRG_update",
3682
- "updateRow": "XNGeRG_updateRow",
3683
- "headText": "XNGeRG_headText",
3684
- "label": "XNGeRG_label",
3685
- "description": "XNGeRG_description",
4052
+ "card": "XNGeRG_card",
4053
+ "choiceRow": "XNGeRG_choiceRow",
4054
+ "chevron": "XNGeRG_chevron",
4055
+ "failure": "XNGeRG_failure",
3686
4056
  "discard": "XNGeRG_discard",
3687
- "save": "XNGeRG_save",
3688
- "cardOpen": "XNGeRG_cardOpen",
4057
+ "updateRow": "XNGeRG_updateRow",
4058
+ "footer": "XNGeRG_footer",
4059
+ "body": "XNGeRG_body",
4060
+ "field": "XNGeRG_field",
3689
4061
  "failed": "XNGeRG_failed",
3690
- "fieldHead": "XNGeRG_fieldHead",
4062
+ "name": "XNGeRG_name",
4063
+ "readOnly": "XNGeRG_readOnly",
4064
+ "chevronOpen": "XNGeRG_chevronOpen",
3691
4065
  "toggle": "XNGeRG_toggle",
3692
- "chevron": "XNGeRG_chevron",
3693
- "hint": "XNGeRG_hint",
3694
- "card": "XNGeRG_card",
3695
- "header": "XNGeRG_header",
4066
+ "choice": "XNGeRG_choice",
4067
+ "choiceInput": "XNGeRG_choiceInput",
4068
+ "description": "XNGeRG_description",
3696
4069
  "pending": "XNGeRG_pending",
3697
- "chevronOpen": "XNGeRG_chevronOpen",
3698
- "readOnly": "XNGeRG_readOnly",
3699
- "field": "XNGeRG_field",
3700
- "version": "XNGeRG_version",
3701
- "failure": "XNGeRG_failure",
3702
4070
  "fieldDisabled": "XNGeRG_fieldDisabled",
3703
- "body": "XNGeRG_body"
4071
+ "headText": "XNGeRG_headText",
4072
+ "fieldHead": "XNGeRG_fieldHead",
4073
+ "label": "XNGeRG_label",
4074
+ "cardOpen": "XNGeRG_cardOpen",
4075
+ "header": "XNGeRG_header"
3704
4076
  };
3705
4077
  //#endregion
3706
4078
  //#region src/client/SmoothStreamCard.tsx
@@ -3816,6 +4188,78 @@ window.__ModuleLoader__.load({
3816
4188
  children: t("controlScrollHint")
3817
4189
  })]
3818
4190
  }),
4191
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
4192
+ className: state.enabled ? SmoothStreamCard_module_css_default.field : `${SmoothStreamCard_module_css_default.field} ${SmoothStreamCard_module_css_default.fieldDisabled}`,
4193
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4194
+ className: SmoothStreamCard_module_css_default.fieldHead,
4195
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4196
+ className: SmoothStreamCard_module_css_default.label,
4197
+ children: t("logarithmicFade")
4198
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4199
+ type: "checkbox",
4200
+ className: SmoothStreamCard_module_css_default.toggle,
4201
+ checked: state.logarithmicFade,
4202
+ disabled: !state.writable || state.saving || !state.enabled,
4203
+ onChange: (event) => {
4204
+ props.edit({ logarithmicFade: event.target.checked });
4205
+ }
4206
+ })]
4207
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4208
+ className: SmoothStreamCard_module_css_default.hint,
4209
+ children: t("logarithmicFadeHint")
4210
+ })]
4211
+ }),
4212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4213
+ className: state.enabled ? SmoothStreamCard_module_css_default.field : `${SmoothStreamCard_module_css_default.field} ${SmoothStreamCard_module_css_default.fieldDisabled}`,
4214
+ children: [
4215
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4216
+ className: SmoothStreamCard_module_css_default.fieldHead,
4217
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4218
+ className: SmoothStreamCard_module_css_default.label,
4219
+ children: t("motionPreference")
4220
+ })
4221
+ }),
4222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4223
+ className: SmoothStreamCard_module_css_default.hint,
4224
+ children: t("motionPreferenceHint")
4225
+ }),
4226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4227
+ className: SmoothStreamCard_module_css_default.choiceRow,
4228
+ role: "radiogroup",
4229
+ "aria-label": t("motionPreference"),
4230
+ children: [
4231
+ [
4232
+ "auto",
4233
+ "motionAuto",
4234
+ "motionAutoHint"
4235
+ ],
4236
+ [
4237
+ "force-smooth",
4238
+ "motionForceSmooth",
4239
+ "motionForceSmoothHint"
4240
+ ],
4241
+ [
4242
+ "force-reduced",
4243
+ "motionForceReduced",
4244
+ "motionForceReducedHint"
4245
+ ]
4246
+ ].map(([value, label, hint]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
4247
+ className: SmoothStreamCard_module_css_default.choice,
4248
+ title: t(hint),
4249
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4250
+ type: "radio",
4251
+ className: SmoothStreamCard_module_css_default.choiceInput,
4252
+ name: "smooth-stream-motion",
4253
+ checked: state.motionPreference === value,
4254
+ disabled: !state.writable || state.saving || !state.enabled,
4255
+ onChange: () => {
4256
+ props.edit({ motionPreference: value });
4257
+ }
4258
+ }), t(label)]
4259
+ }, value))
4260
+ })
4261
+ ]
4262
+ }),
3819
4263
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3820
4264
  className: state.enabled ? SmoothStreamCard_module_css_default.field : `${SmoothStreamCard_module_css_default.field} ${SmoothStreamCard_module_css_default.fieldDisabled}`,
3821
4265
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -3958,11 +4402,13 @@ window.__ModuleLoader__.load({
3958
4402
  hooks: { smoothStreamCard: this.store },
3959
4403
  edit: (patch) => {
3960
4404
  if (this.saving) return;
3961
- if (patch.enabled !== void 0 || patch.controlScroll !== void 0 || patch.thinkAutoExpand !== void 0) this.stagedBase = {
4405
+ if (patch.enabled !== void 0 || patch.controlScroll !== void 0 || patch.motionPreference !== void 0 || patch.thinkAutoExpand !== void 0 || patch.logarithmicFade !== void 0) this.stagedBase = {
3962
4406
  ...this.baseValues(),
3963
4407
  ...patch.enabled === void 0 ? {} : { enabled: patch.enabled },
3964
4408
  ...patch.controlScroll === void 0 ? {} : { controlScroll: patch.controlScroll },
3965
- ...patch.thinkAutoExpand === void 0 ? {} : { thinkAutoExpand: patch.thinkAutoExpand }
4409
+ ...patch.motionPreference === void 0 ? {} : { motionPreference: patch.motionPreference },
4410
+ ...patch.thinkAutoExpand === void 0 ? {} : { thinkAutoExpand: patch.thinkAutoExpand },
4411
+ ...patch.logarithmicFade === void 0 ? {} : { logarithmicFade: patch.logarithmicFade }
3966
4412
  };
3967
4413
  if (this.loadedDebug !== void 0 && (patch.debugEnabled !== void 0 || patch.debugTuning !== void 0)) this.stagedDebug = {
3968
4414
  ...this.debugValues(),
@@ -4015,7 +4461,9 @@ window.__ModuleLoader__.load({
4015
4461
  return this.stagedBase ?? {
4016
4462
  enabled: this.loaded?.enabled ?? DEFAULT_STREAM_SETTINGS.enabled,
4017
4463
  controlScroll: this.loaded?.controlScroll ?? DEFAULT_STREAM_SETTINGS.controlScroll,
4018
- thinkAutoExpand: this.loaded?.thinkAutoExpand ?? DEFAULT_STREAM_SETTINGS.thinkAutoExpand
4464
+ motionPreference: this.loaded?.motionPreference ?? DEFAULT_STREAM_SETTINGS.motionPreference,
4465
+ thinkAutoExpand: this.loaded?.thinkAutoExpand ?? DEFAULT_STREAM_SETTINGS.thinkAutoExpand,
4466
+ logarithmicFade: this.loaded?.logarithmicFade ?? DEFAULT_STREAM_SETTINGS.logarithmicFade
4019
4467
  };
4020
4468
  }
4021
4469
  debugValues() {
@@ -4135,8 +4583,15 @@ window.__ModuleLoader__.load({
4135
4583
  "npm",
4136
4584
  "development",
4137
4585
  "unmanaged"
4138
- ].includes(data.installation) || typeof data.writable !== "boolean" || typeof data.enabled !== "boolean" || typeof data.controlScroll !== "boolean" || typeof data.thinkAutoExpand !== "boolean" || typeof data.canUpgrade !== "boolean") throw new Error("dsh-smooth-stream: malformed settings response");
4139
- return data;
4586
+ ].includes(data.installation) || typeof data.writable !== "boolean" || typeof data.enabled !== "boolean" || typeof data.controlScroll !== "boolean" || ![
4587
+ "auto",
4588
+ "force-smooth",
4589
+ "force-reduced"
4590
+ ].includes(data.motionPreference) || typeof data.thinkAutoExpand !== "boolean" || data.logarithmicFade !== void 0 && typeof data.logarithmicFade !== "boolean" || typeof data.canUpgrade !== "boolean") throw new Error("dsh-smooth-stream: malformed settings response");
4591
+ return {
4592
+ ...data,
4593
+ logarithmicFade: data.logarithmicFade ?? true
4594
+ };
4140
4595
  }
4141
4596
  function upgradeView(value) {
4142
4597
  if (record(value)?.restartRequired !== true) throw new Error("dsh-smooth-stream: malformed update response");
@@ -4165,7 +4620,9 @@ window.__ModuleLoader__.load({
4165
4620
  return settingsView(accepted(await connection.rpc.call(STREAM_SETTINGS_RPC_CHANNEL, STREAM_SETTINGS_RPC.write, {
4166
4621
  enabled: settings.enabled,
4167
4622
  controlScroll: settings.controlScroll,
4623
+ motionPreference: settings.motionPreference,
4168
4624
  thinkAutoExpand: settings.thinkAutoExpand,
4625
+ logarithmicFade: settings.logarithmicFade,
4169
4626
  ...settings.debugEnabled === void 0 || settings.debugTuning === void 0 ? {} : {
4170
4627
  debugEnabled: settings.debugEnabled,
4171
4628
  debugTuning: settings.debugTuning
@@ -4201,34 +4658,34 @@ window.__ModuleLoader__.load({
4201
4658
  tag.textContent = css;
4202
4659
  }
4203
4660
  var DebugPanel_module_css_default = {
4204
- "metric": "m4_tdG_metric",
4205
- "trigger": "m4_tdG_trigger",
4206
- "panel": "m4_tdG_panel",
4207
- "statusLive": "m4_tdG_statusLive",
4661
+ "section": "m4_tdG_section",
4208
4662
  "guide": "m4_tdG_guide",
4209
- "triggerActive": "m4_tdG_triggerActive",
4663
+ "metrics": "m4_tdG_metrics",
4664
+ "numberWrap": "m4_tdG_numberWrap",
4665
+ "statusLive": "m4_tdG_statusLive",
4666
+ "visuallyHidden": "m4_tdG_visuallyHidden",
4667
+ "statusDot": "m4_tdG_statusDot",
4210
4668
  "secondaryButton": "m4_tdG_secondaryButton",
4211
- "number": "m4_tdG_number",
4669
+ "controlLabel": "m4_tdG_controlLabel",
4212
4670
  "title": "m4_tdG_title",
4213
- "controlHead": "m4_tdG_controlHead",
4214
- "unit": "m4_tdG_unit",
4215
- "visuallyHidden": "m4_tdG_visuallyHidden",
4216
- "panelHeader": "m4_tdG_panelHeader",
4217
- "section": "m4_tdG_section",
4218
- "range": "m4_tdG_range",
4219
- "unsaved": "m4_tdG_unsaved",
4220
- "state": "m4_tdG_state",
4221
4671
  "control": "m4_tdG_control",
4222
- "numberWrap": "m4_tdG_numberWrap",
4223
- "metrics": "m4_tdG_metrics",
4672
+ "trigger": "m4_tdG_trigger",
4673
+ "triggerActive": "m4_tdG_triggerActive",
4674
+ "infoButton": "m4_tdG_infoButton",
4224
4675
  "footerSpacer": "m4_tdG_footerSpacer",
4225
- "statusDot": "m4_tdG_statusDot",
4226
- "controlLabel": "m4_tdG_controlLabel",
4676
+ "primaryButton": "m4_tdG_primaryButton",
4227
4677
  "footer": "m4_tdG_footer",
4678
+ "state": "m4_tdG_state",
4679
+ "range": "m4_tdG_range",
4680
+ "number": "m4_tdG_number",
4681
+ "panel": "m4_tdG_panel",
4682
+ "scrollArea": "m4_tdG_scrollArea",
4683
+ "metric": "m4_tdG_metric",
4684
+ "panelHeader": "m4_tdG_panelHeader",
4685
+ "unit": "m4_tdG_unit",
4686
+ "controlHead": "m4_tdG_controlHead",
4228
4687
  "iconButton": "m4_tdG_iconButton",
4229
- "infoButton": "m4_tdG_infoButton",
4230
- "primaryButton": "m4_tdG_primaryButton",
4231
- "scrollArea": "m4_tdG_scrollArea"
4688
+ "unsaved": "m4_tdG_unsaved"
4232
4689
  };
4233
4690
  //#endregion
4234
4691
  //#region src/client/DebugPanel.tsx
@@ -4626,7 +5083,17 @@ window.__ModuleLoader__.load({
4626
5083
  enabledHint: "Let this plugin render and follow streaming replies. Turn off to use the built-in Harness renderer.",
4627
5084
  controlScroll: "Take over scrolling",
4628
5085
  controlScrollHint: "On by default; smooth-stream writes the conversation scroll position. Turn off to leave bottom-follow to Harness.",
5086
+ motionPreference: "Motion",
5087
+ motionPreferenceHint: "How streaming responds to the system reduce-motion setting.",
5088
+ motionAuto: "Follow system",
5089
+ motionAutoHint: "Reduced-motion systems get raw text (accessibility first).",
5090
+ motionForceSmooth: "Always smooth",
5091
+ motionForceSmoothHint: "Keep the smoothing engine even when the system asks for reduced motion.",
5092
+ motionForceReduced: "Always raw",
5093
+ motionForceReducedHint: "Render raw text even when the system allows motion.",
4629
5094
  thinkAutoExpand: "Auto-expand thinking",
5095
+ logarithmicFade: "Logarithmic fade",
5096
+ logarithmicFadeHint: "Fade new answer and expanded thinking text into view. Follows the motion preference.",
4630
5097
  thinkAutoExpandHint: "Open the thinking block while it streams. Turn off to keep it collapsed.",
4631
5098
  debugEnabled: "Show render diagnostics",
4632
5099
  debugEnabledHint: "Show live streaming and scroll metrics on the right side of the chat. Tune values there, then save them here.",
@@ -4705,7 +5172,17 @@ window.__ModuleLoader__.load({
4705
5172
  enabledHint: "由本插件渲染并跟随流式回复;关闭后使用 Harness 内置渲染。",
4706
5173
  controlScroll: "接管滚动",
4707
5174
  controlScrollHint: "默认开启,由丝滑流式写入会话滚动位置;关闭后贴底滚动交给 Harness。",
5175
+ motionPreference: "动效偏好",
5176
+ motionPreferenceHint: "流式渲染如何响应系统的「减少动态效果」设置。",
5177
+ motionAuto: "跟随系统",
5178
+ motionAutoHint: "系统开启减少动态效果时直接呈现原始文本(优先无障碍)。",
5179
+ motionForceSmooth: "始终平滑",
5180
+ motionForceSmoothHint: "即使系统要求减少动态效果,仍保持平滑流式渲染。",
5181
+ motionForceReduced: "始终原始",
5182
+ motionForceReducedHint: "即使系统允许动效,也直接呈现原始文本。",
4708
5183
  thinkAutoExpand: "自动展开思考",
5184
+ logarithmicFade: "对数淡入",
5185
+ logarithmicFadeHint: "让回答正文和展开的思考文字由淡变实,遵循动效偏好。",
4709
5186
  thinkAutoExpandHint: "思考块在流式时自动展开;关闭后保持折叠,可手动展开。",
4710
5187
  debugEnabled: "显示渲染调试面板",
4711
5188
  debugEnabledHint: "在聊天右侧显示流式渲染和滚动的实时参数,可在面板中调节并在这里保存。",
@@ -4899,7 +5376,7 @@ window.__ModuleLoader__.load({
4899
5376
  refresh() {
4900
5377
  const next = this.read();
4901
5378
  const pending = this.card?.getSnapshot().status === "loading";
4902
- if (pending === this.pending && next.enabled === this.value.enabled && next.controlScroll === this.value.controlScroll && next.thinkAutoExpand === this.value.thinkAutoExpand && next.debugEnabled === this.value.debugEnabled && next.debugTuning === this.value.debugTuning) return;
5379
+ if (pending === this.pending && next.enabled === this.value.enabled && next.controlScroll === this.value.controlScroll && next.motionPreference === this.value.motionPreference && next.thinkAutoExpand === this.value.thinkAutoExpand && next.logarithmicFade === this.value.logarithmicFade && next.debugEnabled === this.value.debugEnabled && next.debugTuning === this.value.debugTuning) return;
4903
5380
  this.pending = pending;
4904
5381
  this.value = next;
4905
5382
  for (const listener of this.listeners) listener();
@@ -4999,7 +5476,9 @@ window.__ModuleLoader__.load({
4999
5476
  scrollSpeedPxPerSec: config.scrollSpeedPxPerSec,
5000
5477
  maxScrollSpeedPxPerSec: config.maxScrollSpeedPxPerSec,
5001
5478
  thinkAutoExpand: preferences.thinkAutoExpand,
5002
- controlScroll: preferences.controlScroll
5479
+ logarithmicFade: preferences.logarithmicFade,
5480
+ controlScroll: preferences.controlScroll,
5481
+ motionPreference: preferences.motionPreference
5003
5482
  });
5004
5483
  };
5005
5484
  ctx.slots.inject("conversation.chat.node", () => {