@oversk7/pi-web-dsh-style 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
package/web/index.html CHANGED
@@ -8,11 +8,15 @@
8
8
  <link rel="manifest" href="/manifest.webmanifest" />
9
9
  <title>Pi Web</title>
10
10
  <link rel="stylesheet" href="/app.css" />
11
+ <link rel="stylesheet" href="/themes.css" />
11
12
  </head>
12
13
  <body>
13
14
  <script>
14
15
  (() => {
15
- const preference = localStorage.getItem("pi-web-theme") || "system";
16
+ const saved = localStorage.getItem("pi-web-theme");
17
+ const preference = ["light", "dark", "system"].includes(saved) ? saved : "system";
18
+ const style = localStorage.getItem("pi-web-theme-style");
19
+ document.body.dataset.themeStyle = ["classic", "sakura", "starlight"].includes(style) ? style : "classic";
16
20
  const systemDark = preference === "system" && matchMedia("(prefers-color-scheme: dark)").matches;
17
21
  const dark = preference === "dark" || systemDark;
18
22
  document.documentElement.style.colorScheme = dark ? "dark" : "light";
@@ -0,0 +1,118 @@
1
+ import MarkdownIt from "markdown-it";
2
+ import hljs from "highlight.js/lib/common";
3
+ import dockerfile from "highlight.js/lib/languages/dockerfile";
4
+ import powershell from "highlight.js/lib/languages/powershell";
5
+
6
+ hljs.registerLanguage("dockerfile", dockerfile);
7
+ hljs.registerLanguage("powershell", powershell);
8
+
9
+ function localFileLink(target: string) {
10
+ let value = target.trim();
11
+ let line: number | null = null;
12
+ const location = /#L(\d+)(?:C\d+)?$/i.exec(value) || /:(\d+)(?::\d+)?$/.exec(value);
13
+ if (location) {
14
+ line = Number(location[1]);
15
+ value = value.slice(0, location.index);
16
+ }
17
+ if (/^file:\/\/\//i.test(value)) {
18
+ try {
19
+ value = decodeURIComponent(new URL(value).pathname).replace(/^\/([A-Za-z]:[\\/])/, "$1");
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ value = value.replace(/^\/([A-Za-z]:[\\/])/, "$1");
25
+ if (!/^[A-Za-z]:[\\/]/.test(value) && !/^\\\\[^\\]+\\[^\\]+/.test(value)) return null;
26
+ const href = `/api/fs/view?path=${encodeURIComponent(value)}${line ? `#L${line}` : ""}`;
27
+ return { path: value, line, href };
28
+ }
29
+
30
+ const parser = new MarkdownIt({ html: false, breaks: false, linkify: true });
31
+ const InlineState = parser.inline.State;
32
+ parser.inline.State = class extends InlineState {
33
+ scanDelims(start: number, canSplitWord: boolean) {
34
+ const scanned = super.scanDelims(start, canSplitWord);
35
+ if (this.src[start] !== "*" || scanned.length < 2) return scanned;
36
+ const before = this.src.slice(Math.max(0, start - 2), start);
37
+ const end = start + scanned.length;
38
+ const after = end < this.posMax ? String.fromCodePoint(this.src.codePointAt(end)!) : "";
39
+ // Chinese punctuation can border emphasis even beside Latin text or numbers.
40
+ const cjkPunctuation = /[\u2000-\u206f\u3000-\u303f\uff00-\uffef]/u;
41
+ if (/^\p{P}/u.test(after) && (cjkPunctuation.test(after) || /\p{Script=Han}$/u.test(before))) scanned.can_open = true;
42
+ if (/\p{P}$/u.test(before) && (cjkPunctuation.test(before.slice(-1)) || /^\p{Script=Han}/u.test(after))) scanned.can_close = true;
43
+ return scanned;
44
+ }
45
+ };
46
+ const escape = parser.utils.escapeHtml;
47
+ const normalizeLink = parser.normalizeLink;
48
+ const validateLink = parser.validateLink;
49
+ parser.normalizeLink = (target) => localFileLink(target) ? target : normalizeLink(target);
50
+ parser.validateLink = (target) => Boolean(localFileLink(target)) || validateLink(target);
51
+
52
+ parser.renderer.rules.link_open = (tokens, index, options, env, renderer) => {
53
+ const token = tokens[index];
54
+ const target = String(token.attrGet("href") || "");
55
+ const local = localFileLink(target);
56
+ if (local) {
57
+ token.attrSet("href", local.href);
58
+ token.attrJoin("class", "md-local-file");
59
+ token.attrSet("data-file-path", local.path);
60
+ token.attrSet("data-file-line", local.line ? String(local.line) : "");
61
+ token.attrSet("title", `${local.path}${local.line ? `:${local.line}` : ""}`);
62
+ } else if (/^https?:\/\//i.test(target)) {
63
+ token.attrSet("target", "_blank");
64
+ token.attrSet("rel", "noopener noreferrer");
65
+ }
66
+ return renderer.renderToken(tokens, index, options);
67
+ };
68
+
69
+ const renderImage = parser.renderer.rules.image!;
70
+ parser.renderer.rules.image = (tokens, index, options, env, renderer) => {
71
+ const local = localFileLink(String(tokens[index].attrGet("src") || ""));
72
+ if (local) tokens[index].attrSet("src", `/api/fs/view?path=${encodeURIComponent(local.path)}&format=image`);
73
+ tokens[index].attrSet("loading", "lazy");
74
+ tokens[index].attrSet("decoding", "async");
75
+ tokens[index].attrSet("referrerpolicy", "no-referrer");
76
+ return renderImage(tokens, index, options, env, renderer);
77
+ };
78
+
79
+ parser.renderer.rules.fence = (tokens, index) => {
80
+ const token = tokens[index];
81
+ const language = token.info.trim().split(/\s+/)[0];
82
+ let code = escape(token.content);
83
+ // Bound synchronous highlighting work while streaming large tool-generated snippets.
84
+ if (language && hljs.getLanguage(language) && token.content.length <= 32 * 1024) {
85
+ code = hljs.highlight(token.content, { language, ignoreIllegals: true }).value;
86
+ }
87
+ const label = language ? `<div class="md-code-language">${escape(language)}</div>` : "";
88
+ return `<div class="md-code-container">${label}<pre class="md-code-block"><code class="hljs">${code}</code></pre></div>\n`;
89
+ };
90
+ parser.renderer.rules.code_block = (tokens, index) => `<pre class="md-code-block"><code>${escape(tokens[index].content)}</code></pre>\n`;
91
+ parser.renderer.rules.table_open = () => '<div class="md-table-wrap"><table>\n';
92
+ parser.renderer.rules.table_close = () => '</table></div>\n';
93
+
94
+ parser.core.ruler.after("inline", "task_lists", (state) => {
95
+ for (let i = 2; i < state.tokens.length; i += 1) {
96
+ const token = state.tokens[i];
97
+ const paragraph = state.tokens[i - 1];
98
+ const item = state.tokens[i - 2];
99
+ if (token.type !== "inline" || paragraph.type !== "paragraph_open" || item.type !== "list_item_open") continue;
100
+ const first = token.children?.[0];
101
+ if (first?.type !== "text") continue;
102
+ const match = /^\[([ xX])\](?:\s+|$)/.exec(first.content);
103
+ if (!match) continue;
104
+ first.content = first.content.slice(match[0].length);
105
+ const checkbox = new state.Token("task_checkbox", "input", 0);
106
+ checkbox.meta = { checked: match[1].toLowerCase() === "x" };
107
+ token.children!.unshift(checkbox);
108
+ item.attrJoin("class", "md-task-item");
109
+ }
110
+ });
111
+ parser.renderer.rules.task_checkbox = (tokens, index) => {
112
+ const checked = tokens[index].meta!.checked;
113
+ return `<input type="checkbox" disabled${checked ? " checked" : ""} aria-label="${checked ? "已完成" : "未完成"}"/> `;
114
+ };
115
+
116
+ export function markdown(src: unknown): string {
117
+ return parser.render(String(src ?? ""));
118
+ }
@@ -0,0 +1,11 @@
1
+ export interface WebSlashCommand {
2
+ name: string;
3
+ description: string;
4
+ acceptsArgs?: boolean;
5
+ source: string;
6
+ local: boolean;
7
+ }
8
+ export const webSlashCommands: WebSlashCommand[];
9
+ export const unsupportedSlashCommands: Record<string, string>;
10
+ export function parseSlashCommand(text: string): { name: string; args: string } | null;
11
+ export function builtinCommandError(name: string): string | null;
@@ -0,0 +1,46 @@
1
+ // Shared by the browser and server so built-in commands never fall through to RPC prompts.
2
+ export const webSlashCommands = [
3
+ { name: "settings", description: "打开界面与运行时设置" },
4
+ { name: "model", description: "选择当前模型", acceptsArgs: true },
5
+ { name: "thinking", description: "选择思考强度", acceptsArgs: true },
6
+ { name: "export", description: "将当前会话下载为 HTML" },
7
+ { name: "copy", description: "复制最后一条助手回复" },
8
+ { name: "name", description: "设置当前会话名称", acceptsArgs: true },
9
+ { name: "session", description: "显示会话统计信息" },
10
+ { name: "new", description: "在当前工作区创建新会话" },
11
+ { name: "resume", description: "打开侧栏搜索并切换会话" },
12
+ { name: "rewind", description: "回溯对话,可选择同步恢复文件" },
13
+ { name: "tree", description: "打开当前会话的分支树" },
14
+ { name: "compact", description: "压缩当前会话,可附加压缩要求", acceptsArgs: true },
15
+ { name: "reload", description: "重新加载当前会话的扩展与配置" },
16
+ ].map((command) => ({ ...command, source: "builtin", local: true }));
17
+
18
+ export const unsupportedSlashCommands = {
19
+ "scoped-models": "Web 暂不支持终端模型轮换范围,请使用 /model 选择模型。",
20
+ import: "Web 暂不支持从命令导入 JSONL 文件,请在 Pi 终端执行 /import。",
21
+ share: "Web 暂不支持发布 GitHub gist,请使用 /export 下载会话,或在 Pi 终端执行 /share。",
22
+ fork: "Web 暂不支持创建分叉副本,请在 Pi 终端执行 /fork;同一会话内切换分支可使用 /tree。",
23
+ clone: "Web 暂不支持复制整个会话,请在 Pi 终端执行 /clone。",
24
+ trust: "项目信任设置需要在 Pi 终端中通过 /trust 管理。",
25
+ changelog: "Web 暂不展示 Pi 更新日志,请在 Pi 终端执行 /changelog。",
26
+ hotkeys: "终端快捷键不适用于网页。网页输入框支持 Enter 发送、Shift+Enter 换行,命令菜单支持方向键选择和 Tab 补全。",
27
+ debug: "此调试命令仅支持 Pi 终端。",
28
+ arminsayshi: "此彩蛋命令仅支持 Pi 终端。",
29
+ dementedelves: "此彩蛋命令仅支持 Pi 终端。",
30
+ login: "Web 暂不支持登录流程,请在启动 Pi 的终端执行 /login。",
31
+ logout: "Web 暂不支持注销流程,请在启动 Pi 的终端执行 /logout。",
32
+ quit: "请关闭网页标签页;如需退出 Pi,请在启动 Pi 的终端执行 /quit。",
33
+ };
34
+
35
+ export function parseSlashCommand(text) {
36
+ const match = /^\/([^\s]+)(?:\s+([\s\S]*))?$/.exec(text.trim());
37
+ return match ? { name: match[1], args: (match[2] || "").trim() } : null;
38
+ }
39
+
40
+ export function builtinCommandError(name) {
41
+ if (Object.hasOwn(unsupportedSlashCommands, name)) return unsupportedSlashCommands[name];
42
+ if (webSlashCommands.some((command) => command.name === name)) {
43
+ return `/${name} 需要由 Web 命令入口执行,请刷新网页后重试。`;
44
+ }
45
+ return null;
46
+ }
package/web/themes.css ADDED
@@ -0,0 +1,158 @@
1
+ body[data-theme-style=classic][data-custom-background]{
2
+ --pi-base:#f9fafb;--pi-surface:#fff;--pi-raised:#fff;--pi-soft:#f1f3f5;--pi-sidebar:#f5f6f7;
3
+ --pi-text:#0f1115;--pi-secondary:#50555e;--pi-muted:#656b76;--pi-accent:#416ee5;--pi-on-accent:#fff;
4
+ --pi-tint:#e4edfd;--pi-border:#dbe0e9;--pi-code:#f5f6f8;--pi-code-banner:#eceff4;
5
+ --pi-art:none;--pi-scene-wash:rgba(249,250,251,.12);--pi-shadow:0 12px 40px rgb(30 40 60 / .12);
6
+ }
7
+ body[data-theme-style=classic][data-custom-background][data-ds-dark-theme]{
8
+ --pi-base:#151517;--pi-surface:#232324;--pi-raised:#353638;--pi-soft:#2c2c2e;--pi-sidebar:#1b1b1c;
9
+ --pi-text:#f5f6f7;--pi-secondary:#cfd3d6;--pi-muted:#adb2b8;--pi-accent:#a5bbff;--pi-on-accent:#182344;
10
+ --pi-tint:#30394e;--pi-border:#454850;--pi-code:#1b1b1c;--pi-code-banner:#2c2c2e;
11
+ --pi-scene-wash:rgba(21,21,23,.2);--pi-shadow:0 12px 40px rgb(0 0 0 / .22);
12
+ }
13
+ body[data-theme-style=sakura]{
14
+ --pi-base:#fff9fb;--pi-surface:#fffdfd;--pi-raised:#fff;--pi-soft:#f8edf3;--pi-sidebar:#f8eef3;
15
+ --pi-text:#382d3b;--pi-secondary:#6c5366;--pi-muted:#876779;--pi-accent:#ac406e;--pi-on-accent:#fff;
16
+ --pi-tint:#f5dfeb;--pi-border:#e9d6e1;--pi-code:#f8f1f6;--pi-code-banner:#f1e7ef;
17
+ --pi-art:url('/assets/themes/sakura.webp');--pi-scene-wash:rgba(255,249,251,.12);
18
+ --pi-shadow:0 12px 40px rgb(114 54 88 / .09);
19
+ }
20
+ body[data-theme-style=sakura][data-ds-dark-theme]{
21
+ --pi-base:#211c28;--pi-surface:#2b2432;--pi-raised:#352c3e;--pi-soft:#342a3b;--pi-sidebar:#251e2e;
22
+ --pi-text:#f3e7f0;--pi-secondary:#cfbace;--pi-muted:#b99eb4;--pi-accent:#efa7c8;--pi-on-accent:#362032;
23
+ --pi-tint:#4c3149;--pi-border:#4d3b51;--pi-code:#241e2d;--pi-code-banner:#312738;
24
+ --pi-scene-wash:rgba(33,28,40,.46);--pi-shadow:0 12px 40px rgb(0 0 0 / .18);
25
+ }
26
+ body[data-theme-style=starlight]{
27
+ --pi-base:#f6f8ff;--pi-surface:#fcfcff;--pi-raised:#fff;--pi-soft:#eaf0fb;--pi-sidebar:#eaf0fb;
28
+ --pi-text:#263252;--pi-secondary:#506084;--pi-muted:#657398;--pi-accent:#5553b6;--pi-on-accent:#fff;
29
+ --pi-tint:#e3e4fb;--pi-border:#d5def0;--pi-code:#eef1fa;--pi-code-banner:#e5e9f5;
30
+ --pi-art:url('/assets/themes/starlight.webp');--pi-scene-wash:rgba(246,248,255,.16);
31
+ --pi-shadow:0 12px 40px rgb(61 79 131 / .1);
32
+ }
33
+ body[data-theme-style=starlight][data-ds-dark-theme]{
34
+ --pi-base:#141b2e;--pi-surface:#1c253c;--pi-raised:#28324f;--pi-soft:#242f49;--pi-sidebar:#172037;
35
+ --pi-text:#e6edff;--pi-secondary:#b8c7e8;--pi-muted:#9aaccf;--pi-accent:#b6afff;--pi-on-accent:#222040;
36
+ --pi-tint:#35345a;--pi-border:#394563;--pi-code:#151e32;--pi-code-banner:#202a42;
37
+ --pi-scene-wash:rgba(20,27,46,.08);--pi-shadow:0 12px 40px rgb(0 0 0 / .22);
38
+ }
39
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]){
40
+ --dsw-alias-bg-base:var(--pi-base);
41
+ --dsw-alias-bg-layer-1:var(--pi-surface);--dsw-alias-bg-layer-2:var(--pi-surface);--dsw-alias-bg-layer-3:var(--pi-raised);
42
+ --dsw-alias-bg-module-platform:var(--pi-soft);--dsw-alias-bg-multi-select:var(--pi-soft);--dsw-alias-bg-overlay:var(--pi-tint);
43
+ --dsw-alias-label-primary:var(--pi-text);--dsw-alias-label-primary-dimmed:var(--pi-text);--dsw-alias-label-primary-bluish:var(--pi-accent);
44
+ --dsw-alias-label-secondary:var(--pi-secondary);--dsw-alias-label-tertiary:var(--pi-muted);--dsw-alias-label-caption:var(--pi-muted);
45
+ --dsw-alias-label-primary-foreground:var(--pi-on-accent);--dsw-alias-label-primary-inverted:var(--pi-on-accent);
46
+ --dsw-alias-brand-primary:var(--pi-accent);--dsw-alias-brand-primary-invert:var(--pi-accent);--dsw-alias-brand-text:var(--pi-text);
47
+ --dsw-alias-state-business-primary:var(--pi-accent);--dsw-alias-state-business-tertiary:var(--pi-tint);
48
+ --dsw-alias-border-l1:color-mix(in srgb,var(--pi-border) 65%,transparent);
49
+ --dsw-alias-border-l2:var(--pi-border);--dsw-alias-border-l2-darkmode-thin:var(--pi-border);
50
+ --dsw-alias-border-l3:color-mix(in srgb,var(--pi-border) 65%,var(--pi-muted));--dsw-alias-border-l4:var(--pi-muted);
51
+ --dsw-alias-button-primary-fill:var(--pi-accent);--dsw-alias-button-primary-hover:color-mix(in srgb,var(--pi-accent) 85%,var(--pi-text));
52
+ --dsw-alias-button-info-fill:var(--pi-accent);--dsw-alias-button-info-hover:color-mix(in srgb,var(--pi-accent) 85%,var(--pi-text));
53
+ --dsw-alias-button-primary-dimmed:var(--pi-border);--dsw-alias-button-elevated-fill:var(--pi-surface);
54
+ --dsw-alias-button-floating-fill:var(--pi-raised);--dsw-alias-button-floating-hover:var(--pi-soft);
55
+ --dsw-alias-button-ghost-active-fill:var(--pi-tint);--dsw-alias-button-ghost-active-hover:var(--pi-soft);
56
+ --dsw-alias-interactive-bg-hover:color-mix(in srgb,var(--pi-accent) 8%,transparent);
57
+ --dsw-alias-interactive-bg-hover-accent:color-mix(in srgb,var(--pi-accent) 16%,transparent);
58
+ --dsw-alias-interactive-bg-active:var(--pi-tint);--dsw-alias-interactive-bg-hover-solid:var(--pi-soft);
59
+ --dsw-alias-markdown-code-block:var(--pi-code);--dsw-alias-markdown-code-block-banner:var(--pi-code-banner);
60
+ --dsw-alias-markdown-inline-code:var(--pi-soft);--dsw-alias-markdown-citation:var(--pi-tint);
61
+ --dsw-alias-markdown-code-segment-selected:var(--pi-raised);--dsw-alias-markdown-code-segment-unselected:var(--pi-code);
62
+ --dsw-alias-markdown-placeholder:var(--pi-soft);--dsw-alias-markdown-tag:var(--pi-soft);
63
+ --dsw-specific-bubble:var(--pi-tint);--dsw-specific-bubble-highlight:var(--pi-border);
64
+ --dsw-specific-input-major:var(--pi-surface);--dsw-specific-selector:var(--pi-soft);--dsw-specific-tip:var(--pi-soft);
65
+ --dsw-specific-sidebar-fill:var(--pi-sidebar);--dsw-specific-sidebar-nav-item-active:var(--pi-tint);
66
+ --dsw-specific-sidebar-nav-item-active-accent:var(--pi-tint);--dsw-specific-sidebar-nav-item-hover:var(--pi-soft);
67
+ --dsw-alias-scrollbar-bg-l1:var(--pi-border);--dsw-alias-scrollbar-bg-l2:var(--pi-border);
68
+ --dsw-alias-scrollbar-hover-l1:var(--pi-muted);--dsw-alias-scrollbar-hover-l2:var(--pi-muted);
69
+ --dsw-linear-gradient-think:linear-gradient(180deg,var(--pi-base) 20%,transparent);
70
+ --dsw-linear-think-select:linear-gradient(180deg,var(--pi-soft) 20%,transparent);
71
+ }
72
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pI_x6G_frame{
73
+ background-image:linear-gradient(var(--pi-scene-wash),var(--pi-scene-wash)),var(--pi-background-image,var(--pi-art));
74
+ background-size:cover;background-position:center;background-repeat:no-repeat;
75
+ }
76
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) :is(.hHd-Xa_root,.wSkVaW_root){background:transparent}
77
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pI_x6G_sidebarCol{
78
+ background:color-mix(in srgb,var(--pi-sidebar) 62%,transparent);
79
+ backdrop-filter:blur(12px);border-right-color:color-mix(in srgb,var(--pi-raised) 45%,transparent);
80
+ }
81
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .wSkVaW_header{
82
+ background:color-mix(in srgb,var(--pi-surface) 72%,transparent);backdrop-filter:blur(12px);
83
+ }
84
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{background:transparent}
85
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) :is(.uV2eYG_card,.pi-settingsPanel){
86
+ background:color-mix(in srgb,var(--pi-surface) 72%,transparent);
87
+ backdrop-filter:blur(16px);border-color:color-mix(in srgb,var(--pi-raised) 55%,var(--pi-border));
88
+ }
89
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) [data-chat-flow-kind=assistant-text]{
90
+ box-sizing:border-box;padding:18px 22px;border:1px solid color-mix(in srgb,var(--pi-raised) 50%,var(--pi-border));border-radius:20px;
91
+ background:color-mix(in srgb,var(--pi-surface) 78%,transparent);backdrop-filter:blur(8px);box-shadow:var(--pi-shadow);
92
+ }
93
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) :is(.gdEzaW_bubble,.oRe1gG_bubble){
94
+ background:color-mix(in srgb,var(--pi-tint) 74%,transparent);backdrop-filter:blur(8px);
95
+ border:1px solid color-mix(in srgb,var(--pi-raised) 50%,var(--pi-border));box-shadow:var(--pi-shadow);
96
+ }
97
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-compactionCard{
98
+ background:color-mix(in srgb,var(--pi-surface) 84%,transparent);backdrop-filter:blur(8px);
99
+ }
100
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .CY-8Ka_card{
101
+ background:color-mix(in srgb,var(--pi-surface) 48%,transparent);backdrop-filter:blur(8px);border-radius:8px;
102
+ }
103
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .CY-8Ka_root{background:transparent}
104
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .CY-8Ka_card :is(.Sxvs8a_root,.Sxvs8a_body,.Y0dWHa_payload){background:transparent}
105
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .CY-8Ka_card .Y0dWHa_payload{color:var(--pi-text)}
106
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) :is(.pXSMma_headline,.wSkVaW_heroWorkspaceRow){
107
+ align-self:center;max-width:calc(100% - 32px);padding:10px 16px;border:1px solid var(--dsw-alias-border-l2);border-radius:18px;
108
+ background:color-mix(in srgb,var(--pi-surface) 72%,transparent);backdrop-filter:blur(12px);
109
+ }
110
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .wSkVaW_heroWorkspaceRow{align-self:flex-start;margin-left:16px;padding:6px 12px}
111
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .p-xYUq_action{background:color-mix(in srgb,var(--pi-surface) 80%,transparent)}
112
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-filePreview{
113
+ background:color-mix(in srgb,var(--pi-surface) 86%,transparent);backdrop-filter:blur(16px);
114
+ }
115
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-filePreviewScroll{background:transparent}
116
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-settingsSidebar{background:color-mix(in srgb,var(--pi-sidebar) 40%,transparent)}
117
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-settingsBackdrop{background:rgb(15 20 30 / .18);backdrop-filter:blur(3px)}
118
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .wSkVaW_heroGlow{display:none}
119
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pXSMma_headlineText{font-weight:600;letter-spacing:.04em;text-shadow:0 2px 18px var(--pi-base)}
120
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) :is(.pi-settingsActionPrimary,.uV2eYG_primary){color:var(--pi-on-accent)}
121
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .cubgiG_seatIcon text{fill:var(--pi-on-accent)}
122
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .uV2eYG_card{box-shadow:var(--pi-shadow)}
123
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pi-settingsPanel{box-shadow:var(--pi-shadow)}
124
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .hHd-Xa_newSession{border-radius:14px;box-shadow:0 3px 12px color-mix(in srgb,var(--pi-accent) 7%,transparent)}
125
+ .pi-backgroundCard{display:grid;grid-template-columns:96px minmax(0,1fr);gap:14px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
126
+ .pi-backgroundPreview{height:72px;overflow:hidden;border-radius:8px;background-color:var(--dsw-alias-bg-module-platform);background-image:var(--pi-art,none);background-size:cover;background-position:center}
127
+ .pi-backgroundPreview img{width:100%;height:100%;object-fit:cover}
128
+ .pi-backgroundCopy{min-width:0;align-self:center}
129
+ .pi-backgroundCopy strong{display:block;font-size:12px;line-height:20px;overflow-wrap:anywhere}
130
+ .pi-backgroundCopy p{margin:4px 0 0;font-size:11px;line-height:18px;color:var(--dsw-alias-label-secondary)}
131
+ .pi-backgroundActions{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:10px}
132
+ .pi-backgroundError{grid-column:1/-1;margin:0;font-size:12px;line-height:20px;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere}
133
+ .pi-themeModeHeading{margin-top:28px}
134
+ .pi-settingsStyles button{text-align:left}
135
+ .pi-stylePreview{position:relative;display:flex;align-items:end;justify-content:center;height:104px;border-radius:7px;overflow:hidden;background-color:#eef1f6;background-size:cover;background-position:center}
136
+ .pi-stylePreview-classic{background-image:linear-gradient(145deg,#f1f3f9,#dce3f1)}
137
+ .pi-stylePreview-sakura{background-image:url('/assets/themes/sakura.webp')}
138
+ .pi-stylePreview-starlight{background-image:url('/assets/themes/starlight.webp')}
139
+ .pi-stylePreviewWindow{display:flex;flex-direction:column;gap:5px;width:68%;height:42px;padding:10px;margin-bottom:10px;border:1px solid rgb(255 255 255 / .7);border-radius:7px;background:rgb(255 255 255 / .85);box-shadow:0 4px 16px rgb(25 30 60 / .1)}
140
+ .pi-stylePreviewWindow i{display:block;width:68%;height:3px;border-radius:3px;background:#b5bdd2}
141
+ .pi-stylePreviewWindow i:first-child{align-self:end;width:48%;height:10px;background:#d9def0}
142
+ .pi-stylePreviewWindow i:last-child{width:45%}
143
+ .pi-stylePreview-sakura .pi-stylePreviewWindow i{background:#c6a0b8}
144
+ .pi-stylePreview-sakura .pi-stylePreviewWindow i:first-child{background:#f0d1e2}
145
+ .pi-stylePreview-starlight .pi-stylePreviewWindow{background:rgb(24 33 56 / .9);border-color:rgb(184 195 238 / .35)}
146
+ .pi-stylePreview-starlight .pi-stylePreviewWindow i{background:#7f91b5}
147
+ .pi-stylePreview-starlight .pi-stylePreviewWindow i:first-child{background:#66659a}
148
+ .pi-styleDescription{display:block;padding:0 3px 4px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}
149
+ @media(max-width:640px){
150
+ .pi-stylePreview{height:84px}
151
+ .pi-stylePreviewWindow{width:72%;height:34px;padding:7px;margin-bottom:7px}
152
+ .pi-styleDescription{padding:2px 1px;font-size:10px}
153
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pXSMma_headline{grid-template-columns:30px minmax(0,auto);row-gap:8px;margin:0 16px;font-size:22px;line-height:30px}
154
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pXSMma_headlineText{letter-spacing:.02em}
155
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pXSMma_previewBadge{grid-area:2/2;justify-self:start;margin:0}
156
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) [data-chat-flow-kind=assistant-text]{padding:14px;border-radius:16px}
157
+ body:is([data-theme-style=sakura],[data-theme-style=starlight],[data-custom-background]) .pXSMma_headline{padding:10px 12px;margin:0;box-sizing:border-box}
158
+ }