dsh-claude-desktop-theme 0.4.0 → 0.4.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/README.md +1 -1
- package/lib/client.js +598 -252
- package/lib/types/client/compat/account-theme.d.ts +1 -1
- package/lib/types/client/compat/browser-header.d.ts +2 -43
- package/lib/types/client/compat/browser-menu.d.ts +0 -1
- package/lib/types/client/compat/pane-labels.d.ts +81 -0
- package/lib/types/client/compat/settings-section.d.ts +21 -0
- package/lib/types/client/compat/sidebar-action-alignment.d.ts +3 -0
- package/lib/types/client/compat/sidebar-session-icons.d.ts +3 -0
- package/lib/types/client/features/settings/locales.d.ts +2 -1
- package/lib/types/client/features/settings/mount.d.ts +1 -1
- package/lib/types/client/features/settings/register.d.ts +3 -15
- package/lib/types/client/theme/palette.d.ts +1 -0
- package/package.json +2 -1
- package/lib/types/client/compat/plugin-manager.d.ts +0 -32
package/lib/client.js
CHANGED
|
@@ -1056,8 +1056,6 @@ function createHostServices(ctx) {
|
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
1058
|
// src/client/compat/browser-header.ts
|
|
1059
|
-
var BROWSER_HEADER_ATTRIBUTE = "data-ccd-header-merged";
|
|
1060
|
-
var HEADER_SCROLL_PROPERTY = "--ccd-header-scroll";
|
|
1061
1059
|
var SESSION_WORDS = Object.freeze([
|
|
1062
1060
|
["\u4F1A\u8BDD", "\u6700\u8FD1\u4F1A\u8BDD"],
|
|
1063
1061
|
["Sessions", "Recents"]
|
|
@@ -1074,27 +1072,10 @@ function browserHeaderWord(text, noHistory) {
|
|
|
1074
1072
|
}
|
|
1075
1073
|
function mountBrowserHeader(document2, report) {
|
|
1076
1074
|
const host = hostSelectors(document2);
|
|
1077
|
-
const anchors = hostAnchors(document2);
|
|
1078
1075
|
const rewritten = /* @__PURE__ */ new Map();
|
|
1079
1076
|
let scheduled = 0;
|
|
1080
1077
|
let observer;
|
|
1081
1078
|
let disposed = false;
|
|
1082
|
-
let marked = null;
|
|
1083
|
-
let scroller = null;
|
|
1084
|
-
const publish = () => {
|
|
1085
|
-
if (marked === null) return;
|
|
1086
|
-
const value = `${scroller?.scrollTop ?? 0}px`;
|
|
1087
|
-
if (marked.style.getPropertyValue(HEADER_SCROLL_PROPERTY) !== value) {
|
|
1088
|
-
marked.style.setProperty(HEADER_SCROLL_PROPERTY, value);
|
|
1089
|
-
}
|
|
1090
|
-
};
|
|
1091
|
-
const leadsWithWorkspace = () => {
|
|
1092
|
-
for (const group of document2.querySelectorAll(host.workspaceGroup)) {
|
|
1093
|
-
if (group.hasAttribute("data-ccd-empty-group")) continue;
|
|
1094
|
-
return group.querySelector(anchors.workspaceRows) !== null;
|
|
1095
|
-
}
|
|
1096
|
-
return false;
|
|
1097
|
-
};
|
|
1098
1079
|
const name = (element, noHistory) => {
|
|
1099
1080
|
if (element === null) return;
|
|
1100
1081
|
const walker = document2.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
@@ -1113,26 +1094,6 @@ function mountBrowserHeader(document2, report) {
|
|
|
1113
1094
|
const sync = () => {
|
|
1114
1095
|
scheduled = 0;
|
|
1115
1096
|
if (disposed) return;
|
|
1116
|
-
const root = document2.querySelector(host.browserRoot);
|
|
1117
|
-
if (root !== marked) {
|
|
1118
|
-
marked?.removeAttribute(BROWSER_HEADER_ATTRIBUTE);
|
|
1119
|
-
marked?.style.removeProperty(HEADER_SCROLL_PROPERTY);
|
|
1120
|
-
marked = root;
|
|
1121
|
-
}
|
|
1122
|
-
if (root !== null) {
|
|
1123
|
-
const merged = leadsWithWorkspace();
|
|
1124
|
-
if (merged !== root.hasAttribute(BROWSER_HEADER_ATTRIBUTE)) {
|
|
1125
|
-
if (merged) root.setAttribute(BROWSER_HEADER_ATTRIBUTE, "");
|
|
1126
|
-
else root.removeAttribute(BROWSER_HEADER_ATTRIBUTE);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
const next = document2.querySelector(host.browserList);
|
|
1130
|
-
if (next !== scroller) {
|
|
1131
|
-
scroller?.removeEventListener("scroll", publish);
|
|
1132
|
-
scroller = next;
|
|
1133
|
-
scroller?.addEventListener("scroll", publish, { passive: true });
|
|
1134
|
-
}
|
|
1135
|
-
publish();
|
|
1136
1097
|
name(
|
|
1137
1098
|
document2.querySelector(host.browserSectionLabel),
|
|
1138
1099
|
document2.querySelector('[data-ccd-empty-state="new"]') !== null
|
|
@@ -1153,14 +1114,6 @@ function mountBrowserHeader(document2, report) {
|
|
|
1153
1114
|
}
|
|
1154
1115
|
rewritten.clear();
|
|
1155
1116
|
};
|
|
1156
|
-
const clear2 = () => {
|
|
1157
|
-
marked?.removeAttribute(BROWSER_HEADER_ATTRIBUTE);
|
|
1158
|
-
marked?.style.removeProperty(HEADER_SCROLL_PROPERTY);
|
|
1159
|
-
marked = null;
|
|
1160
|
-
scroller?.removeEventListener("scroll", publish);
|
|
1161
|
-
scroller = null;
|
|
1162
|
-
restore();
|
|
1163
|
-
};
|
|
1164
1117
|
try {
|
|
1165
1118
|
observer = new MutationObserver(schedule);
|
|
1166
1119
|
observer.observe(document2.body, {
|
|
@@ -1168,14 +1121,12 @@ function mountBrowserHeader(document2, report) {
|
|
|
1168
1121
|
subtree: true,
|
|
1169
1122
|
characterData: true,
|
|
1170
1123
|
attributes: true,
|
|
1171
|
-
|
|
1172
|
-
facts the merge and the word both turn on. */
|
|
1173
|
-
attributeFilter: ["data-row-key", "data-ccd-empty-group", "data-ccd-empty-state"]
|
|
1124
|
+
attributeFilter: ["data-ccd-empty-state"]
|
|
1174
1125
|
});
|
|
1175
1126
|
sync();
|
|
1176
1127
|
} catch (error) {
|
|
1177
1128
|
observer?.disconnect();
|
|
1178
|
-
|
|
1129
|
+
restore();
|
|
1179
1130
|
report(error);
|
|
1180
1131
|
return () => {
|
|
1181
1132
|
};
|
|
@@ -1184,7 +1135,7 @@ function mountBrowserHeader(document2, report) {
|
|
|
1184
1135
|
disposed = true;
|
|
1185
1136
|
scheduled = 0;
|
|
1186
1137
|
observer?.disconnect();
|
|
1187
|
-
|
|
1138
|
+
restore();
|
|
1188
1139
|
};
|
|
1189
1140
|
}
|
|
1190
1141
|
|
|
@@ -2177,6 +2128,91 @@ function paneIcon(name) {
|
|
|
2177
2128
|
return ICONS[name];
|
|
2178
2129
|
}
|
|
2179
2130
|
|
|
2131
|
+
// src/client/compat/pane-labels.ts
|
|
2132
|
+
var ZH2 = {
|
|
2133
|
+
files: {
|
|
2134
|
+
title: "\u6587\u4EF6",
|
|
2135
|
+
filter: "\u8FC7\u6EE4\u6587\u4EF6\uFF0C\u6216\u6309 ? \u5728\u6587\u4EF6\u5185\u5BB9\u4E2D\u641C\u7D22",
|
|
2136
|
+
filterLabel: "\u8FC7\u6EE4\u6587\u4EF6",
|
|
2137
|
+
clear: "\u6E05\u9664\u8FC7\u6EE4",
|
|
2138
|
+
hide: "\u6536\u8D77\u6587\u4EF6\u6811",
|
|
2139
|
+
show: "\u5C55\u5F00\u6587\u4EF6\u6811",
|
|
2140
|
+
noMatch: "\u6CA1\u6709\u5339\u914D\u7684\u6587\u4EF6",
|
|
2141
|
+
emptyTitle: "\u6253\u5F00\u7684\u6587\u4EF6\u4F1A\u663E\u793A\u5728\u8FD9\u91CC",
|
|
2142
|
+
emptyBody: "\u5728\u6587\u4EF6\u6811\u4E2D\u9009\u62E9\u4E00\u4E2A\u6587\u4EF6\uFF0C\u6216\u70B9\u51FB\u5BF9\u8BDD\u4E2D\u7684\u6587\u4EF6\u8DEF\u5F84\u3002"
|
|
2143
|
+
},
|
|
2144
|
+
chrome: {
|
|
2145
|
+
more: "\u66F4\u591A",
|
|
2146
|
+
expand: "\u653E\u5927\u9762\u677F",
|
|
2147
|
+
restore: "\u8FD8\u539F\u9762\u677F",
|
|
2148
|
+
search: "\u641C\u7D22\u6587\u4EF6",
|
|
2149
|
+
reload: "\u5237\u65B0",
|
|
2150
|
+
back: "\u540E\u9000",
|
|
2151
|
+
forward: "\u524D\u8FDB",
|
|
2152
|
+
pick: "\u9009\u53D6\u5143\u7D20 \u2014 DSH \u6682\u4E0D\u652F\u6301\u7F51\u9875\u5143\u7D20\u9009\u53D6",
|
|
2153
|
+
pickNotice: "DSH \u6682\u4E0D\u652F\u6301\u9009\u53D6\u6D4F\u89C8\u5668\u9875\u9762\u5143\u7D20\u3002",
|
|
2154
|
+
address: "\u7F16\u8F91\u5730\u5740",
|
|
2155
|
+
terminal: "\u7EC8\u7AEF",
|
|
2156
|
+
terminals: "\u7EC8\u7AEF",
|
|
2157
|
+
newTerminal: "\u65B0\u5EFA\u7EC8\u7AEF",
|
|
2158
|
+
closeTab: "\u5173\u95ED",
|
|
2159
|
+
refresh: "\u5237\u65B0\u6587\u4EF6",
|
|
2160
|
+
openFolder: "\u5728\u5E94\u7528\u4E2D\u6253\u5F00\u6587\u4EF6\u5939",
|
|
2161
|
+
hideSidebar: "\u6536\u8D77\u4FA7\u8FB9\u680F",
|
|
2162
|
+
close: "\u5173\u95ED"
|
|
2163
|
+
},
|
|
2164
|
+
browser: {
|
|
2165
|
+
saveScreenshot: "\u4FDD\u5B58\u622A\u56FE",
|
|
2166
|
+
awaitingServer: "\u7B49\u5F85\u670D\u52A1\u5668\u54CD\u5E94\u2026",
|
|
2167
|
+
enterAddress: "\u8F93\u5165\u670D\u52A1\u5730\u5740"
|
|
2168
|
+
}
|
|
2169
|
+
};
|
|
2170
|
+
var EN2 = {
|
|
2171
|
+
files: {
|
|
2172
|
+
title: "Files",
|
|
2173
|
+
filter: "Filter, or ? to search in files",
|
|
2174
|
+
filterLabel: "Filter files",
|
|
2175
|
+
clear: "Clear filter",
|
|
2176
|
+
hide: "Hide file tree",
|
|
2177
|
+
show: "Show file tree",
|
|
2178
|
+
noMatch: "No matching files",
|
|
2179
|
+
emptyTitle: "Open files appear here",
|
|
2180
|
+
emptyBody: "Pick a file in the tree, or click a file path in the conversation."
|
|
2181
|
+
},
|
|
2182
|
+
chrome: {
|
|
2183
|
+
more: "More",
|
|
2184
|
+
expand: "Expand pane",
|
|
2185
|
+
restore: "Restore pane",
|
|
2186
|
+
search: "Search files",
|
|
2187
|
+
reload: "Reload",
|
|
2188
|
+
back: "Back",
|
|
2189
|
+
forward: "Forward",
|
|
2190
|
+
pick: "Select element \u2014 DSH does not support page picking",
|
|
2191
|
+
pickNotice: "DSH does not support picking browser page elements yet.",
|
|
2192
|
+
address: "Edit address",
|
|
2193
|
+
terminal: "Terminal",
|
|
2194
|
+
terminals: "Terminals",
|
|
2195
|
+
newTerminal: "New terminal",
|
|
2196
|
+
closeTab: "Close",
|
|
2197
|
+
refresh: "Refresh files",
|
|
2198
|
+
openFolder: "Open folder in app",
|
|
2199
|
+
hideSidebar: "Hide sidebar",
|
|
2200
|
+
close: "Close"
|
|
2201
|
+
},
|
|
2202
|
+
browser: {
|
|
2203
|
+
saveScreenshot: "Save screenshot",
|
|
2204
|
+
awaitingServer: "Awaiting server\u2026",
|
|
2205
|
+
enterAddress: "Enter server address"
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
function paneLanguage(document2) {
|
|
2209
|
+
const language = (document2.documentElement.lang || globalThis.navigator?.language || "").toLowerCase();
|
|
2210
|
+
return language.startsWith("zh") ? "zh" : "en";
|
|
2211
|
+
}
|
|
2212
|
+
function paneLabels(language) {
|
|
2213
|
+
return language === "zh" ? ZH2 : EN2;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2180
2216
|
// src/client/compat/files-pane.ts
|
|
2181
2217
|
var TREE_ATTRIBUTE = "data-ccd-files-tree";
|
|
2182
2218
|
var ROW_ATTRIBUTE = "data-ccd-files-hidden";
|
|
@@ -2192,16 +2228,6 @@ var EMPTY_MARK_ATTRIBUTE = "data-ccd-files-empty-mark";
|
|
|
2192
2228
|
var EMPTY_TITLE_ATTRIBUTE = "data-ccd-files-empty-title";
|
|
2193
2229
|
var EMPTY_BODY_ATTRIBUTE = "data-ccd-files-empty-body";
|
|
2194
2230
|
var NOMATCH_ATTRIBUTE = "data-ccd-files-nomatch";
|
|
2195
|
-
var COPY = Object.freeze({
|
|
2196
|
-
filter: "Filter, or ? to search in files",
|
|
2197
|
-
filterLabel: "\u8FC7\u6EE4\u6587\u4EF6",
|
|
2198
|
-
clear: "\u6E05\u9664\u8FC7\u6EE4",
|
|
2199
|
-
hide: "\u6536\u8D77\u6587\u4EF6\u6811",
|
|
2200
|
-
show: "\u5C55\u5F00\u6587\u4EF6\u6811",
|
|
2201
|
-
noMatch: "\u6CA1\u6709\u5339\u914D\u7684\u6587\u4EF6",
|
|
2202
|
-
emptyTitle: "Open files appear here",
|
|
2203
|
-
emptyBody: "Pick a file in the tree, or click a file path in the conversation."
|
|
2204
|
-
});
|
|
2205
2231
|
function basename(path) {
|
|
2206
2232
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
2207
2233
|
}
|
|
@@ -2214,12 +2240,10 @@ function headerOf(root) {
|
|
|
2214
2240
|
}
|
|
2215
2241
|
return null;
|
|
2216
2242
|
}
|
|
2217
|
-
function iconButton(document2, attribute
|
|
2243
|
+
function iconButton(document2, attribute) {
|
|
2218
2244
|
const button = document2.createElement("button");
|
|
2219
2245
|
button.type = "button";
|
|
2220
2246
|
button.setAttribute(attribute, "");
|
|
2221
|
-
button.setAttribute("aria-label", label);
|
|
2222
|
-
button.title = label;
|
|
2223
2247
|
return button;
|
|
2224
2248
|
}
|
|
2225
2249
|
function buildField(document2) {
|
|
@@ -2229,9 +2253,7 @@ function buildField(document2) {
|
|
|
2229
2253
|
input.type = "text";
|
|
2230
2254
|
input.spellcheck = false;
|
|
2231
2255
|
input.autocomplete = "off";
|
|
2232
|
-
|
|
2233
|
-
input.setAttribute("aria-label", COPY.filterLabel);
|
|
2234
|
-
const clear2 = iconButton(document2, CLEAR_ATTRIBUTE, COPY.clear);
|
|
2256
|
+
const clear2 = iconButton(document2, CLEAR_ATTRIBUTE);
|
|
2235
2257
|
clear2.hidden = true;
|
|
2236
2258
|
const search = document2.createElement("span");
|
|
2237
2259
|
search.setAttribute("data-ccd-files-search-icon", "");
|
|
@@ -2248,10 +2270,8 @@ function buildEmpty(document2) {
|
|
|
2248
2270
|
mark.innerHTML = paneIcon("Folder");
|
|
2249
2271
|
const title = document2.createElement("p");
|
|
2250
2272
|
title.setAttribute(EMPTY_TITLE_ATTRIBUTE, "");
|
|
2251
|
-
title.textContent = COPY.emptyTitle;
|
|
2252
2273
|
const body = document2.createElement("p");
|
|
2253
2274
|
body.setAttribute(EMPTY_BODY_ATTRIBUTE, "");
|
|
2254
|
-
body.textContent = COPY.emptyBody;
|
|
2255
2275
|
block.append(mark, title, body);
|
|
2256
2276
|
return block;
|
|
2257
2277
|
}
|
|
@@ -2261,12 +2281,38 @@ function mountFilesPane(document2, report) {
|
|
|
2261
2281
|
const preferences = /* @__PURE__ */ new Map();
|
|
2262
2282
|
const empties = /* @__PURE__ */ new Map();
|
|
2263
2283
|
const marks = /* @__PURE__ */ new Map();
|
|
2284
|
+
const name = (element, label) => {
|
|
2285
|
+
if (element.getAttribute("aria-label") !== label) element.setAttribute("aria-label", label);
|
|
2286
|
+
if (element.title !== label) element.title = label;
|
|
2287
|
+
};
|
|
2288
|
+
const text = (element, value) => {
|
|
2289
|
+
if (element !== null && element.textContent !== value) element.textContent = value;
|
|
2290
|
+
};
|
|
2291
|
+
const writeEmpty = (block, labels) => {
|
|
2292
|
+
text(block.querySelector(`[${EMPTY_TITLE_ATTRIBUTE}]`), labels.emptyTitle);
|
|
2293
|
+
text(block.querySelector(`[${EMPTY_BODY_ATTRIBUTE}]`), labels.emptyBody);
|
|
2294
|
+
};
|
|
2295
|
+
const labelToggle = (pane) => {
|
|
2296
|
+
const hidden = pane.root.hasAttribute(TREE_ATTRIBUTE);
|
|
2297
|
+
pane.toggle.setAttribute("aria-expanded", hidden ? "false" : "true");
|
|
2298
|
+
name(pane.toggle, hidden ? pane.labels.show : pane.labels.hide);
|
|
2299
|
+
};
|
|
2300
|
+
const applyCopy = (pane) => {
|
|
2301
|
+
pane.language = paneLanguage(document2);
|
|
2302
|
+
pane.labels = paneLabels(pane.language).files;
|
|
2303
|
+
if (pane.input.placeholder !== pane.labels.filter) pane.input.placeholder = pane.labels.filter;
|
|
2304
|
+
name(pane.input, pane.labels.filterLabel);
|
|
2305
|
+
name(pane.clear, pane.labels.clear);
|
|
2306
|
+
name(pane.expand, pane.labels.show);
|
|
2307
|
+
text(pane.expand, pane.labels.show);
|
|
2308
|
+
labelToggle(pane);
|
|
2309
|
+
text(pane.noMatch, pane.labels.noMatch);
|
|
2310
|
+
writeEmpty(pane.landing, pane.labels);
|
|
2311
|
+
};
|
|
2264
2312
|
const setTree = (pane, hidden) => {
|
|
2265
2313
|
if (hidden) pane.root.setAttribute(TREE_ATTRIBUTE, "hidden");
|
|
2266
2314
|
else pane.root.removeAttribute(TREE_ATTRIBUTE);
|
|
2267
|
-
pane
|
|
2268
|
-
pane.toggle.setAttribute("aria-label", hidden ? COPY.show : COPY.hide);
|
|
2269
|
-
pane.toggle.title = hidden ? COPY.show : COPY.hide;
|
|
2315
|
+
labelToggle(pane);
|
|
2270
2316
|
preferences.set(pane.key, { query: pane.query, hidden });
|
|
2271
2317
|
window.dispatchEvent(new Event("resize"));
|
|
2272
2318
|
};
|
|
@@ -2281,8 +2327,8 @@ function mountFilesPane(document2, report) {
|
|
|
2281
2327
|
const visible = /* @__PURE__ */ new Set();
|
|
2282
2328
|
let hits = 0;
|
|
2283
2329
|
for (const row of rows) {
|
|
2284
|
-
const
|
|
2285
|
-
if (!
|
|
2330
|
+
const name2 = basename(row.getAttribute("data-files-path") ?? "").toLowerCase();
|
|
2331
|
+
if (!name2.includes(query)) continue;
|
|
2286
2332
|
hits++;
|
|
2287
2333
|
for (let node = row; node !== null; node = enclosingRow(node)) visible.add(node);
|
|
2288
2334
|
}
|
|
@@ -2302,13 +2348,11 @@ function mountFilesPane(document2, report) {
|
|
|
2302
2348
|
const adopt = (root, body) => {
|
|
2303
2349
|
const header = headerOf(root);
|
|
2304
2350
|
if (header === null) return;
|
|
2305
|
-
const toggle2 = iconButton(document2, TOGGLE_ATTRIBUTE
|
|
2351
|
+
const toggle2 = iconButton(document2, TOGGLE_ATTRIBUTE);
|
|
2306
2352
|
const { field, input, clear: clear2 } = buildField(document2);
|
|
2307
|
-
const expand = iconButton(document2, EXPAND_ATTRIBUTE
|
|
2308
|
-
expand.append(COPY.show);
|
|
2353
|
+
const expand = iconButton(document2, EXPAND_ATTRIBUTE);
|
|
2309
2354
|
const noMatch = document2.createElement("p");
|
|
2310
2355
|
noMatch.setAttribute(NOMATCH_ATTRIBUTE, "");
|
|
2311
|
-
noMatch.textContent = COPY.noMatch;
|
|
2312
2356
|
noMatch.hidden = true;
|
|
2313
2357
|
header.prepend(field);
|
|
2314
2358
|
header.prepend(toggle2);
|
|
@@ -2320,6 +2364,7 @@ function mountFilesPane(document2, report) {
|
|
|
2320
2364
|
root.append(landing);
|
|
2321
2365
|
const key = `${root.closest("[data-sidebar-right-session]")?.getAttribute("data-sidebar-right-session")}:${root.closest("[data-dockkit-content]")?.getAttribute("data-dockkit-content")}`;
|
|
2322
2366
|
const saved = preferences.get(key);
|
|
2367
|
+
const language = paneLanguage(document2);
|
|
2323
2368
|
const pane = {
|
|
2324
2369
|
root,
|
|
2325
2370
|
body,
|
|
@@ -2331,9 +2376,12 @@ function mountFilesPane(document2, report) {
|
|
|
2331
2376
|
noMatch,
|
|
2332
2377
|
landing,
|
|
2333
2378
|
key,
|
|
2379
|
+
language,
|
|
2380
|
+
labels: paneLabels(language).files,
|
|
2334
2381
|
query: saved?.query ?? ""
|
|
2335
2382
|
};
|
|
2336
2383
|
panes.set(root, pane);
|
|
2384
|
+
applyCopy(pane);
|
|
2337
2385
|
input.addEventListener("input", () => setQuery(pane, input.value));
|
|
2338
2386
|
input.addEventListener("keydown", (event) => {
|
|
2339
2387
|
if (event.key !== "Escape" || input.value === "") return;
|
|
@@ -2390,11 +2438,14 @@ function mountFilesPane(document2, report) {
|
|
|
2390
2438
|
empties.set(line, block);
|
|
2391
2439
|
}
|
|
2392
2440
|
if (block.parentElement !== body) body.append(block);
|
|
2441
|
+
writeEmpty(block, paneLabels(paneLanguage(document2)).files);
|
|
2393
2442
|
};
|
|
2394
2443
|
const sync = () => {
|
|
2395
2444
|
for (const pane of [...panes.values()]) {
|
|
2396
2445
|
if (!pane.root.isConnected || pane.body !== pane.root.querySelector(host.filesBody) || pane.field.parentElement !== headerOf(pane.root)) release(pane);
|
|
2397
2446
|
}
|
|
2447
|
+
const language = paneLanguage(document2);
|
|
2448
|
+
for (const pane of panes.values()) if (pane.language !== language) applyCopy(pane);
|
|
2398
2449
|
for (const root of document2.querySelectorAll(host.filesRoot)) {
|
|
2399
2450
|
const body = root.querySelector(host.filesBody);
|
|
2400
2451
|
if (body === null) continue;
|
|
@@ -2426,6 +2477,7 @@ function mountFilesPane(document2, report) {
|
|
|
2426
2477
|
try {
|
|
2427
2478
|
observer = new MutationObserver(sync);
|
|
2428
2479
|
observer.observe(document2.body, { childList: true, subtree: true });
|
|
2480
|
+
observer.observe(document2.documentElement, { attributes: true, attributeFilter: ["lang"] });
|
|
2429
2481
|
sync();
|
|
2430
2482
|
} catch (error) {
|
|
2431
2483
|
observer?.disconnect();
|
|
@@ -2519,7 +2571,8 @@ function mountBrowserMenus(node, actions) {
|
|
|
2519
2571
|
};
|
|
2520
2572
|
const more = (anchor) => {
|
|
2521
2573
|
const content = menu("capture");
|
|
2522
|
-
const
|
|
2574
|
+
const labels = paneLabels(paneLanguage(document2));
|
|
2575
|
+
const save = row(content, labels.browser.saveScreenshot, () => {
|
|
2523
2576
|
void capture(anchor);
|
|
2524
2577
|
}, "data-ccd-browser-save-screenshot");
|
|
2525
2578
|
save.disabled = !canCapture();
|
|
@@ -2556,9 +2609,12 @@ function mountPaneChrome(node) {
|
|
|
2556
2609
|
if (!grip || !title || !close) return null;
|
|
2557
2610
|
let options;
|
|
2558
2611
|
let signature = "";
|
|
2612
|
+
let labels = paneLabels(paneLanguage(document2));
|
|
2559
2613
|
let menu = null;
|
|
2560
2614
|
let form = null;
|
|
2561
2615
|
let wait = null;
|
|
2616
|
+
let waitText = null;
|
|
2617
|
+
let fallbackPlaceholder = "";
|
|
2562
2618
|
let menuAnchor = null;
|
|
2563
2619
|
let addressSlot = null;
|
|
2564
2620
|
const paths = /* @__PURE__ */ new Map();
|
|
@@ -2584,7 +2640,14 @@ function mountPaneChrome(node) {
|
|
|
2584
2640
|
event.preventDefault();
|
|
2585
2641
|
event.stopImmediatePropagation();
|
|
2586
2642
|
const { closeTabs, onClose } = options;
|
|
2587
|
-
|
|
2643
|
+
const pending = [...closeTabs];
|
|
2644
|
+
const step = () => {
|
|
2645
|
+
const id = pending.shift();
|
|
2646
|
+
if (id === void 0) return;
|
|
2647
|
+
if (document2.querySelector(`[data-dockkit-content="${id}"]`) !== null) onClose(id);
|
|
2648
|
+
window.setTimeout(step, 0);
|
|
2649
|
+
};
|
|
2650
|
+
window.setTimeout(step, 0);
|
|
2588
2651
|
};
|
|
2589
2652
|
close.addEventListener("click", closeGroup, true);
|
|
2590
2653
|
const dismiss = () => {
|
|
@@ -2656,16 +2719,16 @@ function mountPaneChrome(node) {
|
|
|
2656
2719
|
};
|
|
2657
2720
|
const files = options.filesRoot;
|
|
2658
2721
|
if (files) {
|
|
2659
|
-
item(files.hasAttribute("data-ccd-files-tree") ?
|
|
2660
|
-
item(
|
|
2722
|
+
item(files.hasAttribute("data-ccd-files-tree") ? labels.files.show : labels.files.hide, () => files.querySelector("[data-ccd-files-toggle]")?.click());
|
|
2723
|
+
item(labels.chrome.refresh, () => files.querySelector("[data-files-reload]")?.click());
|
|
2661
2724
|
const open = files.querySelector('[data-slot="sidebar.right.tab.files.actions"] button');
|
|
2662
|
-
if (open) item(open.getAttribute("aria-label") ??
|
|
2725
|
+
if (open) item(open.getAttribute("aria-label") ?? labels.chrome.openFolder, () => open.click());
|
|
2663
2726
|
}
|
|
2664
2727
|
for (const file of options.files) item(`${file.selected ? "\u2713 " : ""}${file.title}`, () => options.onSelect(file.id));
|
|
2665
|
-
item(options.zoomed ?
|
|
2728
|
+
item(options.zoomed ? labels.chrome.restore : labels.chrome.expand, options.onZoom);
|
|
2666
2729
|
const collapse = options.panel.querySelector("[data-sidebar-right-toggle]");
|
|
2667
|
-
if (collapse) item(
|
|
2668
|
-
item(
|
|
2730
|
+
if (collapse) item(labels.chrome.hideSidebar, () => collapse.click());
|
|
2731
|
+
item(labels.chrome.close, () => close.click());
|
|
2669
2732
|
popup(anchor, content);
|
|
2670
2733
|
content.querySelector("button")?.focus();
|
|
2671
2734
|
};
|
|
@@ -2739,7 +2802,10 @@ function mountPaneChrome(node) {
|
|
|
2739
2802
|
if (form) {
|
|
2740
2803
|
form.setAttribute("data-ccd-browser-toolbar", "");
|
|
2741
2804
|
const input = form.querySelector("input");
|
|
2742
|
-
if (input &&
|
|
2805
|
+
if (input !== null && (input.placeholder === "" || input.placeholder === fallbackPlaceholder)) {
|
|
2806
|
+
input.placeholder = labels.browser.enterAddress;
|
|
2807
|
+
fallbackPlaceholder = labels.browser.enterAddress;
|
|
2808
|
+
}
|
|
2743
2809
|
}
|
|
2744
2810
|
}
|
|
2745
2811
|
syncAddress();
|
|
@@ -2753,6 +2819,7 @@ function mountPaneChrome(node) {
|
|
|
2753
2819
|
if (!area || loaded) {
|
|
2754
2820
|
wait?.remove();
|
|
2755
2821
|
wait = null;
|
|
2822
|
+
waitText = null;
|
|
2756
2823
|
return;
|
|
2757
2824
|
}
|
|
2758
2825
|
if (wait?.parentElement !== area) {
|
|
@@ -2763,28 +2830,30 @@ function mountPaneChrome(node) {
|
|
|
2763
2830
|
mark.setAttribute("data-ccd-browser-wait-mark", "");
|
|
2764
2831
|
mark.innerHTML = '<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="3" y="4" width="18" height="13" rx="2" stroke="currentColor" stroke-width="1.4"/><path d="M12 17v4m-4 0h8" stroke="currentColor" stroke-width="1.4"/></svg>';
|
|
2765
2832
|
const text = document2.createElement("span");
|
|
2766
|
-
|
|
2833
|
+
waitText = text;
|
|
2767
2834
|
wait.append(mark, text);
|
|
2768
2835
|
area.append(wait);
|
|
2769
2836
|
}
|
|
2837
|
+
if (waitText !== null && waitText.textContent !== labels.browser.awaitingServer) waitText.textContent = labels.browser.awaitingServer;
|
|
2770
2838
|
wait.setAttribute("data-ccd-browser-wait", area.getAttribute("aria-busy") === "true" ? "loading" : "idle");
|
|
2771
2839
|
};
|
|
2772
2840
|
const observer = new MutationObserver(refreshNative);
|
|
2773
2841
|
observer.observe(node, { subtree: true, childList: true, attributes: true, attributeFilter: ["disabled", "aria-busy", "title"] });
|
|
2774
2842
|
const terminalText = (element, text) => {
|
|
2775
|
-
const match = /^(Terminal(?: \d+)?)(?: (.*))?$/u.exec(text);
|
|
2776
|
-
element.textContent = match
|
|
2777
|
-
if (match?.[
|
|
2843
|
+
const match = /^(Terminal|终端)((?: \d+)?)(?: (.*))?$/u.exec(text);
|
|
2844
|
+
element.textContent = match === null ? text : `${match[1]}${match[2] ?? ""}`;
|
|
2845
|
+
if (match?.[3]) {
|
|
2778
2846
|
const workspace = document2.createElement("span");
|
|
2779
2847
|
workspace.setAttribute("data-ccd-terminal-workspace", "");
|
|
2780
|
-
workspace.textContent = ` ${match[
|
|
2848
|
+
workspace.textContent = ` ${match[3]}`;
|
|
2781
2849
|
element.append(workspace);
|
|
2782
2850
|
}
|
|
2783
2851
|
};
|
|
2784
2852
|
const update = (next) => {
|
|
2785
2853
|
options = next;
|
|
2854
|
+
labels = paneLabels(paneLanguage(document2));
|
|
2786
2855
|
const hidden = next.filesRoot?.hasAttribute("data-ccd-files-tree") ?? false;
|
|
2787
|
-
const value = `${next.kind}|${next.title}|${next.zoomed}|${hidden}|${next.files.map((file) => `${file.id}:${file.selected}`).join(",")}|${next.terminals.map((tab) => `${tab.id}:${tab.title}:${tab.selected}`).join(",")}`;
|
|
2856
|
+
const value = `${paneLanguage(document2)}|${next.kind}|${next.title}|${next.zoomed}|${hidden}|${next.files.map((file) => `${file.id}:${file.selected}`).join(",")}|${next.terminals.map((tab) => `${tab.id}:${tab.title}:${tab.selected}`).join(",")}`;
|
|
2788
2857
|
if (value === signature) {
|
|
2789
2858
|
refreshNative();
|
|
2790
2859
|
return;
|
|
@@ -2797,8 +2866,7 @@ function mountPaneChrome(node) {
|
|
|
2797
2866
|
controls.replaceChildren();
|
|
2798
2867
|
node.setAttribute("data-ccd-pane-kind", next.kind);
|
|
2799
2868
|
if (next.kind === "browser") {
|
|
2800
|
-
const globe = button(caption,
|
|
2801
|
-
globe.title = "\u7F16\u8F91\u5730\u5740";
|
|
2869
|
+
const globe = button(caption, labels.chrome.address, "data-ccd-browser-address", "Globe", address);
|
|
2802
2870
|
globe.addEventListener("contextmenu", (event) => {
|
|
2803
2871
|
event.preventDefault();
|
|
2804
2872
|
dismiss();
|
|
@@ -2808,14 +2876,14 @@ function mountPaneChrome(node) {
|
|
|
2808
2876
|
addressSlot.setAttribute("data-ccd-browser-address-slot", "");
|
|
2809
2877
|
caption.append(addressSlot);
|
|
2810
2878
|
addressResize?.observe(addressSlot);
|
|
2811
|
-
button(controls,
|
|
2812
|
-
button(controls,
|
|
2813
|
-
const pick = button(controls,
|
|
2879
|
+
button(controls, labels.chrome.back, "data-ccd-browser-back", "CaretLeft", () => nativeNavigation(0)?.click());
|
|
2880
|
+
button(controls, labels.chrome.forward, "data-ccd-browser-forward", "CaretRight", () => nativeNavigation(1)?.click());
|
|
2881
|
+
const pick = button(controls, labels.chrome.pick, "data-ccd-browser-pick", "Cursor", (anchor) => notice(anchor, labels.chrome.pickNotice));
|
|
2814
2882
|
pick.setAttribute("aria-disabled", "true");
|
|
2815
|
-
button(controls,
|
|
2883
|
+
button(controls, labels.chrome.reload, "data-ccd-browser-reload", "ArrowClockwise", () => nativeNavigation(2)?.click());
|
|
2816
2884
|
} else {
|
|
2817
2885
|
if (next.filesRoot) {
|
|
2818
|
-
const toggle2 = button(caption, hidden ?
|
|
2886
|
+
const toggle2 = button(caption, hidden ? labels.files.show : labels.files.hide, "data-ccd-files-switch", "Files", () => next.filesRoot?.querySelector("[data-ccd-files-toggle]")?.click());
|
|
2819
2887
|
toggle2.setAttribute("data-ccd-files-mark", "");
|
|
2820
2888
|
toggle2.setAttribute("aria-expanded", String(!hidden));
|
|
2821
2889
|
}
|
|
@@ -2823,7 +2891,7 @@ function mountPaneChrome(node) {
|
|
|
2823
2891
|
const tabs = document2.createElement("span");
|
|
2824
2892
|
tabs.setAttribute("data-ccd-terminal-tabs", "");
|
|
2825
2893
|
tabs.setAttribute("role", "tablist");
|
|
2826
|
-
tabs.setAttribute("aria-label",
|
|
2894
|
+
tabs.setAttribute("aria-label", labels.chrome.terminals);
|
|
2827
2895
|
caption.append(tabs);
|
|
2828
2896
|
for (const tab of next.terminals) {
|
|
2829
2897
|
const cell = document2.createElement("span");
|
|
@@ -2846,7 +2914,7 @@ function mountPaneChrome(node) {
|
|
|
2846
2914
|
document2.querySelector(`[data-dockkit-content="${next.terminals[target].id}"] [role="tab"][aria-selected="true"]`)?.focus();
|
|
2847
2915
|
});
|
|
2848
2916
|
cell.append(select);
|
|
2849
|
-
const remove = button(cell,
|
|
2917
|
+
const remove = button(cell, `${labels.chrome.closeTab} ${tab.title}`, "data-ccd-terminal-close", "X", () => next.onClose(tab.id));
|
|
2850
2918
|
remove.tabIndex = -1;
|
|
2851
2919
|
tabs.append(cell);
|
|
2852
2920
|
}
|
|
@@ -2856,18 +2924,18 @@ function mountPaneChrome(node) {
|
|
|
2856
2924
|
else name.textContent = next.title;
|
|
2857
2925
|
caption.append(name);
|
|
2858
2926
|
}
|
|
2859
|
-
if (next.kind === "terminal") button(caption,
|
|
2860
|
-
else if (next.filesRoot || next.kind === "text") button(controls,
|
|
2927
|
+
if (next.kind === "terminal") button(caption, labels.chrome.newTerminal, "data-ccd-terminal-add", "Add", next.onNew);
|
|
2928
|
+
else if (next.filesRoot || next.kind === "text") button(controls, labels.chrome.search, "data-ccd-pane-search", "Search", () => {
|
|
2861
2929
|
const toggle2 = next.filesRoot?.querySelector("[data-ccd-files-toggle]");
|
|
2862
2930
|
if (hidden) toggle2?.click();
|
|
2863
2931
|
next.filesRoot?.querySelector("[data-ccd-files-filter] input")?.focus();
|
|
2864
2932
|
});
|
|
2865
|
-
if (next.kind === "text") button(controls,
|
|
2933
|
+
if (next.kind === "text") button(controls, labels.chrome.reload, "data-ccd-preview-reload", "ArrowClockwise", () => node.querySelector('[data-textpreview-tool="reload"]')?.click());
|
|
2866
2934
|
}
|
|
2867
|
-
const more = button(controls,
|
|
2935
|
+
const more = button(controls, labels.chrome.more, "data-ccd-pane-more", "DotsVertical", next.kind === "browser" ? browserMenus.more : openMenu);
|
|
2868
2936
|
more.setAttribute("aria-haspopup", "menu");
|
|
2869
2937
|
more.setAttribute("aria-expanded", "false");
|
|
2870
|
-
button(controls, next.zoomed ?
|
|
2938
|
+
button(controls, next.zoomed ? labels.chrome.restore : labels.chrome.expand, "data-ccd-pane-zoom", next.zoomed ? "Collapse" : "Expand", next.onZoom);
|
|
2871
2939
|
refreshNative();
|
|
2872
2940
|
};
|
|
2873
2941
|
return { update, release() {
|
|
@@ -2880,6 +2948,8 @@ function mountPaneChrome(node) {
|
|
|
2880
2948
|
caption.remove();
|
|
2881
2949
|
controls.remove();
|
|
2882
2950
|
closeIcon.remove();
|
|
2951
|
+
waitText = null;
|
|
2952
|
+
fallbackPlaceholder = "";
|
|
2883
2953
|
for (const attribute of ["data-ccd-pane-chrome", "data-ccd-pane-kind"]) node.removeAttribute(attribute);
|
|
2884
2954
|
clearAddress(form);
|
|
2885
2955
|
for (const [source, label] of paths) {
|
|
@@ -3038,7 +3108,7 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3038
3108
|
const stateOf = (session) => {
|
|
3039
3109
|
let state = sessions.get(session);
|
|
3040
3110
|
if (state === void 0) {
|
|
3041
|
-
state = { layout: EMPTY_LAYOUT, preview: null, terminal: null, terminals: /* @__PURE__ */ new Set(), previews: /* @__PURE__ */ new Set(), fileShare: 0.4, maximized: null, requestedFiles: false, hadViews: false, active: null };
|
|
3111
|
+
state = { layout: EMPTY_LAYOUT, preview: null, terminal: null, terminals: /* @__PURE__ */ new Set(), previews: /* @__PURE__ */ new Set(), fileShare: 0.4, maximized: null, requestedFiles: false, hadViews: false, active: null, seeded: false, records: -1 };
|
|
3042
3112
|
sessions.set(session, state);
|
|
3043
3113
|
}
|
|
3044
3114
|
return state;
|
|
@@ -3052,6 +3122,21 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3052
3122
|
if (node.style.getPropertyValue(name) !== value) node.style.setProperty(name, value);
|
|
3053
3123
|
};
|
|
3054
3124
|
const isFile = (record) => record.kind === "text" && record.contentId?.startsWith("dsh-resource://file/") === true;
|
|
3125
|
+
const pairPreviewWithTree = (session, panel, state, records, previews, opened) => {
|
|
3126
|
+
if (previews.length === 0) state.requestedFiles = false;
|
|
3127
|
+
if (!opened || state.requestedFiles || records.some((record) => record.kind === "files")) return;
|
|
3128
|
+
state.requestedFiles = true;
|
|
3129
|
+
window.setTimeout(() => {
|
|
3130
|
+
if (disposed || !panel.isConnected || sessionOf2(panel) !== session) return;
|
|
3131
|
+
const live = (sidebar.openTabs?.getSnapshot?.() ?? []).filter((record) => record.sessionId === session);
|
|
3132
|
+
if (live.some((record) => record.kind === "files") || !live.some(isFile)) return;
|
|
3133
|
+
try {
|
|
3134
|
+
sidebar.openTab("files");
|
|
3135
|
+
} catch (error) {
|
|
3136
|
+
report(error);
|
|
3137
|
+
}
|
|
3138
|
+
}, 0);
|
|
3139
|
+
};
|
|
3055
3140
|
const groupsOf = (records, state, active) => {
|
|
3056
3141
|
const tree = records.find((record) => record.kind === "files");
|
|
3057
3142
|
const previews = records.filter(isFile).map((record) => record.tabId);
|
|
@@ -3142,7 +3227,8 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3142
3227
|
const kind = record?.kind ?? "";
|
|
3143
3228
|
const nativeTitle = node.querySelector("[data-dockkit-tab-title]")?.textContent?.trim() ?? "";
|
|
3144
3229
|
const terminalName = nativeTitle && !/^(?:zsh|bash|fish|pwsh|powershell|cmd|终端|terminal)$/iu.test(nativeTitle) && nativeTitle !== record?.tabId ? nativeTitle : workspace;
|
|
3145
|
-
const
|
|
3230
|
+
const labels = paneLabels(paneLanguage(document2));
|
|
3231
|
+
const title = kind === "files" ? labels.files.title : kind === "terminal" ? `${labels.chrome.terminal}${terminalName ? ` ${terminalName}` : ""}` : group.preview ? filename(group.preview) : node.querySelector("[data-dockkit-tab-title]")?.textContent?.trim() ?? "";
|
|
3146
3232
|
chrome.update({
|
|
3147
3233
|
kind,
|
|
3148
3234
|
title,
|
|
@@ -3172,7 +3258,7 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3172
3258
|
close.removeAttribute("data-ccd-close-tab");
|
|
3173
3259
|
}
|
|
3174
3260
|
},
|
|
3175
|
-
terminals: group.id === TERMINAL_GROUP ? group.tabs.map((id, index) => ({ id, title: group.tabs.length > 1 ?
|
|
3261
|
+
terminals: group.id === TERMINAL_GROUP ? group.tabs.map((id, index) => ({ id, title: group.tabs.length > 1 ? `${labels.chrome.terminal} ${index + 1}${workspace ? ` ${workspace}` : ""}` : title, selected: id === group.terminal })) : [],
|
|
3176
3262
|
files: group.tabs.filter((id) => id !== group.tree && records.find((record2) => record2.tabId === id)?.kind === "text").map((id) => ({ id, title: filename(id), selected: id === group.preview }))
|
|
3177
3263
|
});
|
|
3178
3264
|
};
|
|
@@ -3227,6 +3313,10 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3227
3313
|
const state = stateOf(session);
|
|
3228
3314
|
const records = (sidebar.openTabs?.getSnapshot?.() ?? []).filter((record) => record.sessionId === session);
|
|
3229
3315
|
const active = root.querySelector("[data-dockkit-float-active]")?.getAttribute("data-dockkit-content") ?? null;
|
|
3316
|
+
const previews = records.filter(isFile).map((record) => record.tabId);
|
|
3317
|
+
const opened = state.seeded && records.length >= state.records && previews.some((id) => !state.previews.has(id));
|
|
3318
|
+
state.seeded = true;
|
|
3319
|
+
state.records = records.length;
|
|
3230
3320
|
const groups = groupsOf(records, state, active);
|
|
3231
3321
|
const ids = groups.map((group) => group.id);
|
|
3232
3322
|
const activeGroup = groups.find((group) => group.tabs.includes(active ?? ""));
|
|
@@ -3244,21 +3334,24 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3244
3334
|
}
|
|
3245
3335
|
if (groups.length === 0) {
|
|
3246
3336
|
clear2();
|
|
3247
|
-
if (state.hadViews && panel.hasAttribute("data-sidebar-right-open"))
|
|
3337
|
+
if (state.hadViews && panel.hasAttribute("data-sidebar-right-open")) {
|
|
3338
|
+
window.setTimeout(() => {
|
|
3339
|
+
if (disposed || !panel.isConnected || !panel.hasAttribute("data-sidebar-right-open")) return;
|
|
3340
|
+
const live = (sidebar.openTabs?.getSnapshot?.() ?? []).filter((record) => record.sessionId === session);
|
|
3341
|
+
if (live.some((record) => record.kind !== "guide")) return;
|
|
3342
|
+
try {
|
|
3343
|
+
sidebar.toggleExpanded?.();
|
|
3344
|
+
} catch (error) {
|
|
3345
|
+
report(error);
|
|
3346
|
+
}
|
|
3347
|
+
}, 0);
|
|
3348
|
+
}
|
|
3248
3349
|
state.hadViews = false;
|
|
3249
3350
|
state.requestedFiles = false;
|
|
3250
3351
|
return;
|
|
3251
3352
|
}
|
|
3252
3353
|
state.hadViews = true;
|
|
3253
|
-
|
|
3254
|
-
state.requestedFiles = true;
|
|
3255
|
-
try {
|
|
3256
|
-
sidebar.openTab("files");
|
|
3257
|
-
} catch (error) {
|
|
3258
|
-
report(error);
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
if (!records.some(isFile)) state.requestedFiles = false;
|
|
3354
|
+
pairPreviewWithTree(session, panel, state, records, previews, opened);
|
|
3262
3355
|
const box = root.getBoundingClientRect();
|
|
3263
3356
|
let area = { x: box.x, y: box.y, width: box.width, height: box.height };
|
|
3264
3357
|
if (state.maximized !== null) {
|
|
@@ -3495,6 +3588,7 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3495
3588
|
try {
|
|
3496
3589
|
observer = new MutationObserver((mutations) => {
|
|
3497
3590
|
const relevant = mutations.some((mutation) => {
|
|
3591
|
+
if (mutation.type === "attributes" && mutation.attributeName === "lang" && mutation.target === document2.documentElement) return true;
|
|
3498
3592
|
const target = mutation.target instanceof Element ? mutation.target : mutation.target.parentElement;
|
|
3499
3593
|
if (target === null) return false;
|
|
3500
3594
|
if (mutation.type === "attributes" && mutation.attributeName === "hidden") return target.matches(host.rightbarSession);
|
|
@@ -3525,6 +3619,7 @@ function createRightPanes(document2, sidebar, report) {
|
|
|
3525
3619
|
"data-ccd-files-tree"
|
|
3526
3620
|
]
|
|
3527
3621
|
});
|
|
3622
|
+
observer.observe(document2.documentElement, { attributes: true, attributeFilter: ["lang"] });
|
|
3528
3623
|
if (typeof ResizeObserver === "function") resize = new ResizeObserver(schedule);
|
|
3529
3624
|
unsubscribe = sidebar.openTabs?.subscribe?.(schedule) ?? (() => {
|
|
3530
3625
|
});
|
|
@@ -3688,6 +3783,18 @@ function headerMenuActions(ctx) {
|
|
|
3688
3783
|
// src/client/compat/header-menus.ts
|
|
3689
3784
|
var CHEVRON = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m3.5 6 4.5 4.5L12.5 6"/></svg>';
|
|
3690
3785
|
var LAPTOP = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.35" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="2.5" width="11" height="8.5" rx="1"/><path d="M1 11h14v2H1z"/></svg>';
|
|
3786
|
+
var HEADER_MENU_ICONS = {
|
|
3787
|
+
"\u5728\u8BBF\u8FBE\u4E2D\u663E\u793A": '<path d="M1.5 5V3.5h5l1.5 2h6.5v8h-13V5Z"/>',
|
|
3788
|
+
"\u590D\u5236": '<rect x="5.5" y="1.5" width="8" height="10" rx="1"/><path d="M10.5 11.5v3h-8v-10h3"/>',
|
|
3789
|
+
"\u5728\u7EC8\u7AEF\u4E2D\u6253\u5F00": '<rect x="1.5" y="2.5" width="13" height="11" rx="1.5"/><path d="m4 6 2 2-2 2M8.5 10h3"/>',
|
|
3790
|
+
"\u6587\u4EF6\u5939\u8DEF\u5F84": '<path d="m6.5 5 1-1a3 3 0 0 1 4.25 4.25l-1 1M9.5 11l-1 1A3 3 0 0 1 4.25 7.75l1-1M6 10l4-4"/>',
|
|
3791
|
+
"\u6587\u4EF6\u5939\u540D\u79F0": '<path d="M2 4.5V3h4l1.5 2H14v8H2V4.5ZM5 8h6M5 10.5h4"/>',
|
|
3792
|
+
"\u6253\u5F00\u65B9\u5F0F": '<rect x="5" y="2" width="9" height="9" rx="1"/><path d="M11 11v3H2V5h3"/>',
|
|
3793
|
+
"\u91CD\u547D\u540D": '<path d="M3 10.5 2.5 14l3.5-.5L14 5.5 10.5 2 3 10.5ZM9 3.5l3.5 3.5"/>',
|
|
3794
|
+
"\u521B\u5EFA\u5206\u652F": '<circle cx="5" cy="3" r="1.5"/><circle cx="11" cy="4" r="1.5"/><circle cx="5" cy="13" r="1.5"/><path d="M5 4.5v7M11 5.5V7a3 3 0 0 1-3 3H5"/>',
|
|
3795
|
+
"\u5F52\u6863": '<rect x="1.5" y="2.5" width="13" height="3" rx=".75"/><path d="M2.5 5.5v8h11v-8M6 8h4"/>',
|
|
3796
|
+
"\u5220\u9664": '<path d="M2 4.5h12M6 4.5V2h4v2.5M3.5 4.5l1 9h7l1-9"/>'
|
|
3797
|
+
};
|
|
3691
3798
|
function mountHeaderMenus(document2, actions, report) {
|
|
3692
3799
|
const host = hostSelectors(document2);
|
|
3693
3800
|
const window2 = document2.defaultView;
|
|
@@ -3787,7 +3894,16 @@ function mountHeaderMenus(document2, actions, report) {
|
|
|
3787
3894
|
const row = (menu, label, act, mark = "", unavailable2 = "") => {
|
|
3788
3895
|
const node = button("");
|
|
3789
3896
|
node.setAttribute("role", "menuitem");
|
|
3897
|
+
const artwork = HEADER_MENU_ICONS[label];
|
|
3898
|
+
if (artwork !== void 0) {
|
|
3899
|
+
const icon = document2.createElement("span");
|
|
3900
|
+
icon.setAttribute("data-ccd-header-row-icon", "");
|
|
3901
|
+
icon.setAttribute("aria-hidden", "true");
|
|
3902
|
+
icon.innerHTML = `<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.15" stroke-linecap="round" stroke-linejoin="round">${artwork}</svg>`;
|
|
3903
|
+
node.append(icon);
|
|
3904
|
+
}
|
|
3790
3905
|
const text = document2.createElement("span");
|
|
3906
|
+
text.setAttribute("data-ccd-header-row-label", "");
|
|
3791
3907
|
text.textContent = label;
|
|
3792
3908
|
node.append(text);
|
|
3793
3909
|
if (mark !== "") {
|
|
@@ -4178,6 +4294,7 @@ var BUILT_IN_DARK = Object.freeze({
|
|
|
4178
4294
|
track: "#1f1e1d",
|
|
4179
4295
|
raised: "#2f2f2d",
|
|
4180
4296
|
hover: "#313130",
|
|
4297
|
+
hoverStrong: "#474743",
|
|
4181
4298
|
selected: "#3a3a37",
|
|
4182
4299
|
border: "#3e3e3b",
|
|
4183
4300
|
borderStrong: "#474743",
|
|
@@ -4187,6 +4304,7 @@ var BUILT_IN_DARK = Object.freeze({
|
|
|
4187
4304
|
var WHITE = Object.freeze({ r: 255, g: 255, b: 255 });
|
|
4188
4305
|
var BLACK = Object.freeze({ r: 0, g: 0, b: 0 });
|
|
4189
4306
|
var HOVER_INK = 0.05;
|
|
4307
|
+
var HOVER_STRONG_INK = 0.105;
|
|
4190
4308
|
var SELECTED_INK = 0.06;
|
|
4191
4309
|
var TRACK_INK = 0.04;
|
|
4192
4310
|
var RAISED_INK = 0.05;
|
|
@@ -4229,6 +4347,7 @@ function derivePalette(canvas, sidebar) {
|
|
|
4229
4347
|
track: formatColour(mixColour(base, BLACK, TRACK_INK)),
|
|
4230
4348
|
raised: formatColour(mixColour(base, BLACK, RAISED_INK)),
|
|
4231
4349
|
hover: formatColour(mixColour(base, BLACK, HOVER_INK)),
|
|
4350
|
+
hoverStrong: formatColour(mixColour(base, BLACK, HOVER_STRONG_INK)),
|
|
4232
4351
|
selected: formatColour(mixColour(base, BLACK, SELECTED_INK)),
|
|
4233
4352
|
border: formatColour(mixColour(base, BLACK, BORDER_INK)),
|
|
4234
4353
|
borderStrong: formatColour(mixColour(base, BLACK, BORDER_STRONG_INK)),
|
|
@@ -4280,6 +4399,7 @@ function surfaceTokens(config) {
|
|
|
4280
4399
|
tokens["--ccd-track"] = pair(palette.track, dark.track);
|
|
4281
4400
|
tokens["--ccd-raised"] = pair(palette.raised, dark.raised);
|
|
4282
4401
|
tokens["--ccd-hover"] = pair(palette.hover, dark.hover);
|
|
4402
|
+
tokens["--ccd-hover-strong"] = pair(palette.hoverStrong, dark.hoverStrong);
|
|
4283
4403
|
tokens["--ccd-selected"] = pair(palette.selected, dark.selected);
|
|
4284
4404
|
tokens["--ccd-border"] = pair(palette.border, dark.border);
|
|
4285
4405
|
tokens["--ccd-border-strong"] = pair(palette.borderStrong, dark.borderStrong);
|
|
@@ -4318,7 +4438,7 @@ var menus_default = '/*\n * Host popup surfaces \u2014 menus and panels (DESIGN.
|
|
|
4318
4438
|
var scrollbars_default = "/*\n * Scrollbars (DESIGN.md \xA7\u4E09, \xA7\u56DB).\n *\n * DSH paints its own scrollbars. `ui-theme/src/styles/scrollbar.css` declares\n * five tokens on `body` \u2014 the thumb, its hover step, the thumb's transparent\n * border, the track's end margin and the track's width \u2014 and one un-scoped\n * `::-webkit-scrollbar` family paints them, so every scroller in the window\n * takes the same bar.\n *\n * Three of those five are geometry this sheet must not touch. The transcript's\n * `scrollbar-gutter: stable` reserves the track's width; the sidebar tree's\n * rows are padded by `--dsh-session-list-scrollbar-width` (5px, the host's own\n * value); the settings dialog's column and the menu cards widen their track to\n * 9px and 6px and inset the thumb inside it. Every one of those is measured\n * against the host's own width, so the interface keeps the host's track and\n * changes what is painted in it.\n *\n * What is painted is nothing, most of the time. The reference interface's\n * scrollbars are the platform's overlay scrollers: they appear while the reader\n * is moving something and fade again, so a window at rest carries no bar at\n * all \u2014 and the platform's own scroller, which `scrollbar-color` cannot reach,\n * is a grey pill the width of the system's. So the ink is ours and it is\n * published, not permanent: `compat/scroll-pill.ts` marks a surface\n * `data-ccd-scrolling` while it moves, and the two rules at the bottom of this\n * sheet are the whole of the state \u2014 transparent at rest, this interface's ink\n * while it is moving or while the pointer is on the bar itself.\n *\n * The five page-level surfaces the same module tracks go one step further and\n * carry no ink at all: `data-ccd-scroll-pill` takes the painted thumb out of\n * the picture and a floating pill takes its place. The painted thumb's length\n * is the content's share of the track \u2014 a short conversation, a panel with one\n * page of content, paints a bar as tall as its own viewport \u2014 while the pill is\n * a fixed short capsule that only slides. `.ccd-scroll-pill`'s own rules are at\n * the end of this sheet; the module owns its geometry.\n *\n * The reset is the half that is easy to miss. The standard `scrollbar-width`\n * and `scrollbar-color` properties *suppress* the `::-webkit-scrollbar` rules\n * whenever either is set to anything but `auto`, so one document-wide\n * `scrollbar-width: thin` \u2014 which the other skin installed beside this plugin\n * in this window makes, and which any page-global stylesheet may make \u2014 hands\n * every scroller in the window back to the platform. Stating `auto` puts the\n * host's painter back; in a document that declares neither property it is a\n * no-op. It is stated on the scrolling element itself rather than on an\n * ancestor, because the host declares the same properties on `body` and an\n * inherited value would otherwise be the one in force.\n *\n * The scope is the interface's own scroll surfaces rather than `*`. The host\n * hides the scrollbar on several horizontal rails \u2014 the draft-attachment rail,\n * the turn-nav popover, the breadcrumb trail, the dock strip and the tab strips\n * all declare `scrollbar-width: none` \u2014 and a blanket reset would give every\n * one of them a bar it does not want. This sheet adds no scrollbar anywhere, it\n * only repaints the ones the interface already shows. (The ink token does\n * inherit into whatever sits inside a scoped scroller \u2014 a custom property\n * inherits and cannot be scoped away \u2014 but a rail that hides its scrollbar\n * paints nothing to read it, and `scrollbar-width` is not inherited, so a\n * descendant keeps the value it was given.)\n *\n * The reset reaches into five of those surfaces and no more. Two of the host's\n * rails live *inside* the first list's members: `ConversationRoot` renders the\n * Composer's seat inside the page's scrolling body, and `ChatView` renders the\n * turn navigator beside the transcript column rather than inside it. A blanket\n * descendant form would reach both and put a bar on each, so the second list\n * names only the surfaces that hold scrollers of their own: the transcript\n * column (whose fenced code blocks and wide tables scroll inside it), the host's\n * popup cards (whose scrolling viewport is a child of the card) and this\n * plugin's own two. The two lists are written out in each of the three rules\n * below, because the reset, the absent ink and its reveal have to land on the\n * same elements and CSS has no way to name a set once.\n */\n\n/* The surfaces themselves, and the five whose contents scroll on their own. */\nhtml[data-dsh-ccd-style=\"true\"] :is(\n /* The Conversation page's scroller, and the transcript column inside it. */\n [data-conversation-scroll],\n .icaHSq_scroll,\n /* The sidebar's session/workspace tree, and the Files pane's. */\n ._7514NG_list,\n [data-files-body],\n /* The agent-team panel's body, the Composer's textarea, the settings\n dialog's two columns. */\n ._2tNPVa_body,\n .yhfFVG_scroll,\n .Dws9Sa_options,\n .Dws9Sa_navList,\n /* The host's popup cards. */\n [data-menu-material],\n /* This plugin's own panels and cards. */\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort,\n .ccd-context-detail,\n .ccd-settings-menu-list\n),\nhtml[data-dsh-ccd-style=\"true\"] :is(\n .icaHSq_scroll,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort\n) * {\n scrollbar-width: auto;\n scrollbar-color: auto;\n /* The thumb the host's own rule paints, in this interface's ink. Stated on\n the scroller and on everything inside one, so it also wins on the surfaces\n that rebind `--dsh-scrollbar-thumb` for themselves \u2014 a menu card, the\n settings panel and the dockkit panes all point it at another host alias,\n and an element's own declaration is the one that reaches the scroller\n there. */\n --dsh-scrollbar-thumb: var(--ccd-scrollbar-thumb);\n --dsh-scrollbar-thumb-hover: var(--ccd-scrollbar-thumb-hover);\n}\n\n/* A surface at rest carries no ink. */\nhtml[data-dsh-ccd-style=\"true\"] :is(\n [data-conversation-scroll],\n .icaHSq_scroll,\n ._7514NG_list,\n [data-files-body],\n ._2tNPVa_body,\n .yhfFVG_scroll,\n .Dws9Sa_options,\n .Dws9Sa_navList,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort,\n .ccd-context-detail,\n .ccd-settings-menu-list\n)::-webkit-scrollbar-thumb,\nhtml[data-dsh-ccd-style=\"true\"] :is(\n .icaHSq_scroll,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort\n) *::-webkit-scrollbar-thumb {\n background: transparent;\n}\n\n/*\n * The two states the ink has: while the surface moves (the module's mark, which\n * it clears again once the surface has been still), and while the pointer is on\n * the bar itself \u2014 the grab a reader makes without moving anything first.\n */\nhtml[data-dsh-ccd-style=\"true\"] :is(\n [data-conversation-scroll],\n .icaHSq_scroll,\n ._7514NG_list,\n [data-files-body],\n ._2tNPVa_body,\n .yhfFVG_scroll,\n .Dws9Sa_options,\n .Dws9Sa_navList,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort,\n .ccd-context-detail,\n .ccd-settings-menu-list\n)[data-ccd-scrolling]::-webkit-scrollbar-thumb,\nhtml[data-dsh-ccd-style=\"true\"] :is(\n .icaHSq_scroll,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort\n) *[data-ccd-scrolling]::-webkit-scrollbar-thumb,\nhtml[data-dsh-ccd-style=\"true\"] :is(\n [data-conversation-scroll],\n .icaHSq_scroll,\n ._7514NG_list,\n [data-files-body],\n ._2tNPVa_body,\n .yhfFVG_scroll,\n .Dws9Sa_options,\n .Dws9Sa_navList,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort,\n .ccd-context-detail,\n .ccd-settings-menu-list\n)::-webkit-scrollbar-thumb:hover,\nhtml[data-dsh-ccd-style=\"true\"] :is(\n .icaHSq_scroll,\n [data-menu-material],\n .ccd-model-panel,\n .ccd-model-error,\n .ccd-effort\n) *::-webkit-scrollbar-thumb:hover {\n background: var(--ccd-scrollbar-thumb);\n}\n\n/*\n * The five pill surfaces keep no ink at all \u2014 the floating capsule speaks for\n * them. They are named by the module's own mark rather than by the two lists,\n * so the sheet never has to know which of the surfaces those are. The module\n * leaves them out of the moving mark, and the two selectors that repeat it here\n * are the belt to that brace: the bar under the pointer and the bar during a\n * drag both stay empty.\n */\nhtml[data-dsh-ccd-style=\"true\"] [data-ccd-scroll-pill]::-webkit-scrollbar-thumb,\nhtml[data-dsh-ccd-style=\"true\"] [data-ccd-scroll-pill][data-ccd-scrolling]::-webkit-scrollbar-thumb,\nhtml[data-dsh-ccd-style=\"true\"] [data-ccd-scroll-pill]::-webkit-scrollbar-thumb:hover {\n background: transparent;\n}\n\n/*\n * The pill: one fixed layer for the whole window, one absolutely positioned\n * capsule per tracked surface, moved with a transform the module computes. It\n * takes no pointer events \u2014 the host's own thumb is still laid out under it, and\n * the capsule is sized and centred to sit inside it, so a drag that starts on\n * the pill grabs that bar.\n */\n[data-ccd-scroll-layer] {\n position: fixed;\n inset: 0;\n z-index: 40;\n pointer-events: none;\n}\n\n/* The macOS host excludes body > :not(#root) from native window dragging.\n This full-window decoration matches that rule even with pointer-events:\n none, so reset its app-region to avoid erasing the header's drag surface.\n Repeat :not(#root) to outrank the host's ID specificity; other portals keep\n their no-drag regions. */\nhtml[data-dsh-ccd-style=\"true\"][data-platform=\"darwin\"] body > [data-ccd-scroll-layer]:not(#root) {\n -webkit-app-region: initial;\n}\n\n[data-ccd-scroll-thumb] {\n position: absolute;\n top: 0;\n left: 0;\n box-sizing: border-box;\n width: 4px;\n border-radius: 999px;\n background: var(--ccd-scrollbar-thumb);\n opacity: 0;\n transition: opacity 140ms ease-out;\n}\n\n[data-ccd-scroll-thumb][data-ccd-scrolling] {\n opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n [data-ccd-scroll-thumb] { transition: none; }\n}\n";
|
|
4319
4439
|
|
|
4320
4440
|
// src/client/theme/tokens.css
|
|
4321
|
-
var tokens_default = "/* CCD geometry, type, artwork and light/dark colour variables.\n * Colours are centralized here; the dark palette follows the host's body marker.\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n /* Geometry */\n /* Top of the blank-session greeting block. The reference puts the title a\n short step below the header instead of centring it, so the statistics card\n hanging under it still clears the Composer on a short window. */\n --ccd-hero-top: 16px;\n --ccd-sidebar-width: 264px;\n --ccd-sidebar-inline-padding: 10px;\n --ccd-sidebar-bottom-padding: 8px;\n --ccd-row-height: 28px;\n /* Workspace (group) row. The host's own 34px, pinned because the browsing\n region's merged header band is this same box: the section header parks on\n the row's line and the two have to agree to the pixel. */\n --ccd-workspace-row-height: 34px;\n /* Navigation stack. The reference's three rows measured 26px tall on a 26.5px\n pitch \u2014 contiguous, not separated \u2014 against the host's own 36px/7px row. */\n --ccd-nav-row-height: 26px;\n --ccd-nav-gap: 1px;\n --ccd-radius-row: 8px;\n --ccd-radius-panel: 12px;\n /* View-options reference: 20 device px corners at @2x. */\n --ccd-view-menu-radius: 10px;\n /* Assistant table card. The reference crop's corner curve fits a 12-device-px\n radius at @2x, so the card is rounder than the row radius it borrows its\n scale from. */\n --ccd-table-radius: 6px;\n /* Fenced code block card. The reference code block shows the same 12-device-px\n curve at @2x as the table card, so the transcript's two boxed surfaces stay\n one family. */\n --ccd-code-radius: 6px;\n --ccd-composer-width: 770px;\n --ccd-composer-min-height: 42px;\n --ccd-composer-radius: 10px;\n --ccd-composer-padding: 8px 14px;\n --ccd-composer-padding-block: 8px;\n --ccd-composer-padding-inline: 14px;\n --ccd-composer-row-gap: 4px;\n --ccd-composer-row-inset: 4px;\n --ccd-composer-bottom-gap: 5px;\n --ccd-control-row-height: 28px;\n /* Status-bar chip. The tool row's controls are all this one box: the row's\n 28px is the layout line, and every control inside it is a chip of this\n height rather than a box stretched to the line. The reference draws the\n model chip's fill as one label line \u2014 40 device px at @2x, so the row's\n 12px label sits 5.5px from the chip's top and bottom where the row itself\n would leave it 10px \u2014 and the same box now carries the command plus, the\n permission control, the voice control, the statistics readouts and the\n context ring, so a pointer crossing the row finds one fill height instead\n of three. The row keeps `--ccd-control-row-height`: the dock, the ring's\n seat and the trailing cluster are all measured from it. The corner follows\n the height \u2014 12 device px at @2x, the same curve the transcript's table and\n code cards carry, rather than the row's 8px radius, which is nearly half of\n a 20px chip and would round every fill towards a pill. */\n --ccd-chip-height: 20px;\n --ccd-chip-radius: 6px;\n /* The chip family's inline padding: the model/effort chips, the permission\n control and the two square glyph buttons (plus, voice), whose boxes are\n their 14px artwork plus one of these on each side. Six to seven px is the\n whole range in the reference; the readouts and the ring keep their own\n slightly tighter 6px, which is a 1px difference in ink and nothing in a\n fill's shape. */\n --ccd-chip-padding-inline: 7px;\n --ccd-send-size: 24px;\n --ccd-send-reserve: 30px;\n /* One gap for the whole status row: the row itself, the leading tools group,\n its modes cluster, the trailing cluster (the native readouts, the context\n ring, the model/effort pair) and the statistics dock all space their\n children with this. The host's own row ran 12px in the leading groups and\n the plugin's 6px in the trailing one, which read as two different rows in\n one bar. Each control carries its own 6-7px inner padding, so an even box\n gap also reads as an even visible rhythm. */\n --ccd-cluster-gap: 6px;\n /* Context ring. The host draws it as 14px artwork (`ContextMeter.module.css`:\n viewBox 0 0 14 14, cx=cy=7, r=5.5, 2px stroke, round cap) inside a 28px\n trigger with 6px of side padding, so the trigger's own box is 26px and the\n seat the status bar has to hold for it \u2014 that box plus one cluster gap \u2014 is\n 32px. The host's ring and this plugin's empty-state ring hang in that one\n seat, which is what keeps the ring's position and size the same before and\n after a session has usage. */\n --ccd-context-ring-size: 14px;\n --ccd-context-ring-trigger: 26px;\n --ccd-context-ring-seat: calc(var(--ccd-context-ring-trigger) + var(--ccd-cluster-gap));\n /* Context breakdown panel. Measured off the supplied reference at @2x\n (698\xD7178 for the collapsed state, 828\xD71006 for the expanded one): a 361px\n card with a 1px outline and a 12px corner, 12px inline and 8px top padding,\n a 13px/20px header, a 4px bar 5px under it, 19px value rows, 17px detail\n rows, and 10px swatches. The width is the one number the crop cut off, so\n it is the reference's own rounded value: the bar and the percentage column\n both end exactly at 360 \u2212 2 \u2212 24 = 334px, which is what the crop shows. */\n --ccd-context-panel-width: 360px;\n --ccd-context-panel-radius: 12px;\n --ccd-context-panel-padding-block: 8px;\n --ccd-context-panel-padding-inline: 12px;\n --ccd-context-panel-gap: 8px;\n --ccd-context-row-height: 19px;\n --ccd-context-detail-height: 17px;\n --ccd-context-swatch-size: 10px;\n --ccd-context-swatch-radius: 3px;\n --ccd-context-bar-height: 4px;\n --ccd-context-bar-radius: 2px;\n --ccd-context-bar-gap: 1px;\n /* 5px under the header line, and nothing below: the card's own bottom padding\n is what follows the bar in the collapsed state, and the rows state their\n own 4px above themselves in the expanded one. */\n --ccd-context-bar-margin-block: 5px 0;\n /* The buffer segment's own step away from the used group: the reference\n leaves 4px there where every used segment is 1px apart, because the grey\n block is a reservation rather than another category. */\n --ccd-context-bar-reserve-gap: 4px;\n /* Ten detail rows before a group scrolls \u2014 the reference's own visible run,\n and what keeps a session with 85 tools from drawing a 1500px panel. */\n --ccd-context-detail-max: 170px;\n /* The two value columns: the token column's right edge sits 48px in from the\n content edge (measured 618 of 715 device px), which is a 40px percentage\n column plus this gap. */\n --ccd-context-percent-width: 40px;\n --ccd-context-column-gap: 8px;\n /* The status bar's own glyph size: the command plus, the statistics readouts\n and the ring all draw 14px artwork in the 28px control row. The\n speech-to-text control draws 18px of its own; the composer sheet brings that\n one down to this size. The permission control draws no glyph at all \u2014 it is\n its text (composer.css). */\n --ccd-row-icon-size: 14px;\n --ccd-account-menu-width: 236px;\n --ccd-account-menu-padding: 5px;\n --ccd-account-row-height: 28px;\n --ccd-account-trigger-height: 30px;\n /* Conversation header action cluster. The CCD reference keeps every control\n on one 30px centre pitch with a 12px trailing inset (measured at @2x from\n docs/reference/ccd-conversation.png: icon centres 28.75/30/30px apart, the\n trailing glyph centre 25.75px from the window edge). That inset is what the\n cluster takes while the Composer is narrower than the column and centred in\n it; where the Composer fills the column, `conversation.css` ends the\n cluster on the input surface's own border instead, which is the line the\n reference puts the closing control on and a measurement rather than a\n second token. */\n --ccd-header-action-size: 28px;\n --ccd-header-action-compact: 24px;\n --ccd-header-icon-size: 16px;\n --ccd-header-action-gap: 2px;\n --ccd-header-trailing-inset: 12px;\n --ccd-header-menu-border: #d6d6d6;\n --ccd-header-menu-separator: #e2e2e2;\n --ccd-header-menu-danger: #b4262b;\n --ccd-menu-danger: #c04742;\n --ccd-menu-danger-ink: #ffffff;\n --ccd-header-trigger-hover: #f0f0ef;\n --ccd-header-project-fill: #e5e5e5;\n --ccd-header-project-active: #cfcfcf;\n /* Transcript edge fade. 24px is the band the host's own internal-request\n viewer uses for `fadeTop`\uFF0F`fadeBottom`, so the whole interface softens its\n scroll viewport edges by the same amount. */\n --ccd-edge-fade: 24px;\n /* Jump-to-bottom control. The reference's own affordance measures 40\xD744\n device px at @2x \u2014 a ~21px mark above the Composer \u2014 against the host's\n 34px floating circle, so the box shrinks to this one step while the glyph\n inside it keeps the host's 16px seat. */\n --ccd-to-bottom-size: 22px;\n /* Right panel (the Files, terminal and browser tabs). The reference draws it\n as a floating card: 16 device px in from the column's top, right and bottom\n edges; a 12px corner (measured off the fill: the curve is 20 device px at\n @2x from its first inset pixel to the straight edge, plus the 1px outline);\n a 32px header strip whose 24px tab mark sits 4px under the card's top; and\n an 8px pane gutter (16 device px), which is where the Files pane's own row\n line begins. */\n --ccd-right-panel-inset: 8px;\n --ccd-right-panel-radius: var(--ccd-radius-panel);\n --ccd-right-panel-strip-height: 32px;\n --ccd-right-panel-gutter: 8px;\n --ccd-right-panel-gap: 12px;\n /* The tab's own mark, measured off the reference: a 24px square (5px corner,\n carried by the chip radius) tinted #d3e2f9 behind the 16px glyph. */\n --ccd-right-panel-glyph-size: 24px;\n /* Files tree. The reference's rows run on a 24px pitch (48 device px at @2x)\n where the host's 13px/1.5 row draws 29.5px, and its pane header is the\n 26px rounded field over them. */\n --ccd-files-row-height: 24px;\n --ccd-files-field-height: 26px;\n --ccd-files-glyph-size: 16px;\n\n /* Claude Desktop 2.31226.1's active flat frame, confirmed by window capture:\n gray-10 canvas; sidebar mixes gray-20 and gray-10 equally in sRGB. */\n --ccd-canvas: #fcfcfb;\n --ccd-sidebar: #fbfbf9;\n --ccd-card: #ffffff;\n /* Segmented-control track. The reference measures #f6f6f4 against a white\n page; the same step down from this canvas keeps the same contrast. */\n --ccd-track: #f3f3f2;\n --ccd-raised: #f0f0ef;\n --ccd-hover: #f0f0ee;\n /* Sampled from the supplied view-options reference, separate from the\n warmer surfaces used by Composer and the host's other menus. */\n --ccd-view-menu-hover: #f5f5f5;\n --ccd-view-menu-text: #0b0b0b;\n --ccd-view-menu-muted: #9b9994;\n --ccd-view-menu-border: #d7d7d6;\n --ccd-view-menu-separator: #ebebeb;\n --ccd-view-menu-accent: #2a78d6;\n --ccd-view-menu-shadow: 0 1px 3px rgba(0, 0, 0, .08), 0 8px 20px rgba(0, 0, 0, .12), 0 16px 32px rgba(0, 0, 0, .06);\n --ccd-selected: #ecebe8;\n /* The right panel's tab mark: the reference's own blue-tinted square,\n sampled at #d3e2f9 with the accent for its glyph. It is the one tinted seat\n in this plugin's surfaces, so it is stated rather than derived. */\n --ccd-right-panel-glyph-bg: #d3e2f9;\n /* The Files pane's own ink, sampled off the reference at @2x. Its tree names\n and its empty state's title measure #0b0b0b \u2014 a step below this palette's\n `--ccd-text`, the ink the rest of the interface draws \u2014 and its tab title\n measures #52514f, between `--ccd-text` and `--ccd-text-secondary`. The tab\n mark's glyph is the one blue that is not this palette's accent: the\n reference draws it #304e91 on the #d3e2f9 square. */\n --ccd-files-ink: #0b0b0b;\n --ccd-right-panel-tab-ink: #52514f;\n --ccd-files-chip-ink: #304e91;\n\n /* Lines */\n --ccd-border: #e3e3e1;\n --ccd-border-strong: #e0e0df;\n --ccd-border-soft: #ebebe9;\n /* The rule under a table head reads one step stronger than the card outline\n in the reference (#d9d9d9 against #e3e3e3). */\n --ccd-table-head-line: #d9d9d8;\n /* The right panel's card outline, sampled at #d7d7d6 \u2014 one step stronger than\n the row outline above and the same ink the menu cards' own border carries,\n which is what makes a floating panel and a menu read as one material. */\n --ccd-right-panel-border: #d7d7d6;\n --ccd-browser-canvas: #f7f7f7;\n --ccd-browser-dot: #d1d0ce;\n\n /* Scrollbar ink. The host paints the scrollbars themselves\n (`ui-theme/src/styles/scrollbar.css`: a 5px track and a pill thumb read\n from `--dsh-scrollbar-thumb`), and this interface keeps that geometry \u2014\n the transcript's stable gutter, the sidebar's\n `--dsh-session-list-scrollbar-width` padding and the dockkit panes are all\n measured against the host's own width \u2014 so these two tokens are the ink\n alone, bound in theme/scrollbars.css.\n The ink is near-black by decision rather than by measurement: the bar is\n 5px wide and carries no surface of its own, so none of this palette's\n surface steps \u2014 5% to 14% black \u2014 reads at that size, and the interface\n this one follows draws a dark scrollbar. Hover goes one step further down,\n the direction the host's own hover step takes. */\n --ccd-scrollbar-thumb: #333331;\n --ccd-scrollbar-thumb-hover: #171716;\n\n /* Text */\n --ccd-text: #1f1f1d;\n --ccd-text-secondary: #6f6f6a;\n --ccd-text-muted: #8f8f8a;\n --ccd-text-placeholder: #89877f;\n /* One step below full strength: a row that is not the current one. The\n reference paints its inactive navigation rows at #4a4a47 \u2014 between this\n palette's --ccd-text and --ccd-text-secondary \u2014 and keeps the current row\n at full black, so the stack reads as one current entry plus quieter\n neighbours instead of three equally loud labels. */\n --ccd-text-nav: #4a4a47;\n /* Archived Session row. The host fades that title with its own caption ink,\n but this plugin's row ink outranks the host pair, so the state needs a step\n of its own: one above --ccd-text-muted on the same warm ramp, which is the\n faded row the reference draws while still reading against the sidebar. A row\n that is current or under the pointer takes the second value, because the\n hover and selected fills sit a step below the sidebar the first one was\n measured on. */\n --ccd-text-archived: #a0a09b;\n --ccd-text-archived-hover: #8a8a85;\n\n /* New-session statistics card. The reference panel is a stacked translucent\n grey: the card is 5% black over the canvas and a stat tile (and an empty\n heat cell) is 10% black over the card, so these are the measured opaque\n equivalents. The four heat levels are the reference's own `hsl(217 70% L%)`\n with L = 72\uFF0F64\uFF0F56\uFF0F48, i.e. \"that day's value / the busiest day\" in four\n equal steps. */\n --ccd-stats-panel: #f0f0f0;\n --ccd-stats-tile: #dadada;\n /* The card header's active tab: the reference paints `fill-ghost-hover`, the\n same 5% black as the card itself, over the card \u2014 one step lighter than a\n stat tile. */\n --ccd-stats-tab: #e6e6e6;\n --ccd-stats-label: #898781;\n --ccd-stats-value: #0b0b0b;\n --ccd-stats-heat-1: hsl(217 70% 72%);\n --ccd-stats-heat-2: hsl(217 70% 64%);\n --ccd-stats-heat-3: hsl(217 70% 56%);\n --ccd-stats-heat-4: hsl(217 70% 48%);\n /* The `Models` view colours its bars and legend by rank:\n `hsl(217 70% min(88, 58 + 7n)%)`, which flattens into these six shades. */\n --ccd-stats-model-1: hsl(217 70% 58%);\n --ccd-stats-model-2: hsl(217 70% 65%);\n --ccd-stats-model-3: hsl(217 70% 72%);\n --ccd-stats-model-4: hsl(217 70% 79%);\n --ccd-stats-model-5: hsl(217 70% 86%);\n --ccd-stats-model-6: hsl(217 70% 88%);\n /* Tooltips are the reference's dark popup in both themes; on a dark panel it\n steps up to a mid grey so the box keeps its contrast. */\n --ccd-stats-tip-bg: #0c0c0c;\n --ccd-stats-tip-fg: #f7f7f5;\n\n /* Assistant Markdown palette matched to the CCD transcript reference. */\n --ccd-link: #2b61b5;\n --ccd-link-underline: #a7badd;\n --ccd-inline-code-text: #b63630;\n --ccd-inline-code-fill: #f1f1f0;\n --ccd-inline-code-border: #e2e2e0;\n\n /* Context meter. The host paints the ring's consumed arc with the same\n tertiary label grey as the percentage beside it, so the reading carries no\n weight. The accent blue is this plugin's one emphasis colour: taking it\n through `var()` lets the ring follow `--ccd-accent` the moment that token\n exists, and the fallback is the blue measured off the target arc\n (docs/issues/img/12-2.png), so the ring is never left grey meanwhile. The\n track underneath stays the host's `--dsw-alias-border-l3`, which\n theme/tokens.ts already overrides. */\n --ccd-context-ring-fill: var(--ccd-accent, #4b76ce);\n\n /* Context breakdown categories, sampled from the supplied reference's bar and\n swatches. Seven steps, in the order the panel and the bar draw them: the\n reference's own hues, which are deliberately outside this palette's blue\n ramp \u2014 a breakdown that reused one hue family would make five categories\n read as one. `--ccd-context-free` is both the free-space swatch and the\n bar's track, exactly as the reference draws them. */\n --ccd-context-mcp: #2a78d8;\n --ccd-context-tools: #e96a33;\n --ccd-context-system: #1ead7c;\n --ccd-context-skills: #eda105;\n --ccd-context-memory: #ea7ca4;\n /* The conversation's own row. The reference's crop happens to hold no\n messages at all \u2014 89k of its 9% reading is prompt, tools and skills \u2014 so\n this one is chosen rather than sampled: the same lightness and chroma as\n its neighbours, one hue family over, so it cannot be mistaken for the\n accent blue of MCP tools. */\n --ccd-context-messages: #8b6fd4;\n --ccd-context-buffer: #c2c0b8;\n --ccd-context-free: #eeeeee;\n\n /* The plugin's one emphasis blue: the selected check in every Menu surface,\n the context ring, and whatever else has to read as \"this one is chosen\".\n It is the blue measured off the reference check mark\n (docs/issues/img/01-3.png: the stroke's own pixels are #4b76d0/#507ad2, so\n the token takes the darker mode) and shares the stats heat ramp's hue\n family (hsl(217 \u2026)), which keeps every blue in the interface one voice. */\n --ccd-accent: #4b76ce;\n\n /* State colours that DSH already owns semantics for. */\n --ccd-diff-added: #508c48;\n --ccd-diff-removed: #b33156;\n\n /* Type. The two fallback tails are what a configured family is prepended to\n (see theme/tokens.ts); with nothing configured the consuming variables keep\n the built-in stacks. Geist leads the interface tail because it is the\n upstream design Anthropic Sans was cut from; it is resolved from the system\n font list, so the tail degrades to the platform stack when it is not\n installed (assets/fonts/ ships the file for a local install only). */\n --ccd-font-fallback: Geist, -apple-system, BlinkMacSystemFont, \"SF Pro Text\", \"Helvetica Neue\",\n \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif;\n --ccd-code-fallback: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace;\n --ccd-font-ui: var(--ccd-font-fallback);\n --ccd-font-code: var(--ccd-code-fallback);\n --ccd-font-size-body: 14px;\n --ccd-font-size-muted: 13px;\n /* Blank-session title. The reference's own type scale puts the greeting on\n `--cds-font-size-title` (1.25rem, ~20px) with a 25px leading at weight 400,\n which is a good deal quieter than the 26px this used to be. */\n --ccd-font-size-headline: 20px;\n /* Transcript headings. The reference's ladder sits one step under the host's\n (DSH draws h1/h2/h3 at 21/19/18px): its own crop measures a 19px h1 and a\n 16px h2 over the 14px body \u2014 27 and 23 device px of CJK ink against the\n 21-device-px body line at @2x \u2014 and the h2 is confirmed independently by\n the inline-code chip, whose 0.95em/1.2 rule this plugin already matches:\n it lands on the reference's 33 device px exactly at 16px. h3 has no crop of\n its own and takes the next step down. */\n --ccd-font-size-h1: 19px;\n --ccd-font-size-h2: 16px;\n --ccd-font-size-h3: 15px;\n /* Transcript leading. The host sets the assistant body at 14px/24px; the\n reference runs the same 14px on a 20px line. Its own window measures a\n 30.7-device-px pitch between two lines of a paragraph where this plugin's\n 24px draws 36.6, and both shots put their body's CJK ink at 20 device px\n with a 770px Composer at 1176 (1.53 device px per CSS px), so the two are\n read at one scale. The reference's paragraph-to-paragraph gap is 46 device\n px \u2014 this 20px line plus the 10px margin both sides already share. */\n --ccd-transcript-line-height: 20px;\n /* The one step up from the host's own 400: used where a control has to read\n as a chosen value rather than as chrome (model, reasoning effort). */\n --ccd-font-weight-strong: 600;\n\n /* Hand-drawn 16px marks matching the CCD interaction recording: return\n arrow and a small square in a ring. The host keeps its buttons, handlers\n and SVG state markers; these masks replace only their visible artwork. */\n --ccd-send-radius: 6px;\n --ccd-icon-send: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M12 4.5V8A2 2 0 0 1 10 10H3.5M6.5 7L3.5 10L6.5 13' stroke='black' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --ccd-icon-stop: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5.5' fill='none' stroke='black' stroke-width='1.25'/%3E%3Crect x='6' y='6' width='4' height='4' rx='.6' fill='black'/%3E%3C/svg%3E\");\n\n /* The header's three painted glyphs, taken from DSH 0.2.0-rc.2 shared\n artwork (MIT) so no host component is copied:\n - IconRightUpOutlineRegular (`ui-primitives/icons`) is the generic \"open\"\n glyph the native open-in-app control falls back to;\n - the terminal prompt is `ui-sidebar-terminal/TerminalIcon`'s own 16px\n geometry, the glyph that view's tab title draws;\n - the globe is `ui-primitives`' IconGlobeOutlineRegular, the glyph\n `ui-sidebar-browser` draws in its tab title.\n Masks let the host keep ownership of its buttons while the plugin supplies\n the artwork. */\n --ccd-icon-open: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M11.7256 2.77441C12.5538 2.77469 13.2256 3.44616 13.2256 4.27441V10.1416H12.2256V4.27441C12.2256 3.99844 12.0015 3.77469 11.7256 3.77441H5.7207V2.77441H11.7256Z' fill='black'/%3E%3Cpath d='M2.77441 13.2255L12.3756 3.62427' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-terminal: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 4L7 8L3 12' stroke='black'/%3E%3Cpath d='M9 12H13' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-browser: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M7.99986 14.0887C11.3626 14.0887 14.0886 11.3627 14.0886 7.99998C14.0886 4.63727 11.3626 1.91125 7.99986 1.91125C4.63715 1.91125 1.91113 4.63727 1.91113 7.99998C1.91113 11.3627 4.63715 14.0887 7.99986 14.0887Z' stroke='black'/%3E%3Cpath d='M2.34619 8H13.6538' stroke='black' stroke-linecap='square'/%3E%3Cpath d='M7.99976 14.0889C9.23509 14.0889 10.1743 11.3629 10.1743 8.00006C10.1743 4.63739 9.23509 1.91138 7.99976 1.91138' stroke='black'/%3E%3Cpath d='M7.99973 14.0889C6.76445 14.0889 5.8252 11.3629 5.8252 8.00006C5.8252 4.63739 6.76445 1.91138 7.99973 1.91138' stroke='black'/%3E%3C/svg%3E\");\n\n /* The session menu's own mark, stacked. The host draws\n `IconEllipsisOutlineRegular` (`ui-primitives`, MIT) as three 2px dots on one\n horizontal line \u2014 circles at (3, 8), (8, 8) and (13, 8) of a 16px box \u2014 and\n the reference stacks them, so this is that same geometry transposed to\n (8, 3), (8, 8) and (8, 13): one dot size, one 5-unit pitch, one 16px box,\n carried as a mask over the button's own `currentColor` so the host keeps its\n button and this interface supplies the mark. */\n --ccd-icon-more: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 4C8.55228 4 9 3.55228 9 3C9 2.44772 8.55228 2 8 2C7.44772 2 7 2.44772 7 3C7 3.55228 7.44772 4 8 4Z' fill='black'/%3E%3Cpath d='M8 9C8.55228 9 9 8.55228 9 8C9 7.44772 8.55228 7 8 7C7.44772 7 7 7.44772 7 8C7 8.55228 7.44772 9 8 9Z' fill='black'/%3E%3Cpath d='M8 14C8.55228 14 9 13.55228 9 13C9 12.44772 8.55228 12 8 12C7.44772 12 7 12.44772 7 13C7 13.55228 7.44772 14 8 14Z' fill='black'/%3E%3C/svg%3E\");\n\n /* A bare plus, the one glyph the reference repeats on every actionable row.\n It is DSH's own `IconPlusOutlineArtwork` geometry (ui-primitives, MIT): two\n 1px strokes across a 16px box, so the plugin can put the same mark on the\n Workspace header's add button and on a project row's create button without\n authoring artwork of its own. */\n --ccd-icon-plus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 2V14' stroke='black'/%3E%3Cpath d='M2 8H14' stroke='black'/%3E%3C/svg%3E\");\n\n /* The workspace picker chip's leading mark. DSH switches that glyph with the\n chip's own state \u2014 `IconFolderOpenRegular` once a workspace is chosen, a\n closed folder while the chip only carries a placeholder \u2014 and the open one\n draws a slanted front panel over a translucent back panel, where the\n reference's button leads with one closed folder in either state. The\n geometry below is DSH's own `FolderCloseArtwork` (`ui-primitives`, MIT) on\n its 16-unit grid and 1px stroke, with the artwork's second path \u2014 the rule\n line across the body \u2014 left out: the reference draws the body empty, and\n the tab, the step and the four rounded corners are the whole of the mark. */\n --ccd-icon-folder: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M1.50439 3.11059C1.50439 2.55831 1.95211 2.1106 2.50439 2.1106H5.43389C5.67773 2.1106 5.91318 2.19969 6.09593 2.36113L7.71649 3.79265C7.89924 3.95409 8.1347 4.04319 8.3785 4.04319H13.4958C14.0481 4.04319 14.4958 4.4909 14.4958 5.04319V12.8894C14.4958 13.4417 14.0481 13.8894 13.4958 13.8894H2.50439C1.95211 13.8894 1.50439 13.4417 1.50439 12.8894V4.04319V3.11059Z' stroke='black'/%3E%3C/svg%3E\");\n\n /* The reference's disclosure mark is a 1px line chevron where the host draws a\n filled triangle; this is DSH's own `IconChevronRightOutlineArtwork` geometry\n (ui-primitives, MIT). It is painted over the host's mark slot, so the host's\n own `arrowOpen` state still drives the quarter turn. */\n --ccd-icon-chevron-right: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M6 12L9.29289 8.70711C9.68342 8.31658 9.68342 7.68342 9.29289 7.29289L6 4' stroke='black'/%3E%3C/svg%3E\");\n\n /* The Files tree's two file marks, measured off the reference at @2x: a page\n with its bottom-right corner folded, and the angle-bracket pair, each drawn\n 8\u20139px wide inside the 16px seat the host's own type glyphs occupy (the\n reference's names then start on the same 33px the row's own gap states).\n DSH classifies a file by name and extension too, but its set is a\n different one \u2014 `.gitignore` is a git file to the host and a plain page to\n the reference, `LICENSE` a page to both \u2014 so `right-panel.css` carries the\n reference's own split as an extension list rather than reading the host's. */\n --ccd-icon-file: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M5.5 4.5H10.5C11.0523 4.5 11.5 4.94772 11.5 5.5V8.5L8.5 11.5H5.5C4.94772 11.5 4.5 11.0523 4.5 10.5V5.5C4.5 4.94772 4.94772 4.5 5.5 4.5Z' stroke='black'/%3E%3Cpath d='M8.5 8.5H11.5L8.5 11.5' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-file-code: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M6.2 5.2L4.2 8.05L6.2 10.9' stroke='black' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M9.8 5.2L11.8 8.05L9.8 10.9' stroke='black' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M9.4 4.6L6.6 11.4' stroke='black' stroke-linecap='round'/%3E%3C/svg%3E\");\n\n /* The Files tab's mark: the reference draws a three-row list \u2014 a bullet and a\n rule per row \u2014 12px of ink on the tab's own blue square, so the artwork is\n stated on the square's 24-unit grid. The square itself is a seat the tab\n sheet paints; this is only the ink that sits in it. */\n --ccd-icon-files-list: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='black'%3E%3Crect x='6' y='6.5' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='6.5' width='8' height='2' rx='.5'/%3E%3Crect x='6' y='11' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='11' width='8' height='2' rx='.5'/%3E%3Crect x='6' y='15.5' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='15.5' width='8' height='2' rx='.5'/%3E%3C/g%3E%3C/svg%3E\");\n\n /* The Files pane's magnifier, for the filter field's leading seat and for the\n one control the pane's header adds: a lens and a handle, 13px of ink in the\n 16px box the field's own row draws, one 1px stroke like the marks around it. */\n --ccd-icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='6.6' cy='6.6' r='4.6' stroke='black'/%3E%3Cpath d='M9.9 9.9L13.9 13.9' stroke='black' stroke-linecap='round'/%3E%3C/svg%3E\");\n\n /* The archived Session row's leading mark. The host deliberately leaves that\n 16px cell empty, so the plugin paints the same geometry itself: DSH's own\n `IconArchiveOutlineRegular` artwork (ui-primitives, MIT) \u2014 a lid, a body and\n a handle drawn with 1px strokes \u2014 carried as a mask like the marks around\n it, so no third-party asset or copied component enters the stylesheet. */\n --ccd-icon-archive: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M13.5 2.5H2.5C1.94772 2.5 1.5 2.94772 1.5 3.5V4.5C1.5 5.05228 1.94772 5.5 2.5 5.5H13.5C14.0523 5.5 14.5 5.05228 14.5 4.5V3.5C14.5 2.94772 14.0523 2.5 13.5 2.5Z' stroke='black'/%3E%3Cpath d='M2.5 5.5V13.5C2.5 13.7652 2.60536 14.0196 2.79289 14.2071C2.98043 14.3946 3.23478 14.5 3.5 14.5H12.5C12.7652 14.5 13.0196 14.3946 13.2071 14.2071C13.3946 14.0196 13.5 13.7652 13.5 13.5V5.5' stroke='black'/%3E%3Cpath d='M6.5 9.5H9.5' stroke='black'/%3E%3C/svg%3E\");\n\n /* The idle Session row's leading ring. The host hands that cell to the\n plugin's `sidebar.session.row.leading` seat as soon as a row has no status\n of its own, and the running row's activity ring is `ui-primitives`'\n StateDot spinner: a 2-unit stroke on a 9.5-unit radius in a 24-unit box.\n The same circle is carried here as a mask, so the still mark and the\n spinning one are one geometry at the one 8px scale the stylesheet already\n gives the spinner \u2014 and the ring takes the cell's own `currentColor`\n (the host's `--dsw-alias-label-tertiary`, the spinner's ink) instead of an\n authored colour. */\n --ccd-icon-session-ring: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Ccircle cx='12' cy='12' r='9.5' stroke='black' stroke-width='2'/%3E%3C/svg%3E\");\n\n /* The context ring's track, for the seat an empty session has to fill. The\n host's own `ContextMeter` returns nothing at all until the token meter knows\n a numerator and the context window, so the plugin draws that ring's track\n itself \u2014 the host's exact geometry from `ContextMeter.module.css`\n (viewBox 0 0 14 14, cx=cy=7, r=5.5, 2px stroke) carried as a mask, so the\n colour stays the host track token above. The consumed arc is not drawn: at\n 0% the host's own arc has no length either. */\n --ccd-icon-context-ring: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none'%3E%3Ccircle cx='7' cy='7' r='5.5' stroke='black' stroke-width='2'/%3E%3C/svg%3E\");\n\n /* The Composer whale. DeepSeek's own mark is a blue whale with a pale belly,\n so the two inks are the brand pair rather than a derived palette step: the\n artwork only ever appears as this one mark. The dark side lifts the blue a\n step so it keeps its contrast on the dark canvas instead of sinking into\n it; the belly stays the light ink in both schemes, because it is what makes\n the silhouette read at 64px. */\n --ccd-pet-blue: #4d6bfe;\n --ccd-pet-light: #dfe6ff;\n\n /* Elevation */\n --ccd-shadow-card: 0 1px 2px rgb(0 0 0 / 4%);\n --ccd-shadow-segment: 0 1px 2px rgb(0 0 0 / 8%);\n /* The right panel's card, read off the reference's own edges: the canvas\n (252/255) sits at 243 half a pixel beside the card, 235 directly under it\n and back to 251 eight pixels out \u2014 a two-layer shadow, the near one for the\n edge and the far one for the falloff. */\n --ccd-right-panel-shadow: 0 1px 3px rgb(0 0 0 / 4%), 0 5px 14px rgb(0 0 0 / 8%);\n}\n\n/*\n * Host-token aliases belong on `body`, exactly where the host writes them.\n *\n * `--dsw-*` values are not in the document stylesheets: DSH's theme presenter\n * writes them, and this plugin's own overrides, as inline styles on `body`\n * (theme/tokens.ts). A custom property is resolved *where it is declared*, so an\n * alias of a host token declared on the root would reference a variable that is\n * not in scope there: it computes to the guaranteed-invalid value and inherits\n * as invalid into every subtree, and the rule consuming it falls back to\n * `transparent` rather than the host's colour. The empty-state context ring\n * (theme/composer.css, `.yhfFVG_dock::after`) vanished exactly that way.\n */\nhtml[data-dsh-ccd-style=\"true\"] body {\n /* Resolve on body so dark mode and configured palettes both participate. */\n --ccd-composer-focus-border: color-mix(in srgb, var(--ccd-card) 60%, var(--ccd-text-secondary));\n /* The empty state's ring draws the host's track alone. It stays the host's\n own track token (`ContextMeter.module.css` strokes `.y0jqnG_track` with\n `--dsw-alias-border-l3`, which theme/tokens.ts already retints), so an\n empty session shows the same hollow ring the host would draw at 0%. */\n --ccd-context-ring-track: var(--dsw-alias-border-l3);\n}\n\n/*\n * Dark palette.\n *\n * DSH's theme presenter writes `body[data-ds-dark-theme]` from the resolved\n * colour scheme (`@deepseek-ai/dsh-client-ui-theme` client styles, DSH\n * 0.2.0-rc.2), so the plugin follows the host's own switch instead of carrying a\n * second one. The block is a descendant of the root activation marker: the\n * variables land on `body`, cover every colour the light block declares, and\n * stay absent while the plugin is off.\n *\n * The warm-neutral family is kept rather than swapping in the host's bluish\n * greys: the same relationship holds in both schemes (canvas a touch lighter\n * than the sidebar, card the brightest surface), while the recessed steps\n * (track, raised, hover, selected) move *up* in lightness where the light\n * palette moves down, because on a dark canvas a surface reads as raised by\n * catching more light. Lines keep one visible step against the surfaces they\n * separate; text keeps the light palette's descending tone order.\n */\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n /* The same flat frame uses gray-850 for the dark page and mixes it with\n 20% black for the sidebar. The control track stays below its raised thumb\n while both sit above the darker page. */\n --ccd-canvas: #151515;\n --ccd-sidebar: #111111;\n --ccd-card: #30302e;\n --ccd-header-menu-border: var(--ccd-border);\n --ccd-header-menu-separator: var(--ccd-border-soft);\n --ccd-header-menu-danger: #f08080;\n --ccd-menu-danger: #c04742;\n --ccd-menu-danger-ink: #ffffff;\n --ccd-header-trigger-hover: var(--ccd-hover);\n --ccd-header-project-fill: var(--ccd-track);\n --ccd-header-project-active: var(--ccd-selected);\n --ccd-track: #1f1e1d;\n --ccd-raised: #2f2f2d;\n --ccd-hover: #313130;\n --ccd-view-menu-hover: var(--ccd-selected);\n --ccd-view-menu-text: var(--ccd-text);\n --ccd-view-menu-muted: var(--ccd-text-muted);\n --ccd-view-menu-border: var(--ccd-border);\n --ccd-view-menu-separator: var(--ccd-border-soft);\n --ccd-view-menu-accent: var(--ccd-accent);\n --ccd-view-menu-shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 8px 20px rgba(0, 0, 0, .3), 0 16px 32px rgba(0, 0, 0, .2);\n --ccd-selected: #3a3a37;\n /* The tab mark's tint, dark side: the accent's own hue over this card, which\n is the #d3e2f9 relationship the light side measures, not its value. */\n --ccd-right-panel-glyph-bg: #2b3a55;\n /* The Files pane's inks go back to the palette's own ramp here: the reference\n is a light-mode capture, and its three sampled values are only meaningful\n as relationships (a step below the body ink, a step above the muted one and\n the accent's own hue) that this side already carries. */\n --ccd-files-ink: var(--ccd-text);\n --ccd-right-panel-tab-ink: var(--ccd-text);\n --ccd-files-chip-ink: var(--ccd-accent);\n\n /* Lines */\n --ccd-border: #3e3e3b;\n --ccd-border-strong: #474743;\n --ccd-border-soft: #343431;\n /* The head rule stays the one line drawn stronger than the card outline. */\n --ccd-table-head-line: #4a4a46;\n /* The card outline's dark side: one step above the row outline, as in the\n light palette. */\n --ccd-right-panel-border: #474743;\n --ccd-browser-canvas: #242423;\n --ccd-browser-dot: #454542;\n\n /* Scrollbar ink, dark side: on this canvas the bar is the one piece of the\n chrome that has to read as raised, so it sits above every surface step\n here and lightens on hover \u2014 the mirror of the light palette, whose ink\n sits below every surface and darkens. */\n --ccd-scrollbar-thumb: #5c5b57;\n --ccd-scrollbar-thumb-hover: #75746f;\n\n /* Text */\n --ccd-text: #f0efec;\n --ccd-text-secondary: #b4b1ab;\n --ccd-text-muted: #918f89;\n /* Same step down from full strength as the light palette: the dark ink sits\n the same distance below --ccd-text as #4a4a47 sits below #1f1f1d. */\n --ccd-text-nav: #d3d0ca;\n --ccd-text-placeholder: #8b8983;\n /* Archived rows, dark side: the same two steps below the row ink, kept\n readable against this sidebar and the selected fill that sits above it. */\n --ccd-text-archived: #82807c;\n --ccd-text-archived-hover: #a6a39c;\n\n /* Composer whale, dark side: the same mark, with the blue raised so it reads\n against this canvas; the belly keeps the light ink. */\n --ccd-pet-blue: #7b93ff;\n --ccd-pet-light: #e8ecff;\n\n /* Statistics card, dark side: the same stacked greys over this canvas, and\n the heat ramp raised one step so the steps stay visible on a dark panel. */\n --ccd-stats-panel: #2c2c2a;\n --ccd-stats-tile: #383835;\n --ccd-stats-tab: #3a3a37;\n --ccd-stats-label: #918f89;\n --ccd-stats-value: #f0efec;\n --ccd-stats-heat-1: hsl(217 62% 78%);\n --ccd-stats-heat-2: hsl(217 64% 70%);\n --ccd-stats-heat-3: hsl(217 66% 62%);\n --ccd-stats-heat-4: hsl(217 70% 54%);\n /* Model ramp, raised for the dark panel; six distinct steps, as the light\n theme's clamped ramp produces. */\n --ccd-stats-model-1: hsl(217 62% 70%);\n --ccd-stats-model-2: hsl(217 64% 75%);\n --ccd-stats-model-3: hsl(217 66% 80%);\n --ccd-stats-model-4: hsl(217 68% 84%);\n --ccd-stats-model-5: hsl(217 70% 87%);\n --ccd-stats-model-6: hsl(217 70% 89%);\n --ccd-stats-tip-bg: #454542;\n --ccd-stats-tip-fg: #f7f7f5;\n\n /* Assistant Markdown palette, lightened for a dark transcript. */\n --ccd-link: #86b0e8;\n --ccd-link-underline: #4a5c76;\n --ccd-inline-code-text: #f0918a;\n --ccd-inline-code-fill: #35332f;\n --ccd-inline-code-border: #454239;\n\n /* Context meter ring, dark side: the same hue as the light accent, one step\n up in lightness (55% \u2192 68%) and saturation so the arc keeps its blue on\n this canvas instead of greying into it. Same `var()` order as the light\n block. */\n --ccd-context-ring-fill: var(--ccd-accent, #789be3);\n\n /* Context breakdown categories, dark side. The reference ships one light\n crop, so these are derived the way the rest of this palette is: the same\n hue, raised in lightness by the step the statistics ramp and the accent\n take on this canvas, so five categories stay five colours instead of\n sinking into the card. The two greys are the exception \u2014 they are surfaces\n rather than inks, so the buffer steps down to a mid warm grey and the free\n track steps up off the card, which is what keeps the reserved block and the\n empty room apart at a glance. */\n --ccd-context-mcp: #5b9ae8;\n --ccd-context-tools: #f0885a;\n --ccd-context-system: #43c79b;\n --ccd-context-skills: #f0b93c;\n --ccd-context-memory: #ef93b5;\n --ccd-context-messages: #a58fe6;\n --ccd-context-buffer: #5f5b53;\n --ccd-context-free: #3f3f3b;\n\n /* The accent, dark side: the same hue and the same 55% \u2192 68% lightness step\n the statistics heat ramp takes on this canvas, so the check keeps its blue\n against the menu's surface instead of sinking into it. The hue is the\n reference's measured blue (220) rather than the ramp's 217, but the two sit\n in one family. */\n --ccd-accent: #789be3;\n\n /* State colours that DSH already owns semantics for. */\n --ccd-diff-added: #7cbd72;\n --ccd-diff-removed: #e08fae;\n\n /* Elevation reads as a shadow under the surface, not as a grey wash. */\n --ccd-shadow-card: 0 1px 2px rgb(0 0 0 / 40%);\n --ccd-shadow-segment: 0 1px 2px rgb(0 0 0 / 50%);\n --ccd-right-panel-shadow: 0 1px 2px rgb(0 0 0 / 35%), 0 4px 10px rgb(0 0 0 / 35%);\n}\n\n/* zanwei effort reference palette, MIT; canvas reads these theme values. */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-effort-color-1: #8c73c9;\n --ccd-effort-color-2: #a17ec2;\n --ccd-effort-color-3: #5f5b58;\n --ccd-effort-color-4: #3f3b38;\n --ccd-effort-color-5: #77736f;\n --ccd-effort-color-6: #edeae8;\n --ccd-effort-color-7: #e0dbd6;\n --ccd-effort-color-8: #ffffff;\n --ccd-effort-color-9: rgba(76, 70, 65, 0.12);\n --ccd-effort-color-10: #2788d6;\n --ccd-effort-color-11: rgba(62, 56, 50, 0.05);\n --ccd-effort-color-12: rgba(62, 56, 50, 0.04);\n --ccd-effort-color-13: rgba(62, 56, 50, 0.06);\n --ccd-effort-color-14: #74706d;\n --ccd-effort-color-15: rgba(82, 76, 70, 0.055);\n --ccd-effort-color-16: rgba(76, 70, 65, 0.1);\n --ccd-effort-color-17: #34312f;\n --ccd-effort-color-18: rgba(35, 31, 29, 0.12);\n --ccd-effort-color-19: #fff;\n --ccd-effort-color-20: rgba(70, 64, 59, 0.035);\n --ccd-effort-color-21: #eeebe9;\n --ccd-effort-color-22: #ece9e7;\n --ccd-effort-color-23: #e2dce3;\n --ccd-effort-color-24: #d9d0df;\n --ccd-effort-color-25: #d0c1da;\n --ccd-effort-color-26: #cdbcd9;\n --ccd-effort-color-27: #cbbad8;\n --ccd-effort-color-28: #d5cadc;\n --ccd-effort-color-29: #c8b5d4;\n --ccd-effort-color-30: #bda6cc;\n --ccd-effort-color-31: #b59bc6;\n --ccd-effort-color-32: #b6b2af;\n --ccd-effort-color-33: rgba(76, 70, 65, 0.13);\n --ccd-effort-color-34: rgba(62, 56, 50, 0.08);\n --ccd-effort-color-35: rgba(62, 56, 50, 0.055);\n --ccd-effort-pixel-leftColor: 210, 206, 214;\n --ccd-effort-pixel-deepViolet: 156, 120, 192;\n --ccd-effort-pixel-deepMid: 156, 132, 192;\n --ccd-effort-pixel-midPurple: 168, 144, 204;\n --ccd-effort-pixel-softMid: 168, 156, 204;\n --ccd-effort-pixel-softLilac: 180, 168, 204;\n --ccd-effort-pixel-paleCool: 192, 180, 204;\n --ccd-effort-pixel-highlightColor: 216, 204, 228;\n --ccd-effort-pixel-peakColor: 232, 224, 242;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-effort-shadow: 0 1px 2px rgba(62, 56, 50, .05), 0 4px 10px rgba(62, 56, 50, .04), 0 12px 28px rgba(62, 56, 50, .06);\n}\n\n/*\n * The same reference field on the dark canvas: the purple ramp keeps its\n * left-to-right direction (neutral \u2192 violet) inside the dark range, the\n * neutrals flip so the panel is a card above the transcript, and the knob stays\n * the brightest thing on the track \u2014 its fill is also the tooltip's text\n * colour, so the two keep following one value.\n */\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-effort-color-1: #a48ede;\n --ccd-effort-color-2: #b294d3;\n --ccd-effort-color-3: #e7e4de;\n --ccd-effort-color-4: #f6f4f0;\n --ccd-effort-color-5: #a09b94;\n --ccd-effort-color-6: #3a3936;\n --ccd-effort-color-7: #4b4944;\n --ccd-effort-color-8: #2b2a28;\n --ccd-effort-color-9: rgba(255, 255, 255, 0.1);\n --ccd-effort-color-10: #4d93f8;\n --ccd-effort-color-11: rgba(0, 0, 0, 0.45);\n --ccd-effort-color-12: rgba(0, 0, 0, 0.35);\n --ccd-effort-color-13: rgba(0, 0, 0, 0.45);\n --ccd-effort-color-14: #b7b2aa;\n --ccd-effort-color-15: rgba(255, 255, 255, 0.06);\n --ccd-effort-color-16: rgba(255, 255, 255, 0.14);\n --ccd-effort-color-17: #3a3936;\n --ccd-effort-color-18: rgba(0, 0, 0, 0.5);\n --ccd-effort-color-19: #ece9e4;\n --ccd-effort-color-20: rgba(255, 255, 255, 0.04);\n --ccd-effort-color-21: #34332f;\n --ccd-effort-color-22: #373430;\n --ccd-effort-color-23: #3e3943;\n --ccd-effort-color-24: #463e51;\n --ccd-effort-color-25: #4f4560;\n --ccd-effort-color-26: #57496a;\n --ccd-effort-color-27: #5c4d71;\n --ccd-effort-color-28: #524667;\n --ccd-effort-color-29: #63527c;\n --ccd-effort-color-30: #6e5989;\n --ccd-effort-color-31: #786096;\n --ccd-effort-color-32: #6f6c66;\n --ccd-effort-color-33: rgba(255, 255, 255, 0.16);\n --ccd-effort-color-34: rgba(0, 0, 0, 0.4);\n --ccd-effort-color-35: rgba(0, 0, 0, 0.35);\n --ccd-effort-pixel-leftColor: 92, 88, 98;\n --ccd-effort-pixel-deepViolet: 150, 116, 196;\n --ccd-effort-pixel-deepMid: 150, 128, 196;\n --ccd-effort-pixel-midPurple: 162, 140, 204;\n --ccd-effort-pixel-softMid: 162, 152, 204;\n --ccd-effort-pixel-softLilac: 174, 164, 206;\n --ccd-effort-pixel-paleCool: 184, 174, 206;\n --ccd-effort-pixel-highlightColor: 200, 188, 224;\n --ccd-effort-pixel-peakColor: 214, 204, 236;\n --ccd-effort-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 10px rgba(0, 0, 0, .3), 0 12px 28px rgba(0, 0, 0, .35);\n}\n\n/*\n * Chosen-value ink. The Composer's model name \u2014 in the tool row and in the menu\n * it opens \u2014 is the value that row exists to show, so it takes full black\n * instead of the warm near-black every other primary label uses; the dark\n * scheme keeps the same relationship with its own strongest ink, white. Neither\n * side is derived from a configured surface, so the pair is declared here\n * rather than in the scheme blocks above.\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-text-strong: #000000;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-text-strong: #ffffff;\n}\n\n/*\n * Header icon ink.\n *\n * The conversation header's trailing cluster is icon-only \u2014 the native session\n * menu, the two views this plugin adds, the scheduled-tasks entry while it has\n * records, the collapsed right panel's re-entry control \u2014 and the reference\n * draws those marks at full strength where the host uses its secondary label\n * grey. Like the chosen-value ink above, this pair answers to no configured\n * surface, so it is declared here rather than in the scheme blocks: the pure\n * black the reference measured on the light canvas, and its mirror white on the\n * dark one, because a black mark would vanish into that canvas.\n *\n * What each state puts behind the mark stays the host's: a near-black wash at\n * 6-14% in the light scheme, a white one at 8-14% in the dark, and the button's\n * own dimmed opacity while it is disabled \u2014 so the ink never meets a fill of its\n * own lightness (see `header-actions.css`).\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-header-icon-color: #000000;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-header-icon-color: #ffffff;\n}\n\n/*\n * The selected check in every Menu surface.\n *\n * The host paints it with `--dsw-alias-label-primary` in the Menu primitive's\n * own `Menu.module.css` (`.check`), so the workspace picker, the permission\n * menu, the view-options menu and the session \u22EF menu all show the same\n * near-black mark \u2014 a selection reads no louder than the label beside it. One\n * rule recolours all of them, because they all come from that one primitive.\n * The model picker is not one of them: it is this plugin's own card, and the\n * block at the end of this file is the rule that reaches its mark.\n *\n * Only the colour changes: the mark keeps the host's 14px seat, its\n * `display: grid` centring, its row height and every hover fill. The class is\n * the one the shipped static web frontend gives that module (`_4ub78_`, whose\n * local names run `_check_4ub78_179`, `_item_4ub78_90`, \u2026), and that asset is\n * platform-independent \u2014 both installers carry the identical\n * `@deepseek-ai/dsh-web-frontend` dist \u2014 so it is the same name on Windows and\n * needs no second spelling in `host-builds.ts` (`host-dom.ts` records the same\n * prefix).\n *\n * The rule covers the seat and its artwork: the svg inherits through\n * `currentColor`, and naming it as well keeps the mark blue even if a future\n * build moves the colour onto the artwork instead of the seat.\n */\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] ._check_4ub78_179,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitem\"] ._check_4ub78_179,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] ._check_4ub78_179 svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitem\"] ._check_4ub78_179 svg {\n color: var(--ccd-accent);\n}\n\n/*\n * The selected mark in the model picker.\n *\n * The Composer's model seat is not the host's `ModelSelect`: this plugin's\n * `ModelControls` wins `conversation.input.model` (its registration carries\n * `priority: -10` while the host registers the same seat at the default 0, and\n * the slot chain takes the lowest priority that answers), and the card that\n * seat opens marks the chosen model with the text `\u2713` in the row's trailing\n * `span[aria-hidden=\"true\"]` (`features/model-controls/ModelControls.tsx`).\n * `features/model-controls/controls.css` paints that row `--ccd-text-strong`,\n * so the mark inherits full black \u2014 which is exactly what it did: it is\n * neither `._check_4ub78_179` nor an svg, so the Menu rule above cannot reach\n * it, and no `fill`/`stroke` override would either, because a text glyph is\n * painted by `color` alone.\n *\n * Only the ink changes: the row keeps its height, padding and hover, and the\n * artwork is named beside the seat so a later icon in the same seat stays\n * covered. The seat is reached two ways \u2014 the row's own selected state\n * (`aria-pressed`, which React writes as `\"true\"`/`\"false\"`) and the seat that\n * actually holds a glyph (`:not(:empty)`, because the unchosen rows render an\n * empty span) \u2014 so a later switch to `aria-checked` on a `menuitemradio` row\n * cannot silently return this mark to black.\n *\n * The host's own `ModelSelect` card is covered as well, for the path where\n * that seat is the one on screen: its `.check` seat holds an svg whose path\n * strokes `currentColor` (ui-primitives `IconCheckOutlineArtwork`), so the\n * same `color` reaches the artwork. `cl2Rlq_` is already in the prefix table\n * (`compat/host-dom.ts`), and the Windows build's `wq12jW_` spelling is what\n * `compat/dom.ts` substitutes when this sheet is mounted.\n */\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button[aria-pressed=\"true\"] > span[aria-hidden=\"true\"],\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button[aria-pressed=\"true\"] > span[aria-hidden=\"true\"] svg,\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button > span[aria-hidden=\"true\"]:not(:empty),\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button > span[aria-hidden=\"true\"]:not(:empty) svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] .cl2Rlq_check,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitemradio\"] .cl2Rlq_check,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] .cl2Rlq_check svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitemradio\"] .cl2Rlq_check svg {\n color: var(--ccd-accent);\n}\n";
|
|
4441
|
+
var tokens_default = "/* CCD geometry, type, artwork and light/dark colour variables.\n * Colours are centralized here; the dark palette follows the host's body marker.\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n /* Geometry */\n /* Top of the blank-session greeting block. The reference puts the title a\n short step below the header instead of centring it, so the statistics card\n hanging under it still clears the Composer on a short window. */\n --ccd-hero-top: 16px;\n --ccd-sidebar-width: 264px;\n --ccd-sidebar-inline-padding: 10px;\n --ccd-sidebar-bottom-padding: 8px;\n --ccd-row-height: 28px;\n /* Workspace (group) row. The host's own 34px, pinned because the browsing\n region's merged header band is this same box: the section header parks on\n the row's line and the two have to agree to the pixel. */\n --ccd-workspace-row-height: 34px;\n /* Navigation stack. The reference's three rows measured 26px tall on a 26.5px\n pitch \u2014 contiguous, not separated \u2014 against the host's own 36px/7px row. */\n --ccd-nav-row-height: 26px;\n --ccd-nav-gap: 1px;\n --ccd-radius-row: 8px;\n --ccd-radius-panel: 12px;\n /* View-options reference: 20 device px corners at @2x. */\n --ccd-view-menu-radius: 10px;\n /* Assistant table card. The reference crop's corner curve fits a 12-device-px\n radius at @2x, so the card is rounder than the row radius it borrows its\n scale from. */\n --ccd-table-radius: 6px;\n /* Fenced code block card. The reference code block shows the same 12-device-px\n curve at @2x as the table card, so the transcript's two boxed surfaces stay\n one family. */\n --ccd-code-radius: 6px;\n --ccd-composer-width: 770px;\n --ccd-composer-min-height: 42px;\n --ccd-composer-radius: 10px;\n --ccd-composer-padding: 8px 14px;\n --ccd-composer-padding-block: 8px;\n --ccd-composer-padding-inline: 14px;\n --ccd-composer-row-gap: 4px;\n --ccd-composer-row-inset: 4px;\n --ccd-composer-bottom-gap: 5px;\n --ccd-control-row-height: 28px;\n /* Status-bar chip. The tool row's controls are all this one box: the row's\n 28px is the layout line, and every control inside it is a chip of this\n height rather than a box stretched to the line. The reference draws the\n model chip's fill as one label line \u2014 40 device px at @2x, so the row's\n 12px label sits 5.5px from the chip's top and bottom where the row itself\n would leave it 10px \u2014 and the same box now carries the command plus, the\n permission control, the voice control, the statistics readouts and the\n context ring, so a pointer crossing the row finds one fill height instead\n of three. The row keeps `--ccd-control-row-height`: the dock, the ring's\n seat and the trailing cluster are all measured from it. The corner follows\n the height \u2014 12 device px at @2x, the same curve the transcript's table and\n code cards carry, rather than the row's 8px radius, which is nearly half of\n a 20px chip and would round every fill towards a pill. */\n --ccd-chip-height: 20px;\n --ccd-chip-radius: 6px;\n /* The chip family's inline padding: the model/effort chips, the permission\n control and the two square glyph buttons (plus, voice), whose boxes are\n their 14px artwork plus one of these on each side. Six to seven px is the\n whole range in the reference; the readouts and the ring keep their own\n slightly tighter 6px, which is a 1px difference in ink and nothing in a\n fill's shape. */\n --ccd-chip-padding-inline: 7px;\n --ccd-send-size: 24px;\n --ccd-send-reserve: 30px;\n /* One gap for the whole status row: the row itself, the leading tools group,\n its modes cluster, the trailing cluster (the native readouts, the context\n ring, the model/effort pair) and the statistics dock all space their\n children with this. The host's own row ran 12px in the leading groups and\n the plugin's 6px in the trailing one, which read as two different rows in\n one bar. Each control carries its own 6-7px inner padding, so an even box\n gap also reads as an even visible rhythm. */\n --ccd-cluster-gap: 6px;\n /* Context ring. The host draws it as 14px artwork (`ContextMeter.module.css`:\n viewBox 0 0 14 14, cx=cy=7, r=5.5, 2px stroke, round cap) inside a 28px\n trigger with 6px of side padding, so the trigger's own box is 26px and the\n seat the status bar has to hold for it \u2014 that box plus one cluster gap \u2014 is\n 32px. The host's ring and this plugin's empty-state ring hang in that one\n seat, which is what keeps the ring's position and size the same before and\n after a session has usage. */\n --ccd-context-ring-size: 14px;\n --ccd-context-ring-trigger: 26px;\n --ccd-context-ring-seat: calc(var(--ccd-context-ring-trigger) + var(--ccd-cluster-gap));\n /* Context breakdown panel. Measured off the supplied reference at @2x\n (698\xD7178 for the collapsed state, 828\xD71006 for the expanded one): a 361px\n card with a 1px outline and a 12px corner, 12px inline and 8px top padding,\n a 13px/20px header, a 4px bar 5px under it, 19px value rows, 17px detail\n rows, and 10px swatches. The width is the one number the crop cut off, so\n it is the reference's own rounded value: the bar and the percentage column\n both end exactly at 360 \u2212 2 \u2212 24 = 334px, which is what the crop shows. */\n --ccd-context-panel-width: 360px;\n --ccd-context-panel-radius: 12px;\n --ccd-context-panel-padding-block: 8px;\n --ccd-context-panel-padding-inline: 12px;\n --ccd-context-panel-gap: 8px;\n --ccd-context-row-height: 19px;\n --ccd-context-detail-height: 17px;\n --ccd-context-swatch-size: 10px;\n --ccd-context-swatch-radius: 3px;\n --ccd-context-bar-height: 4px;\n --ccd-context-bar-radius: 2px;\n --ccd-context-bar-gap: 1px;\n /* 5px under the header line, and nothing below: the card's own bottom padding\n is what follows the bar in the collapsed state, and the rows state their\n own 4px above themselves in the expanded one. */\n --ccd-context-bar-margin-block: 5px 0;\n /* The buffer segment's own step away from the used group: the reference\n leaves 4px there where every used segment is 1px apart, because the grey\n block is a reservation rather than another category. */\n --ccd-context-bar-reserve-gap: 4px;\n /* Ten detail rows before a group scrolls \u2014 the reference's own visible run,\n and what keeps a session with 85 tools from drawing a 1500px panel. */\n --ccd-context-detail-max: 170px;\n /* The two value columns: the token column's right edge sits 48px in from the\n content edge (measured 618 of 715 device px), which is a 40px percentage\n column plus this gap. */\n --ccd-context-percent-width: 40px;\n --ccd-context-column-gap: 8px;\n /* The status bar's own glyph size: the command plus, the statistics readouts\n and the ring all draw 14px artwork in the 28px control row. The\n speech-to-text control draws 18px of its own; the composer sheet brings that\n one down to this size. The permission control draws no glyph at all \u2014 it is\n its text (composer.css). */\n --ccd-row-icon-size: 14px;\n --ccd-account-menu-width: 236px;\n --ccd-account-menu-padding: 5px;\n --ccd-account-row-height: 28px;\n --ccd-account-trigger-height: 30px;\n /* Conversation header action cluster. The CCD reference keeps every control\n on one 30px centre pitch with a 12px trailing inset (measured at @2x from\n docs/reference/ccd-conversation.png: icon centres 28.75/30/30px apart, the\n trailing glyph centre 25.75px from the window edge). That inset is what the\n cluster takes while the Composer is narrower than the column and centred in\n it; where the Composer fills the column, `conversation.css` ends the\n cluster on the input surface's own border instead, which is the line the\n reference puts the closing control on and a measurement rather than a\n second token. */\n --ccd-header-action-size: 28px;\n --ccd-header-action-compact: 24px;\n --ccd-header-icon-size: 16px;\n --ccd-header-action-gap: 2px;\n --ccd-header-trailing-inset: 12px;\n --ccd-header-menu-border: #d6d6d6;\n --ccd-header-menu-separator: #e2e2e2;\n --ccd-header-menu-danger: #b4262b;\n --ccd-menu-danger: #c04742;\n --ccd-menu-danger-ink: #ffffff;\n --ccd-header-trigger-hover: #f0f0ef;\n --ccd-header-project-fill: #e5e5e5;\n --ccd-header-project-active: #cfcfcf;\n /* Transcript edge fade. 24px is the band the host's own internal-request\n viewer uses for `fadeTop`\uFF0F`fadeBottom`, so the whole interface softens its\n scroll viewport edges by the same amount. */\n --ccd-edge-fade: 24px;\n /* Jump-to-bottom control. The reference's own affordance measures 40\xD744\n device px at @2x \u2014 a ~21px mark above the Composer \u2014 against the host's\n 34px floating circle, so the box shrinks to this one step while the glyph\n inside it keeps the host's 16px seat. */\n --ccd-to-bottom-size: 22px;\n /* Right panel (the Files, terminal and browser tabs). The reference draws it\n as a floating card: 16 device px in from the column's top, right and bottom\n edges; a 12px corner (measured off the fill: the curve is 20 device px at\n @2x from its first inset pixel to the straight edge, plus the 1px outline);\n a 32px header strip whose 24px tab mark sits 4px under the card's top; and\n an 8px pane gutter (16 device px), which is where the Files pane's own row\n line begins. */\n --ccd-right-panel-inset: 8px;\n --ccd-right-panel-radius: var(--ccd-radius-panel);\n --ccd-right-panel-strip-height: 32px;\n --ccd-right-panel-gutter: 8px;\n --ccd-right-panel-gap: 12px;\n /* The tab's own mark, measured off the reference: a 24px square (5px corner,\n carried by the chip radius) tinted #d3e2f9 behind the 16px glyph. */\n --ccd-right-panel-glyph-size: 24px;\n /* Files tree. The reference's rows run on a 24px pitch (48 device px at @2x)\n where the host's 13px/1.5 row draws 29.5px, and its pane header is the\n 26px rounded field over them. */\n --ccd-files-row-height: 24px;\n --ccd-files-field-height: 26px;\n --ccd-files-glyph-size: 16px;\n\n /* Claude Desktop 2.31226.1's active flat frame, confirmed by window capture:\n gray-10 canvas; sidebar mixes gray-20 and gray-10 equally in sRGB. */\n --ccd-canvas: #fcfcfb;\n --ccd-sidebar: #fbfbf9;\n --ccd-card: #ffffff;\n /* Segmented-control track. The reference measures #f6f6f4 against a white\n page; the same step down from this canvas keeps the same contrast. */\n --ccd-track: #f3f3f2;\n --ccd-raised: #f0f0ef;\n --ccd-hover: #f0f0ee;\n /* Sampled from the supplied view-options reference, separate from the\n warmer surfaces used by Composer and the host's other menus. */\n --ccd-view-menu-hover: #f5f5f5;\n --ccd-view-menu-text: #0b0b0b;\n --ccd-view-menu-muted: #9b9994;\n --ccd-view-menu-border: #d7d7d6;\n --ccd-view-menu-separator: #ebebeb;\n --ccd-view-menu-accent: #2a78d6;\n --ccd-view-menu-shadow: 0 1px 3px rgba(0, 0, 0, .08), 0 8px 20px rgba(0, 0, 0, .12), 0 16px 32px rgba(0, 0, 0, .06);\n --ccd-selected: #ecebe8;\n /* The fill a control takes while it sits on a row that is already filled:\n a Session row paints `--ccd-selected` under the pointer, so its \u22EE takes\n this one to stay a step below what it stands on. Sampled from the supplied\n reference at @2x, where that row measures #edece9 under the control's own\n #e1e0dd \u2014 the same 12/255 step, and the relationship `theme/palette.ts`\n derives for a configured canvas. */\n --ccd-hover-strong: #e1e0dd;\n /* The right panel's tab mark: the reference's own blue-tinted square,\n sampled at #d3e2f9 with the accent for its glyph. It is the one tinted seat\n in this plugin's surfaces, so it is stated rather than derived. */\n --ccd-right-panel-glyph-bg: #d3e2f9;\n /* The Files pane's own ink, sampled off the reference at @2x. Its tree names\n and its empty state's title measure #0b0b0b \u2014 a step below this palette's\n `--ccd-text`, the ink the rest of the interface draws \u2014 and its tab title\n measures #52514f, between `--ccd-text` and `--ccd-text-secondary`. The tab\n mark's glyph is the one blue that is not this palette's accent: the\n reference draws it #304e91 on the #d3e2f9 square. */\n --ccd-files-ink: #0b0b0b;\n --ccd-right-panel-tab-ink: #52514f;\n --ccd-files-chip-ink: #304e91;\n\n /* Lines */\n --ccd-border: #e3e3e1;\n --ccd-border-strong: #e0e0df;\n --ccd-border-soft: #ebebe9;\n /* The rule under a table head reads one step stronger than the card outline\n in the reference (#d9d9d9 against #e3e3e3). */\n --ccd-table-head-line: #d9d9d8;\n /* The right panel's card outline, sampled at #d7d7d6 \u2014 one step stronger than\n the row outline above and the same ink the menu cards' own border carries,\n which is what makes a floating panel and a menu read as one material. */\n --ccd-right-panel-border: #d7d7d6;\n --ccd-browser-canvas: #f7f7f7;\n --ccd-browser-dot: #d1d0ce;\n\n /* Scrollbar ink. The host paints the scrollbars themselves\n (`ui-theme/src/styles/scrollbar.css`: a 5px track and a pill thumb read\n from `--dsh-scrollbar-thumb`), and this interface keeps that geometry \u2014\n the transcript's stable gutter, the sidebar's\n `--dsh-session-list-scrollbar-width` padding and the dockkit panes are all\n measured against the host's own width \u2014 so these two tokens are the ink\n alone, bound in theme/scrollbars.css.\n The ink is near-black by decision rather than by measurement: the bar is\n 5px wide and carries no surface of its own, so none of this palette's\n surface steps \u2014 5% to 14% black \u2014 reads at that size, and the interface\n this one follows draws a dark scrollbar. Hover goes one step further down,\n the direction the host's own hover step takes. */\n --ccd-scrollbar-thumb: #333331;\n --ccd-scrollbar-thumb-hover: #171716;\n\n /* Text */\n --ccd-text: #1f1f1d;\n --ccd-text-secondary: #6f6f6a;\n --ccd-text-muted: #8f8f8a;\n --ccd-text-placeholder: #89877f;\n /* One step below full strength: a row that is not the current one. The\n reference paints its inactive navigation rows at #4a4a47 \u2014 between this\n palette's --ccd-text and --ccd-text-secondary \u2014 and keeps the current row\n at full black, so the stack reads as one current entry plus quieter\n neighbours instead of three equally loud labels. */\n --ccd-text-nav: #4a4a47;\n /* Archived Session row. The host fades that title with its own caption ink,\n but this plugin's row ink outranks the host pair, so the state needs a step\n of its own: one above --ccd-text-muted on the same warm ramp, which is the\n faded row the reference draws while still reading against the sidebar. A row\n that is current or under the pointer takes the second value, because the\n hover and selected fills sit a step below the sidebar the first one was\n measured on. */\n --ccd-text-archived: #a0a09b;\n --ccd-text-archived-hover: #8a8a85;\n\n /* New-session statistics card. The reference panel is a stacked translucent\n grey: the card is 5% black over the canvas and a stat tile (and an empty\n heat cell) is 10% black over the card, so these are the measured opaque\n equivalents. The four heat levels are the reference's own `hsl(217 70% L%)`\n with L = 72\uFF0F64\uFF0F56\uFF0F48, i.e. \"that day's value / the busiest day\" in four\n equal steps. */\n --ccd-stats-panel: #f0f0f0;\n --ccd-stats-tile: #dadada;\n /* The card header's active tab: the reference paints `fill-ghost-hover`, the\n same 5% black as the card itself, over the card \u2014 one step lighter than a\n stat tile. */\n --ccd-stats-tab: #e6e6e6;\n --ccd-stats-label: #898781;\n --ccd-stats-value: #0b0b0b;\n --ccd-stats-heat-1: hsl(217 70% 72%);\n --ccd-stats-heat-2: hsl(217 70% 64%);\n --ccd-stats-heat-3: hsl(217 70% 56%);\n --ccd-stats-heat-4: hsl(217 70% 48%);\n /* The `Models` view colours its bars and legend by rank:\n `hsl(217 70% min(88, 58 + 7n)%)`, which flattens into these six shades. */\n --ccd-stats-model-1: hsl(217 70% 58%);\n --ccd-stats-model-2: hsl(217 70% 65%);\n --ccd-stats-model-3: hsl(217 70% 72%);\n --ccd-stats-model-4: hsl(217 70% 79%);\n --ccd-stats-model-5: hsl(217 70% 86%);\n --ccd-stats-model-6: hsl(217 70% 88%);\n /* Tooltips are the reference's dark popup in both themes; on a dark panel it\n steps up to a mid grey so the box keeps its contrast. */\n --ccd-stats-tip-bg: #0c0c0c;\n --ccd-stats-tip-fg: #f7f7f5;\n\n /* Assistant Markdown palette matched to the CCD transcript reference. */\n --ccd-link: #2b61b5;\n --ccd-link-underline: #a7badd;\n --ccd-inline-code-text: #b63630;\n --ccd-inline-code-fill: #f1f1f0;\n --ccd-inline-code-border: #e2e2e0;\n\n /* Context meter. The host paints the ring's consumed arc with the same\n tertiary label grey as the percentage beside it, so the reading carries no\n weight. The accent blue is this plugin's one emphasis colour: taking it\n through `var()` lets the ring follow `--ccd-accent` the moment that token\n exists, and the fallback is the blue measured off the target arc\n (docs/issues/img/12-2.png), so the ring is never left grey meanwhile. The\n track underneath stays the host's `--dsw-alias-border-l3`, which\n theme/tokens.ts already overrides. */\n --ccd-context-ring-fill: var(--ccd-accent, #4b76ce);\n\n /* Context breakdown categories, sampled from the supplied reference's bar and\n swatches. Seven steps, in the order the panel and the bar draw them: the\n reference's own hues, which are deliberately outside this palette's blue\n ramp \u2014 a breakdown that reused one hue family would make five categories\n read as one. `--ccd-context-free` is both the free-space swatch and the\n bar's track, exactly as the reference draws them. */\n --ccd-context-mcp: #2a78d8;\n --ccd-context-tools: #e96a33;\n --ccd-context-system: #1ead7c;\n --ccd-context-skills: #eda105;\n --ccd-context-memory: #ea7ca4;\n /* The conversation's own row. The reference's crop happens to hold no\n messages at all \u2014 89k of its 9% reading is prompt, tools and skills \u2014 so\n this one is chosen rather than sampled: the same lightness and chroma as\n its neighbours, one hue family over, so it cannot be mistaken for the\n accent blue of MCP tools. */\n --ccd-context-messages: #8b6fd4;\n --ccd-context-buffer: #c2c0b8;\n --ccd-context-free: #eeeeee;\n\n /* The plugin's one emphasis blue: the selected check in every Menu surface,\n the context ring, and whatever else has to read as \"this one is chosen\".\n It is the blue measured off the reference check mark\n (docs/issues/img/01-3.png: the stroke's own pixels are #4b76d0/#507ad2, so\n the token takes the darker mode) and shares the stats heat ramp's hue\n family (hsl(217 \u2026)), which keeps every blue in the interface one voice. */\n --ccd-accent: #4b76ce;\n\n /* State colours that DSH already owns semantics for. */\n --ccd-diff-added: #508c48;\n --ccd-diff-removed: #b33156;\n\n /* Type. The two fallback tails are what a configured family is prepended to\n (see theme/tokens.ts); with nothing configured the consuming variables keep\n the built-in stacks. Geist leads the interface tail because it is the\n upstream design Anthropic Sans was cut from; it is resolved from the system\n font list, so the tail degrades to the platform stack when it is not\n installed (assets/fonts/ ships the file for a local install only). */\n --ccd-font-fallback: Geist, -apple-system, BlinkMacSystemFont, \"SF Pro Text\", \"Helvetica Neue\",\n \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif;\n --ccd-code-fallback: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace;\n --ccd-font-ui: var(--ccd-font-fallback);\n --ccd-font-code: var(--ccd-code-fallback);\n --ccd-font-size-body: 14px;\n --ccd-font-size-muted: 13px;\n /* Blank-session title. The reference's own type scale puts the greeting on\n `--cds-font-size-title` (1.25rem, ~20px) with a 25px leading at weight 400,\n which is a good deal quieter than the 26px this used to be. */\n --ccd-font-size-headline: 20px;\n /* Transcript headings. The reference's ladder sits one step under the host's\n (DSH draws h1/h2/h3 at 21/19/18px): its own crop measures a 19px h1 and a\n 16px h2 over the 14px body \u2014 27 and 23 device px of CJK ink against the\n 21-device-px body line at @2x \u2014 and the h2 is confirmed independently by\n the inline-code chip, whose 0.95em/1.2 rule this plugin already matches:\n it lands on the reference's 33 device px exactly at 16px. h3 has no crop of\n its own and takes the next step down. */\n --ccd-font-size-h1: 19px;\n --ccd-font-size-h2: 16px;\n --ccd-font-size-h3: 15px;\n /* Transcript leading. The host sets the assistant body at 14px/24px; the\n reference runs the same 14px on a 20px line. Its own window measures a\n 30.7-device-px pitch between two lines of a paragraph where this plugin's\n 24px draws 36.6, and both shots put their body's CJK ink at 20 device px\n with a 770px Composer at 1176 (1.53 device px per CSS px), so the two are\n read at one scale. The reference's paragraph-to-paragraph gap is 46 device\n px \u2014 this 20px line plus the 10px margin both sides already share. */\n --ccd-transcript-line-height: 20px;\n /* The one step up from the host's own 400: used where a control has to read\n as a chosen value rather than as chrome (model, reasoning effort). */\n --ccd-font-weight-strong: 600;\n\n /* Hand-drawn 16px marks matching the CCD interaction recording: return\n arrow and a small square in a ring. The host keeps its buttons, handlers\n and SVG state markers; these masks replace only their visible artwork. */\n --ccd-send-radius: 6px;\n --ccd-icon-send: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M12 4.5V8A2 2 0 0 1 10 10H3.5M6.5 7L3.5 10L6.5 13' stroke='black' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n --ccd-icon-stop: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5.5' fill='none' stroke='black' stroke-width='1.25'/%3E%3Crect x='6' y='6' width='4' height='4' rx='.6' fill='black'/%3E%3C/svg%3E\");\n\n /* The header's three painted glyphs, taken from DSH 0.2.0-rc.2 shared\n artwork (MIT) so no host component is copied:\n - IconRightUpOutlineRegular (`ui-primitives/icons`) is the generic \"open\"\n glyph the native open-in-app control falls back to;\n - the terminal prompt is `ui-sidebar-terminal/TerminalIcon`'s own 16px\n geometry, the glyph that view's tab title draws;\n - the globe is `ui-primitives`' IconGlobeOutlineRegular, the glyph\n `ui-sidebar-browser` draws in its tab title.\n Masks let the host keep ownership of its buttons while the plugin supplies\n the artwork. */\n --ccd-icon-open: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M11.7256 2.77441C12.5538 2.77469 13.2256 3.44616 13.2256 4.27441V10.1416H12.2256V4.27441C12.2256 3.99844 12.0015 3.77469 11.7256 3.77441H5.7207V2.77441H11.7256Z' fill='black'/%3E%3Cpath d='M2.77441 13.2255L12.3756 3.62427' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-terminal: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 4L7 8L3 12' stroke='black'/%3E%3Cpath d='M9 12H13' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-browser: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M7.99986 14.0887C11.3626 14.0887 14.0886 11.3627 14.0886 7.99998C14.0886 4.63727 11.3626 1.91125 7.99986 1.91125C4.63715 1.91125 1.91113 4.63727 1.91113 7.99998C1.91113 11.3627 4.63715 14.0887 7.99986 14.0887Z' stroke='black'/%3E%3Cpath d='M2.34619 8H13.6538' stroke='black' stroke-linecap='square'/%3E%3Cpath d='M7.99976 14.0889C9.23509 14.0889 10.1743 11.3629 10.1743 8.00006C10.1743 4.63739 9.23509 1.91138 7.99976 1.91138' stroke='black'/%3E%3Cpath d='M7.99973 14.0889C6.76445 14.0889 5.8252 11.3629 5.8252 8.00006C5.8252 4.63739 6.76445 1.91138 7.99973 1.91138' stroke='black'/%3E%3C/svg%3E\");\n\n /* The session menu's own mark, stacked. The host draws\n `IconEllipsisOutlineRegular` (`ui-primitives`, MIT) as three 2px dots on one\n horizontal line \u2014 circles at (3, 8), (8, 8) and (13, 8) of a 16px box \u2014 and\n the reference stacks them, so this is that same geometry transposed to\n (8, 3), (8, 8) and (8, 13): one dot size, one 5-unit pitch, one 16px box,\n carried as a mask over the button's own `currentColor` so the host keeps its\n button and this interface supplies the mark. */\n --ccd-icon-more: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 4C8.55228 4 9 3.55228 9 3C9 2.44772 8.55228 2 8 2C7.44772 2 7 2.44772 7 3C7 3.55228 7.44772 4 8 4Z' fill='black'/%3E%3Cpath d='M8 9C8.55228 9 9 8.55228 9 8C9 7.44772 8.55228 7 8 7C7.44772 7 7 7.44772 7 8C7 8.55228 7.44772 9 8 9Z' fill='black'/%3E%3Cpath d='M8 14C8.55228 14 9 13.55228 9 13C9 12.44772 8.55228 12 8 12C7.44772 12 7 12.44772 7 13C7 13.55228 7.44772 14 8 14Z' fill='black'/%3E%3C/svg%3E\");\n\n /* A bare plus, the one glyph the reference repeats on every actionable row.\n It is DSH's own `IconPlusOutlineArtwork` geometry (ui-primitives, MIT): two\n 1px strokes across a 16px box, so the plugin can put the same mark on the\n Workspace header's add button and on a project row's create button without\n authoring artwork of its own. */\n --ccd-icon-plus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 2V14' stroke='black'/%3E%3Cpath d='M2 8H14' stroke='black'/%3E%3C/svg%3E\");\n\n /* The workspace picker chip's leading mark. DSH switches that glyph with the\n chip's own state \u2014 `IconFolderOpenRegular` once a workspace is chosen, a\n closed folder while the chip only carries a placeholder \u2014 and the open one\n draws a slanted front panel over a translucent back panel, where the\n reference's button leads with one closed folder in either state. The\n geometry below is DSH's own `FolderCloseArtwork` (`ui-primitives`, MIT) on\n its 16-unit grid and 1px stroke, with the artwork's second path \u2014 the rule\n line across the body \u2014 left out: the reference draws the body empty, and\n the tab, the step and the four rounded corners are the whole of the mark. */\n --ccd-icon-folder: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M1.50439 3.11059C1.50439 2.55831 1.95211 2.1106 2.50439 2.1106H5.43389C5.67773 2.1106 5.91318 2.19969 6.09593 2.36113L7.71649 3.79265C7.89924 3.95409 8.1347 4.04319 8.3785 4.04319H13.4958C14.0481 4.04319 14.4958 4.4909 14.4958 5.04319V12.8894C14.4958 13.4417 14.0481 13.8894 13.4958 13.8894H2.50439C1.95211 13.8894 1.50439 13.4417 1.50439 12.8894V4.04319V3.11059Z' stroke='black'/%3E%3C/svg%3E\");\n\n /* The reference's disclosure mark is a 1px line chevron where the host draws a\n filled triangle; this is DSH's own `IconChevronRightOutlineArtwork` geometry\n (ui-primitives, MIT). It is painted over the host's mark slot, so the host's\n own `arrowOpen` state still drives the quarter turn. */\n --ccd-icon-chevron-right: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M6 12L9.29289 8.70711C9.68342 8.31658 9.68342 7.68342 9.29289 7.29289L6 4' stroke='black'/%3E%3C/svg%3E\");\n\n /* The Files tree's two file marks, measured off the reference at @2x: a page\n with its bottom-right corner folded, and the angle-bracket pair, each drawn\n 8\u20139px wide inside the 16px seat the host's own type glyphs occupy (the\n reference's names then start on the same 33px the row's own gap states).\n DSH classifies a file by name and extension too, but its set is a\n different one \u2014 `.gitignore` is a git file to the host and a plain page to\n the reference, `LICENSE` a page to both \u2014 so `right-panel.css` carries the\n reference's own split as an extension list rather than reading the host's. */\n --ccd-icon-file: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M5.5 4.5H10.5C11.0523 4.5 11.5 4.94772 11.5 5.5V8.5L8.5 11.5H5.5C4.94772 11.5 4.5 11.0523 4.5 10.5V5.5C4.5 4.94772 4.94772 4.5 5.5 4.5Z' stroke='black'/%3E%3Cpath d='M8.5 8.5H11.5L8.5 11.5' stroke='black'/%3E%3C/svg%3E\");\n --ccd-icon-file-code: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M6.2 5.2L4.2 8.05L6.2 10.9' stroke='black' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M9.8 5.2L11.8 8.05L9.8 10.9' stroke='black' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M9.4 4.6L6.6 11.4' stroke='black' stroke-linecap='round'/%3E%3C/svg%3E\");\n\n /* The Files tab's mark: the reference draws a three-row list \u2014 a bullet and a\n rule per row \u2014 12px of ink on the tab's own blue square, so the artwork is\n stated on the square's 24-unit grid. The square itself is a seat the tab\n sheet paints; this is only the ink that sits in it. */\n --ccd-icon-files-list: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='black'%3E%3Crect x='6' y='6.5' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='6.5' width='8' height='2' rx='.5'/%3E%3Crect x='6' y='11' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='11' width='8' height='2' rx='.5'/%3E%3Crect x='6' y='15.5' width='2' height='2' rx='.5'/%3E%3Crect x='9.5' y='15.5' width='8' height='2' rx='.5'/%3E%3C/g%3E%3C/svg%3E\");\n\n /* The Files pane's magnifier, for the filter field's leading seat and for the\n one control the pane's header adds: a lens and a handle, 13px of ink in the\n 16px box the field's own row draws, one 1px stroke like the marks around it. */\n --ccd-icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='6.6' cy='6.6' r='4.6' stroke='black'/%3E%3Cpath d='M9.9 9.9L13.9 13.9' stroke='black' stroke-linecap='round'/%3E%3C/svg%3E\");\n\n /* The archived Session row's leading mark. The host deliberately leaves that\n 16px cell empty, so the plugin paints the same geometry itself: DSH's own\n `IconArchiveOutlineRegular` artwork (ui-primitives, MIT) \u2014 a lid, a body and\n a handle drawn with 1px strokes \u2014 carried as a mask like the marks around\n it, so no third-party asset or copied component enters the stylesheet. */\n --ccd-icon-archive: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M13.5 2.5H2.5C1.94772 2.5 1.5 2.94772 1.5 3.5V4.5C1.5 5.05228 1.94772 5.5 2.5 5.5H13.5C14.0523 5.5 14.5 5.05228 14.5 4.5V3.5C14.5 2.94772 14.0523 2.5 13.5 2.5Z' stroke='black'/%3E%3Cpath d='M2.5 5.5V13.5C2.5 13.7652 2.60536 14.0196 2.79289 14.2071C2.98043 14.3946 3.23478 14.5 3.5 14.5H12.5C12.7652 14.5 13.0196 14.3946 13.2071 14.2071C13.3946 14.0196 13.5 13.7652 13.5 13.5V5.5' stroke='black'/%3E%3Cpath d='M6.5 9.5H9.5' stroke='black'/%3E%3C/svg%3E\");\n\n /* The idle Session row's leading ring. The host hands that cell to the\n plugin's `sidebar.session.row.leading` seat as soon as a row has no status\n of its own, and the running row's activity ring is `ui-primitives`'\n StateDot spinner: a 2-unit stroke on a 9.5-unit radius in a 24-unit box.\n The same circle is carried here as a mask, so the still mark and the\n spinning one are one geometry at the one 8px scale the stylesheet already\n gives the spinner \u2014 and the ring takes the cell's own `currentColor`\n (the host's `--dsw-alias-label-tertiary`, the spinner's ink) instead of an\n authored colour. */\n --ccd-icon-session-ring: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Ccircle cx='12' cy='12' r='9.5' stroke='black' stroke-width='2'/%3E%3C/svg%3E\");\n\n /* The context ring's track, for the seat an empty session has to fill. The\n host's own `ContextMeter` returns nothing at all until the token meter knows\n a numerator and the context window, so the plugin draws that ring's track\n itself \u2014 the host's exact geometry from `ContextMeter.module.css`\n (viewBox 0 0 14 14, cx=cy=7, r=5.5, 2px stroke) carried as a mask, so the\n colour stays the host track token above. The consumed arc is not drawn: at\n 0% the host's own arc has no length either. */\n --ccd-icon-context-ring: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none'%3E%3Ccircle cx='7' cy='7' r='5.5' stroke='black' stroke-width='2'/%3E%3C/svg%3E\");\n\n /* The Composer whale. DeepSeek's own mark is a blue whale with a pale belly,\n so the two inks are the brand pair rather than a derived palette step: the\n artwork only ever appears as this one mark. The dark side lifts the blue a\n step so it keeps its contrast on the dark canvas instead of sinking into\n it; the belly stays the light ink in both schemes, because it is what makes\n the silhouette read at 64px. */\n --ccd-pet-blue: #4d6bfe;\n --ccd-pet-light: #dfe6ff;\n\n /* Elevation */\n --ccd-shadow-card: 0 1px 2px rgb(0 0 0 / 4%);\n --ccd-shadow-segment: 0 1px 2px rgb(0 0 0 / 8%);\n /* The right panel's card, read off the reference's own edges: the canvas\n (252/255) sits at 243 half a pixel beside the card, 235 directly under it\n and back to 251 eight pixels out \u2014 a two-layer shadow, the near one for the\n edge and the far one for the falloff. */\n --ccd-right-panel-shadow: 0 1px 3px rgb(0 0 0 / 4%), 0 5px 14px rgb(0 0 0 / 8%);\n}\n\n/*\n * Host-token aliases belong on `body`, exactly where the host writes them.\n *\n * `--dsw-*` values are not in the document stylesheets: DSH's theme presenter\n * writes them, and this plugin's own overrides, as inline styles on `body`\n * (theme/tokens.ts). A custom property is resolved *where it is declared*, so an\n * alias of a host token declared on the root would reference a variable that is\n * not in scope there: it computes to the guaranteed-invalid value and inherits\n * as invalid into every subtree, and the rule consuming it falls back to\n * `transparent` rather than the host's colour. The empty-state context ring\n * (theme/composer.css, `.yhfFVG_dock::after`) vanished exactly that way.\n */\nhtml[data-dsh-ccd-style=\"true\"] body {\n /* Resolve on body so dark mode and configured palettes both participate. */\n --ccd-composer-focus-border: color-mix(in srgb, var(--ccd-card) 60%, var(--ccd-text-secondary));\n /* The empty state's ring draws the host's track alone. It stays the host's\n own track token (`ContextMeter.module.css` strokes `.y0jqnG_track` with\n `--dsw-alias-border-l3`, which theme/tokens.ts already retints), so an\n empty session shows the same hollow ring the host would draw at 0%. */\n --ccd-context-ring-track: var(--dsw-alias-border-l3);\n}\n\n/*\n * Dark palette.\n *\n * DSH's theme presenter writes `body[data-ds-dark-theme]` from the resolved\n * colour scheme (`@deepseek-ai/dsh-client-ui-theme` client styles, DSH\n * 0.2.0-rc.2), so the plugin follows the host's own switch instead of carrying a\n * second one. The block is a descendant of the root activation marker: the\n * variables land on `body`, cover every colour the light block declares, and\n * stay absent while the plugin is off.\n *\n * The warm-neutral family is kept rather than swapping in the host's bluish\n * greys: the same relationship holds in both schemes (canvas a touch lighter\n * than the sidebar, card the brightest surface), while the recessed steps\n * (track, raised, hover, selected) move *up* in lightness where the light\n * palette moves down, because on a dark canvas a surface reads as raised by\n * catching more light. Lines keep one visible step against the surfaces they\n * separate; text keeps the light palette's descending tone order.\n */\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n /* The same flat frame uses gray-850 for the dark page and mixes it with\n 20% black for the sidebar. The control track stays below its raised thumb\n while both sit above the darker page. */\n --ccd-canvas: #151515;\n --ccd-sidebar: #111111;\n --ccd-card: #30302e;\n --ccd-header-menu-border: var(--ccd-border);\n --ccd-header-menu-separator: var(--ccd-border-soft);\n --ccd-header-menu-danger: #f08080;\n --ccd-menu-danger: #c04742;\n --ccd-menu-danger-ink: #ffffff;\n --ccd-header-trigger-hover: var(--ccd-hover);\n --ccd-header-project-fill: var(--ccd-track);\n --ccd-header-project-active: var(--ccd-selected);\n --ccd-track: #1f1e1d;\n --ccd-raised: #2f2f2d;\n --ccd-hover: #313130;\n --ccd-view-menu-hover: var(--ccd-selected);\n --ccd-view-menu-text: var(--ccd-text);\n --ccd-view-menu-muted: var(--ccd-text-muted);\n --ccd-view-menu-border: var(--ccd-border);\n --ccd-view-menu-separator: var(--ccd-border-soft);\n --ccd-view-menu-accent: var(--ccd-accent);\n --ccd-view-menu-shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 8px 20px rgba(0, 0, 0, .3), 0 16px 32px rgba(0, 0, 0, .2);\n --ccd-selected: #3a3a37;\n /* The same step as the light side, in the direction this canvas recesses:\n the fill goes one step up from `selected` here \u2014 which happens to land on\n the strong-outline step below, a coincidence of the two ramps rather than\n the reason for the value. */\n --ccd-hover-strong: #474743;\n /* The tab mark's tint, dark side: the accent's own hue over this card, which\n is the #d3e2f9 relationship the light side measures, not its value. */\n --ccd-right-panel-glyph-bg: #2b3a55;\n /* The Files pane's inks go back to the palette's own ramp here: the reference\n is a light-mode capture, and its three sampled values are only meaningful\n as relationships (a step below the body ink, a step above the muted one and\n the accent's own hue) that this side already carries. */\n --ccd-files-ink: var(--ccd-text);\n --ccd-right-panel-tab-ink: var(--ccd-text);\n --ccd-files-chip-ink: var(--ccd-accent);\n\n /* Lines */\n --ccd-border: #3e3e3b;\n --ccd-border-strong: #474743;\n --ccd-border-soft: #343431;\n /* The head rule stays the one line drawn stronger than the card outline. */\n --ccd-table-head-line: #4a4a46;\n /* The card outline's dark side: one step above the row outline, as in the\n light palette. */\n --ccd-right-panel-border: #474743;\n --ccd-browser-canvas: #242423;\n --ccd-browser-dot: #454542;\n\n /* Scrollbar ink, dark side: on this canvas the bar is the one piece of the\n chrome that has to read as raised, so it sits above every surface step\n here and lightens on hover \u2014 the mirror of the light palette, whose ink\n sits below every surface and darkens. */\n --ccd-scrollbar-thumb: #5c5b57;\n --ccd-scrollbar-thumb-hover: #75746f;\n\n /* Text */\n --ccd-text: #f0efec;\n --ccd-text-secondary: #b4b1ab;\n --ccd-text-muted: #918f89;\n /* Same step down from full strength as the light palette: the dark ink sits\n the same distance below --ccd-text as #4a4a47 sits below #1f1f1d. */\n --ccd-text-nav: #d3d0ca;\n --ccd-text-placeholder: #8b8983;\n /* Archived rows, dark side: the same two steps below the row ink, kept\n readable against this sidebar and the selected fill that sits above it. */\n --ccd-text-archived: #82807c;\n --ccd-text-archived-hover: #a6a39c;\n\n /* Composer whale, dark side: the same mark, with the blue raised so it reads\n against this canvas; the belly keeps the light ink. */\n --ccd-pet-blue: #7b93ff;\n --ccd-pet-light: #e8ecff;\n\n /* Statistics card, dark side: the same stacked greys over this canvas, and\n the heat ramp raised one step so the steps stay visible on a dark panel. */\n --ccd-stats-panel: #2c2c2a;\n --ccd-stats-tile: #383835;\n --ccd-stats-tab: #3a3a37;\n --ccd-stats-label: #918f89;\n --ccd-stats-value: #f0efec;\n --ccd-stats-heat-1: hsl(217 62% 78%);\n --ccd-stats-heat-2: hsl(217 64% 70%);\n --ccd-stats-heat-3: hsl(217 66% 62%);\n --ccd-stats-heat-4: hsl(217 70% 54%);\n /* Model ramp, raised for the dark panel; six distinct steps, as the light\n theme's clamped ramp produces. */\n --ccd-stats-model-1: hsl(217 62% 70%);\n --ccd-stats-model-2: hsl(217 64% 75%);\n --ccd-stats-model-3: hsl(217 66% 80%);\n --ccd-stats-model-4: hsl(217 68% 84%);\n --ccd-stats-model-5: hsl(217 70% 87%);\n --ccd-stats-model-6: hsl(217 70% 89%);\n --ccd-stats-tip-bg: #454542;\n --ccd-stats-tip-fg: #f7f7f5;\n\n /* Assistant Markdown palette, lightened for a dark transcript. */\n --ccd-link: #86b0e8;\n --ccd-link-underline: #4a5c76;\n --ccd-inline-code-text: #f0918a;\n --ccd-inline-code-fill: #35332f;\n --ccd-inline-code-border: #454239;\n\n /* Context meter ring, dark side: the same hue as the light accent, one step\n up in lightness (55% \u2192 68%) and saturation so the arc keeps its blue on\n this canvas instead of greying into it. Same `var()` order as the light\n block. */\n --ccd-context-ring-fill: var(--ccd-accent, #789be3);\n\n /* Context breakdown categories, dark side. The reference ships one light\n crop, so these are derived the way the rest of this palette is: the same\n hue, raised in lightness by the step the statistics ramp and the accent\n take on this canvas, so five categories stay five colours instead of\n sinking into the card. The two greys are the exception \u2014 they are surfaces\n rather than inks, so the buffer steps down to a mid warm grey and the free\n track steps up off the card, which is what keeps the reserved block and the\n empty room apart at a glance. */\n --ccd-context-mcp: #5b9ae8;\n --ccd-context-tools: #f0885a;\n --ccd-context-system: #43c79b;\n --ccd-context-skills: #f0b93c;\n --ccd-context-memory: #ef93b5;\n --ccd-context-messages: #a58fe6;\n --ccd-context-buffer: #5f5b53;\n --ccd-context-free: #3f3f3b;\n\n /* The accent, dark side: the same hue and the same 55% \u2192 68% lightness step\n the statistics heat ramp takes on this canvas, so the check keeps its blue\n against the menu's surface instead of sinking into it. The hue is the\n reference's measured blue (220) rather than the ramp's 217, but the two sit\n in one family. */\n --ccd-accent: #789be3;\n\n /* State colours that DSH already owns semantics for. */\n --ccd-diff-added: #7cbd72;\n --ccd-diff-removed: #e08fae;\n\n /* Elevation reads as a shadow under the surface, not as a grey wash. */\n --ccd-shadow-card: 0 1px 2px rgb(0 0 0 / 40%);\n --ccd-shadow-segment: 0 1px 2px rgb(0 0 0 / 50%);\n --ccd-right-panel-shadow: 0 1px 2px rgb(0 0 0 / 35%), 0 4px 10px rgb(0 0 0 / 35%);\n}\n\n/* zanwei effort reference palette, MIT; canvas reads these theme values. */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-effort-color-1: #8c73c9;\n --ccd-effort-color-2: #a17ec2;\n --ccd-effort-color-3: #5f5b58;\n --ccd-effort-color-4: #3f3b38;\n --ccd-effort-color-5: #77736f;\n --ccd-effort-color-6: #edeae8;\n --ccd-effort-color-7: #e0dbd6;\n --ccd-effort-color-8: #ffffff;\n --ccd-effort-color-9: rgba(76, 70, 65, 0.12);\n --ccd-effort-color-10: #2788d6;\n --ccd-effort-color-11: rgba(62, 56, 50, 0.05);\n --ccd-effort-color-12: rgba(62, 56, 50, 0.04);\n --ccd-effort-color-13: rgba(62, 56, 50, 0.06);\n --ccd-effort-color-14: #74706d;\n --ccd-effort-color-15: rgba(82, 76, 70, 0.055);\n --ccd-effort-color-16: rgba(76, 70, 65, 0.1);\n --ccd-effort-color-17: #34312f;\n --ccd-effort-color-18: rgba(35, 31, 29, 0.12);\n --ccd-effort-color-19: #fff;\n --ccd-effort-color-20: rgba(70, 64, 59, 0.035);\n --ccd-effort-color-21: #eeebe9;\n --ccd-effort-color-22: #ece9e7;\n --ccd-effort-color-23: #e2dce3;\n --ccd-effort-color-24: #d9d0df;\n --ccd-effort-color-25: #d0c1da;\n --ccd-effort-color-26: #cdbcd9;\n --ccd-effort-color-27: #cbbad8;\n --ccd-effort-color-28: #d5cadc;\n --ccd-effort-color-29: #c8b5d4;\n --ccd-effort-color-30: #bda6cc;\n --ccd-effort-color-31: #b59bc6;\n --ccd-effort-color-32: #b6b2af;\n --ccd-effort-color-33: rgba(76, 70, 65, 0.13);\n --ccd-effort-color-34: rgba(62, 56, 50, 0.08);\n --ccd-effort-color-35: rgba(62, 56, 50, 0.055);\n --ccd-effort-pixel-leftColor: 210, 206, 214;\n --ccd-effort-pixel-deepViolet: 156, 120, 192;\n --ccd-effort-pixel-deepMid: 156, 132, 192;\n --ccd-effort-pixel-midPurple: 168, 144, 204;\n --ccd-effort-pixel-softMid: 168, 156, 204;\n --ccd-effort-pixel-softLilac: 180, 168, 204;\n --ccd-effort-pixel-paleCool: 192, 180, 204;\n --ccd-effort-pixel-highlightColor: 216, 204, 228;\n --ccd-effort-pixel-peakColor: 232, 224, 242;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-effort-shadow: 0 1px 2px rgba(62, 56, 50, .05), 0 4px 10px rgba(62, 56, 50, .04), 0 12px 28px rgba(62, 56, 50, .06);\n}\n\n/*\n * The same reference field on the dark canvas: the purple ramp keeps its\n * left-to-right direction (neutral \u2192 violet) inside the dark range, the\n * neutrals flip so the panel is a card above the transcript, and the knob stays\n * the brightest thing on the track \u2014 its fill is also the tooltip's text\n * colour, so the two keep following one value.\n */\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-effort-color-1: #a48ede;\n --ccd-effort-color-2: #b294d3;\n --ccd-effort-color-3: #e7e4de;\n --ccd-effort-color-4: #f6f4f0;\n --ccd-effort-color-5: #a09b94;\n --ccd-effort-color-6: #3a3936;\n --ccd-effort-color-7: #4b4944;\n --ccd-effort-color-8: #2b2a28;\n --ccd-effort-color-9: rgba(255, 255, 255, 0.1);\n --ccd-effort-color-10: #4d93f8;\n --ccd-effort-color-11: rgba(0, 0, 0, 0.45);\n --ccd-effort-color-12: rgba(0, 0, 0, 0.35);\n --ccd-effort-color-13: rgba(0, 0, 0, 0.45);\n --ccd-effort-color-14: #b7b2aa;\n --ccd-effort-color-15: rgba(255, 255, 255, 0.06);\n --ccd-effort-color-16: rgba(255, 255, 255, 0.14);\n --ccd-effort-color-17: #3a3936;\n --ccd-effort-color-18: rgba(0, 0, 0, 0.5);\n --ccd-effort-color-19: #ece9e4;\n --ccd-effort-color-20: rgba(255, 255, 255, 0.04);\n --ccd-effort-color-21: #34332f;\n --ccd-effort-color-22: #373430;\n --ccd-effort-color-23: #3e3943;\n --ccd-effort-color-24: #463e51;\n --ccd-effort-color-25: #4f4560;\n --ccd-effort-color-26: #57496a;\n --ccd-effort-color-27: #5c4d71;\n --ccd-effort-color-28: #524667;\n --ccd-effort-color-29: #63527c;\n --ccd-effort-color-30: #6e5989;\n --ccd-effort-color-31: #786096;\n --ccd-effort-color-32: #6f6c66;\n --ccd-effort-color-33: rgba(255, 255, 255, 0.16);\n --ccd-effort-color-34: rgba(0, 0, 0, 0.4);\n --ccd-effort-color-35: rgba(0, 0, 0, 0.35);\n --ccd-effort-pixel-leftColor: 92, 88, 98;\n --ccd-effort-pixel-deepViolet: 150, 116, 196;\n --ccd-effort-pixel-deepMid: 150, 128, 196;\n --ccd-effort-pixel-midPurple: 162, 140, 204;\n --ccd-effort-pixel-softMid: 162, 152, 204;\n --ccd-effort-pixel-softLilac: 174, 164, 206;\n --ccd-effort-pixel-paleCool: 184, 174, 206;\n --ccd-effort-pixel-highlightColor: 200, 188, 224;\n --ccd-effort-pixel-peakColor: 214, 204, 236;\n --ccd-effort-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 10px rgba(0, 0, 0, .3), 0 12px 28px rgba(0, 0, 0, .35);\n}\n\n/*\n * Chosen-value ink. The Composer's model name \u2014 in the tool row and in the menu\n * it opens \u2014 is the value that row exists to show, so it takes full black\n * instead of the warm near-black every other primary label uses; the dark\n * scheme keeps the same relationship with its own strongest ink, white. Neither\n * side is derived from a configured surface, so the pair is declared here\n * rather than in the scheme blocks above.\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-text-strong: #000000;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-text-strong: #ffffff;\n}\n\n/*\n * Header icon ink.\n *\n * The conversation header's trailing cluster is icon-only \u2014 the native session\n * menu, the two views this plugin adds, the scheduled-tasks entry while it has\n * records, the collapsed right panel's re-entry control \u2014 and the reference\n * draws those marks at full strength where the host uses its secondary label\n * grey. Like the chosen-value ink above, this pair answers to no configured\n * surface, so it is declared here rather than in the scheme blocks: the pure\n * black the reference measured on the light canvas, and its mirror white on the\n * dark one, because a black mark would vanish into that canvas.\n *\n * What each state puts behind the mark stays the host's: a near-black wash at\n * 6-14% in the light scheme, a white one at 8-14% in the dark, and the button's\n * own dimmed opacity while it is disabled \u2014 so the ink never meets a fill of its\n * own lightness (see `header-actions.css`).\n */\nhtml[data-dsh-ccd-style=\"true\"] {\n --ccd-header-icon-color: #000000;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] body[data-ds-dark-theme] {\n --ccd-header-icon-color: #ffffff;\n}\n\n/*\n * The selected check in every Menu surface.\n *\n * The host paints it with `--dsw-alias-label-primary` in the Menu primitive's\n * own `Menu.module.css` (`.check`), so the workspace picker, the permission\n * menu, the view-options menu and the session \u22EF menu all show the same\n * near-black mark \u2014 a selection reads no louder than the label beside it. One\n * rule recolours all of them, because they all come from that one primitive.\n * The model picker is not one of them: it is this plugin's own card, and the\n * block at the end of this file is the rule that reaches its mark.\n *\n * Only the colour changes: the mark keeps the host's 14px seat, its\n * `display: grid` centring, its row height and every hover fill. The class is\n * the one the shipped static web frontend gives that module (`_4ub78_`, whose\n * local names run `_check_4ub78_179`, `_item_4ub78_90`, \u2026), and that asset is\n * platform-independent \u2014 both installers carry the identical\n * `@deepseek-ai/dsh-web-frontend` dist \u2014 so it is the same name on Windows and\n * needs no second spelling in `host-builds.ts` (`host-dom.ts` records the same\n * prefix).\n *\n * The rule covers the seat and its artwork: the svg inherits through\n * `currentColor`, and naming it as well keeps the mark blue even if a future\n * build moves the colour onto the artwork instead of the seat.\n */\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] ._check_4ub78_179,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitem\"] ._check_4ub78_179,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] ._check_4ub78_179 svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitem\"] ._check_4ub78_179 svg {\n color: var(--ccd-accent);\n}\n\n/*\n * The selected mark in the model picker.\n *\n * The Composer's model seat is not the host's `ModelSelect`: this plugin's\n * `ModelControls` wins `conversation.input.model` (its registration carries\n * `priority: -10` while the host registers the same seat at the default 0, and\n * the slot chain takes the lowest priority that answers), and the card that\n * seat opens marks the chosen model with the text `\u2713` in the row's trailing\n * `span[aria-hidden=\"true\"]` (`features/model-controls/ModelControls.tsx`).\n * `features/model-controls/controls.css` paints that row `--ccd-text-strong`,\n * so the mark inherits full black \u2014 which is exactly what it did: it is\n * neither `._check_4ub78_179` nor an svg, so the Menu rule above cannot reach\n * it, and no `fill`/`stroke` override would either, because a text glyph is\n * painted by `color` alone.\n *\n * Only the ink changes: the row keeps its height, padding and hover, and the\n * artwork is named beside the seat so a later icon in the same seat stays\n * covered. The seat is reached two ways \u2014 the row's own selected state\n * (`aria-pressed`, which React writes as `\"true\"`/`\"false\"`) and the seat that\n * actually holds a glyph (`:not(:empty)`, because the unchosen rows render an\n * empty span) \u2014 so a later switch to `aria-checked` on a `menuitemradio` row\n * cannot silently return this mark to black.\n *\n * The host's own `ModelSelect` card is covered as well, for the path where\n * that seat is the one on screen: its `.check` seat holds an svg whose path\n * strokes `currentColor` (ui-primitives `IconCheckOutlineArtwork`), so the\n * same `color` reaches the artwork. `cl2Rlq_` is already in the prefix table\n * (`compat/host-dom.ts`), and the Windows build's `wq12jW_` spelling is what\n * `compat/dom.ts` substitutes when this sheet is mounted.\n */\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button[aria-pressed=\"true\"] > span[aria-hidden=\"true\"],\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button[aria-pressed=\"true\"] > span[aria-hidden=\"true\"] svg,\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button > span[aria-hidden=\"true\"]:not(:empty),\nhtml[data-dsh-ccd-style=\"true\"] .ccd-model-controls .ccd-model-options button > span[aria-hidden=\"true\"]:not(:empty) svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] .cl2Rlq_check,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitemradio\"] .cl2Rlq_check,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menu\"] .cl2Rlq_check svg,\nhtml[data-dsh-ccd-style=\"true\"] [role=\"menuitemradio\"] .cl2Rlq_check svg {\n color: var(--ccd-accent);\n}\n";
|
|
4322
4442
|
|
|
4323
4443
|
// src/client/theme/mount.ts
|
|
4324
4444
|
function mountTheme(environment, scope) {
|
|
@@ -5414,7 +5534,7 @@ function createViewOptionsDriver(document2, report) {
|
|
|
5414
5534
|
// src/client/features/view-options/ViewOptionsCard.tsx
|
|
5415
5535
|
var import_react5 = require("react");
|
|
5416
5536
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
5417
|
-
var
|
|
5537
|
+
var COPY = {
|
|
5418
5538
|
zh: {
|
|
5419
5539
|
viewOptions: "\u89C6\u56FE\u9009\u9879",
|
|
5420
5540
|
status: "\u72B6\u6001",
|
|
@@ -5436,7 +5556,7 @@ var ROW_ORDER = [2, 0, 1];
|
|
|
5436
5556
|
var SUBMENU_GAP = 1;
|
|
5437
5557
|
function copyFor(document2) {
|
|
5438
5558
|
const language = (document2.documentElement.lang || globalThis.navigator?.language || "").toLowerCase();
|
|
5439
|
-
return language.startsWith("zh") ?
|
|
5559
|
+
return language.startsWith("zh") ? COPY.zh : COPY.en;
|
|
5440
5560
|
}
|
|
5441
5561
|
function optionsOf(group, index, copy) {
|
|
5442
5562
|
const order = index === FILTER_GROUP ? FILTER_ORDER : group.labels.map((_, host) => host);
|
|
@@ -6035,7 +6155,7 @@ function createContextPanelDriver(document2, projections, report) {
|
|
|
6035
6155
|
// src/client/features/context-panel/ContextPanel.tsx
|
|
6036
6156
|
var import_react6 = require("react");
|
|
6037
6157
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
6038
|
-
var
|
|
6158
|
+
var COPY2 = {
|
|
6039
6159
|
zh: {
|
|
6040
6160
|
title: "\u4E0A\u4E0B\u6587\u7A97\u53E3",
|
|
6041
6161
|
waiting: "\u7B49\u5F85\u9996\u4E2A\u8BF7\u6C42",
|
|
@@ -6082,7 +6202,7 @@ var GROUP_SOURCES = [
|
|
|
6082
6202
|
var ASSUMED_BAR_WIDTH = 334;
|
|
6083
6203
|
function copyFor2(document2) {
|
|
6084
6204
|
const language = (document2.documentElement.lang || globalThis.navigator?.language || "").toLowerCase();
|
|
6085
|
-
return language.startsWith("zh") ?
|
|
6205
|
+
return language.startsWith("zh") ? COPY2.zh : COPY2.en;
|
|
6086
6206
|
}
|
|
6087
6207
|
function Chevron2({ open }) {
|
|
6088
6208
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -6510,7 +6630,7 @@ function openView(sidebar, kind, sessionId) {
|
|
|
6510
6630
|
var header_actions_default = "/*\n * The conversation header's trailing cluster: the three right-panel views this\n * plugin adds \u2014 the project folder first, then terminal and browser \u2014 plus the\n * reference's own adaptations to the host controls of the same row (issue 16).\n * The corner seat past the cluster is retired, so these three are the whole of\n * the row's own additions.\n *\n * The views' 28px box, hover surface, spacing and compact width all come from\n * the cluster rules in `features/conversation/conversation.css`, so these\n * buttons sit in exactly the same rhythm as the native controls beside them.\n * Their artwork is declared here: masks over DSH's own 16px glyph geometry,\n * taken from the packages that draw them (see theme/tokens.css).\n *\n * The host classes named below are the pinned ones of `compat/host-dom.ts`:\n * `ST7X_W_` for the header and its two trailing seats, `iq4beG_` for the\n * open-in-app control (`openTargetAnchor`\uFF0F`openTargetSplit`) and `Da3aKq_` for\n * the native session menu (`sessionMoreButton`). `compat/dom.ts` rewrites each\n * prefix for the build actually on screen, through `compat/host-builds.ts`.\n */\n.ccd-header-action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--ccd-header-icon-color);\n cursor: pointer;\n}\n\n/* The hover/focus signal is the host's own fill; the ink keeps its full\n strength in every state, exactly as the native ghost buttons beside this one\n behave. */\n.ccd-header-action:hover:not(:disabled),\n.ccd-header-action:focus-visible {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ccd-header-action:disabled {\n cursor: default;\n opacity: 0.4;\n}\n\n.ccd-header-action::before {\n content: \"\";\n width: var(--ccd-header-icon-size);\n height: var(--ccd-header-icon-size);\n background-color: currentColor;\n mask: var(--ccd-icon-terminal) center / var(--ccd-header-icon-size) var(--ccd-header-icon-size) no-repeat;\n}\n\n.ccd-header-action[data-ccd-header-view=\"browser\"]::before {\n mask-image: var(--ccd-icon-browser);\n}\n\n/*\n * The folder opens the row, and is the mark of the control that does it.\n *\n * Its seat is the head of the utilities group \u2014 the reference draws the project\n * folder as the cluster's first control, ahead of the terminal and browser views\n * and ahead of every native entry in that group \u2014 and what it opens is the right\n * panel's file list for the Session's own directory. The glyph is the closed\n * folder the workspace chip already draws (`theme/tokens.css`), so the interface\n * has one folder, not two.\n */\n.ccd-header-action[data-ccd-header-view=\"files\"]::before {\n mask-image: var(--ccd-icon-folder);\n}\n\n/*\n * The header's own open-in-app control is retired here (16).\n *\n * `ui-open-in-app` registers `open-in-app` into\n * `conversation.session.header.utilities` at order -10, so its split box is the\n * first control of that group; in the DOM it is the `Menu` primitive's anchor\n * wrapper span (`iq4beG_menuAnchor`) wrapped around the `iq4beG_split` box with\n * its `iq4beG_main` and `iq4beG_chevron` halves. This plugin used to repaint\n * that box as one generic \"open\" glyph; the feature moves elsewhere, so the\n * wrapper goes instead.\n *\n * Scoped to the header's utilities seat: the same package's entries in the\n * right panel (`sidebar.right.tab.files.actions`, the document viewer's own\n * `sidebar.right.tab.document.actions` and its unpreviewable seat) keep their\n * control untouched. The wrapper is the flex item \u2014 the slot seat around it is\n * `display: contents` \u2014 so taking it out of the box tree takes the whole split\n * box with it, leaves the group's own `gap` measured between the controls that\n * remain (no empty cell to compensate, no padding to trim) and keeps both halves\n * out of the tab order. The width it used to hold is absorbed by the flexible\n * gap ahead of the group, so the row still ends on the same trailing inset.\n */\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities .iq4beG_menuAnchor {\n display: none;\n}\n\n/*\n * One ink for the trailing cluster (16).\n *\n * Every control in the utilities seat is an icon-only ghost button:\n * the native session menu (`Da3aKq_moreButton`, the \"More actions\" menu), the\n * three views this plugin adds and the scheduled-tasks entry while a Session\n * has records. The host paints each with its own secondary label grey; the\n * reference draws them at full strength,\n * so the cluster takes one token \u2014 pure black on the light canvas, its white\n * mirror on the dark one (theme/tokens.css) \u2014 and every state the host owns\n * stays its own.\n *\n * The seat is named in the selector rather than only the group:\n * `conversation.css` paints this group's buttons with the secondary ink as well,\n * and that sheet mounts after this one, so an equal-specificity rule here would\n * lose the cascade. Naming the seat lifts this above it without `!important`,\n * and keeps the reach at controls: the header's text, its View switcher and the\n * leading Agent-preset\uFF0Fteam chrome are not in this seat.\n *\n * Naming the button and its `svg` covers both a glyph that inherits\n * `currentColor` (the session menu's ellipsis) and one a later build might paint\n * with a fill of its own. Hover, active and keyboard focus keep the host's\n * translucent fills, disabled keeps the button's own dimmed opacity, so this ink\n * never lands on a fill of its own lightness.\n */\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities > [data-slot] button,\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities > [data-slot] button svg {\n color: var(--ccd-header-icon-color);\n}\n\n/*\n * The session menu's mark, stacked (16).\n *\n * The host draws `IconEllipsisOutlineRegular` (`ui-primitives`, MIT) as three\n * 2px dots on one horizontal line \u2014 circles at (3, 8), (8, 8) and (13, 8) of\n * its 16px box. The reference stacks them, so the host's own glyph steps aside\n * and the same geometry, transposed to (8, 3), (8, 8) and (8, 13), is painted as\n * a mask over the button's `currentColor` (theme/tokens.css, `--ccd-icon-more`).\n *\n * Menu wraps the button in an inline-flex span: the cluster sizes that span,\n * while Button's native small size remains 28px. Fill the wrapper so the real\n * button also becomes 24px in a narrow column, including its hover surface.\n * The menu and click handler stay the host's own. Explicit flex centring keeps\n * the replacement mark off the text baseline; disabled opacity remains native.\n */\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities .Da3aKq_moreButton {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities .Da3aKq_moreButton svg {\n display: none;\n}\n\nhtml[data-dsh-ccd-style=\"true\"] .ST7X_W_headerUtilities .Da3aKq_moreButton::before {\n content: \"\";\n display: block;\n flex: none;\n width: var(--ccd-header-icon-size);\n height: var(--ccd-header-icon-size);\n background-color: currentColor;\n mask: var(--ccd-icon-more) center / var(--ccd-header-icon-size) var(--ccd-header-icon-size) no-repeat;\n}\n";
|
|
6511
6631
|
|
|
6512
6632
|
// src/client/features/conversation/header-actions/header-menus.css
|
|
6513
|
-
var header_menus_default = '/* Reference crops are @2x: 136/192px cards, 24px rows and 10px corners. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header:has([data-ccd-session-title]) {\n /* Equal spacing between the title controls, project chip and team entry. */\n --ccd-header-group-gap: 10px;\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 18px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title] {\n flex: 0 1 auto;\n gap: 6px;\n overflow: hidden;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title] .ST7X_W_crumb {\n padding: 0;\n font-size: 14px;\n line-height: 24px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-editing] > :not([data-ccd-session-icon], [data-ccd-session-trigger], [data-ccd-session-rename]) {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-rename] {\n box-sizing: border-box;\n flex: 0 1 auto;\n min-width: 32px;\n height: 24px;\n padding: 0 2px;\n border: 0;\n border-radius: 4px;\n outline: none;\n background: transparent;\n color: var(--ccd-text);\n font: 500 14px/24px var(--ccd-font-ui);\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title][data-ccd-session-editing] {\n overflow: visible;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-rename]:focus {\n outline: 2px solid Highlight;\n outline-offset: 1px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-icon] {\n display: inline-flex;\n flex: none;\n align-items: center;\n width: 16px;\n height: 24px;\n color: var(--ccd-header-icon-color);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger] {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--ccd-text-secondary);\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger][aria-expanded="true"] {\n background: var(--ccd-header-trigger-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger] {\n order: 0;\n flex: 0 1 auto;\n min-width: 0;\n max-width: min(220px, 40%);\n height: 20px;\n margin-left: var(--ccd-header-group-gap);\n padding: 0 5px;\n border: 0;\n border-radius: 6px;\n background: var(--ccd-header-project-fill);\n color: var(--ccd-text-secondary);\n font: inherit;\n font-size: 13px;\n line-height: 20px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger][hidden] { display: none; }\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger][aria-expanded="true"] {\n background: var(--ccd-header-project-active);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n width: max-content;\n min-width: 136px;\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n overflow: auto;\n margin: 0;\n padding: 4px;\n border: 1px solid var(--ccd-header-menu-border);\n border-radius: 10px;\n background: var(--ccd-card);\n color: var(--ccd-view-menu-text);\n box-shadow: var(--ccd-view-menu-shadow);\n font-family: var(--ccd-font-ui);\n font-size: 13px;\n line-height: 20px;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu="session"] { width:
|
|
6633
|
+
var header_menus_default = '/* Reference crops are @2x: 136/192px cards, 24px rows and 10px corners. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header:has([data-ccd-session-title]) {\n /* Equal spacing between the title controls, project chip and team entry. */\n --ccd-header-group-gap: 10px;\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 18px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title] {\n flex: 0 1 auto;\n gap: 6px;\n overflow: hidden;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title] .ST7X_W_crumb {\n padding: 0;\n font-size: 14px;\n line-height: 24px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-editing] > :not([data-ccd-session-icon], [data-ccd-session-trigger], [data-ccd-session-rename]) {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-rename] {\n box-sizing: border-box;\n flex: 0 1 auto;\n min-width: 32px;\n height: 24px;\n padding: 0 2px;\n border: 0;\n border-radius: 4px;\n outline: none;\n background: transparent;\n color: var(--ccd-text);\n font: 500 14px/24px var(--ccd-font-ui);\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-title][data-ccd-session-editing] {\n overflow: visible;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-rename]:focus {\n outline: 2px solid Highlight;\n outline-offset: 1px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-icon] {\n display: inline-flex;\n flex: none;\n align-items: center;\n width: 16px;\n height: 24px;\n color: var(--ccd-header-icon-color);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger] {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--ccd-text-secondary);\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-session-trigger][aria-expanded="true"] {\n background: var(--ccd-header-trigger-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger] {\n order: 0;\n flex: 0 1 auto;\n min-width: 0;\n max-width: min(220px, 40%);\n height: 20px;\n margin-left: var(--ccd-header-group-gap);\n padding: 0 5px;\n border: 0;\n border-radius: 6px;\n background: var(--ccd-header-project-fill);\n color: var(--ccd-text-secondary);\n font: inherit;\n font-size: 13px;\n line-height: 20px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger][hidden] { display: none; }\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-project-trigger][aria-expanded="true"] {\n background: var(--ccd-header-project-active);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n width: max-content;\n min-width: 136px;\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n overflow: auto;\n margin: 0;\n padding: 4px;\n border: 1px solid var(--ccd-header-menu-border);\n border-radius: 10px;\n background: var(--ccd-card);\n color: var(--ccd-view-menu-text);\n box-shadow: var(--ccd-view-menu-shadow);\n font-family: var(--ccd-font-ui);\n font-size: 13px;\n line-height: 20px;\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu="session"] { width: 160px; }\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu="project"] { width: 192px; }\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 24px;\n padding: 2px 8px;\n border: 0;\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n white-space: nowrap;\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button > [data-ccd-header-row-label] { flex: 1; }\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button:focus-visible,\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button[aria-expanded="true"] {\n outline: none;\n background: var(--ccd-view-menu-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-mark] {\n flex: none;\n color: var(--ccd-text-muted);\n font-size: 12px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [aria-haspopup] [data-ccd-menu-mark] {\n display: flex;\n width: 12px;\n height: 16px;\n align-items: center;\n justify-content: center;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [aria-haspopup] [data-ccd-menu-mark] svg {\n flex: none;\n width: 14px;\n height: 14px;\n transform: rotate(-90deg);\n}\n\n/* The destructive row rests in the host\'s red ink. Only the pointer or the\n * keyboard walk fills it: the red fill with white ink, the shortcut included, the\n * same as the host\'s danger rows (`menus.css`). */\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-destructive] { color: var(--ccd-header-menu-danger); }\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-destructive]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-destructive]:focus-visible {\n background: var(--ccd-menu-danger);\n color: var(--ccd-menu-danger-ink);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-destructive]:hover [data-ccd-menu-mark],\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-menu-destructive]:focus-visible [data-ccd-menu-mark] { color: inherit; }\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] hr {\n height: 1px;\n margin: 4px 8px;\n border: 0;\n background: var(--ccd-header-menu-separator);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-dialog] {\n box-sizing: border-box;\n width: min(360px, calc(100vw - 32px));\n padding: 16px;\n border: 1px solid var(--ccd-header-menu-border);\n border-radius: 10px;\n background: var(--ccd-card);\n color: var(--ccd-text);\n box-shadow: var(--ccd-view-menu-shadow);\n font: 13px/20px var(--ccd-font-ui);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-dialog] p { margin: 0 0 12px; }\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-dialog] button {\n margin-right: 6px;\n padding: 4px 12px;\n border: 1px solid var(--ccd-border);\n border-radius: 5px;\n background: var(--ccd-track);\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n/* Only the decorative seat gets icon geometry; labels retain the flexible cell. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] button {\n gap: 8px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-menu] [data-ccd-header-row-icon] {\n display: inline-flex;\n flex: 0 0 16px;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: inherit;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-header-row-icon] svg {\n flex: none;\n width: 16px;\n height: 16px;\n}\n';
|
|
6514
6634
|
|
|
6515
6635
|
// src/client/features/conversation/header-actions/mount.ts
|
|
6516
6636
|
function renderNothing() {
|
|
@@ -7461,6 +7581,7 @@ function FontRow(props) {
|
|
|
7461
7581
|
// src/client/features/settings/locales.ts
|
|
7462
7582
|
var SETTINGS_NAMESPACE = "ccdSettings";
|
|
7463
7583
|
var zh = {
|
|
7584
|
+
"nav": "Claude \u4E3B\u9898",
|
|
7464
7585
|
"summary": "CCD \u98CE\u683C\u754C\u9762 \xB7 \u5916\u89C2 \xB7 \u5B57\u4F53",
|
|
7465
7586
|
"section.general": "\u901A\u7528",
|
|
7466
7587
|
"section.features": "\u6A21\u5757",
|
|
@@ -7510,6 +7631,7 @@ var zh = {
|
|
|
7510
7631
|
"hint.context-panel": "\u70B9\u73AF\u6253\u5F00\u7684\u5206\u6BB5\u9762\u677F\uFF1B\u5173\u6389\u65F6\u73AF\u70B9\u5F00\u7684\u662F DSH \u539F\u751F\u9762\u677F"
|
|
7511
7632
|
};
|
|
7512
7633
|
var en = {
|
|
7634
|
+
"nav": "Claude Theme",
|
|
7513
7635
|
"summary": "CCD interface \xB7 appearance \xB7 typefaces",
|
|
7514
7636
|
"section.general": "General",
|
|
7515
7637
|
"section.features": "Modules",
|
|
@@ -7828,37 +7950,68 @@ function ConfigPage(props) {
|
|
|
7828
7950
|
] });
|
|
7829
7951
|
}
|
|
7830
7952
|
|
|
7831
|
-
// src/client/compat/
|
|
7832
|
-
var
|
|
7833
|
-
function
|
|
7953
|
+
// src/client/compat/settings-section.ts
|
|
7954
|
+
var SETTINGS_SECTION_SLOT = "settings.section";
|
|
7955
|
+
function mountSettingsSection(ctx, id, locale, label, component) {
|
|
7834
7956
|
const slots = ctx.slots;
|
|
7835
|
-
return slots.inject(
|
|
7836
|
-
name:
|
|
7837
|
-
|
|
7838
|
-
|
|
7957
|
+
return slots.inject(SETTINGS_SECTION_SLOT, () => slots.register({
|
|
7958
|
+
name: SETTINGS_SECTION_SLOT,
|
|
7959
|
+
id,
|
|
7960
|
+
order: 20,
|
|
7961
|
+
label,
|
|
7962
|
+
locale
|
|
7839
7963
|
}, component));
|
|
7840
7964
|
}
|
|
7965
|
+
function mountSettingsSectionIcon(document2, labels) {
|
|
7966
|
+
const marked = /* @__PURE__ */ new Set();
|
|
7967
|
+
const update = () => {
|
|
7968
|
+
const matches = /* @__PURE__ */ new Set();
|
|
7969
|
+
for (const button of document2.querySelectorAll('[role="dialog"][data-shortcut-modal="settings"] nav button')) {
|
|
7970
|
+
if (labels.includes(button.textContent?.trim() ?? "")) matches.add(button);
|
|
7971
|
+
}
|
|
7972
|
+
for (const button of marked) {
|
|
7973
|
+
if (!matches.has(button)) {
|
|
7974
|
+
button.removeAttribute("data-ccd-settings-icon");
|
|
7975
|
+
marked.delete(button);
|
|
7976
|
+
}
|
|
7977
|
+
}
|
|
7978
|
+
for (const button of matches) {
|
|
7979
|
+
button.setAttribute("data-ccd-settings-icon", "");
|
|
7980
|
+
marked.add(button);
|
|
7981
|
+
}
|
|
7982
|
+
};
|
|
7983
|
+
const observer = new MutationObserver(update);
|
|
7984
|
+
observer.observe(document2.body, { childList: true, subtree: true, characterData: true });
|
|
7985
|
+
update();
|
|
7986
|
+
return () => {
|
|
7987
|
+
observer.disconnect();
|
|
7988
|
+
for (const button of marked) button.removeAttribute("data-ccd-settings-icon");
|
|
7989
|
+
marked.clear();
|
|
7990
|
+
};
|
|
7991
|
+
}
|
|
7841
7992
|
|
|
7842
7993
|
// src/client/features/settings/register.ts
|
|
7843
|
-
function registerSettingsPage(ctx,
|
|
7994
|
+
function registerSettingsPage(ctx, id, component) {
|
|
7844
7995
|
return ctx.inject(["slots", "locale"], (child) => {
|
|
7845
7996
|
child.effect(
|
|
7846
7997
|
() => child.locale.register(SETTINGS_NAMESPACE, { zh, en }),
|
|
7847
7998
|
"ccd-style: configuration page copy"
|
|
7848
7999
|
);
|
|
7849
|
-
|
|
8000
|
+
const t = child.locale.bind(SETTINGS_NAMESPACE);
|
|
8001
|
+
return mountSettingsSection(child, id, SETTINGS_NAMESPACE, () => t("nav"), component);
|
|
7850
8002
|
});
|
|
7851
8003
|
}
|
|
7852
8004
|
|
|
7853
8005
|
// src/client/features/settings/settings.css
|
|
7854
|
-
var settings_default = "/*\n * Row configuration page.\n *\n * The page is drawn on the host's own settings surface and stays readable in\n * both plugin states, so it consumes host `--dsw-*` tokens: while the plugin is\n * enabled the theme layer has already pointed the surfaces and fonts that matter\n * at the configured values, and while it is disabled the page still renders\n * (that is how the interface is switched back on). The one exception is the\n * segmented theme control below, whose recessed track and raised segment have a\n * relationship the host's dark palette does not carry: it reads `--ccd-*` with a\n * host fallback, so it follows both plugin palettes while enabled and keeps\n * working (on host tokens) while disabled.\n *\n * Layout is one column of cards capped at a readable measure: the Plugins panel\n * is wide, and a settings form stretched across it is hard to scan.\n */\n\n.ccd-settings-page {\n display: flex;\n flex-direction: column;\n gap: 12px;\n max-width: 760px;\n margin-top: 16px;\n padding-bottom: 24px;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-summary {\n color: var(--dsw-alias-label-secondary);\n}\n\n.ccd-settings-notice {\n margin: 12px 0;\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-section {\n display: flex;\n flex-direction: column;\n padding: 8px 0 4px;\n}\n\n.ccd-settings-section + .ccd-settings-section {\n margin-top: 14px;\n}\n\n.ccd-settings-title {\n margin: 0;\n padding: 0 2px 4px;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-strong-14);\n}\n\n.ccd-settings-row {\n display: grid;\n grid-template-columns: minmax(180px, 1fr) auto;\n align-items: center;\n gap: 4px 12px;\n min-height: 48px;\n padding: 8px 0;\n}\n\n.ccd-settings-row + .ccd-settings-row {\n border-top: .5px solid var(--dsw-alias-border-l2);\n}\n\n.ccd-settings-label {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.ccd-settings-name {\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-hint,\n.ccd-settings-note {\n color: var(--dsw-alias-label-caption);\n font: var(--dsw-font-xxs-12);\n}\n\n/* The caption under a group of rows (today: the two colour rows). Rows carry\n their own 8px padding, so the note only needs to close the group. */\n.ccd-settings-note {\n margin: 0;\n padding: 0 2px 6px;\n}\n\n/* An unregistered DSH build leaves the native interface in place while every\n switch still reads \"on\"; the page says so in the host's warning colour. */\n.ccd-settings-warning {\n color: var(--dsw-alias-state-warn-label);\n padding: 0 2px 10px;\n}\n\n.ccd-settings-control {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* Segmented theme control: a recessed track with the chosen segment raised.\n The reference measures 92x32 with 16px glyphs and a 1px inner card; the track\n and the raised card come from the plugin palette when it is active (both\n schemes define the relationship) and from the host palette otherwise. */\n.ccd-settings-segmented {\n display: inline-flex;\n align-items: center;\n padding: 1px;\n border-radius: 9px;\n background: var(--ccd-track, var(--dsw-alias-interactive-bg-hover));\n}\n\n.ccd-settings-segment {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: 30px;\n height: 30px;\n padding: 0;\n border: 1px solid transparent;\n border-radius: 8px;\n background: none;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n transition: color 120ms ease, background-color 120ms ease;\n}\n\n.ccd-settings-segment:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.ccd-settings-segment[aria-checked='true'] {\n border-color: var(--ccd-border-soft, var(--dsw-alias-border-l2));\n background: var(--ccd-card, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-shadow-lv1);\n}\n\n/* Switch: the host's own dimensions and tokens (36\xD720 capsule, 16px thumb). */\n.ccd-settings-switch {\n position: relative;\n box-sizing: border-box;\n flex: 0 0 auto;\n width: 36px;\n height: 20px;\n padding: 2px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-border-l3);\n cursor: pointer;\n transition: background 120ms ease;\n}\n\n.ccd-settings-switch[aria-checked='true'] {\n background: var(--dsw-static-blue-450);\n}\n\n.ccd-settings-thumb {\n display: block;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-switch-thumb);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.ccd-settings-switch[aria-checked='true'] .ccd-settings-thumb {\n background: var(--dsw-alias-label-primary-foreground);\n transform: translateX(16px);\n}\n\n.ccd-settings-text {\n width: 220px;\n height: 34px;\n padding: 0 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font: inherit;\n}\n\n.ccd-settings-text-short {\n width: 108px;\n font: var(--dsw-font-xs-13);\n}\n\n.ccd-settings-text[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.ccd-settings-text:focus-visible,\n.ccd-settings-switch:focus-visible,\n.ccd-settings-segment:focus-visible,\n.ccd-settings-button:focus-visible,\n.ccd-settings-button-quiet:focus-visible,\n.ccd-settings-menu-search:focus-visible,\n.ccd-settings-menu-item:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Quiet button: the bordered shape the host's own settings rows use. */\n.ccd-settings-button-quiet {\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: none;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.ccd-settings-button-quiet:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n/* Select box: one bordered box with the chevron inside it. */\n.ccd-settings-select {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n box-sizing: border-box;\n width: 260px;\n height: 34px;\n padding: 0 12px;\n border: .5px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.ccd-settings-select:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ccd-settings-select[data-empty='true'] .ccd-settings-select-value {\n color: var(--dsw-alias-label-caption);\n}\n\n.ccd-settings-select-value {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.ccd-settings-select > svg {\n flex: 0 0 auto;\n color: var(--dsw-alias-label-caption);\n}\n\n/* Installed-family menu, anchored to its select box. */\n.ccd-settings-menu {\n position: fixed;\n z-index: 1000;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-2);\n box-shadow: var(--dsw-elevation-prominent);\n}\n\n.ccd-settings-menu-search {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 10px;\n border: .5px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font: inherit;\n}\n\n.ccd-settings-menu-count,\n.ccd-settings-menu-empty {\n margin: 0;\n padding: 0 6px;\n color: var(--dsw-alias-label-caption);\n font: var(--dsw-font-xxs-12);\n}\n\n/* The list keeps the window's own scrollbar: `theme/scrollbars.css` lists this\n scroller, so the host's painted 5px bar is what appears here. (`scrollbar-\n width: thin` used to stand in its place; the standard property suppresses the\n host's painting, which is the whole thing that sheet exists to undo.) */\n.ccd-settings-menu-list {\n max-height: 260px;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n list-style: none;\n}\n\n.ccd-settings-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n text-align: left;\n cursor: pointer;\n}\n\n.ccd-settings-menu-item[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ccd-settings-menu-name {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The check closes the row and carries the switch's blue. */\n.ccd-settings-menu-check {\n flex: 0 0 auto;\n margin-left: auto;\n color: var(--dsw-static-blue-450);\n font-size: 13px;\n}\n\n.ccd-settings-status {\n margin: 0;\n padding: 0 2px;\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-xs-13);\n}\n\n/* Silent while nothing is being written. */\n.ccd-settings-status:empty {\n display: none;\n}\n\n.ccd-settings-button {\n height: 34px;\n padding: 0 14px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-label-primary-foreground);\n font: var(--dsw-font-xs-strong-13);\n cursor: pointer;\n}\n\n.ccd-settings-button-quiet {\n border: 1px solid var(--dsw-alias-border-l2);\n background: none;\n color: var(--dsw-alias-label-primary);\n}\n\n.ccd-settings-button:disabled {\n opacity: .5;\n cursor: default;\n}\n\n@media (max-width: 620px) {\n .ccd-settings-row {\n grid-template-columns: 1fr;\n }\n\n .ccd-settings-control {\n justify-content: flex-start;\n }\n\n .ccd-settings-text {\n width: 100%;\n min-width: 0;\n }\n}\n";
|
|
8006
|
+
var settings_default = "/*\n * Row configuration page.\n *\n * The page is drawn on the host's own settings surface and stays readable in\n * both plugin states, so it consumes host `--dsw-*` tokens: while the plugin is\n * enabled the theme layer has already pointed the surfaces and fonts that matter\n * at the configured values, and while it is disabled the page still renders\n * (that is how the interface is switched back on). The one exception is the\n * segmented theme control below, whose recessed track and raised segment have a\n * relationship the host's dark palette does not carry: it reads `--ccd-*` with a\n * host fallback, so it follows both plugin palettes while enabled and keeps\n * working (on host tokens) while disabled.\n *\n * Layout is one column of cards capped at a readable measure: the Plugins panel\n * is wide, and a settings form stretched across it is hard to scan.\n */\n\n.ccd-settings-page {\n display: flex;\n flex-direction: column;\n gap: 12px;\n max-width: 760px;\n margin-top: 16px;\n padding-bottom: 24px;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-summary {\n color: var(--dsw-alias-label-secondary);\n}\n\n.ccd-settings-notice {\n margin: 12px 0;\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-section {\n display: flex;\n flex-direction: column;\n padding: 8px 0 4px;\n}\n\n.ccd-settings-section + .ccd-settings-section {\n margin-top: 14px;\n}\n\n.ccd-settings-title {\n margin: 0;\n padding: 0 2px 4px;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-strong-14);\n}\n\n.ccd-settings-row {\n display: grid;\n grid-template-columns: minmax(180px, 1fr) auto;\n align-items: center;\n gap: 4px 12px;\n min-height: 48px;\n padding: 8px 0;\n}\n\n.ccd-settings-row + .ccd-settings-row {\n border-top: .5px solid var(--dsw-alias-border-l2);\n}\n\n.ccd-settings-label {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.ccd-settings-name {\n font: var(--dsw-font-s-14);\n}\n\n.ccd-settings-hint,\n.ccd-settings-note {\n color: var(--dsw-alias-label-caption);\n font: var(--dsw-font-xxs-12);\n}\n\n/* The caption under a group of rows (today: the two colour rows). Rows carry\n their own 8px padding, so the note only needs to close the group. */\n.ccd-settings-note {\n margin: 0;\n padding: 0 2px 6px;\n}\n\n/* An unregistered DSH build leaves the native interface in place while every\n switch still reads \"on\"; the page says so in the host's warning colour. */\n.ccd-settings-warning {\n color: var(--dsw-alias-state-warn-label);\n padding: 0 2px 10px;\n}\n\n.ccd-settings-control {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* Segmented theme control: a recessed track with the chosen segment raised.\n The reference measures 92x32 with 16px glyphs and a 1px inner card; the track\n and the raised card come from the plugin palette when it is active (both\n schemes define the relationship) and from the host palette otherwise. */\n.ccd-settings-segmented {\n display: inline-flex;\n align-items: center;\n padding: 1px;\n border-radius: 9px;\n background: var(--ccd-track, var(--dsw-alias-interactive-bg-hover));\n}\n\n.ccd-settings-segment {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: 30px;\n height: 30px;\n padding: 0;\n border: 1px solid transparent;\n border-radius: 8px;\n background: none;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n transition: color 120ms ease, background-color 120ms ease;\n}\n\n.ccd-settings-segment:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.ccd-settings-segment[aria-checked='true'] {\n border-color: var(--ccd-border-soft, var(--dsw-alias-border-l2));\n background: var(--ccd-card, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-shadow-lv1);\n}\n\n/* Switch: the host's own dimensions and tokens (36\xD720 capsule, 16px thumb). */\n.ccd-settings-switch {\n position: relative;\n box-sizing: border-box;\n flex: 0 0 auto;\n width: 36px;\n height: 20px;\n padding: 2px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-border-l3);\n cursor: pointer;\n transition: background 120ms ease;\n}\n\n.ccd-settings-switch[aria-checked='true'] {\n background: var(--dsw-static-blue-450);\n}\n\n.ccd-settings-thumb {\n display: block;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-switch-thumb);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.ccd-settings-switch[aria-checked='true'] .ccd-settings-thumb {\n background: var(--dsw-alias-label-primary-foreground);\n transform: translateX(16px);\n}\n\n.ccd-settings-text {\n width: 220px;\n height: 34px;\n padding: 0 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font: inherit;\n}\n\n.ccd-settings-text-short {\n width: 108px;\n font: var(--dsw-font-xs-13);\n}\n\n.ccd-settings-text[aria-invalid='true'] {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n.ccd-settings-text:focus-visible,\n.ccd-settings-switch:focus-visible,\n.ccd-settings-segment:focus-visible,\n.ccd-settings-button:focus-visible,\n.ccd-settings-button-quiet:focus-visible,\n.ccd-settings-menu-search:focus-visible,\n.ccd-settings-menu-item:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Quiet button: the bordered shape the host's own settings rows use. */\n.ccd-settings-button-quiet {\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: none;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.ccd-settings-button-quiet:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n/* Select box: one bordered box with the chevron inside it. */\n.ccd-settings-select {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n box-sizing: border-box;\n width: 260px;\n height: 34px;\n padding: 0 12px;\n border: .5px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.ccd-settings-select:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ccd-settings-select[data-empty='true'] .ccd-settings-select-value {\n color: var(--dsw-alias-label-caption);\n}\n\n.ccd-settings-select-value {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.ccd-settings-select > svg {\n flex: 0 0 auto;\n color: var(--dsw-alias-label-caption);\n}\n\n/* Installed-family menu, anchored to its select box. */\n.ccd-settings-menu {\n position: fixed;\n z-index: 1000;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-2);\n box-shadow: var(--dsw-elevation-prominent);\n}\n\n.ccd-settings-menu-search {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 10px;\n border: .5px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font: inherit;\n}\n\n.ccd-settings-menu-count,\n.ccd-settings-menu-empty {\n margin: 0;\n padding: 0 6px;\n color: var(--dsw-alias-label-caption);\n font: var(--dsw-font-xxs-12);\n}\n\n/* The list keeps the window's own scrollbar: `theme/scrollbars.css` lists this\n scroller, so the host's painted 5px bar is what appears here. (`scrollbar-\n width: thin` used to stand in its place; the standard property suppresses the\n host's painting, which is the whole thing that sheet exists to undo.) */\n.ccd-settings-menu-list {\n max-height: 260px;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n list-style: none;\n}\n\n.ccd-settings-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n min-height: 34px;\n padding: 0 10px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n text-align: left;\n cursor: pointer;\n}\n\n.ccd-settings-menu-item[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ccd-settings-menu-name {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The check closes the row and carries the switch's blue. */\n.ccd-settings-menu-check {\n flex: 0 0 auto;\n margin-left: auto;\n color: var(--dsw-static-blue-450);\n font-size: 13px;\n}\n\n.ccd-settings-status {\n margin: 0;\n padding: 0 2px;\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-xs-13);\n}\n\n/* Silent while nothing is being written. */\n.ccd-settings-status:empty {\n display: none;\n}\n\n.ccd-settings-button {\n height: 34px;\n padding: 0 14px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-label-primary-foreground);\n font: var(--dsw-font-xs-strong-13);\n cursor: pointer;\n}\n\n.ccd-settings-button-quiet {\n border: 1px solid var(--dsw-alias-border-l2);\n background: none;\n color: var(--dsw-alias-label-primary);\n}\n\n.ccd-settings-button:disabled {\n opacity: .5;\n cursor: default;\n}\n\n@media (max-width: 620px) {\n .ccd-settings-row {\n grid-template-columns: 1fr;\n }\n\n .ccd-settings-control {\n justify-content: flex-start;\n }\n\n .ccd-settings-text {\n width: 100%;\n min-width: 0;\n }\n}\n\n/* Hand-drawn Claude-like burst. Preserve the host SVG's layout and React ownership. */\n[data-ccd-settings-icon] > svg:first-child {\n display: none;\n}\n\n[data-ccd-settings-icon]::before {\n content: '';\n display: block;\n width: 16px;\n height: 16px;\n flex: 0 0 16px;\n background: currentColor;\n mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m12 12 1-10m-1 10 6-8m-6 8 10-4m-10 4 10 2m-10-2 7 7m-7-7 2 10m-2-10-4 10m4-10-8 6m8-6L2 11m10 1L4 5m8 7L8 2' fill='none' stroke='black' stroke-width='2.3' stroke-linecap='round'/%3E%3C/svg%3E\") center / contain no-repeat;\n}\n";
|
|
7855
8007
|
|
|
7856
8008
|
// src/client/features/settings/mount.ts
|
|
7857
8009
|
function mountSettingsPage(ctx, dom, form, themePreference, scope) {
|
|
7858
8010
|
scope.add(dom.mountStyles(settings_default));
|
|
8011
|
+
scope.add(mountSettingsSectionIcon(document, [zh.nav, en.nav]));
|
|
7859
8012
|
const registration = registerSettingsPage(
|
|
7860
8013
|
ctx,
|
|
7861
|
-
|
|
8014
|
+
ENTRY_ID,
|
|
7862
8015
|
(props) => (0, import_react12.createElement)(ConfigPage, { ...props, form, themePreference })
|
|
7863
8016
|
);
|
|
7864
8017
|
scope.add(() => {
|
|
@@ -9203,6 +9356,52 @@ var shellFeature = {
|
|
|
9203
9356
|
}
|
|
9204
9357
|
};
|
|
9205
9358
|
|
|
9359
|
+
// src/client/compat/sidebar-action-alignment.ts
|
|
9360
|
+
function mountSidebarActionAlignment(document2) {
|
|
9361
|
+
const host = hostSelectors(document2);
|
|
9362
|
+
const originals = /* @__PURE__ */ new Map();
|
|
9363
|
+
const resize = new ResizeObserver(() => sync());
|
|
9364
|
+
const watched = /* @__PURE__ */ new Set();
|
|
9365
|
+
const sync = () => {
|
|
9366
|
+
for (const sidebar of document2.querySelectorAll(host.sidebarRoot)) {
|
|
9367
|
+
const header = sidebar.querySelector(host.browserSectionHeader);
|
|
9368
|
+
const row = sidebar.querySelector(host.workspaceRow);
|
|
9369
|
+
if (header === null || row === null) continue;
|
|
9370
|
+
if (!originals.has(header)) originals.set(header, header.style.paddingRight);
|
|
9371
|
+
for (const element of [header, row]) {
|
|
9372
|
+
if (!watched.has(element)) {
|
|
9373
|
+
watched.add(element);
|
|
9374
|
+
resize.observe(element);
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
if (header.getBoundingClientRect().width === 0 || row.getBoundingClientRect().width === 0) continue;
|
|
9378
|
+
const inset = Math.max(0, header.getBoundingClientRect().right - row.getBoundingClientRect().right);
|
|
9379
|
+
const value = `${inset}px`;
|
|
9380
|
+
if (header.style.paddingRight !== value) header.style.paddingRight = value;
|
|
9381
|
+
}
|
|
9382
|
+
for (const element of watched) {
|
|
9383
|
+
if (!element.isConnected) {
|
|
9384
|
+
resize.unobserve(element);
|
|
9385
|
+
watched.delete(element);
|
|
9386
|
+
}
|
|
9387
|
+
}
|
|
9388
|
+
for (const [header, original] of originals) {
|
|
9389
|
+
if (!header.isConnected) {
|
|
9390
|
+
header.style.paddingRight = original;
|
|
9391
|
+
originals.delete(header);
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
};
|
|
9395
|
+
const mutations = new MutationObserver(sync);
|
|
9396
|
+
mutations.observe(document2.documentElement, { childList: true, subtree: true });
|
|
9397
|
+
sync();
|
|
9398
|
+
return () => {
|
|
9399
|
+
mutations.disconnect();
|
|
9400
|
+
resize.disconnect();
|
|
9401
|
+
for (const [header, original] of originals) header.style.paddingRight = original;
|
|
9402
|
+
};
|
|
9403
|
+
}
|
|
9404
|
+
|
|
9206
9405
|
// src/client/compat/account-more.ts
|
|
9207
9406
|
function mountAccountMore(menu) {
|
|
9208
9407
|
const document2 = menu.ownerDocument;
|
|
@@ -9397,20 +9596,17 @@ function mountAccountMore(menu) {
|
|
|
9397
9596
|
|
|
9398
9597
|
// src/client/compat/account-theme.ts
|
|
9399
9598
|
function mountAccountTheme(menu, theme) {
|
|
9400
|
-
const
|
|
9401
|
-
|
|
9402
|
-
if (theme === null || !anchor?.parentElement) return () => {
|
|
9599
|
+
const anchor = menu.firstElementChild;
|
|
9600
|
+
if (theme === null || !anchor) return () => {
|
|
9403
9601
|
};
|
|
9404
9602
|
const document2 = menu.ownerDocument;
|
|
9405
9603
|
const zh2 = (document2.documentElement.lang || document2.defaultView?.navigator.language || "").toLowerCase().startsWith("zh");
|
|
9406
9604
|
const row = document2.createElement("div");
|
|
9407
9605
|
row.setAttribute("data-ccd-account-theme", "");
|
|
9408
|
-
const label = document2.createElement("span");
|
|
9409
|
-
label.textContent = zh2 ? "\u4E3B\u9898" : "Theme";
|
|
9410
9606
|
const group = document2.createElement("span");
|
|
9411
9607
|
group.setAttribute("role", "group");
|
|
9412
|
-
group.setAttribute("aria-label",
|
|
9413
|
-
row.append(
|
|
9608
|
+
group.setAttribute("aria-label", zh2 ? "\u4E3B\u9898" : "Theme");
|
|
9609
|
+
row.append(group);
|
|
9414
9610
|
const options = [
|
|
9415
9611
|
{ id: "system", label: zh2 ? "\u8DDF\u968F\u7CFB\u7EDF" : "System", artwork: '<rect x="2.3" y="3.1" width="11.4" height="7.9" rx="1.5"/><path d="M8 11v1.4M6.3 12.9h3.4"/>' },
|
|
9416
9612
|
{ id: "light", label: zh2 ? "\u6D45\u8272" : "Light", artwork: '<circle cx="8" cy="8" r="3.2"/><path d="M8 1.2v1.6M8 13.2v1.6M1.2 8h1.6M13.2 8h1.6M3.2 3.2l1.1 1.1M11.7 11.7l1.1 1.1M12.8 3.2l-1.1 1.1M4.3 11.7l-1.1 1.1"/>' },
|
|
@@ -9455,7 +9651,7 @@ function mountAccountTheme(menu, theme) {
|
|
|
9455
9651
|
});
|
|
9456
9652
|
sync();
|
|
9457
9653
|
const unsubscribe = theme.subscribe(sync);
|
|
9458
|
-
|
|
9654
|
+
menu.insertBefore(row, anchor);
|
|
9459
9655
|
return () => {
|
|
9460
9656
|
unsubscribe();
|
|
9461
9657
|
row.remove();
|
|
@@ -9710,8 +9906,44 @@ function mountSidebarNavigation(document2, icons, report) {
|
|
|
9710
9906
|
};
|
|
9711
9907
|
}
|
|
9712
9908
|
|
|
9909
|
+
// src/client/compat/sidebar-session-icons.ts
|
|
9910
|
+
function mountSidebarSessionIcons(document2) {
|
|
9911
|
+
const attribute = "data-ccd-sidebar-session-icon";
|
|
9912
|
+
const shortcutAttribute = "data-ccd-sidebar-session-shortcut";
|
|
9913
|
+
const workspaceAttribute = "data-ccd-sidebar-workspace-menu";
|
|
9914
|
+
const sync = () => {
|
|
9915
|
+
for (const menu of document2.querySelectorAll('[data-menu-material][role="menu"]')) {
|
|
9916
|
+
const labels = [...menu.querySelectorAll('[role="menuitem"]')].map((row) => row.querySelector("._itemLabel_4ub78_190")?.textContent?.trim() ?? "");
|
|
9917
|
+
const workspace = labels.length === 2 && /^(重命名|Rename)$/u.test(labels[0] ?? "") && /^(删除工作区|Delete workspace)$/u.test(labels[1] ?? "");
|
|
9918
|
+
if (workspace) {
|
|
9919
|
+
if (!menu.hasAttribute(workspaceAttribute)) menu.setAttribute(workspaceAttribute, "");
|
|
9920
|
+
} else menu.removeAttribute(workspaceAttribute);
|
|
9921
|
+
}
|
|
9922
|
+
for (const row of document2.querySelectorAll(
|
|
9923
|
+
'[data-slot="sidebar.workspaces.session.menu.item"] [role="menuitem"]'
|
|
9924
|
+
)) {
|
|
9925
|
+
const label = [...row.querySelectorAll("span")].filter((span) => span.children.length === 0).map((span) => span.textContent?.trim() ?? "");
|
|
9926
|
+
const icon = label.some((text) => /^(置顶会话|Pin session)$/u.test(text)) ? "pin" : label.some((text) => /^(重命名|重命名会话|Rename|Rename session)$/u.test(text)) ? "rename" : null;
|
|
9927
|
+
const shortcut = label.some((text) => /^(置顶会话|取消置顶|Pin session|Unpin session)$/u.test(text)) ? "P" : label.some((text) => /^(重命名|重命名会话|Rename|Rename session)$/u.test(text)) ? "R" : label.some((text) => /^(分叉会话|分支会话|创建分支|Fork session)$/u.test(text)) ? "F" : label.some((text) => /^(归档会话|取消归档|Archive session|Unarchive session)$/u.test(text)) ? "A" : null;
|
|
9928
|
+
if (shortcut === null) row.removeAttribute(shortcutAttribute);
|
|
9929
|
+
else if (row.getAttribute(shortcutAttribute) !== shortcut) row.setAttribute(shortcutAttribute, shortcut);
|
|
9930
|
+
if (icon === null) row.removeAttribute(attribute);
|
|
9931
|
+
else if (row.getAttribute(attribute) !== icon) row.setAttribute(attribute, icon);
|
|
9932
|
+
}
|
|
9933
|
+
};
|
|
9934
|
+
const observer = new MutationObserver(sync);
|
|
9935
|
+
observer.observe(document2.documentElement, { childList: true, subtree: true, characterData: true });
|
|
9936
|
+
sync();
|
|
9937
|
+
return () => {
|
|
9938
|
+
observer.disconnect();
|
|
9939
|
+
for (const row of document2.querySelectorAll(`[${shortcutAttribute}]`)) row.removeAttribute(shortcutAttribute);
|
|
9940
|
+
for (const row of document2.querySelectorAll(`[${attribute}]`)) row.removeAttribute(attribute);
|
|
9941
|
+
for (const menu of document2.querySelectorAll(`[${workspaceAttribute}]`)) menu.removeAttribute(workspaceAttribute);
|
|
9942
|
+
};
|
|
9943
|
+
}
|
|
9944
|
+
|
|
9713
9945
|
// src/client/features/sidebar/account-menu.css
|
|
9714
|
-
var account_menu_default = '/*\n * Signed-in account menu.\n *\n * The reference draws the card the sidebar\'s account row opens as a wide menu\n * whose first block is the account itself. The compat layer tags the open menu\n * (`compat/account-menu.ts`) and mirrors the signed-in name onto it, so these\n * rules reshape the host\'s rows and the plugin\'s More submenu.\n *\n * Menu surfaces and rows come from ui-primitives `Menu.module.css`; the tag is\n * the plugin\'s own. Sources are pinned in src/client/compat/host-dom.ts.\n */\n/* The foot row is a hit target, not a panel: the reference\'s fill is a slim bar,\n so the row is as short as the avatar allows and stays pinned to the window\'s\n bottom edge. */\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger,\nhtml[data-dsh-ccd-style="true"] .Dws9Sa_trigger {\n height: var(--ccd-account-trigger-height);\n padding: 0 6px;\n border-radius: var(--ccd-radius-row);\n}\n\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger[data-collapsed="true"] {\n height: var(--ccd-account-trigger-height);\n}\n\n/* The expanded launcher ends in the reference\'s small downward chevron,\n including while its menu is open. Keep a fixed icon seat after the label so\n long names ellipsize before it; the collapsed rail only shows the avatar. */\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger:not([data-collapsed="true"])::after {\n content: "";\n width: 16px;\n height: 16px;\n flex: none;\n margin-inline-start: auto;\n background: var(--ccd-text-muted);\n mask: var(--ccd-icon-chevron-right) center / 16px 16px no-repeat;\n transform: rotate(90deg);\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] {\n box-sizing: border-box;\n width: var(--ccd-account-menu-width);\n min-width: var(--ccd-account-menu-width);\n max-width: var(--ccd-account-menu-width);\n padding: var(--ccd-account-menu-padding);\n border-radius: var(--ccd-radius-panel);\n}\n\n/* The account header the reference shows above the rows.\n *\n * The name sits on the row icon\'s own left edge rather than on the rows\' text\n * edge: the card\'s first column is the icon seat, and both the row icons and\n * this line start it. A row starts its content at its own padding, a fixed\n * distance from the card edge (the `padding: 0 10px` on the row rule below,\n * which the card\'s own padding sits outside of), so the header takes that same\n * inline padding and the two left edges stay one line. The vertical padding is\n * deliberately left alone: the name\'s top and bottom whitespace and the card\'s\n * height depend on it, and the alignment is horizontal.\n *\n * The property holds one *quoted* CSS string token (`compat/account-menu.ts`\n * `accountNameToken`), and the fallback is a quoted string for the same reason:\n * `content` takes no bare word, and a value that is not one `<string>` is\n * invalid at computed-value time, which computes to `none` on `::before` and\n * drops this whole line \u2014 padding included. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu]::before {\n content: var(--ccd-account-name, "");\n display: block;\n padding: 4px 10px 8px;\n color: var(--ccd-text-muted);\n font-size: var(--ccd-font-size-muted);\n font-weight: 400;\n line-height: 18px;\n /* The header is painted content, not an element the host lays text into, so\n the trigger\'s own ellipsis never reaches it: without these the name runs\n out of the card and the window edge cuts it. Keep it on the header\'s one\n line and let the long end ellipsize, as the trigger\'s own label does. */\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"] {\n min-height: var(--ccd-account-row-height);\n padding: 0 10px;\n border-radius: var(--ccd-radius-row);\n color: var(--ccd-text);\n font-size: var(--ccd-font-size-muted);\n line-height: 20px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"]:focus-visible {\n background: var(--ccd-hover);\n}\n\n/* Row cells are wrapped by the primitive; the last group reads as its own\n block, which is where the reference draws its final hairline. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] div:has(> [role="menuitem"]):last-child {\n margin-top: 4px;\n padding-top: 4px;\n border-top: 0.5px solid var(--ccd-border-soft);\n}\n\n/* Sign out is the one row whose icon does not come from the product icon set:\n ui-settings-account inlines it from a 14-unit artwork (`LogoutIcon`,\n `viewBox="0 0 14 14"`, fill-only) that fills its whole canvas, while Settings\n and Feedback are 16-unit artworks that the Menu primitive\'s icon seat scales\n down to its 14px box (`ui-primitives/lib/Menu.js` `MenuItemButton`, whose\n `.itemIcon svg` rule wins over the artwork\'s own width and height). Sign out\n is therefore the only glyph drawn at full slot size: in a 2x capture it inks\n 13.5px against 12 and 10 for its neighbours, with a 1.4px wall against their\n 1.14px stroke. Scaling it by the same 14/16 the product icons already get\n returns it to their size; the scale is taken about the svg\'s own box, so the\n glyph keeps the slot\'s centre. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"] > span:first-child > span > svg {\n transform: scale(0.875);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] > [data-ccd-account-more-original] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] > span[aria-hidden],\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] span[aria-hidden] {\n display: flex;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] svg,\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] svg {\n width: 14px;\n height: 14px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-chevron] {\n margin-inline-start: auto;\n color: var(--ccd-text-muted);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more][aria-expanded="true"] {\n background: var(--ccd-hover);\n}\n\n/* The top layer keeps the flyout clear of the native menu\'s scroll viewport. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n width: var(--ccd-account-menu-width);\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n overflow-y: auto;\n margin: 0;\n padding: var(--ccd-account-menu-padding);\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-radius-panel);\n background: var(--ccd-card);\n color: var(--ccd-text);\n box-shadow: var(--ccd-effort-shadow);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu][hidden] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] > button {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n width: 100%;\n border: 0;\n background: transparent;\n font-family: inherit;\n font-weight: 400;\n text-align: start;\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] > [role="separator"] {\n height: 1px;\n margin: 4px 10px;\n background: var(--ccd-border-soft);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n
|
|
9946
|
+
var account_menu_default = '/*\n * Signed-in account menu.\n *\n * The reference draws the card the sidebar\'s account row opens as a wide menu\n * whose first block is the account itself. The compat layer tags the open menu\n * (`compat/account-menu.ts`) and mirrors the signed-in name onto it, so these\n * rules reshape the host\'s rows and the plugin\'s More submenu.\n *\n * Menu surfaces and rows come from ui-primitives `Menu.module.css`; the tag is\n * the plugin\'s own. Sources are pinned in src/client/compat/host-dom.ts.\n */\n/* The foot row is a hit target, not a panel: the reference\'s fill is a slim bar,\n so the row is as short as the avatar allows and stays pinned to the window\'s\n bottom edge. */\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger,\nhtml[data-dsh-ccd-style="true"] .Dws9Sa_trigger {\n height: var(--ccd-account-trigger-height);\n padding: 0 6px;\n border-radius: var(--ccd-radius-row);\n}\n\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger[data-collapsed="true"] {\n height: var(--ccd-account-trigger-height);\n}\n\n/* The expanded launcher ends in the reference\'s small downward chevron,\n including while its menu is open. Keep a fixed icon seat after the label so\n long names ellipsize before it; the collapsed rail only shows the avatar. */\nhtml[data-dsh-ccd-style="true"] .ZogL4G_trigger:not([data-collapsed="true"])::after {\n content: "";\n width: 16px;\n height: 16px;\n flex: none;\n margin-inline-start: auto;\n background: var(--ccd-text-muted);\n mask: var(--ccd-icon-chevron-right) center / 16px 16px no-repeat;\n transform: rotate(90deg);\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] {\n box-sizing: border-box;\n width: var(--ccd-account-menu-width);\n min-width: var(--ccd-account-menu-width);\n max-width: var(--ccd-account-menu-width);\n padding: var(--ccd-account-menu-padding);\n border-radius: var(--ccd-radius-panel);\n}\n\n/* The account header the reference shows above the rows.\n *\n * The name sits on the row icon\'s own left edge rather than on the rows\' text\n * edge: the card\'s first column is the icon seat, and both the row icons and\n * this line start it. A row starts its content at its own padding, a fixed\n * distance from the card edge (the `padding: 0 10px` on the row rule below,\n * which the card\'s own padding sits outside of), so the header takes that same\n * inline padding and the two left edges stay one line. The vertical padding is\n * deliberately left alone: the name\'s top and bottom whitespace and the card\'s\n * height depend on it, and the alignment is horizontal.\n *\n * The property holds one *quoted* CSS string token (`compat/account-menu.ts`\n * `accountNameToken`), and the fallback is a quoted string for the same reason:\n * `content` takes no bare word, and a value that is not one `<string>` is\n * invalid at computed-value time, which computes to `none` on `::before` and\n * drops this whole line \u2014 padding included. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu]::before {\n content: var(--ccd-account-name, "");\n display: block;\n padding: 4px 10px 8px;\n color: var(--ccd-text-muted);\n font-size: var(--ccd-font-size-muted);\n font-weight: 400;\n line-height: 18px;\n /* The header is painted content, not an element the host lays text into, so\n the trigger\'s own ellipsis never reaches it: without these the name runs\n out of the card and the window edge cuts it. Keep it on the header\'s one\n line and let the long end ellipsize, as the trigger\'s own label does. */\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"] {\n min-height: var(--ccd-account-row-height);\n padding: 0 10px;\n border-radius: var(--ccd-radius-row);\n color: var(--ccd-text);\n font-size: var(--ccd-font-size-muted);\n line-height: 20px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"]:hover,\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"]:focus-visible {\n background: var(--ccd-hover);\n}\n\n/* Row cells are wrapped by the primitive; the last group reads as its own\n block, which is where the reference draws its final hairline. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] div:has(> [role="menuitem"]):last-child {\n margin-top: 4px;\n padding-top: 4px;\n border-top: 0.5px solid var(--ccd-border-soft);\n}\n\n/* Sign out is the one row whose icon does not come from the product icon set:\n ui-settings-account inlines it from a 14-unit artwork (`LogoutIcon`,\n `viewBox="0 0 14 14"`, fill-only) that fills its whole canvas, while Settings\n and Feedback are 16-unit artworks that the Menu primitive\'s icon seat scales\n down to its 14px box (`ui-primitives/lib/Menu.js` `MenuItemButton`, whose\n `.itemIcon svg` rule wins over the artwork\'s own width and height). Sign out\n is therefore the only glyph drawn at full slot size: in a 2x capture it inks\n 13.5px against 12 and 10 for its neighbours, with a 1.4px wall against their\n 1.14px stroke. Scaling it by the same 14/16 the product icons already get\n returns it to their size; the scale is taken about the svg\'s own box, so the\n glyph keeps the slot\'s centre. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu] [role="menuitem"] > span:first-child > span > svg {\n transform: scale(0.875);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] > [data-ccd-account-more-original] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] > span[aria-hidden],\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] span[aria-hidden] {\n display: flex;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more] svg,\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] svg {\n width: 14px;\n height: 14px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-chevron] {\n margin-inline-start: auto;\n color: var(--ccd-text-muted);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more][aria-expanded="true"] {\n background: var(--ccd-hover);\n}\n\n/* The top layer keeps the flyout clear of the native menu\'s scroll viewport. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] {\n position: fixed;\n inset: auto;\n box-sizing: border-box;\n width: var(--ccd-account-menu-width);\n max-width: calc(100vw - 16px);\n max-height: calc(100vh - 16px);\n overflow-y: auto;\n margin: 0;\n padding: var(--ccd-account-menu-padding);\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-radius-panel);\n background: var(--ccd-card);\n color: var(--ccd-text);\n box-shadow: var(--ccd-effort-shadow);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu][hidden] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] > button {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n width: 100%;\n border: 0;\n background: transparent;\n font-family: inherit;\n font-weight: 400;\n text-align: start;\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-more-menu] > [role="separator"] {\n height: 1px;\n margin: 4px 10px;\n background: var(--ccd-border-soft);\n}\n\n/* With theme controls available, the name and controls share one header. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-menu]:has([data-ccd-account-theme])::before {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 4px 10px 8px;\n color: var(--ccd-text-muted);\n font-size: var(--ccd-font-size-muted);\n line-height: 18px;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme]::before {\n content: var(--ccd-account-name, "");\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] > [role="group"] {\n display: inline-flex;\n flex: none;\n gap: 1px;\n padding: 2px;\n border-radius: var(--ccd-radius-row);\n background: var(--ccd-track);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] button {\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: 28px;\n height: 26px;\n padding: 0;\n border: 1px solid transparent;\n border-radius: var(--ccd-radius-row);\n color: var(--ccd-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] button:hover {\n color: var(--ccd-text);\n background: var(--ccd-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] button[aria-checked="true"] {\n border-color: var(--ccd-border-soft);\n color: var(--ccd-text);\n background: var(--ccd-card);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-account-theme] button:focus-visible {\n outline: 1px solid var(--ccd-text-muted);\n outline-offset: 1px;\n}\n';
|
|
9715
9947
|
|
|
9716
9948
|
// src/client/features/sidebar/sidebar.css
|
|
9717
9949
|
var sidebar_default = `/*
|
|
@@ -9786,13 +10018,37 @@ html[data-dsh-ccd-style="true"][data-platform="darwin"] [data-sidebar-collapsed]
|
|
|
9786
10018
|
html[data-dsh-ccd-style="true"][data-platform="darwin"] [data-shell-leading] {
|
|
9787
10019
|
top: 11px;
|
|
9788
10020
|
left: var(--ccd-sidebar-toggle-left);
|
|
10021
|
+
display: flex;
|
|
10022
|
+
align-items: center;
|
|
10023
|
+
height: 28px;
|
|
9789
10024
|
}
|
|
9790
10025
|
|
|
10026
|
+
/* Collapsing exposes shell shortcuts beside the toggle. Their native button
|
|
10027
|
+
sizes differ; keep every hit box centred at y=25, like the conversation
|
|
10028
|
+
header, and give the larger shortcut artwork the same 16px icon seat. */
|
|
9791
10029
|
html[data-dsh-ccd-style="true"][data-platform="darwin"] [data-shell-leading] button {
|
|
10030
|
+
box-sizing: border-box;
|
|
10031
|
+
display: inline-flex;
|
|
10032
|
+
align-items: center;
|
|
10033
|
+
justify-content: center;
|
|
10034
|
+
flex: none;
|
|
10035
|
+
width: 28px;
|
|
10036
|
+
height: 28px;
|
|
10037
|
+
min-width: 0;
|
|
10038
|
+
min-height: 0;
|
|
10039
|
+
margin-block: 0;
|
|
10040
|
+
padding: 0;
|
|
9792
10041
|
border-radius: 8px;
|
|
9793
10042
|
color: var(--ccd-text-secondary);
|
|
9794
10043
|
}
|
|
9795
10044
|
|
|
10045
|
+
html[data-dsh-ccd-style="true"][data-platform="darwin"] [data-shell-leading] button svg {
|
|
10046
|
+
flex: none;
|
|
10047
|
+
width: 16px;
|
|
10048
|
+
height: 16px;
|
|
10049
|
+
display: block;
|
|
10050
|
+
}
|
|
10051
|
+
|
|
9796
10052
|
html[data-dsh-ccd-style="true"][data-platform="darwin"] [data-shell-leading] button:hover {
|
|
9797
10053
|
background: var(--ccd-hover);
|
|
9798
10054
|
}
|
|
@@ -9917,7 +10173,7 @@ html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) ._3WPZCG_n
|
|
|
9917
10173
|
the row gap, which lifts the icon row and the list together by 9px and leaves
|
|
9918
10174
|
the 28px hit areas, the header's 30px box and every row above untouched. The
|
|
9919
10175
|
host's own \`margin-top: 2px\` on that header never applies: the plugin's
|
|
9920
|
-
|
|
10176
|
+
margin shorthand below outranks its \`:not(rail)\` rule. */
|
|
9921
10177
|
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) ._3WPZCG_panelList {
|
|
9922
10178
|
gap: var(--ccd-nav-gap);
|
|
9923
10179
|
margin-bottom: var(--ccd-nav-gap);
|
|
@@ -9992,92 +10248,29 @@ html[data-dsh-ccd-style="true"] ._3WPZCG_regionArea {
|
|
|
9992
10248
|
padding-left: 0;
|
|
9993
10249
|
}
|
|
9994
10250
|
|
|
9995
|
-
/* Browsing region:
|
|
9996
|
-
Sessions. */
|
|
10251
|
+
/* Browsing region: a separate toolbar above compact project groups. */
|
|
9997
10252
|
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) ._7514NG_root {
|
|
9998
10253
|
--dsh-session-list-edge-inset: 0px;
|
|
9999
10254
|
padding-right: 0;
|
|
10000
10255
|
}
|
|
10001
10256
|
|
|
10002
|
-
/*
|
|
10003
|
-
|
|
10004
|
-
|
|
10257
|
+
/* Align the heading with the project labels' 4px inset. Overlap the toolbar
|
|
10258
|
+
and first project's empty vertical padding by 4px: their centres then sit
|
|
10259
|
+
28px apart, close to the navigation rhythm above, without shrinking controls.
|
|
10260
|
+
The collapsed rail keeps the host's own insets for its add-workspace icon. */
|
|
10005
10261
|
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) ._7514NG_sectionHeader {
|
|
10006
10262
|
position: relative;
|
|
10007
10263
|
height: 30px;
|
|
10008
|
-
margin: 0 0
|
|
10009
|
-
padding-left:
|
|
10264
|
+
margin: 0 0 -4px;
|
|
10265
|
+
padding-left: 4px;
|
|
10266
|
+
/* Runtime measures the tree edge, including the actual scrollbar gutter. */
|
|
10267
|
+
padding-right: 0;
|
|
10010
10268
|
color: var(--ccd-text-muted);
|
|
10011
10269
|
}
|
|
10012
10270
|
|
|
10013
|
-
/*
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
* inline start and, at the trailing edge, the plus that starts a Session,
|
|
10017
|
-
* Search and the view options. DSH renders those controls on a section header
|
|
10018
|
-
* of its own, above a tree whose first row is the first Workspace's, so while
|
|
10019
|
-
* \`compat/browser-header.ts\` reports that the tree leads with such a row the
|
|
10020
|
-
* header leaves the flow and is parked on that row's line: the tree then starts
|
|
10021
|
-
* at the region's top and its first row lands under the parked header to the
|
|
10022
|
-
* pixel, because the band's height is the Workspace row's own height.
|
|
10023
|
-
*
|
|
10024
|
-
* Nothing moves in the DOM \u2014 React still owns every node \u2014 and the parked box
|
|
10025
|
-
* takes no pointer events of its own, only its two control groups do, so the row
|
|
10026
|
-
* underneath keeps its click, its hover and its own buttons.
|
|
10027
|
-
*
|
|
10028
|
-
* The band is locked to the tree's content, not to the region's top edge: it
|
|
10029
|
-
* sits on the first Workspace row's line, so it leaves with that row when the
|
|
10030
|
-
* tree scrolls, exactly as the host's own row did. The distance comes from
|
|
10031
|
-
* \`compat/browser-header.ts\` (\`--ccd-header-scroll\`, measured on the scroller \u2014
|
|
10032
|
-
* a sibling of this header, which CSS cannot see) and the region clips it: the
|
|
10033
|
-
* band is not inside the scroller and cannot be carried into it, so the region
|
|
10034
|
-
* box is what a scrolled-away band leaves. Nothing else in the region paints
|
|
10035
|
-
* outside that box \u2014 the host's tooltip bubbles and hover cards are fixed and
|
|
10036
|
-
* its menus are portalled \u2014 and the clip is only declared while merged. */
|
|
10037
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] {
|
|
10038
|
-
position: relative;
|
|
10039
|
-
overflow: hidden;
|
|
10040
|
-
}
|
|
10041
|
-
|
|
10042
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] ._7514NG_sectionHeader {
|
|
10043
|
-
position: absolute;
|
|
10044
|
-
top: calc(-1 * var(--ccd-header-scroll, 0px));
|
|
10045
|
-
left: 0;
|
|
10046
|
-
right: 0;
|
|
10047
|
-
height: var(--ccd-workspace-row-height);
|
|
10048
|
-
margin: 0;
|
|
10049
|
-
z-index: 1;
|
|
10050
|
-
pointer-events: none;
|
|
10051
|
-
}
|
|
10052
|
-
|
|
10053
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] ._7514NG_sectionHeader > :is(._7514NG_searchSlot, ._7514NG_headerActions) {
|
|
10054
|
-
pointer-events: auto;
|
|
10055
|
-
}
|
|
10056
|
-
|
|
10057
|
-
/* The merged band is named by the Workspace row it sits on, so the header's own
|
|
10058
|
-
word stands down there. Where no group is on screen the header is the region's
|
|
10059
|
-
title line instead and keeps a word: \u6700\u8FD1\u4F1A\u8BDD / Recents, written over the
|
|
10060
|
-
host's own dictionary string by \`compat/browser-header.ts\`. */
|
|
10061
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] ._7514NG_sectionLabel {
|
|
10062
|
-
display: none;
|
|
10063
|
-
}
|
|
10064
|
-
|
|
10065
|
-
/* A search replaces the band for the length of the query: the host expands its
|
|
10066
|
-
field over the whole line and hides the label and the actions it owns, so the
|
|
10067
|
-
band takes the sidebar's own fill \u2014 the Workspace row's name and its buttons
|
|
10068
|
-
stay laid out underneath it and must not read through the field. */
|
|
10069
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] ._7514NG_sectionHeader:has(._7514NG_searchExpanded) {
|
|
10070
|
-
background: var(--ccd-sidebar);
|
|
10071
|
-
}
|
|
10072
|
-
|
|
10073
|
-
/* The Workspace row under the band gives the parked controls their room. Search
|
|
10074
|
-
and the view options are two 28px boxes on the header's own 4px gap, so the
|
|
10075
|
-
row's trailing group ends 2px short of that 60px (its own 8px padding spends
|
|
10076
|
-
the rest) and the plus's artwork keeps the reference's 10px to the Search
|
|
10077
|
-
glyph. Every Workspace row takes the same offset, so the groups below the band
|
|
10078
|
-
keep one trailing edge. */
|
|
10079
|
-
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) [data-ccd-header-merged] .jJkEga_projectRow .jJkEga_rowActions {
|
|
10080
|
-
margin-right: calc(28px + 4px + 28px - 8px + 2px);
|
|
10271
|
+
/* Search and view options keep their own line above the project tree. */
|
|
10272
|
+
html[data-dsh-ccd-style="true"] ._3WPZCG_root:not(._3WPZCG_collapsed) ._7514NG_searchSlot:not(._7514NG_searchSlotExpanded) {
|
|
10273
|
+
max-width: 22px;
|
|
10081
10274
|
}
|
|
10082
10275
|
|
|
10083
10276
|
/* The reference gives a Workspace row one standing action \u2014 the plus that starts
|
|
@@ -10102,24 +10295,8 @@ html[data-dsh-ccd-style="true"] .jJkEga_projectRow .jJkEga_rowActions > :first-c
|
|
|
10102
10295
|
}
|
|
10103
10296
|
}
|
|
10104
10297
|
|
|
10105
|
-
/*
|
|
10106
|
-
|
|
10107
|
-
new-session button one row below \u2014 two bare pluses a row apart read as one
|
|
10108
|
-
control. The host's control therefore leaves with \`display: none\`, not the
|
|
10109
|
-
hover fade this plugin shipped first: a faded box still holds a 28px cell on
|
|
10110
|
-
the line, a tab stop and a tooltip for a control nobody can see, click or
|
|
10111
|
-
read, and the fade was driven by a Workspace row's own hover, so it turned up
|
|
10112
|
-
whenever the pointer crossed any group \u2014 a button standing on the line of a
|
|
10113
|
-
row the reader was not aiming at.
|
|
10114
|
-
|
|
10115
|
-
Nothing else on the line moves when it goes: it sat outside the cluster's own
|
|
10116
|
-
flow already \u2014 the fade parked it there \u2014 and a \`display: none\` child takes no
|
|
10117
|
-
space either, so Search and the view options keep the trailing edge they had,
|
|
10118
|
-
and the Workspace row's actions keep the 62px those two 28px boxes, their 4px
|
|
10119
|
-
gap and 4px of air occupy. React still owns the node, so dropping this rule is
|
|
10120
|
-
all it takes to put the host's own line back, and the rail \u2014 this region's
|
|
10121
|
-
other layout, where the control is the region's only entry \u2014 keeps the host's
|
|
10122
|
-
own geometry and its standing button. */
|
|
10298
|
+
/* Keep the toolbar limited to Search and view options. The collapsed rail
|
|
10299
|
+
retains its native add-workspace entry. */
|
|
10123
10300
|
html[data-dsh-ccd-style="true"] ._7514NG_root:not(._7514NG_rail) ._7514NG_headerActions > button:last-of-type {
|
|
10124
10301
|
display: none;
|
|
10125
10302
|
}
|
|
@@ -10145,6 +10322,8 @@ html[data-dsh-ccd-style="true"] ._7514NG_listArea {
|
|
|
10145
10322
|
html[data-dsh-ccd-style="true"] .jJkEga_projectRow {
|
|
10146
10323
|
height: 34px;
|
|
10147
10324
|
padding-inline-start: calc(4px + var(--dsh-workspace-indent, 0px));
|
|
10325
|
+
/* Optical inset: the lower action group sits 4px inside the tree edge. */
|
|
10326
|
+
padding-inline-end: 4px;
|
|
10148
10327
|
color: var(--ccd-text-secondary);
|
|
10149
10328
|
}
|
|
10150
10329
|
|
|
@@ -10240,8 +10419,8 @@ html[data-dsh-ccd-style="true"] ._7514NG_sectionHeader :is(._7514NG_iconButton,
|
|
|
10240
10419
|
flex: none;
|
|
10241
10420
|
align-items: center;
|
|
10242
10421
|
justify-content: center;
|
|
10243
|
-
width:
|
|
10244
|
-
height:
|
|
10422
|
+
width: 22px;
|
|
10423
|
+
height: 22px;
|
|
10245
10424
|
padding: 0;
|
|
10246
10425
|
border: 0;
|
|
10247
10426
|
border-radius: 6px;
|
|
@@ -10258,8 +10437,8 @@ html[data-dsh-ccd-style="true"] ._7514NG_sectionHeader :is(._7514NG_iconButton,
|
|
|
10258
10437
|
html[data-dsh-ccd-style="true"] .jJkEga_projectRow .jJkEga_rowActions button svg,
|
|
10259
10438
|
html[data-dsh-ccd-style="true"] ._7514NG_sectionHeader :is(._7514NG_iconButton, ._7514NG_searchButton) svg {
|
|
10260
10439
|
flex: none;
|
|
10261
|
-
width:
|
|
10262
|
-
height:
|
|
10440
|
+
width: 14px;
|
|
10441
|
+
height: 14px;
|
|
10263
10442
|
}
|
|
10264
10443
|
|
|
10265
10444
|
/* The create button is the container's last *button*, not its last child \u2014 the
|
|
@@ -10278,10 +10457,10 @@ html[data-dsh-ccd-style="true"] .jJkEga_projectRow .jJkEga_rowActions > button:l
|
|
|
10278
10457
|
html[data-dsh-ccd-style="true"] .jJkEga_projectRow .jJkEga_rowActions > button:last-of-type::before {
|
|
10279
10458
|
content: "";
|
|
10280
10459
|
flex: none;
|
|
10281
|
-
width:
|
|
10282
|
-
height:
|
|
10460
|
+
width: 14px;
|
|
10461
|
+
height: 14px;
|
|
10283
10462
|
background-color: currentColor;
|
|
10284
|
-
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 2V14M2 8H14' stroke='black' stroke-width='1.25' stroke-linecap='round'/%3E%3C/svg%3E") center /
|
|
10463
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 2V14M2 8H14' stroke='black' stroke-width='1.25' stroke-linecap='round'/%3E%3C/svg%3E") center / 14px 14px no-repeat;
|
|
10285
10464
|
}
|
|
10286
10465
|
|
|
10287
10466
|
html[data-dsh-ccd-style="true"] .jJkEga_projectRow .jJkEga_title {
|
|
@@ -10309,6 +10488,12 @@ html[data-dsh-ccd-style="true"] .jJkEga_sessionRow {
|
|
|
10309
10488
|
height: 28px;
|
|
10310
10489
|
}
|
|
10311
10490
|
|
|
10491
|
+
/* Hide the session hover card's surface, including its padding and shadow.
|
|
10492
|
+
Status lines distinguish session cards from workspace path cards. */
|
|
10493
|
+
html[data-dsh-ccd-style="true"] :has(> .jJkEga_hoverContent > .jJkEga_hoverStatus) {
|
|
10494
|
+
display: none;
|
|
10495
|
+
}
|
|
10496
|
+
|
|
10312
10497
|
/* The row's leading 16px cell is the reference's shape already \u2014 the label
|
|
10313
10498
|
lands on the same 38px edge as a navigation label. What arrives there is
|
|
10314
10499
|
either a 6px solid state dot or the 14px activity ring; the ring is scaled to
|
|
@@ -10366,8 +10551,66 @@ html[data-dsh-ccd-style="true"] .jJkEga_sessionRow.jJkEga_selected {
|
|
|
10366
10551
|
background: var(--ccd-selected);
|
|
10367
10552
|
}
|
|
10368
10553
|
|
|
10369
|
-
|
|
10370
|
-
|
|
10554
|
+
/* Relative timestamps stay out of the conversation list in every row state. */
|
|
10555
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_time {
|
|
10556
|
+
display: none;
|
|
10557
|
+
}
|
|
10558
|
+
|
|
10559
|
+
/* A Session row's trailing side is one control: the \u22EE that opens its menu.
|
|
10560
|
+
*
|
|
10561
|
+
* The host hangs two hover buttons of its own there \u2014 archive and pin,
|
|
10562
|
+
* registered into its \`sidebar.workspaces.session.row.action\` list \u2014 beside the
|
|
10563
|
+
* \u22EF trigger, so a pointed-at row draws three marks where the reference draws
|
|
10564
|
+
* one. Nothing is lost with them: the same two actions are rows of that \u22EF card
|
|
10565
|
+
* (pin, rename, fork, archive \u2014 \`ui-workspace\`'s own registrations into
|
|
10566
|
+
* \`sidebar.workspaces.session.menu.item\`), which is what the reference's menu
|
|
10567
|
+
* holds. The list's outlet therefore leaves the line, and the seat with it: a
|
|
10568
|
+
* row's trailing control is the menu trigger alone, so an entry a later plugin
|
|
10569
|
+
* registers there is not drawn either. React keeps every node and the host
|
|
10570
|
+
* keeps its own hover state \u2014 dropping this rule puts the two buttons back.
|
|
10571
|
+
*
|
|
10572
|
+
* The \`!important\` answers an inline style rather than a host rule: \`renderSlot\`
|
|
10573
|
+
* renders its outlet as a \`div[data-slot]\` carrying the renderer's own anchor
|
|
10574
|
+
* style, \`display: contents\`, which keeps the wrapper out of layout, and an
|
|
10575
|
+
* author declaration only outranks an inline one with it. */
|
|
10576
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions > div[data-slot="sidebar.workspaces.session.row.action"] {
|
|
10577
|
+
display: none !important;
|
|
10578
|
+
}
|
|
10579
|
+
|
|
10580
|
+
/* Match the toolbar and project menu's 22px button and 14px artwork, retaining
|
|
10581
|
+
the vertical ellipsis and the stronger hover fill on a selected row. */
|
|
10582
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions .jJkEga_iconButton {
|
|
10583
|
+
box-sizing: border-box;
|
|
10584
|
+
display: inline-flex;
|
|
10585
|
+
flex: none;
|
|
10586
|
+
align-items: center;
|
|
10587
|
+
justify-content: center;
|
|
10588
|
+
padding: 0;
|
|
10589
|
+
border: 0;
|
|
10590
|
+
background: transparent;
|
|
10591
|
+
width: 22px;
|
|
10592
|
+
height: 22px;
|
|
10593
|
+
border-radius: 6px;
|
|
10594
|
+
color: var(--ccd-text-secondary);
|
|
10595
|
+
}
|
|
10596
|
+
|
|
10597
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions .jJkEga_iconButton:hover {
|
|
10598
|
+
background: var(--ccd-hover-strong);
|
|
10599
|
+
color: var(--ccd-text);
|
|
10600
|
+
}
|
|
10601
|
+
|
|
10602
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions .jJkEga_iconButton svg {
|
|
10603
|
+
display: none;
|
|
10604
|
+
}
|
|
10605
|
+
|
|
10606
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions .jJkEga_iconButton::before {
|
|
10607
|
+
content: "";
|
|
10608
|
+
display: block;
|
|
10609
|
+
flex: none;
|
|
10610
|
+
width: 14px;
|
|
10611
|
+
height: 14px;
|
|
10612
|
+
background-color: currentColor;
|
|
10613
|
+
mask: var(--ccd-icon-more) center / 14px 14px no-repeat;
|
|
10371
10614
|
}
|
|
10372
10615
|
|
|
10373
10616
|
/* Archived rows. The host fades an archived title with its own caption ink, but
|
|
@@ -10539,10 +10782,111 @@ html[data-dsh-ccd-style="true"] .ccd-sidebar-empty button:focus-visible {
|
|
|
10539
10782
|
html[data-dsh-ccd-style="true"] [data-ccd-list-empty] [data-row-key="empty"] {
|
|
10540
10783
|
display: none;
|
|
10541
10784
|
}
|
|
10785
|
+
|
|
10786
|
+
/* Claude's conversation overflow is one trailing cell. Keep its right inset
|
|
10787
|
+
independent of the title length and of the host's hidden quick actions. */
|
|
10788
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow .jJkEga_rowActions {
|
|
10789
|
+
flex: none;
|
|
10790
|
+
margin-left: auto;
|
|
10791
|
+
gap: 0;
|
|
10792
|
+
}
|
|
10793
|
+
|
|
10794
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow:has(.jJkEga_rowActions) {
|
|
10795
|
+
padding-inline-end: 0;
|
|
10796
|
+
}
|
|
10797
|
+
|
|
10798
|
+
/* The reference keeps the trigger highlighted while its popup is open. */
|
|
10799
|
+
html[data-dsh-ccd-style="true"] .jJkEga_sessionRow.jJkEga_menuOpen .jJkEga_rowActions button[aria-expanded="true"] {
|
|
10800
|
+
background: var(--ccd-hover-strong);
|
|
10801
|
+
color: var(--ccd-text);
|
|
10802
|
+
}
|
|
10803
|
+
|
|
10804
|
+
/* Scope through the host's outlet: this also reaches a portalled popup, with
|
|
10805
|
+
no dependency on translated labels or the number of registered actions.
|
|
10806
|
+
Keep DSH's pin/unpin, rename, fork and archive/restore artwork and behavior;
|
|
10807
|
+
unlike the other compact menus, this reference has a leading icon column. */
|
|
10808
|
+
html[data-dsh-ccd-style="true"] [data-menu-material]:has([data-slot="sidebar.workspaces.session.menu.item"]) {
|
|
10809
|
+
min-width: 144px;
|
|
10810
|
+
padding: 4px;
|
|
10811
|
+
}
|
|
10812
|
+
|
|
10813
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-slot="sidebar.workspaces.session.menu.item"] [role="menuitem"] {
|
|
10814
|
+
min-height: 24px;
|
|
10815
|
+
padding: 2px 8px;
|
|
10816
|
+
gap: 8px;
|
|
10817
|
+
font-size: 13px;
|
|
10818
|
+
line-height: 20px;
|
|
10819
|
+
color: var(--ccd-text);
|
|
10820
|
+
}
|
|
10821
|
+
|
|
10822
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-slot="sidebar.workspaces.session.menu.item"] [role="menuitem"] > ._itemIcon_4ub78_148 {
|
|
10823
|
+
display: inline-flex;
|
|
10824
|
+
flex: 0 0 16px;
|
|
10825
|
+
width: 16px;
|
|
10826
|
+
height: 16px;
|
|
10827
|
+
align-items: center;
|
|
10828
|
+
justify-content: center;
|
|
10829
|
+
color: currentColor;
|
|
10830
|
+
}
|
|
10831
|
+
|
|
10832
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-slot="sidebar.workspaces.session.menu.item"] ._itemIcon_4ub78_148 svg {
|
|
10833
|
+
width: 16px;
|
|
10834
|
+
height: 16px;
|
|
10835
|
+
}
|
|
10836
|
+
|
|
10837
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-ccd-sidebar-session-icon="pin"] > ._itemIcon_4ub78_148 {
|
|
10838
|
+
background-color: currentColor;
|
|
10839
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M9.5 2.5 13.5 6.5 11 8l-.5 3.5-1 1-3-3-3-3 1-1L8 5l1.5-2.5ZM6.5 9.5 3 13' stroke='black' stroke-width='1.15' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
|
|
10840
|
+
}
|
|
10841
|
+
|
|
10842
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-ccd-sidebar-session-icon="rename"] > ._itemIcon_4ub78_148 {
|
|
10843
|
+
background-color: currentColor;
|
|
10844
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 10.5 2.5 14l3.5-.5L14 5.5 10.5 2 3 10.5ZM9 3.5l3.5 3.5' stroke='black' stroke-width='1.15' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
|
|
10845
|
+
}
|
|
10846
|
+
|
|
10847
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-ccd-sidebar-session-icon] > ._itemIcon_4ub78_148 svg {
|
|
10848
|
+
display: none;
|
|
10849
|
+
}
|
|
10850
|
+
|
|
10851
|
+
/* Workspace overflow already supplies native edit/trash art; reveal only this
|
|
10852
|
+
popup's seats, preserving the host's destructive ink and click handlers. */
|
|
10853
|
+
html[data-dsh-ccd-style="true"] [data-menu-material][data-ccd-sidebar-workspace-menu] [role="menuitem"] {
|
|
10854
|
+
gap: 8px;
|
|
10855
|
+
}
|
|
10856
|
+
|
|
10857
|
+
html[data-dsh-ccd-style="true"] [data-menu-material][data-ccd-sidebar-workspace-menu] [role="menuitem"] > ._itemIcon_4ub78_148 {
|
|
10858
|
+
display: inline-flex;
|
|
10859
|
+
flex: 0 0 16px;
|
|
10860
|
+
width: 16px;
|
|
10861
|
+
height: 16px;
|
|
10862
|
+
align-items: center;
|
|
10863
|
+
justify-content: center;
|
|
10864
|
+
color: currentColor;
|
|
10865
|
+
}
|
|
10866
|
+
|
|
10867
|
+
html[data-dsh-ccd-style="true"] [data-menu-material][data-ccd-sidebar-workspace-menu] ._itemIcon_4ub78_148 svg {
|
|
10868
|
+
width: 16px;
|
|
10869
|
+
height: 16px;
|
|
10870
|
+
}
|
|
10871
|
+
|
|
10872
|
+
/* Claude-style single-letter hints replace the host's multi-key artwork only
|
|
10873
|
+
in the sidebar conversation popup. Native shortcut bindings stay with DSH. */
|
|
10874
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-ccd-sidebar-session-shortcut] > :not(._itemIcon_4ub78_148):not(._itemLabel_4ub78_190) {
|
|
10875
|
+
display: none;
|
|
10876
|
+
}
|
|
10877
|
+
|
|
10878
|
+
html[data-dsh-ccd-style="true"] [data-menu-material] [data-ccd-sidebar-session-shortcut]::after {
|
|
10879
|
+
content: attr(data-ccd-sidebar-session-shortcut);
|
|
10880
|
+
flex: none;
|
|
10881
|
+
margin-left: auto;
|
|
10882
|
+
color: var(--ccd-text-muted);
|
|
10883
|
+
font-size: 12px;
|
|
10884
|
+
line-height: 20px;
|
|
10885
|
+
}
|
|
10542
10886
|
`;
|
|
10543
10887
|
|
|
10544
10888
|
// src/client/features/sidebar/navigation.css
|
|
10545
|
-
var navigation_default = '/* Replace only the decorated native glyphs; all click/focus/selection remains\n owned by DSH. A 16px seat preserves the existing text column in both layouts. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav="newSession"] ._3WPZCG_newSessionContent > svg,\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav] ._3WPZCG_panelGlyph > [data-slot="sidebar.panellist"] svg {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav] .ccd-nav-glyph {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] ._3WPZCG_root [data-ccd-nav] .ccd-nav-glyph > svg {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n overflow: visible;\n}\n\nhtml[data-dsh-ccd-style="true"] ._3WPZCG_root [data-ccd-nav="newSession"] .ccd-nav-glyph > svg {\n width: 18px;\n height: 18px;\n}\n\nhtml[data-dsh-ccd-style="true"] .ccd-nav-glyph :is(.customize-case, .routine-long-hand) {\n transform-box: view-box;\n transform-origin: 12px 12px;\n transition: transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\nhtml[data-dsh-ccd-style="true"] .ccd-nav-glyph .icon-disc {\n transition: opacity 180ms ease;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav]:is(:hover, :focus-visible
|
|
10889
|
+
var navigation_default = '/* Replace only the decorated native glyphs; all click/focus/selection remains\n owned by DSH. A 16px seat preserves the existing text column in both layouts. */\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav="newSession"] ._3WPZCG_newSessionContent > svg,\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav] ._3WPZCG_panelGlyph > [data-slot="sidebar.panellist"] svg {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav] .ccd-nav-glyph {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] ._3WPZCG_root [data-ccd-nav] .ccd-nav-glyph > svg {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n overflow: visible;\n}\n\nhtml[data-dsh-ccd-style="true"] ._3WPZCG_root [data-ccd-nav="newSession"] .ccd-nav-glyph > svg {\n width: 18px;\n height: 18px;\n}\n\nhtml[data-dsh-ccd-style="true"] .ccd-nav-glyph :is(.customize-case, .routine-long-hand) {\n transform-box: view-box;\n transform-origin: 12px 12px;\n transition: transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\nhtml[data-dsh-ccd-style="true"] .ccd-nav-glyph .icon-disc {\n transition: opacity 180ms ease;\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav]:is(:hover, :focus-visible) .customize-case {\n transform: rotate(-6deg);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav]:is(:hover, :focus-visible) .routine-long-hand {\n transform: rotate(45deg);\n}\n\nhtml[data-dsh-ccd-style="true"] [data-ccd-nav]:is(:hover, :focus-visible) .icon-disc {\n opacity: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n html[data-dsh-ccd-style="true"] .ccd-nav-glyph :is(.customize-case, .routine-long-hand, .icon-disc) {\n transition: none;\n }\n}\n';
|
|
10546
10890
|
|
|
10547
10891
|
// src/client/features/sidebar/navigation-icons.ts
|
|
10548
10892
|
var SIDEBAR_NAVIGATION_ICONS = Object.freeze({
|
|
@@ -10562,6 +10906,8 @@ var sidebarFeature = {
|
|
|
10562
10906
|
scope.add(environment.dom.mountStyles(sidebar_default));
|
|
10563
10907
|
scope.add(environment.dom.mountStyles(account_menu_default));
|
|
10564
10908
|
scope.add(environment.dom.mountStyles(navigation_default));
|
|
10909
|
+
scope.add(mountSidebarSessionIcons(document));
|
|
10910
|
+
scope.add(mountSidebarActionAlignment(document));
|
|
10565
10911
|
scope.add(mountSidebarNavigation(
|
|
10566
10912
|
document,
|
|
10567
10913
|
SIDEBAR_NAVIGATION_ICONS,
|
|
@@ -10945,7 +11291,7 @@ function round(value) {
|
|
|
10945
11291
|
}
|
|
10946
11292
|
|
|
10947
11293
|
// src/client/features/conversation/conversation.css
|
|
10948
|
-
var conversation_default = '/*\n * Conversation page: header chrome, transcript column and message surfaces.\n *\n * The transcript, its scroll behaviour, tool rendering and approval surfaces\n * stay entirely DSH\'s; only width, type and surface colours change. Host\n * classes are pinned in src/client/compat/host-dom.ts.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_root {\n container: ccd-conversation / inline-size;\n}\n\n/*\n * Transcript width handles: hidden here, because this interface removed what\n * they control (17).\n *\n * `ui-conversation`\'s `ConversationWidthControls` renders one handle per side as\n * the Conversation body\'s last child (ConversationRoot.module.css,\n * `ST7X_W_widthHandle`, stable hook `data-width-handle`; component\n * `skeleton/ConversationWidthControls.tsx`). Each is a transparent full-height\n * strip \u2014 `position: absolute; top: 0; bottom: 0`, `cursor: col-resize`,\n * `width: min(10px, (100% - var(--dsh-chat-content-width)) / 2 - 48px)` \u2014 parked\n * 24px outside the transcript column, whose only ink is the 2px rule its own\n * `::after` reveals on hover or while dragging. Dragging one publishes\n * `--dsh-chat-user-width` on the Conversation root.\n *\n * That property has exactly one consumer in the host, the body rule\n * `--dsh-chat-content-width: var(--dsh-chat-user-width, clamp(680px, \u2026))`, and\n * this interface replaces it: `theme/composer.css` pins\n * `--dsh-chat-content-width: var(--ccd-composer-width)` (770px) on the same\n * element with higher specificity. A drag therefore changes nothing \u2014 not the\n * transcript column, the user stack, the jump-to-bottom slot or the wide-table\n * bleed \u2014 while the handle keeps its pointer capture, its resize cursor and its\n * hover rule. It is a false affordance whose state cannot be reached: hiding it\n * takes away no behaviour, and with the plugin off the host\'s own rule returns\n * and the handles drag again.\n *\n * `display: none`, not `visibility` or a transparent paint, and scoped to the\n * Conversation root so `ui-layout`\'s real column handles (`_6Qf49G_handle`, 8px,\n * on the sidebar and rightbar tracks) are never touched. The handle is an\n * absolutely positioned, empty box outside the body\'s flex flow, so removing it\n * cannot move a sibling: transcript width, the scroll viewport\'s stable\n * scrollbar gutter and the page\'s scroll range keep the values they had.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_root [data-width-handle] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header {\n background: var(--ccd-canvas);\n color: var(--ccd-text);\n /* The host marks this header as its window-drag surface. The compact flex\n row replaces the host\'s two-row grid, so keep that surface explicit on\n macOS; the host\'s header controls remain no-drag children. */\n -webkit-app-region: drag;\n /*\n * The reference has no rule between the header and the transcript \u2014 the two\n * read as one page. The host draws a hairline here (`border-bottom: .5px\n * solid`), so it is painted out rather than removed: keeping the border\'s\n * width leaves the header\'s own height untouched.\n */\n border-bottom-color: transparent;\n /*\n * One header row. DSH stacks a title row and, below it, its View tablist; the\n * reference keeps every piece of header chrome on the title line. The two\n * wrapper boxes dissolve (`display: contents`) instead of being re-parented,\n * so the host\'s own children stay where React put them and only their order\n * changes: title, View switcher, Agent-preset chip, utilities, corner.\n */\n display: flex;\n align-items: center;\n /* The host reserves the second row only while its tablist is a row of its\n own; that row is gone, so its `min-height: 76px` goes with it. */\n min-height: 0;\n padding: 10px var(--ccd-header-trailing-inset) 10px 12px;\n /*\n * Where the Composer\'s input surface ends, measured from the column\'s right\n * edge in the numbers that draw it, for the narrow-column rules below: the\n * Composer root\'s own side clearance (`theme/composer.css` pins the host\'s\n * `--dsh-composer-side-clearance` at 16px), the stable scrollbar gutter the\n * page\'s scroll viewport reserves (`ST7X_W_scrollBody { scrollbar-gutter:\n * stable }` over the theme\'s 5px `--dsh-scrollbar-width` track) and that\n * viewport\'s own `margin-right: 2px`.\n */\n --ccd-composer-trailing-edge: calc(\n var(--dsh-composer-side-clearance, 16px) + var(--dsh-scrollbar-width, 5px) + 2px);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerBlank {\n /* Blank Sessions keep the single-row height they had as a grid row. */\n min-height: 40px;\n padding-bottom: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerSessionless {\n min-height: 50px;\n}\n\n/*\n * On macOS the title line shares the window-control row\'s centre line: the\n * traffic lights, the collapse toggle (`top: 11px` + 28 / 2) and the parked\n * switcher (`top: 12px` + 26 / 2) all centre on y = 25. The flex items above\n * centre on the header\'s content box, and with the base padding (10px top and\n * bottom) that box centred on 20 \u2014 the title, the team chip and the right-hand\n * panel buttons sat 5px above the line they are meant to share.\n *\n * Holding the header at 40px \u2014 the height it already has, with 20px items \u2014\n * and dropping the bottom padding leaves a 30px content box from y = 10 to\n * y = 40 whatever the items\' own heights (up to 30px): its centre is 25. A\n * collapsed inline switcher (26px) therefore centres on the same line too.\n * Windows has no such row, so its header keeps the base rule, and the\n * sessionless header already centres on 25 with its own 10px bottom padding.\n */\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] .ST7X_W_header:not(.ST7X_W_headerSessionless) {\n min-height: 40px;\n padding-bottom: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_titleRow,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_titleCluster {\n display: contents;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumbs {\n /* Stable natural title width (capped at 112px) keeps the following switcher\n anchored while the rightbar changes column width. */\n flex: none;\n box-sizing: border-box;\n max-width: calc(112px + max(0px, var(--dsh-frame-leading-clearance, 0px) - 12px));\n padding-inline-start: max(0px, calc(var(--dsh-frame-leading-clearance, 0px) - 12px));\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions {\n order: 2;\n /* Stable gap between switcher and team entry.\n `margin-right: auto` is the header\'s flexible gap: the title, the View\n switcher and the chip stay grouped at the leading edge, as in the\n reference, and the utilities keep the trailing edge they had before. The\n chip always renders, so the gap survives an empty tools group. */\n /* The preceding title has 8px end padding + the track\'s 2px margin.\n Give the track-to-team boundary the same visible 10px separation. */\n margin-left: var(--ccd-header-group-gap, 10px);\n gap: 4px;\n margin-right: auto;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities {\n order: 3;\n margin-left: 0;\n /* One uniform gap, so every visible space in the cluster is equal. */\n gap: var(--ccd-header-action-gap);\n}\n\n/*\n * The corner seat is retired, and the utilities group owns the trailing edge.\n *\n * That single cell\'s shipped occupant is `ui-sidebar-right`\'s collapsed-panel\n * expand control, which this interface does not draw; the plugin shadows it with\n * an entry that renders nothing (`features/conversation/header-actions/entries.ts`)\n * and keeps the expand action in the Session menu instead. So the seat has no\n * box of its own to place \u2014 its own gap in front of the utilities would be 2px\n * of trailing space after the last control, and the reference measures the\n * cluster\'s inset from the header\'s own padding. A Blank Session renders the\n * same empty seat, which is why the host\'s `margin-left: auto` for that row\n * needs no answer here: there is nothing left in the corner to place either way.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerCorner {\n margin: 0;\n}\n\n/*\n * View switcher: the host\'s own `role="tablist"`, reshaped into the reference\'s\n * segmented control. The selected segment is drawn by one thumb \u2014 the\n * `::before` of the tablist \u2014 moved with the geometry published by\n * `compat/view-switch.ts`; the buttons keep their roles, labels and handlers,\n * and the host\'s own underline is dropped.\n *\n * Geometry is the reference\'s own pill (docs/issues/img/todo-sidebar-sessions-target.webp,\n * @2x): a 66 \xD7 26 track \u2014 131 \xD7 52 device px, so two 33px segments \u2014 6px\n * corner, with the raised thumb inset 1px top and bottom and carrying a 5px\n * corner, a 1px outline and the segment shadow. The two segments are the icon\n * buttons below, not text: `compat/view-switch.ts` swaps each shipped View\'s\n * label for the bundled artwork in `view-switch-icons.ts`.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs {\n order: 1;\n position: relative;\n /* Never squeezed: a narrow header truncates the title instead. */\n flex: none;\n display: inline-flex;\n align-items: stretch;\n gap: 0;\n /* The switcher sits directly after the Session title; later header chrome\n (the Agent-preset chip today, more to come) follows it. */\n margin: 0 0 0 var(--ccd-header-group-gap, 2px);\n padding: 0;\n border-radius: 6px;\n background: var(--ccd-track);\n -webkit-app-region: no-drag;\n}\n\n/* The docked pill sits over the sidebar\'s native window-drag strip. Let its\n empty chrome participate in dragging while keeping the view buttons clickable. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] {\n -webkit-app-region: drag;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] .ST7X_W_tab {\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs::before {\n content: "";\n position: absolute;\n top: 1px;\n bottom: 1px;\n left: 0;\n box-sizing: border-box;\n width: var(--ccd-view-w, 0px);\n transform: translateX(var(--ccd-view-x, 0px));\n border: 1px solid var(--ccd-border-soft);\n border-radius: 5px;\n background: var(--ccd-card);\n box-shadow: var(--ccd-shadow-segment);\n pointer-events: none;\n transition: transform var(--ccd-view-duration, 0ms) var(--ds-ease-in-out, ease),\n width var(--ccd-view-duration, 0ms) var(--ds-ease-in-out, ease);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n /* The reference\'s 33px segment is a floor, not a fixed width: a View this\n plugin has no artwork for keeps its own label and its own room. */\n flex: 0 1 auto;\n min-width: 33px;\n height: 26px;\n padding: 0 6px;\n border: 0;\n border-radius: 5px;\n background: transparent;\n color: var(--ccd-text-muted);\n font-size: var(--ccd-font-size-muted);\n font-weight: 500;\n line-height: 20px;\n white-space: nowrap;\n}\n\n/* A decorated tab draws bundled artwork in place of the host\'s label text;\n `compat/view-switch.ts` writes the marker and the button\'s accessible name.\n An unknown View keeps its label and is left alone. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n font-size: 0;\n line-height: 0;\n}\n\n/*\n * The artwork seat leaves the button\'s own flow and centres on the button\'s\n * box \u2014 not on a line box beside the host\'s label, and not inside whatever\n * content box the host\'s own rules leave here. The host\'s `.tab` gives this\n * button `padding: 0 0 9px`, its own 16px line and its own alignment, and any\n * of them winning back even one of those declarations moved the icon ~4.5px\n * above the segment; the seat is absolutely centred on the padding box\n * instead, which is the box the sliding thumb is drawn on. Measured in\n * `tests/view-switch-browser.test.mjs`, including a state that hands the\n * button\'s inner layout back to the host\'s rules.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] > [data-ccd-view-glyph] {\n position: absolute;\n inset: 0;\n margin: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n line-height: 0;\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] > [data-ccd-view-glyph] > svg {\n display: block;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab::after {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabActive {\n color: var(--ccd-text);\n}\n\n/*\n * Docked: the switcher leaves the header for the sidebar\'s window-control row.\n *\n * The reference keeps it at the top-right of the sidebar column, on the same\n * row as the traffic lights and the collapse toggle \u2014 measured at 8px inside\n * the column\'s right edge (its divider sits 16 device px right of the pill),\n * with the pill\'s 26px centre on the toggle\'s own centre (11px + 28 / 2 = 25).\n * The node stays in the header where React rendered it: `position: fixed` takes\n * it out of that row and the coordinates come from `compat/view-switch.ts`,\n * measured live from the sidebar column \u2014 the same way the macOS sidebar toggle\n * is parked. It is written only where the column has the corner to hold it:\n * macOS with the sidebar expanded, so the host\'s own row (Windows, or the\n * collapsed shell\'s 0px column) keeps the switcher inline.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] {\n position: fixed;\n top: 12px;\n right: var(--ccd-view-dock-right, 8px);\n z-index: 15;\n margin: 0;\n}\n\n/* With the switcher parked, native crumbs supply 8px end padding. The custom\n title has no end padding, so its project and team use the full group gap. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header:has(.ST7X_W_tabs[data-ccd-view-dock]) .ST7X_W_headerActions {\n margin-left: var(--ccd-header-group-gap, 2px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n html[data-dsh-ccd-style="true"] .ST7X_W_tabs::before {\n transition: none;\n }\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumbs,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumb {\n color: var(--ccd-text);\n font-size: var(--ccd-font-size-muted);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumb {\n max-width: 100%;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions button,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities button {\n color: var(--ccd-text-secondary);\n}\n\n/* The collapsed macOS shell consumes 160px for native window controls. Keep\n that reservation stable and omit title crumbs in this shell state, so a\n 400px column still fits the complete team entry and every native button. */\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] [data-sidebar-collapsed] .ST7X_W_header:not(.ST7X_W_headerBlank) .ST7X_W_crumbs {\n max-width: none;\n}\n\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] [data-sidebar-collapsed] .ST7X_W_header:not(.ST7X_W_headerBlank) .ST7X_W_crumb {\n display: none;\n}\n\n/* Keep the actionable team entry complete; omit the passive header mode. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._2tNPVa_triggerLabel {\n display: inline;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._3li69W_label {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._2tNPVa_trigger {\n padding-inline: 0;\n}\n\n/*\n * Trailing action cluster. Every control takes the same square hit box, so the\n * visible gaps between glyphs are equal rather than only the box gaps: the\n * previous build zeroed the host\'s `gap` and shrank single controls, which left\n * ~7px after the split button but ~14px after the 24px menu button. Geometry is\n * declared once in theme/tokens.css. The host\'s own 15px artwork stays native\n * inside these boxes; the plugin only paints the three glyphs below.\n *\n * The renderer wraps every list entry in a `display: contents` seat\n * (`[data-slot="conversation.session.header.utilities"]`), so the boxes are the\n * seat\'s children \u2014 the seat itself has no box to size. (The corner seat is\n * retired and holds nothing: see the rule above.)\n *\n * `[role="tooltip"]` is named out because a seat\'s children are not always\n * controls. `ui-primitives`\' `Tooltip` clones its anchor and renders its bubble\n * as a *sibling* of it, inside the same React fragment \u2014 which lands both nodes\n * in the seat. Sizing that bubble to the control box clipped it to one glyph\n * and a half the moment it appeared; the bubble keeps its own geometry on\n * every hover.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities > [data-slot] > *:not([role="tooltip"]) {\n box-sizing: border-box;\n flex: none;\n width: var(--ccd-header-action-size);\n height: var(--ccd-header-action-size);\n border-radius: var(--ccd-radius-row);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .Da3aKq_moreButton {\n padding: 0;\n}\n\n/*\n * The "open in app" control becomes one generic glyph whose whole box opens the\n * native application menu. The chevron half \u2014 the only control that opens that\n * menu \u2014 is stretched over the split box as the hit area, while the application\n * image and the chevron glyph are replaced by shared artwork. The host keeps the\n * menu, its items, its icon route and its callbacks; `compat/open-target.ts`\n * marks the no-menu state, which hides this control instead of direct-opening.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_split {\n position: relative;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border: 0;\n border-radius: inherit;\n overflow: hidden;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron {\n position: absolute;\n inset: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n padding: 0;\n border: 0;\n background: transparent;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron svg {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron:hover:not(:disabled),\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron:focus-visible,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main {\n width: 100%;\n height: 100%;\n gap: 0;\n padding: 0;\n color: var(--ccd-text-secondary);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main > * {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main::before {\n content: "";\n width: var(--ccd-header-icon-size);\n height: var(--ccd-header-icon-size);\n background-color: currentColor;\n mask: var(--ccd-icon-open) center / var(--ccd-header-icon-size) var(--ccd-header-icon-size) no-repeat;\n}\n\n/* No application menu exists (a directory with at most one candidate): a chooser\n glyph would promise what the host cannot show, so the control stays away. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities [data-ccd-open-mode="direct"] {\n display: none;\n}\n\n/*\n * Narrow columns: the cluster ends on the Composer\'s own trailing edge.\n *\n * The design\'s 12px inset (`--ccd-header-trailing-inset`) is measured in a\n * window whose transcript column is wider than the Composer\'s 770px cap, so the\n * Composer is centred inside the column and the two rows end at different\n * places \u2014 an inset the reference keeps at every width. Where the Composer\n * *fills* the column instead, its input surface\'s right border is a line the\n * cluster sits directly above, and the reference draws the cluster ending on it:\n * the last control\'s centre on that border, so the \u22EE reads as the row\'s closing\n * mark rather than as an icon hanging outside the Composer. That state is the\n * one an expanded right panel leaves, and this is where it is answered.\n *\n * The column that fills its Composer is the Composer\'s own 770px cap plus what\n * surrounds the surface: the root\'s two clearances and the page scroll\n * viewport\'s stable gutter and 2px margin, i.e. 810px. Below it the trailing\n * padding is the surface\'s own edge (`--ccd-composer-trailing-edge`, declared\n * on the header above) less half the closing control, so the box is centred on\n * the border rather than ending on it; `min()` keeps the design\'s inset as the\n * ceiling, for a deployment that hands the Composer a wider clearance.\n */\n@container ccd-conversation (max-width: 810px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header {\n padding-right: min(\n var(--ccd-header-trailing-inset),\n calc(var(--ccd-composer-trailing-edge) - var(--ccd-header-action-size) / 2));\n }\n}\n\n/* Very narrow columns keep every control on the collapsed macOS shell\'s 24px\n box, so the same edge is taken against the smaller box: half of it is 2px\n less, and the cluster\'s last control stays centred on the input surface\'s\n border. */\n@container ccd-conversation (max-width: 520px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header {\n padding-right: min(\n var(--ccd-header-trailing-inset),\n calc(var(--ccd-composer-trailing-edge) - var(--ccd-header-action-compact) / 2));\n }\n\n html[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities > [data-slot] > *:not([role="tooltip"]) {\n width: var(--ccd-header-action-compact);\n height: var(--ccd-header-action-compact);\n }\n}\n\n/*\n * The title yields before the cluster does \u2014 and, like the three views below,\n * only to a switcher that is still in the row.\n *\n * With the switcher in it, the row is four pieces \u2014 title, switcher, native team\n * entry, cluster \u2014 and at this width they cannot share one line. The title is\n * the only piece the sidebar also shows, so it goes: the same trade the\n * collapsed macOS shell already makes, and every native control keeps its full\n * label.\n *\n * Parked in the sidebar\'s window-control row (`compat/view-switch.ts` writes\n * `data-ccd-view-dock`; macOS with the sidebar expanded, which is where an\n * expanded right panel leaves the column), the switcher takes its 66px track and\n * the two margins around it out of the row, and the three pieces that remain\n * occupy 377px of the 400px floor the frame protects for this column while the\n * right panel is open (`ui-layout`\'s `CENTER_MIN`) \u2014 so they fit, with the 72px\n * between the chip and the cluster left to `margin-right: auto`. Withdrawing the\n * title there bought nothing and cost the one place a narrow column still names\n * its session.\n */\n@container ccd-conversation (max-width: 420px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header:not(.ST7X_W_headerBlank):has(.ST7X_W_tabs:not([data-ccd-view-dock]))\n .ST7X_W_crumbs {\n display: none;\n }\n}\n\n/*\n * The three views this plugin adds \u2014 the project folder among them \u2014 step aside\n * only while the row still carries the View switcher.\n *\n * The switcher is normally parked in the sidebar\'s window-control row\n * (`compat/view-switch.ts` writes `data-ccd-view-dock` on the tablist wherever\n * that column has the corner to hold it), and the row is then the title, the\n * team chip and the cluster: at most ~235px of chrome, so all three stay drawn\n * at any width the Composer can still be used at \u2014 including the column an\n * expanded right panel leaves, where they are the only way to switch the\n * panel\'s view back. With the switcher still in the row \u2014 a Windows build, or a\n * collapsed macOS sidebar whose window is narrow \u2014 there are four pieces on the\n * line, and these three are the ones that go: they are the plugin\'s own\n * controls, they have a second entry in the right panel\'s own tab strip, and\n * the native team chip keeps its full label either way.\n */\n@container ccd-conversation (max-width: 420px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header:has(.ST7X_W_tabs:not([data-ccd-view-dock]))\n .ST7X_W_headerUtilities [data-ccd-header-view] {\n display: none;\n }\n}\n\n/* Transcript column keeps the reference\'s breathing room. */\nhtml[data-dsh-ccd-style="true"] .icaHSq_scroll {\n padding-top: 16px;\n padding-bottom: 8px;\n}\n\n/* Center and size the host\'s jump-to-bottom control.\n * Source: ui-chat/ChatView.module.css, HOST.chatViewToBottomSlot/toBottom.\n * Negative margin follows the button size to retain its gap above Composer.\n */\nhtml[data-dsh-ccd-style="true"] .icaHSq_toBottomSlot {\n justify-content: center;\n padding-right: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .icaHSq_toBottom {\n width: var(--ccd-to-bottom-size);\n height: var(--ccd-to-bottom-size);\n margin-top: calc(-1 * var(--ccd-to-bottom-size));\n}\n\n/* Paint edge gradients on the page body above the transcript and below\n * sticky Composer. conversation-fade.ts publishes scroll flags and the bottom\n * inset; the lower overlay covers Composer\'s full footprint. Since Composer\n * is inside the scroller, the gradient belongs on this separate layer.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::before,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n height: var(--ccd-edge-fade);\n background: var(--ccd-canvas);\n pointer-events: none;\n /* Above the transcript, below the Composer seat (7) and the jump-to-bottom\n control (8) so neither is veiled. */\n z-index: 1;\n opacity: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::before {\n top: 0;\n background: linear-gradient(to bottom, var(--ccd-canvas), transparent);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::after {\n bottom: 0;\n height: calc(var(--ccd-fade-bottom-inset, 0px) + var(--ccd-edge-fade));\n background: linear-gradient(\n to top,\n var(--ccd-canvas) 0,\n var(--ccd-canvas) calc(100% - var(--ccd-edge-fade)),\n transparent 100%\n );\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body:has([data-conversation-scroll][data-ccd-fade-top])::before {\n opacity: 1;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body:has([data-conversation-scroll][data-ccd-fade-bottom])::after {\n opacity: 1;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root {\n font-size: var(--dsh-content-font-size, 14px);\n line-height: 24px;\n color: var(--ccd-text);\n}\n\n/* Official MarkdownText in assistant replies only. Compact reasoning/tool\n Markdown, user references and the Composer retain their own presentation.\n Sources and static-library class names are pinned in compat/host-dom.ts. */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) {\n font-family: var(--ccd-font-ui);\n font-size: inherit;\n /* The host runs the assistant body at 14px/24px; the reference runs the same\n 14px on a 20px line, which is what its paragraphs and its paragraph gaps\n are measured against. Reasoning and tool Markdown (`[data-markdown-variant\n ="compact"]`) keep the host\'s own leading. */\n line-height: var(--ccd-transcript-line-height);\n color: var(--ccd-text);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(a, ._fileMention_1ypvv_85) {\n max-width: 100%;\n color: var(--ccd-link);\n font-weight: inherit;\n text-decoration-line: underline;\n text-decoration-style: solid;\n text-decoration-color: var(--ccd-link-underline);\n text-decoration-thickness: 1px;\n text-underline-offset: 3px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(a, ._fileMention_1ypvv_85):is(:hover, :focus) {\n text-decoration-color: var(--ccd-link);\n}\n\n/*\n * The host prefixes a URL link with a category glyph \u2014 `MarkdownText.module.css`\n * seats a `.linkIcon` globe inside the anchor (1.1em, -0.25em of optical\n * offset) \u2014 so "\u5916\u94FE" draws as "\u2295 \u5916\u94FE" where the reference draws the link text\n * alone. The glyph is not painted inside an anchor; the anchor keeps its text,\n * its underline and its hit area. The other two shapes that carry the class \u2014\n * a file mention and URL-promoted inline code \u2014 are not anchors but file chips,\n * and keep their own glyph.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) a ._linkIcon_1ypvv_94 {\n display: none;\n}\n\n/* Limit chips to the text column so long identifiers can wrap inside them.\n The host uses !important for its code-size ratio, so this override must too.\n The fenced block is not a chip: it takes its own rule below. */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :not(pre) > code {\n display: inline-block;\n max-width: 100%;\n vertical-align: baseline;\n font-family: var(--ccd-font-code);\n font-size: 0.95em !important;\n font-weight: inherit;\n line-height: 1.2;\n color: var(--ccd-inline-code-text);\n background: var(--ccd-inline-code-fill);\n border: 1px solid var(--ccd-inline-code-border);\n border-radius: 5px;\n padding: 1px 4px;\n overflow-wrap: anywhere;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) strong {\n font-weight: var(--ccd-font-weight-strong);\n}\n\n/*\n * Headings. The host draws the transcript\'s h1/h2/h3 at 21/19/18px inside a\n * 32px top and 16px bottom margin, a full step larger and a good deal looser\n * than the reference: its crop measures a 19px h1 and a 16px h2 (the tokens in\n * `theme/tokens.css` carry that measurement), and the ink between two stacked\n * headings is 20 device px against this plugin\'s 68. The margin below is what\n * puts that gap back \u2014 the collapsed 8px plus each heading\'s own half-leading\n * lands within a couple of device px of the reference at @2x. h4-h6 keep the\n * host\'s size (body size, weight 600) and take the same rhythm.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(h1, h2, h3) {\n margin: 8px 0 6px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h1 {\n font-size: var(--ccd-font-size-h1);\n line-height: 26px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h2 {\n font-size: var(--ccd-font-size-h2);\n line-height: 22px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h3 {\n font-size: var(--ccd-font-size-h3);\n line-height: 20px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(h4, h5, h6) {\n margin: 10px 0 6px;\n}\n\n/*\n * Block rhythm. The host spaces the transcript\'s blocks at 16px. The reference\n * runs tighter around prose and quotes \u2014 its crop puts a paragraph-to-quote and\n * a quote-to-list run at 18 device px of ink, which is ~7-10px of collapsed\n * margin once each block\'s half-leading is taken off \u2014 while its lists and its\n * table and code cards keep the host\'s step. Only the two that differ move;\n * list items keep the host\'s own 8px rhythm.\n *\n * The list guard is written on the paragraph \u2014 `p:not(li p)` \u2014 and not as a\n * `:not(li) > p` child of the root: a paragraph in this DOM is the root\'s own\n * child, and a descendant combinator there asks for a parent *below* the root,\n * so it matched nothing but the paragraphs nested one level deeper (a quote\'s)\n * and every top-level paragraph kept the host\'s 16px.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) p:not(li p) {\n margin: 10px 0;\n}\n\n/*\n * Blockquote. The host draws a 2px rule in `--dsw-alias-label-caption` \u2014 its\n * own mid grey \u2014 and leaves the text at full body ink, so a quote reads as an\n * indented paragraph rather than as a quote. The reference draws a 4px rule in\n * the same value as this plugin\'s outline token, with its text one step down in\n * ink (this plugin\'s secondary step, against a body that stays near-black). The\n * rule-to-text distance matches in both (27 and 29 device px), so only the\n * rule\'s weight, its colour and the text\'s ink move.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) blockquote {\n margin: 10px 0;\n border-left: 4px solid var(--ccd-border);\n padding-left: 15px;\n color: var(--ccd-text-secondary);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) hr {\n /* The host spaces the rule at 32px on each side; the reference\'s crop puts\n its card-rule-copy run at 71 device px of ink, which is ~20px a side. */\n margin: 20px 0;\n}\n\n/*\n * List rhythm. The host sizes its marker\'s own line at the 24px it used to draw\n * the body at, so the marker box stands a step taller than the transcript\'s\n * leading and stretches every list row to 22px \u2014 the item pitch lands at 28\n * where the reference\'s own rows measure 26 (its 40 device px at 1.53). The\n * marker rides the item\'s line instead, which is what a browser that sets no\n * marker line at all would do.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) li::marker {\n line-height: inherit;\n}\n\n/*\n * Task lists. The host leaves the list marker in place, so a `- [x]` row draws\n * "\u2022 \u2611 label" where the reference draws the checkbox alone, and its 6px\n * inter-item margin \u2014 which the reference\'s own rows do not carry \u2014 widens the\n * pitch to 46 device px against the reference\'s 35. The marker goes and the\n * margin goes with it; the checkbox itself already matches (the reference\'s\n * fill measures the same 20 device px in the host\'s grey accent).\n *\n * The checkbox sits directly in the item in a tight list and inside the item\'s\n * paragraph in a loose one, so both shapes are named.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(li:has(> input[type="checkbox"]), li:has(> p:first-child > input[type="checkbox"])) {\n list-style: none;\n margin-top: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) input[type="checkbox"] {\n /* The host\'s 8px trailing margin leaves 20 device px before the label where\n the reference leaves 10. */\n margin-right: 6px;\n}\n\n/*\n * Fenced code blocks take the reference\'s outlined card: a white fill inside a\n * single hairline, replacing the host\'s cool wash. The host paints three nested\n * surfaces with that wash \u2014 the wrapper, the language banner and `pre` itself \u2014\n * and the banner\'s outer wrapper falls back to the page token, so every one of\n * them is repainted here; leaving any single layer would show a grey band.\n *\n * `data-code-wrap` is a stable host anchor (the class list also carries\n * `md-code-block`); the inner layers are reached through it so no hashed class\n * name is repeated here.\n *\n * The card is also a *row*, because the reference\'s is. Its one-line fence\n * draws as a single 33px-tall card (50 device px at @2x) that hugs its content \u2014\n * code first, the copy control (and the wrap toggle, and the run control on a\n * shell fence) trailing it \u2014 and floors at 320px, which is why its own short\n * `npm run check` card carries a wide gap between the code and its controls.\n * The host instead fills the column and stacks a 36px language banner over a\n * `pre` padded `6px 22px 20px`, which is 135 device px for that same one line.\n *\n * So the block becomes a flex row with the banner reversed behind the code: the\n * banner\'s controls ride the first code line, the `pre` takes the row\'s spare\n * width (pushing those controls to the trailing edge exactly as the reference\'s\n * floored card does) and the column stays the ceiling. `min(320px, 100%)` keeps\n * a narrow transcript from being pushed out by the floor.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] {\n box-sizing: border-box;\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-code-radius);\n background: var(--ccd-card);\n display: flex;\n /* The banner is the DOM\'s first child; the code reads first. */\n flex-direction: row-reverse;\n align-items: flex-start;\n width: fit-content;\n min-width: min(320px, 100%);\n max-width: 100%;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] > *,\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner],\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] pre {\n /* The card owns the surface now; the layers inside it only carry text. */\n background: transparent;\n border-radius: 0;\n}\n\n/*\n * The banner stops being a row above the code. Its wrapper is the sticky\n * scroller that used to pin the language row to the top of a tall card; in a\n * row it is the card\'s trailing control strip, seated on the first code line\n * (31px = the `pre`\'s 6px padding over the host\'s 19px code line), which is the\n * whole card when the fence is one line. The host\'s own compact variant\n * neutralises the same wrapper the same way.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] > :has(> [data-code-block-banner]) {\n position: static;\n z-index: auto;\n display: flex;\n align-items: center;\n height: 31px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner] {\n width: 100%;\n /* 11px, not 12: the card\'s own 1px outline sits outside this padding and the\n reference measures its 18 device px from the card\'s outer edge. */\n padding: 0 11px 0 0;\n font: inherit;\n}\n\n/*\n * The language label is not painted: the reference\'s card shows the code and its\n * controls alone, and its short card is 320px wide for 90px of code precisely\n * because nothing else sits in that row. The label is the banner\'s leading\n * group in both of the host\'s toolbar shapes, so it is named structurally\n * rather than by its hashed class; the copy and wrap controls, their labels and\n * the run control on a shell fence all stay.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner] > :first-child {\n display: none;\n}\n\n/*\n * The code keeps the host\'s 19px line and takes the reference\'s size (one step\n * under the body, where the host draws it at 11px) and its padding: the\n * reference holds the line with ~6px above and below and 16px of leading inset\n * (26 device px at @2x), against the host\'s `6px 22px 20px`. `min-width: 0`\n * lets the code shrink below its own content when the wrap toggle is off.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] pre {\n flex: 1 1 auto;\n min-width: 0;\n padding: 6px 16px;\n font-size: var(--ccd-font-size-muted);\n}\n\n/*\n * Tables: one rounded card, as in the reference. The host collapses borders,\n * takes every cell\'s leading padding away (`padding: 10px 16px 10px 0`) and\n * leaves the row rule to each cell, so a card that can carry a radius needs\n * separate borders, one outline of its own and its own cell padding. The head\n * keeps a filled surface and a rule one step darker than the outline; body rows\n * are separated by hairlines, and the card\'s own edge closes the last one.\n * Column alignment markers stay the host\'s business.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) table {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-table-radius);\n border-collapse: separate;\n border-spacing: 0;\n /* The head fill and the row rules are painted by the cells, so the card has\n to clip them to its own radius. */\n overflow: hidden;\n font-size: inherit;\n line-height: inherit;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(th, td) {\n /* The host sizes table text one step below the transcript; the reference\n keeps a table at body size. Its row is 33px \u2014 the transcript\'s 20px line\n with 6px above and below, which is the 51 device px both shots measure \u2014\n so the cells keep the body leading and pay the difference in padding. */\n font-size: inherit;\n line-height: inherit;\n padding: 6px 10px;\n border: 0;\n border-bottom: 1px solid var(--ccd-border);\n vertical-align: middle;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) thead th {\n background: var(--ccd-raised);\n border-bottom-color: var(--ccd-table-head-line);\n color: var(--ccd-text);\n font-weight: var(--ccd-font-weight-strong);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) tbody tr:last-child :is(th, td) {\n border-bottom: 0;\n}\n\n/*\n * Wide tables stay inside the content column.\n *\n * The host marks every table of four columns or more `md-table-wide`\n * (AssistantMarkdown.module.css) and bleeds that wrapper out to the scroller\'s\n * full width through `--dsh-table-spare`\uFF0F`--dsh-table-lead`, pinning the table\'s\n * leading edge back to the column with a negative margin and a matching leading\n * pad. In the host\'s own geometry the Composer card is 32px wider than the\n * column, so the borrowed width lands inside its edges; here the card and the\n * column are the same width, and a bleeded table left the card and the Composer\n * on different right edges (measured +86px at the reference window, growing with\n * the view area). Dropping the bleed keeps the table on the column; a table\n * whose rows cannot wrap far enough still uses the host\'s own `md-table-wide`\n * scroll, which needs the wrapper\'s own `overflow-x` and scrollbar gutter, so\n * neither is touched here.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root .gKv1-q_body .md-table-wide {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n margin-left: 0;\n padding-left: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .icaHSq_column {\n --dsh-chat-flow-gap: 10px;\n}\n\n/* User message: soft raised bubble, as in the reference. */\nhtml[data-dsh-ccd-style="true"] .IzP3Va_bubble {\n padding: 7px 14px;\n border-radius: var(--ccd-composer-radius);\n background: var(--ccd-raised);\n color: var(--ccd-text);\n font-size: var(--dsh-content-font-size, 14px);\n line-height: 22px;\n}\n\nhtml[data-dsh-ccd-style="true"] .IzP3Va_userStack {\n max-width: min(calc(var(--dsh-chat-content-width) * 0.72), 82%);\n gap: 6px;\n}\n\n/* Tool and reasoning rows: quiet single lines. */\nhtml[data-dsh-ccd-style="true"] .Q2dzhW_root,\nhtml[data-dsh-ccd-style="true"] .HiSsxa_root,\nhtml[data-dsh-ccd-style="true"] .-gRAhq_root {\n color: var(--ccd-text-secondary);\n font-size: var(--ccd-font-size-body);\n}\n';
|
|
11294
|
+
var conversation_default = '/*\n * Conversation page: header chrome, transcript column and message surfaces.\n *\n * The transcript, its scroll behaviour, tool rendering and approval surfaces\n * stay entirely DSH\'s; only width, type and surface colours change. Host\n * classes are pinned in src/client/compat/host-dom.ts.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_root {\n container: ccd-conversation / inline-size;\n}\n\n/*\n * Transcript width handles: hidden here, because this interface removed what\n * they control (17).\n *\n * `ui-conversation`\'s `ConversationWidthControls` renders one handle per side as\n * the Conversation body\'s last child (ConversationRoot.module.css,\n * `ST7X_W_widthHandle`, stable hook `data-width-handle`; component\n * `skeleton/ConversationWidthControls.tsx`). Each is a transparent full-height\n * strip \u2014 `position: absolute; top: 0; bottom: 0`, `cursor: col-resize`,\n * `width: min(10px, (100% - var(--dsh-chat-content-width)) / 2 - 48px)` \u2014 parked\n * 24px outside the transcript column, whose only ink is the 2px rule its own\n * `::after` reveals on hover or while dragging. Dragging one publishes\n * `--dsh-chat-user-width` on the Conversation root.\n *\n * That property has exactly one consumer in the host, the body rule\n * `--dsh-chat-content-width: var(--dsh-chat-user-width, clamp(680px, \u2026))`, and\n * this interface replaces it: `theme/composer.css` pins\n * `--dsh-chat-content-width: var(--ccd-composer-width)` (770px) on the same\n * element with higher specificity. A drag therefore changes nothing \u2014 not the\n * transcript column, the user stack, the jump-to-bottom slot or the wide-table\n * bleed \u2014 while the handle keeps its pointer capture, its resize cursor and its\n * hover rule. It is a false affordance whose state cannot be reached: hiding it\n * takes away no behaviour, and with the plugin off the host\'s own rule returns\n * and the handles drag again.\n *\n * `display: none`, not `visibility` or a transparent paint, and scoped to the\n * Conversation root so `ui-layout`\'s real column handles (`_6Qf49G_handle`, 8px,\n * on the sidebar and rightbar tracks) are never touched. The handle is an\n * absolutely positioned, empty box outside the body\'s flex flow, so removing it\n * cannot move a sibling: transcript width, the scroll viewport\'s stable\n * scrollbar gutter and the page\'s scroll range keep the values they had.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_root [data-width-handle] {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header {\n background: var(--ccd-canvas);\n color: var(--ccd-text);\n /*\n * The reference has no rule between the header and the transcript \u2014 the two\n * read as one page. The host draws a hairline here (`border-bottom: .5px\n * solid`), so it is painted out rather than removed: keeping the border\'s\n * width leaves the header\'s own height untouched.\n */\n border-bottom-color: transparent;\n /*\n * One header row. DSH stacks a title row and, below it, its View tablist; the\n * reference keeps every piece of header chrome on the title line. The two\n * wrapper boxes dissolve (`display: contents`) instead of being re-parented,\n * so the host\'s own children stay where React put them and only their order\n * changes: title, View switcher, Agent-preset chip, utilities, corner.\n */\n display: flex;\n align-items: center;\n /* The host reserves the second row only while its tablist is a row of its\n own; that row is gone, so its `min-height: 76px` goes with it. */\n min-height: 0;\n padding: 10px var(--ccd-header-trailing-inset) 10px 12px;\n /*\n * Where the Composer\'s input surface ends, measured from the column\'s right\n * edge in the numbers that draw it, for the narrow-column rules below: the\n * Composer root\'s own side clearance (`theme/composer.css` pins the host\'s\n * `--dsh-composer-side-clearance` at 16px), the stable scrollbar gutter the\n * page\'s scroll viewport reserves (`ST7X_W_scrollBody { scrollbar-gutter:\n * stable }` over the theme\'s 5px `--dsh-scrollbar-width` track) and that\n * viewport\'s own `margin-right: 2px`.\n */\n --ccd-composer-trailing-edge: calc(\n var(--dsh-composer-side-clearance, 16px) + var(--dsh-scrollbar-width, 5px) + 2px);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerBlank {\n /* Blank Sessions keep the single-row height they had as a grid row. */\n min-height: 40px;\n padding-bottom: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerSessionless {\n min-height: 50px;\n}\n\n/*\n * On macOS the title line shares the window-control row\'s centre line: the\n * traffic lights, the collapse toggle (`top: 11px` + 28 / 2) and the parked\n * switcher (`top: 12px` + 26 / 2) all centre on y = 25. The flex items above\n * centre on the header\'s content box, and with the base padding (10px top and\n * bottom) that box centred on 20 \u2014 the title, the team chip and the right-hand\n * panel buttons sat 5px above the line they are meant to share.\n *\n * Holding the header at 40px \u2014 the height it already has, with 20px items \u2014\n * and dropping the bottom padding leaves a 30px content box from y = 10 to\n * y = 40 whatever the items\' own heights (up to 30px): its centre is 25. A\n * collapsed inline switcher (26px) therefore centres on the same line too.\n * Windows has no such row, so its header keeps the base rule, and the\n * sessionless header already centres on 25 with its own 10px bottom padding.\n */\n/* Only macOS shares the conversation header with the window drag surface.\n The host excludes its controls from dragging only on darwin; Windows has a\n separate caption strip, so making this row draggable swallows button clicks. */\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] .ST7X_W_header {\n -webkit-app-region: drag;\n}\n\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] .ST7X_W_header:not(.ST7X_W_headerSessionless) {\n min-height: 40px;\n padding-bottom: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_titleRow,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_titleCluster {\n display: contents;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumbs {\n /* Stable natural title width (capped at 112px) keeps the following switcher\n anchored while the rightbar changes column width. */\n flex: none;\n box-sizing: border-box;\n max-width: calc(112px + max(0px, var(--dsh-frame-leading-clearance, 0px) - 12px));\n padding-inline-start: max(0px, calc(var(--dsh-frame-leading-clearance, 0px) - 12px));\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions {\n order: 2;\n /* Stable gap between switcher and team entry.\n `margin-right: auto` is the header\'s flexible gap: the title, the View\n switcher and the chip stay grouped at the leading edge, as in the\n reference, and the utilities keep the trailing edge they had before. The\n chip always renders, so the gap survives an empty tools group. */\n /* The preceding title has 8px end padding + the track\'s 2px margin.\n Give the track-to-team boundary the same visible 10px separation. */\n margin-left: var(--ccd-header-group-gap, 10px);\n gap: 4px;\n margin-right: auto;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities {\n order: 3;\n margin-left: 0;\n /* One uniform gap, so every visible space in the cluster is equal. */\n gap: var(--ccd-header-action-gap);\n}\n\n/*\n * The corner seat is retired, and the utilities group owns the trailing edge.\n *\n * That single cell\'s shipped occupant is `ui-sidebar-right`\'s collapsed-panel\n * expand control, which this interface does not draw; the plugin shadows it with\n * an entry that renders nothing (`features/conversation/header-actions/entries.ts`)\n * and keeps the expand action in the Session menu instead. So the seat has no\n * box of its own to place \u2014 its own gap in front of the utilities would be 2px\n * of trailing space after the last control, and the reference measures the\n * cluster\'s inset from the header\'s own padding. A Blank Session renders the\n * same empty seat, which is why the host\'s `margin-left: auto` for that row\n * needs no answer here: there is nothing left in the corner to place either way.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerCorner {\n margin: 0;\n}\n\n/*\n * View switcher: the host\'s own `role="tablist"`, reshaped into the reference\'s\n * segmented control. The selected segment is drawn by one thumb \u2014 the\n * `::before` of the tablist \u2014 moved with the geometry published by\n * `compat/view-switch.ts`; the buttons keep their roles, labels and handlers,\n * and the host\'s own underline is dropped.\n *\n * Geometry is the reference\'s own pill (docs/issues/img/todo-sidebar-sessions-target.webp,\n * @2x): a 66 \xD7 26 track \u2014 131 \xD7 52 device px, so two 33px segments \u2014 6px\n * corner, with the raised thumb inset 1px top and bottom and carrying a 5px\n * corner, a 1px outline and the segment shadow. The two segments are the icon\n * buttons below, not text: `compat/view-switch.ts` swaps each shipped View\'s\n * label for the bundled artwork in `view-switch-icons.ts`.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs {\n order: 1;\n position: relative;\n /* Never squeezed: a narrow header truncates the title instead. */\n flex: none;\n display: inline-flex;\n align-items: stretch;\n gap: 0;\n /* The switcher sits directly after the Session title; later header chrome\n (the Agent-preset chip today, more to come) follows it. */\n margin: 0 0 0 var(--ccd-header-group-gap, 2px);\n padding: 0;\n border-radius: 6px;\n background: var(--ccd-track);\n -webkit-app-region: no-drag;\n}\n\n/* The docked pill sits over the sidebar\'s native window-drag strip. Let its\n empty chrome participate in dragging while keeping the view buttons clickable. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] {\n -webkit-app-region: drag;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] .ST7X_W_tab {\n -webkit-app-region: no-drag;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs::before {\n content: "";\n position: absolute;\n top: 1px;\n bottom: 1px;\n left: 0;\n box-sizing: border-box;\n width: var(--ccd-view-w, 0px);\n transform: translateX(var(--ccd-view-x, 0px));\n border: 1px solid var(--ccd-border-soft);\n border-radius: 5px;\n background: var(--ccd-card);\n box-shadow: var(--ccd-shadow-segment);\n pointer-events: none;\n transition: transform var(--ccd-view-duration, 0ms) var(--ds-ease-in-out, ease),\n width var(--ccd-view-duration, 0ms) var(--ds-ease-in-out, ease);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n /* The reference\'s 33px segment is a floor, not a fixed width: a View this\n plugin has no artwork for keeps its own label and its own room. */\n flex: 0 1 auto;\n min-width: 33px;\n height: 26px;\n padding: 0 6px;\n border: 0;\n border-radius: 5px;\n background: transparent;\n color: var(--ccd-text-muted);\n font-size: var(--ccd-font-size-muted);\n font-weight: 500;\n line-height: 20px;\n white-space: nowrap;\n}\n\n/* A decorated tab draws bundled artwork in place of the host\'s label text;\n `compat/view-switch.ts` writes the marker and the button\'s accessible name.\n An unknown View keeps its label and is left alone. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n font-size: 0;\n line-height: 0;\n}\n\n/*\n * The artwork seat leaves the button\'s own flow and centres on the button\'s\n * box \u2014 not on a line box beside the host\'s label, and not inside whatever\n * content box the host\'s own rules leave here. The host\'s `.tab` gives this\n * button `padding: 0 0 9px`, its own 16px line and its own alignment, and any\n * of them winning back even one of those declarations moved the icon ~4.5px\n * above the segment; the seat is absolutely centred on the padding box\n * instead, which is the box the sliding thumb is drawn on. Measured in\n * `tests/view-switch-browser.test.mjs`, including a state that hands the\n * button\'s inner layout back to the host\'s rules.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] > [data-ccd-view-glyph] {\n position: absolute;\n inset: 0;\n margin: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n line-height: 0;\n pointer-events: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab[data-ccd-view] > [data-ccd-view-glyph] > svg {\n display: block;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tab::after {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabActive {\n color: var(--ccd-text);\n}\n\n/*\n * Docked: the switcher leaves the header for the sidebar\'s window-control row.\n *\n * The reference keeps it at the top-right of the sidebar column, on the same\n * row as the traffic lights and the collapse toggle \u2014 measured at 8px inside\n * the column\'s right edge (its divider sits 16 device px right of the pill),\n * with the pill\'s 26px centre on the toggle\'s own centre (11px + 28 / 2 = 25).\n * The node stays in the header where React rendered it: `position: fixed` takes\n * it out of that row and the coordinates come from `compat/view-switch.ts`,\n * measured live from the sidebar column \u2014 the same way the macOS sidebar toggle\n * is parked. It is written only where the column has the corner to hold it:\n * macOS with the sidebar expanded, so the host\'s own row (Windows, or the\n * collapsed shell\'s 0px column) keeps the switcher inline.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_tabs[data-ccd-view-dock="sidebar"] {\n position: fixed;\n top: 12px;\n right: var(--ccd-view-dock-right, 8px);\n z-index: 15;\n margin: 0;\n}\n\n/* With the switcher parked, native crumbs supply 8px end padding. The custom\n title has no end padding, so its project and team use the full group gap. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_header:has(.ST7X_W_tabs[data-ccd-view-dock]) .ST7X_W_headerActions {\n margin-left: var(--ccd-header-group-gap, 2px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n html[data-dsh-ccd-style="true"] .ST7X_W_tabs::before {\n transition: none;\n }\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumbs,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumb {\n color: var(--ccd-text);\n font-size: var(--ccd-font-size-muted);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_crumb {\n max-width: 100%;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions button,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities button {\n color: var(--ccd-text-secondary);\n}\n\n/* The collapsed macOS shell consumes 160px for native window controls. Keep\n that reservation stable and omit title crumbs in this shell state, so a\n 400px column still fits the complete team entry and every native button. */\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] [data-sidebar-collapsed] .ST7X_W_header:not(.ST7X_W_headerBlank) .ST7X_W_crumbs {\n max-width: none;\n}\n\nhtml[data-dsh-ccd-style="true"][data-platform="darwin"] [data-sidebar-collapsed] .ST7X_W_header:not(.ST7X_W_headerBlank) .ST7X_W_crumb {\n display: none;\n}\n\n/* Keep the actionable team entry complete; omit the passive header mode. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._2tNPVa_triggerLabel {\n display: inline;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._3li69W_label {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerActions ._2tNPVa_trigger {\n padding-inline: 0;\n}\n\n/*\n * Trailing action cluster. Every control takes the same square hit box, so the\n * visible gaps between glyphs are equal rather than only the box gaps: the\n * previous build zeroed the host\'s `gap` and shrank single controls, which left\n * ~7px after the split button but ~14px after the 24px menu button. Geometry is\n * declared once in theme/tokens.css. The host\'s own 15px artwork stays native\n * inside these boxes; the plugin only paints the three glyphs below.\n *\n * The renderer wraps every list entry in a `display: contents` seat\n * (`[data-slot="conversation.session.header.utilities"]`), so the boxes are the\n * seat\'s children \u2014 the seat itself has no box to size. (The corner seat is\n * retired and holds nothing: see the rule above.)\n *\n * `[role="tooltip"]` is named out because a seat\'s children are not always\n * controls. `ui-primitives`\' `Tooltip` clones its anchor and renders its bubble\n * as a *sibling* of it, inside the same React fragment \u2014 which lands both nodes\n * in the seat. Sizing that bubble to the control box clipped it to one glyph\n * and a half the moment it appeared; the bubble keeps its own geometry on\n * every hover.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities > [data-slot] > *:not([role="tooltip"]) {\n box-sizing: border-box;\n flex: none;\n width: var(--ccd-header-action-size);\n height: var(--ccd-header-action-size);\n border-radius: var(--ccd-radius-row);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .Da3aKq_moreButton {\n padding: 0;\n}\n\n/*\n * The "open in app" control becomes one generic glyph whose whole box opens the\n * native application menu. The chevron half \u2014 the only control that opens that\n * menu \u2014 is stretched over the split box as the hit area, while the application\n * image and the chevron glyph are replaced by shared artwork. The host keeps the\n * menu, its items, its icon route and its callbacks; `compat/open-target.ts`\n * marks the no-menu state, which hides this control instead of direct-opening.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_split {\n position: relative;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border: 0;\n border-radius: inherit;\n overflow: hidden;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron {\n position: absolute;\n inset: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n padding: 0;\n border: 0;\n background: transparent;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron svg {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron:hover:not(:disabled),\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_chevron:focus-visible,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main {\n width: 100%;\n height: 100%;\n gap: 0;\n padding: 0;\n color: var(--ccd-text-secondary);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main > * {\n display: none;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities .iq4beG_main::before {\n content: "";\n width: var(--ccd-header-icon-size);\n height: var(--ccd-header-icon-size);\n background-color: currentColor;\n mask: var(--ccd-icon-open) center / var(--ccd-header-icon-size) var(--ccd-header-icon-size) no-repeat;\n}\n\n/* No application menu exists (a directory with at most one candidate): a chooser\n glyph would promise what the host cannot show, so the control stays away. */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities [data-ccd-open-mode="direct"] {\n display: none;\n}\n\n/*\n * Narrow columns: the cluster ends on the Composer\'s own trailing edge.\n *\n * The design\'s 12px inset (`--ccd-header-trailing-inset`) is measured in a\n * window whose transcript column is wider than the Composer\'s 770px cap, so the\n * Composer is centred inside the column and the two rows end at different\n * places \u2014 an inset the reference keeps at every width. Where the Composer\n * *fills* the column instead, its input surface\'s right border is a line the\n * cluster sits directly above, and the reference draws the cluster ending on it:\n * the last control\'s centre on that border, so the \u22EE reads as the row\'s closing\n * mark rather than as an icon hanging outside the Composer. That state is the\n * one an expanded right panel leaves, and this is where it is answered.\n *\n * The column that fills its Composer is the Composer\'s own 770px cap plus what\n * surrounds the surface: the root\'s two clearances and the page scroll\n * viewport\'s stable gutter and 2px margin, i.e. 810px. Below it the trailing\n * padding is the surface\'s own edge (`--ccd-composer-trailing-edge`, declared\n * on the header above) less half the closing control, so the box is centred on\n * the border rather than ending on it; `min()` keeps the design\'s inset as the\n * ceiling, for a deployment that hands the Composer a wider clearance.\n */\n@container ccd-conversation (max-width: 810px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header {\n padding-right: min(\n var(--ccd-header-trailing-inset),\n calc(var(--ccd-composer-trailing-edge) - var(--ccd-header-action-size) / 2));\n }\n}\n\n/* Very narrow columns keep every control on the collapsed macOS shell\'s 24px\n box, so the same edge is taken against the smaller box: half of it is 2px\n less, and the cluster\'s last control stays centred on the input surface\'s\n border. */\n@container ccd-conversation (max-width: 520px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header {\n padding-right: min(\n var(--ccd-header-trailing-inset),\n calc(var(--ccd-composer-trailing-edge) - var(--ccd-header-action-compact) / 2));\n }\n\n html[data-dsh-ccd-style="true"] .ST7X_W_headerUtilities > [data-slot] > *:not([role="tooltip"]) {\n width: var(--ccd-header-action-compact);\n height: var(--ccd-header-action-compact);\n }\n}\n\n/*\n * The title yields before the cluster does \u2014 and, like the three views below,\n * only to a switcher that is still in the row.\n *\n * With the switcher in it, the row is four pieces \u2014 title, switcher, native team\n * entry, cluster \u2014 and at this width they cannot share one line. The title is\n * the only piece the sidebar also shows, so it goes: the same trade the\n * collapsed macOS shell already makes, and every native control keeps its full\n * label.\n *\n * Parked in the sidebar\'s window-control row (`compat/view-switch.ts` writes\n * `data-ccd-view-dock`; macOS with the sidebar expanded, which is where an\n * expanded right panel leaves the column), the switcher takes its 66px track and\n * the two margins around it out of the row, and the three pieces that remain\n * occupy 377px of the 400px floor the frame protects for this column while the\n * right panel is open (`ui-layout`\'s `CENTER_MIN`) \u2014 so they fit, with the 72px\n * between the chip and the cluster left to `margin-right: auto`. Withdrawing the\n * title there bought nothing and cost the one place a narrow column still names\n * its session.\n */\n@container ccd-conversation (max-width: 420px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header:not(.ST7X_W_headerBlank):has(.ST7X_W_tabs:not([data-ccd-view-dock]))\n .ST7X_W_crumbs {\n display: none;\n }\n}\n\n/*\n * The three views this plugin adds \u2014 the project folder among them \u2014 step aside\n * only while the row still carries the View switcher.\n *\n * The switcher is normally parked in the sidebar\'s window-control row\n * (`compat/view-switch.ts` writes `data-ccd-view-dock` on the tablist wherever\n * that column has the corner to hold it), and the row is then the title, the\n * team chip and the cluster: at most ~235px of chrome, so all three stay drawn\n * at any width the Composer can still be used at \u2014 including the column an\n * expanded right panel leaves, where they are the only way to switch the\n * panel\'s view back. With the switcher still in the row \u2014 a Windows build, or a\n * collapsed macOS sidebar whose window is narrow \u2014 there are four pieces on the\n * line, and these three are the ones that go: they are the plugin\'s own\n * controls, they have a second entry in the right panel\'s own tab strip, and\n * the native team chip keeps its full label either way.\n */\n@container ccd-conversation (max-width: 420px) {\n html[data-dsh-ccd-style="true"] .ST7X_W_header:has(.ST7X_W_tabs:not([data-ccd-view-dock]))\n .ST7X_W_headerUtilities [data-ccd-header-view] {\n display: none;\n }\n}\n\n/* Transcript column keeps the reference\'s breathing room. */\nhtml[data-dsh-ccd-style="true"] .icaHSq_scroll {\n padding-top: 16px;\n padding-bottom: 8px;\n}\n\n/* Center and size the host\'s jump-to-bottom control.\n * Source: ui-chat/ChatView.module.css, HOST.chatViewToBottomSlot/toBottom.\n * Negative margin follows the button size to retain its gap above Composer.\n */\nhtml[data-dsh-ccd-style="true"] .icaHSq_toBottomSlot {\n justify-content: center;\n padding-right: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .icaHSq_toBottom {\n width: var(--ccd-to-bottom-size);\n height: var(--ccd-to-bottom-size);\n margin-top: calc(-1 * var(--ccd-to-bottom-size));\n}\n\n/* Paint edge gradients on the page body above the transcript and below\n * sticky Composer. conversation-fade.ts publishes scroll flags and the bottom\n * inset; the lower overlay covers Composer\'s full footprint. Since Composer\n * is inside the scroller, the gradient belongs on this separate layer.\n */\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::before,\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n height: var(--ccd-edge-fade);\n background: var(--ccd-canvas);\n pointer-events: none;\n /* Above the transcript, below the Composer seat (7) and the jump-to-bottom\n control (8) so neither is veiled. */\n z-index: 1;\n opacity: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::before {\n top: 0;\n background: linear-gradient(to bottom, var(--ccd-canvas), transparent);\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body::after {\n bottom: 0;\n height: calc(var(--ccd-fade-bottom-inset, 0px) + var(--ccd-edge-fade));\n background: linear-gradient(\n to top,\n var(--ccd-canvas) 0,\n var(--ccd-canvas) calc(100% - var(--ccd-edge-fade)),\n transparent 100%\n );\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body:has([data-conversation-scroll][data-ccd-fade-top])::before {\n opacity: 1;\n}\n\nhtml[data-dsh-ccd-style="true"] .ST7X_W_body:has([data-conversation-scroll][data-ccd-fade-bottom])::after {\n opacity: 1;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root {\n font-size: var(--dsh-content-font-size, 14px);\n line-height: 24px;\n color: var(--ccd-text);\n}\n\n/* Official MarkdownText in assistant replies only. Compact reasoning/tool\n Markdown, user references and the Composer retain their own presentation.\n Sources and static-library class names are pinned in compat/host-dom.ts. */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) {\n font-family: var(--ccd-font-ui);\n font-size: inherit;\n /* The host runs the assistant body at 14px/24px; the reference runs the same\n 14px on a 20px line, which is what its paragraphs and its paragraph gaps\n are measured against. Reasoning and tool Markdown (`[data-markdown-variant\n ="compact"]`) keep the host\'s own leading. */\n line-height: var(--ccd-transcript-line-height);\n color: var(--ccd-text);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(a, ._fileMention_1ypvv_85) {\n max-width: 100%;\n color: var(--ccd-link);\n font-weight: inherit;\n text-decoration-line: underline;\n text-decoration-style: solid;\n text-decoration-color: var(--ccd-link-underline);\n text-decoration-thickness: 1px;\n text-underline-offset: 3px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(a, ._fileMention_1ypvv_85):is(:hover, :focus) {\n text-decoration-color: var(--ccd-link);\n}\n\n/*\n * The host prefixes a URL link with a category glyph \u2014 `MarkdownText.module.css`\n * seats a `.linkIcon` globe inside the anchor (1.1em, -0.25em of optical\n * offset) \u2014 so "\u5916\u94FE" draws as "\u2295 \u5916\u94FE" where the reference draws the link text\n * alone. The glyph is not painted inside an anchor; the anchor keeps its text,\n * its underline and its hit area. The other two shapes that carry the class \u2014\n * a file mention and URL-promoted inline code \u2014 are not anchors but file chips,\n * and keep their own glyph.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) a ._linkIcon_1ypvv_94 {\n display: none;\n}\n\n/* Limit chips to the text column so long identifiers can wrap inside them.\n The host uses !important for its code-size ratio, so this override must too.\n The fenced block is not a chip: it takes its own rule below. */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :not(pre) > code {\n display: inline-block;\n max-width: 100%;\n vertical-align: baseline;\n font-family: var(--ccd-font-code);\n font-size: 0.95em !important;\n font-weight: inherit;\n line-height: 1.2;\n color: var(--ccd-inline-code-text);\n background: var(--ccd-inline-code-fill);\n border: 1px solid var(--ccd-inline-code-border);\n border-radius: 5px;\n padding: 1px 4px;\n overflow-wrap: anywhere;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) strong {\n font-weight: var(--ccd-font-weight-strong);\n}\n\n/*\n * Headings. The host draws the transcript\'s h1/h2/h3 at 21/19/18px inside a\n * 32px top and 16px bottom margin, a full step larger and a good deal looser\n * than the reference: its crop measures a 19px h1 and a 16px h2 (the tokens in\n * `theme/tokens.css` carry that measurement), and the ink between two stacked\n * headings is 20 device px against this plugin\'s 68. The margin below is what\n * puts that gap back \u2014 the collapsed 8px plus each heading\'s own half-leading\n * lands within a couple of device px of the reference at @2x. h4-h6 keep the\n * host\'s size (body size, weight 600) and take the same rhythm.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(h1, h2, h3) {\n margin: 8px 0 6px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h1 {\n font-size: var(--ccd-font-size-h1);\n line-height: 26px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h2 {\n font-size: var(--ccd-font-size-h2);\n line-height: 22px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) h3 {\n font-size: var(--ccd-font-size-h3);\n line-height: 20px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(h4, h5, h6) {\n margin: 10px 0 6px;\n}\n\n/*\n * Block rhythm. The host spaces the transcript\'s blocks at 16px. The reference\n * runs tighter around prose and quotes \u2014 its crop puts a paragraph-to-quote and\n * a quote-to-list run at 18 device px of ink, which is ~7-10px of collapsed\n * margin once each block\'s half-leading is taken off \u2014 while its lists and its\n * table and code cards keep the host\'s step. Only the two that differ move;\n * list items keep the host\'s own 8px rhythm.\n *\n * The list guard is written on the paragraph \u2014 `p:not(li p)` \u2014 and not as a\n * `:not(li) > p` child of the root: a paragraph in this DOM is the root\'s own\n * child, and a descendant combinator there asks for a parent *below* the root,\n * so it matched nothing but the paragraphs nested one level deeper (a quote\'s)\n * and every top-level paragraph kept the host\'s 16px.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) p:not(li p) {\n margin: 10px 0;\n}\n\n/*\n * Blockquote. The host draws a 2px rule in `--dsw-alias-label-caption` \u2014 its\n * own mid grey \u2014 and leaves the text at full body ink, so a quote reads as an\n * indented paragraph rather than as a quote. The reference draws a 4px rule in\n * the same value as this plugin\'s outline token, with its text one step down in\n * ink (this plugin\'s secondary step, against a body that stays near-black). The\n * rule-to-text distance matches in both (27 and 29 device px), so only the\n * rule\'s weight, its colour and the text\'s ink move.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) blockquote {\n margin: 10px 0;\n border-left: 4px solid var(--ccd-border);\n padding-left: 15px;\n color: var(--ccd-text-secondary);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) hr {\n /* The host spaces the rule at 32px on each side; the reference\'s crop puts\n its card-rule-copy run at 71 device px of ink, which is ~20px a side. */\n margin: 20px 0;\n}\n\n/*\n * List rhythm. The host sizes its marker\'s own line at the 24px it used to draw\n * the body at, so the marker box stands a step taller than the transcript\'s\n * leading and stretches every list row to 22px \u2014 the item pitch lands at 28\n * where the reference\'s own rows measure 26 (its 40 device px at 1.53). The\n * marker rides the item\'s line instead, which is what a browser that sets no\n * marker line at all would do.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) li::marker {\n line-height: inherit;\n}\n\n/*\n * Task lists. The host leaves the list marker in place, so a `- [x]` row draws\n * "\u2022 \u2611 label" where the reference draws the checkbox alone, and its 6px\n * inter-item margin \u2014 which the reference\'s own rows do not carry \u2014 widens the\n * pitch to 46 device px against the reference\'s 35. The marker goes and the\n * margin goes with it; the checkbox itself already matches (the reference\'s\n * fill measures the same 20 device px in the host\'s grey accent).\n *\n * The checkbox sits directly in the item in a tight list and inside the item\'s\n * paragraph in a loose one, so both shapes are named.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(li:has(> input[type="checkbox"]), li:has(> p:first-child > input[type="checkbox"])) {\n list-style: none;\n margin-top: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) input[type="checkbox"] {\n /* The host\'s 8px trailing margin leaves 20 device px before the label where\n the reference leaves 10. */\n margin-right: 6px;\n}\n\n/*\n * Fenced code blocks take the reference\'s outlined card: a white fill inside a\n * single hairline, replacing the host\'s cool wash. The host paints three nested\n * surfaces with that wash \u2014 the wrapper, the language banner and `pre` itself \u2014\n * and the banner\'s outer wrapper falls back to the page token, so every one of\n * them is repainted here; leaving any single layer would show a grey band.\n *\n * `data-code-wrap` is a stable host anchor (the class list also carries\n * `md-code-block`); the inner layers are reached through it so no hashed class\n * name is repeated here.\n *\n * The card is also a *row*, because the reference\'s is. Its one-line fence\n * draws as a single 33px-tall card (50 device px at @2x) that hugs its content \u2014\n * code first, the copy control (and the wrap toggle, and the run control on a\n * shell fence) trailing it \u2014 and floors at 320px, which is why its own short\n * `npm run check` card carries a wide gap between the code and its controls.\n * The host instead fills the column and stacks a 36px language banner over a\n * `pre` padded `6px 22px 20px`, which is 135 device px for that same one line.\n *\n * So the block becomes a flex row with the banner reversed behind the code: the\n * banner\'s controls ride the first code line, the `pre` takes the row\'s spare\n * width (pushing those controls to the trailing edge exactly as the reference\'s\n * floored card does) and the column stays the ceiling. `min(320px, 100%)` keeps\n * a narrow transcript from being pushed out by the floor.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] {\n box-sizing: border-box;\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-code-radius);\n background: var(--ccd-card);\n display: flex;\n /* The banner is the DOM\'s first child; the code reads first. */\n flex-direction: row-reverse;\n align-items: flex-start;\n width: fit-content;\n min-width: min(320px, 100%);\n max-width: 100%;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] > *,\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner],\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] pre {\n /* The card owns the surface now; the layers inside it only carry text. */\n background: transparent;\n border-radius: 0;\n}\n\n/*\n * The banner stops being a row above the code. Its wrapper is the sticky\n * scroller that used to pin the language row to the top of a tall card; in a\n * row it is the card\'s trailing control strip, seated on the first code line\n * (31px = the `pre`\'s 6px padding over the host\'s 19px code line), which is the\n * whole card when the fence is one line. The host\'s own compact variant\n * neutralises the same wrapper the same way.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] > :has(> [data-code-block-banner]) {\n position: static;\n z-index: auto;\n display: flex;\n align-items: center;\n height: 31px;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner] {\n width: 100%;\n /* 11px, not 12: the card\'s own 1px outline sits outside this padding and the\n reference measures its 18 device px from the card\'s outer edge. */\n padding: 0 11px 0 0;\n font: inherit;\n}\n\n/*\n * The language label is not painted: the reference\'s card shows the code and its\n * controls alone, and its short card is 320px wide for 90px of code precisely\n * because nothing else sits in that row. The label is the banner\'s leading\n * group in both of the host\'s toolbar shapes, so it is named structurally\n * rather than by its hashed class; the copy and wrap controls, their labels and\n * the run control on a shell fence all stay.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] [data-code-block-banner] > :first-child {\n display: none;\n}\n\n/*\n * The code keeps the host\'s 19px line and takes the reference\'s size (one step\n * under the body, where the host draws it at 11px) and its padding: the\n * reference holds the line with ~6px above and below and 16px of leading inset\n * (26 device px at @2x), against the host\'s `6px 22px 20px`. `min-width: 0`\n * lets the code shrink below its own content when the wrap toggle is off.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) [data-code-wrap] pre {\n flex: 1 1 auto;\n min-width: 0;\n padding: 6px 16px;\n font-size: var(--ccd-font-size-muted);\n}\n\n/*\n * Tables: one rounded card, as in the reference. The host collapses borders,\n * takes every cell\'s leading padding away (`padding: 10px 16px 10px 0`) and\n * leaves the row rule to each cell, so a card that can carry a radius needs\n * separate borders, one outline of its own and its own cell padding. The head\n * keeps a filled surface and a rule one step darker than the outline; body rows\n * are separated by hairlines, and the card\'s own edge closes the last one.\n * Column alignment markers stay the host\'s business.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) table {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n border: 1px solid var(--ccd-border);\n border-radius: var(--ccd-table-radius);\n border-collapse: separate;\n border-spacing: 0;\n /* The head fill and the row rules are painted by the cells, so the card has\n to clip them to its own radius. */\n overflow: hidden;\n font-size: inherit;\n line-height: inherit;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) :is(th, td) {\n /* The host sizes table text one step below the transcript; the reference\n keeps a table at body size. Its row is 33px \u2014 the transcript\'s 20px line\n with 6px above and below, which is the 51 device px both shots measure \u2014\n so the cells keep the body leading and pay the difference in padding. */\n font-size: inherit;\n line-height: inherit;\n padding: 6px 10px;\n border: 0;\n border-bottom: 1px solid var(--ccd-border);\n vertical-align: middle;\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) thead th {\n background: var(--ccd-raised);\n border-bottom-color: var(--ccd-table-head-line);\n color: var(--ccd-text);\n font-weight: var(--ccd-font-weight-strong);\n}\n\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root ._markdown_1ypvv_5:not([data-markdown-variant="compact"]) tbody tr:last-child :is(th, td) {\n border-bottom: 0;\n}\n\n/*\n * Wide tables stay inside the content column.\n *\n * The host marks every table of four columns or more `md-table-wide`\n * (AssistantMarkdown.module.css) and bleeds that wrapper out to the scroller\'s\n * full width through `--dsh-table-spare`\uFF0F`--dsh-table-lead`, pinning the table\'s\n * leading edge back to the column with a negative margin and a matching leading\n * pad. In the host\'s own geometry the Composer card is 32px wider than the\n * column, so the borrowed width lands inside its edges; here the card and the\n * column are the same width, and a bleeded table left the card and the Composer\n * on different right edges (measured +86px at the reference window, growing with\n * the view area). Dropping the bleed keeps the table on the column; a table\n * whose rows cannot wrap far enough still uses the host\'s own `md-table-wide`\n * scroll, which needs the wrapper\'s own `overflow-x` and scrollbar gutter, so\n * neither is touched here.\n */\nhtml[data-dsh-ccd-style="true"] .gKv1-q_root .gKv1-q_body .md-table-wide {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n margin-left: 0;\n padding-left: 0;\n}\n\nhtml[data-dsh-ccd-style="true"] .icaHSq_column {\n --dsh-chat-flow-gap: 10px;\n}\n\n/* User message: soft raised bubble, as in the reference. */\nhtml[data-dsh-ccd-style="true"] .IzP3Va_bubble {\n padding: 7px 14px;\n border-radius: var(--ccd-composer-radius);\n background: var(--ccd-raised);\n color: var(--ccd-text);\n font-size: var(--dsh-content-font-size, 14px);\n line-height: 22px;\n}\n\nhtml[data-dsh-ccd-style="true"] .IzP3Va_userStack {\n max-width: min(calc(var(--dsh-chat-content-width) * 0.72), 82%);\n gap: 6px;\n}\n\n/* Tool and reasoning rows: quiet single lines. */\nhtml[data-dsh-ccd-style="true"] .Q2dzhW_root,\nhtml[data-dsh-ccd-style="true"] .HiSsxa_root,\nhtml[data-dsh-ccd-style="true"] .-gRAhq_root {\n color: var(--ccd-text-secondary);\n font-size: var(--ccd-font-size-body);\n}\n';
|
|
10949
11295
|
|
|
10950
11296
|
// src/client/features/conversation/view-switch-icons.ts
|
|
10951
11297
|
var VIEW_SWITCH_ICONS = Object.freeze({
|