@starwish-ai/xingyuan-dsh 0.6.2 → 0.6.3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.6.3] - 2026-09-06
9
+
10
+ ### Changed
11
+ - **Settings page information architecture**: the former single "chat preferences"
12
+ card is split into two focused cards — "Confirmation before writes" (master
13
+ switch + six category rows + an always-on badge for deletes) and "Chat
14
+ preferences" (memory injection limit + confirmation-card language). Toggle and
15
+ enum settings now follow the settings-row convention used by OS settings pages
16
+ (label + description left, control right, hairline dividers); form fields keep
17
+ the label-above layout. Both themes and narrow viewports verified against the
18
+ static style mock.
19
+ - Confirmation-card language uses a segmented control (consistent with coach
20
+ style / tab visibility) instead of a dropdown; tab visibility chips gain a ✓
21
+ prefix to distinguish multi-select chips from single-select segmented controls.
22
+ - The locked delete category shows an "Always on" badge instead of a disabled
23
+ checkbox: a disabled control read as "broken", the badge states the fact.
24
+ - Coach style hint is static guidance (the segmented buttons already carry the
25
+ current selection).
26
+
27
+ ### Fixed
28
+ - Disabled controls now look disabled: custom toggles and segmented buttons get
29
+ explicit grey-out styling when the settings namespace is read-only or a write
30
+ is in flight (they ignore native disabled rendering).
31
+ - With the write-confirmation master switch off, the locked delete row is no
32
+ longer greyed out — it is not governed by the master switch, and the dimmed
33
+ label contradicted its "Always on" badge.
34
+ - Entering an out-of-range memory injection limit (e.g. 300) shows an
35
+ informational note that the nearest bound was saved, instead of an "enter an
36
+ integer between 5 and 200" error while the clamped value had in fact been
37
+ saved. Genuinely invalid input (non-integers) keeps the inline error.
38
+ - Free-standing hint lines (namespace notice, trailing data note) align with the
39
+ card text column instead of hugging the container's left edge.
40
+ - Memory-limit input: `autocomplete="off"` and tabular numerals; corrected a
41
+ stale style comment.
42
+
8
43
  ## [0.6.2] - 2026-09-06
9
44
 
10
45
  ### Added
@@ -255,27 +255,28 @@ export const ZH_DICT = {
255
255
  'settings.coach.gentle': '温柔型',
256
256
  'settings.coach.strict': '严格型',
257
257
  'settings.coach.humorous': '幽默型',
258
- 'settings.coach.current': '当前:{label}。决定对话语气与人设,也可在对话中说「对我严格一点」。',
258
+ 'settings.coach.hint': '决定对话语气与人设,也可在对话中说「对我严格一点」。',
259
259
  'settings.coach.saved': '教练风格已更新,对后续对话生效',
260
260
  'settings.coach.loadFailed': '加载失败:{error}',
261
261
  'settings.profile.title': '昵称与画像',
262
262
  'settings.profile.nickname': '昵称',
263
263
  'settings.profile.occupation': '职业',
264
264
  'settings.profile.interests': '兴趣',
265
- 'settings.profile.nicknamePlaceholder': '昵称:希望被怎么称呼(留空清除)',
266
- 'settings.profile.occupationPlaceholder': '职业(留空清除)',
267
- 'settings.profile.interestsPlaceholder': '兴趣:用顿号或逗号分隔(如 阅读、跑步)',
265
+ 'settings.profile.nicknamePlaceholder': '希望被怎么称呼',
266
+ 'settings.profile.occupationPlaceholder': '如:教师、产品经理',
267
+ 'settings.profile.interestsPlaceholder': '如:阅读、跑步',
268
268
  'settings.profile.save': '保存画像',
269
269
  'settings.profile.saving': '保存中…',
270
270
  'settings.profile.saved': '画像已保存',
271
- 'settings.profile.sharedHint': '与对话侧共享同一份档案;对话里说「叫我小星」也会更新。',
271
+ 'settings.profile.sharedHint': '留空的字段会被清除;画像与对话侧共享,对话里说「叫我小星」也会更新。',
272
272
  'settings.pref.title': '对话偏好',
273
273
  'settings.pref.unavailable': '当前连接不支持持久化偏好(远程或临时模式),以下选项不可用。',
274
274
  'settings.pref.loading': '偏好加载中…',
275
275
  'settings.pref.notRegistered': '偏好暂不可用(组件未就绪),请稍后重试。',
276
276
  'settings.pref.readOnly': '当前设置为只读,无法保存修改。',
277
- 'settings.pref.confirmWrites': '写操作二次确认',
278
- 'settings.pref.confirmWritesHint': '总开关:开启后按下方类目决定是否弹确认卡,关闭后除删除(始终确认)外一律直接执行。',
277
+ 'settings.confirm.title': '写操作确认',
278
+ 'settings.confirm.master': '总开关',
279
+ 'settings.pref.confirmWritesHint': '开启后按下方类目决定是否弹确认卡;关闭后除删除(始终确认)外一律直接执行。',
279
280
  'settings.pref.confirmOps.group': '确认类目',
280
281
  'settings.pref.confirmOps.create': '创建愿望/任务(含微行动拆解)',
281
282
  'settings.pref.confirmOps.checkin': '打卡',
@@ -284,11 +285,13 @@ export const ZH_DICT = {
284
285
  'settings.pref.confirmOps.update': '修改愿望/任务/分类',
285
286
  'settings.pref.confirmOps.memorySave': '保存记忆',
286
287
  'settings.pref.confirmOps.delete': '删除(含批量、微行动重开)',
288
+ 'settings.pref.confirmOps.locked': '始终开启',
287
289
  'settings.pref.confirmOps.deleteHint': '始终确认,不可关闭:删除不可恢复。',
288
290
  'settings.pref.confirmOps.hint': '类目明细在总开关开启时生效;默认与之前版本一致。',
289
291
  'settings.pref.memoryLimit': '记忆注入上限',
290
292
  'settings.pref.memoryLimitHint': '每次对话自动注入上下文的记忆条数上限(5-200,默认 40);失焦后保存。',
291
293
  'settings.pref.limitInvalid': '请输入 5-200 的整数',
294
+ 'settings.pref.limitClamped': '超出 5-200 范围,已按最近的边界值保存',
292
295
  'settings.pref.writeFailed': '保存未生效,请重试。',
293
296
  'settings.pref.confirmLang': '确认卡语言',
294
297
  'settings.pref.confirmLangHint': '对话中写操作确认卡与问题的显示语言。确认卡无法自动跟随界面语言,需在此选择;默认中文。',
@@ -684,27 +687,28 @@ const EN_DICT = {
684
687
  'settings.coach.gentle': 'Gentle',
685
688
  'settings.coach.strict': 'Strict',
686
689
  'settings.coach.humorous': 'Humorous',
687
- 'settings.coach.current': 'Current: {label}. Shapes the coaching tone; you can also say “be tougher on me” in chat.',
690
+ 'settings.coach.hint': 'Shapes the coaching tone; you can also say “be tougher on me” in chat.',
688
691
  'settings.coach.saved': 'Coach style updated; applies to future chats',
689
692
  'settings.coach.loadFailed': 'Failed to load: {error}',
690
693
  'settings.profile.title': 'Nickname & profile',
691
694
  'settings.profile.nickname': 'Nickname',
692
695
  'settings.profile.occupation': 'Occupation',
693
696
  'settings.profile.interests': 'Interests',
694
- 'settings.profile.nicknamePlaceholder': 'Nickname: how should I call you? (empty clears)',
695
- 'settings.profile.occupationPlaceholder': 'Occupation (empty clears)',
696
- 'settings.profile.interestsPlaceholder': 'Interests: separate with commas (e.g. reading, running)',
697
+ 'settings.profile.nicknamePlaceholder': 'How should I call you?',
698
+ 'settings.profile.occupationPlaceholder': 'e.g. teacher, product manager',
699
+ 'settings.profile.interestsPlaceholder': 'e.g. reading, running',
697
700
  'settings.profile.save': 'Save profile',
698
701
  'settings.profile.saving': 'Saving…',
699
702
  'settings.profile.saved': 'Profile saved',
700
- 'settings.profile.sharedHint': 'Shared with the chat side; saying “call me Star” in chat updates it too.',
703
+ 'settings.profile.sharedHint': 'Empty fields are cleared. The profile is shared with chat; saying “call me Star” updates it too.',
701
704
  'settings.pref.title': 'Chat preferences',
702
705
  'settings.pref.unavailable': 'This connection cannot persist preferences (remote or temporary mode); the options below are disabled.',
703
706
  'settings.pref.loading': 'Loading preferences…',
704
707
  'settings.pref.notRegistered': 'Preferences are unavailable right now (component not ready); please retry later.',
705
708
  'settings.pref.readOnly': 'Settings are read-only; changes cannot be saved.',
706
- 'settings.pref.confirmWrites': 'Confirm write actions',
707
- 'settings.pref.confirmWritesHint': 'Master switch: when on, confirmations follow the categories below; when off, everything except deletes (always confirmed) runs directly.',
709
+ 'settings.confirm.title': 'Confirmation before writes',
710
+ 'settings.confirm.master': 'Master switch',
711
+ 'settings.pref.confirmWritesHint': 'When on, confirmations follow the categories below; when off, everything except deletes (always confirmed) runs directly.',
708
712
  'settings.pref.confirmOps.group': 'Confirmation categories',
709
713
  'settings.pref.confirmOps.create': 'Create wishes/tasks (incl. micro-action plans)',
710
714
  'settings.pref.confirmOps.checkin': 'Check-ins',
@@ -713,11 +717,13 @@ const EN_DICT = {
713
717
  'settings.pref.confirmOps.update': 'Editing wishes/tasks/categories',
714
718
  'settings.pref.confirmOps.memorySave': 'Saving memories',
715
719
  'settings.pref.confirmOps.delete': 'Deletes (incl. batch & restarts)',
720
+ 'settings.pref.confirmOps.locked': 'Always on',
716
721
  'settings.pref.confirmOps.deleteHint': 'Always confirms and cannot be turned off; deletes are irreversible.',
717
722
  'settings.pref.confirmOps.hint': 'Category switches apply while the master switch is on; defaults match previous versions.',
718
723
  'settings.pref.memoryLimit': 'Memory injection limit',
719
724
  'settings.pref.memoryLimitHint': 'Max memories auto-injected per chat (5-200, default 40); saved when you leave the field.',
720
725
  'settings.pref.limitInvalid': 'Enter an integer between 5 and 200',
726
+ 'settings.pref.limitClamped': 'Out of the 5-200 range; saved as the nearest allowed value.',
721
727
  'settings.pref.writeFailed': 'The change did not save; please try again.',
722
728
  'settings.pref.confirmLang': 'Confirm card language',
723
729
  'settings.pref.confirmLangHint': 'Language of the in-chat confirmation card and its question. The card cannot follow the interface language automatically, so pick it here; defaults to Chinese.',
@@ -49,9 +49,10 @@ export function SettingsSection(props) {
49
49
  const [nicknameDraft, setNicknameDraft] = useState('');
50
50
  const [occupationDraft, setOccupationDraft] = useState('');
51
51
  const [interestsDraft, setInterestsDraft] = useState('');
52
- // 记忆注入上限:草稿态编辑(null=显示快照值),失焦才校验提交——避免逐键持久化与非法中间值死锁
52
+ // 记忆注入上限:草稿态编辑(null=显示快照值),失焦才校验提交——避免逐键持久化与非法中间值死锁。
53
+ // 错误态分两档:invalid=未保存的就地报错;clamped=越界已按边界值保存的说明性提示(不是错误)
53
54
  const [limitDraft, setLimitDraft] = useState(null);
54
- const [limitError, setLimitError] = useState(false);
55
+ const [limitError, setLimitError] = useState(undefined);
55
56
  // 记忆注入上限:写入在途的乐观值(与开关的 pendingToggle 同款,用于禁用控件并顶住回显,
56
57
  // 否则提交后到快照回折前会闪回旧值)
57
58
  const [pendingLimit, setPendingLimit] = useState(undefined);
@@ -237,7 +238,7 @@ export function SettingsSection(props) {
237
238
  const commitLimit = () => {
238
239
  const raw = limitDraft;
239
240
  setLimitDraft(null);
240
- setLimitError(false);
241
+ setLimitError(undefined);
241
242
  if (raw === null || !writable)
242
243
  return;
243
244
  // 空串视为放弃编辑:静默回显保存值。若在此报错,会同时出现「已填回旧值」与
@@ -247,11 +248,12 @@ export function SettingsSection(props) {
247
248
  const parsed = parseMemoryLimit(raw);
248
249
  // 非法输入就地报错(不再静默回弹):用户明确知道哪里错、该怎么改
249
250
  if (parsed === undefined) {
250
- setLimitError(true);
251
+ setLimitError('invalid');
251
252
  return;
252
253
  }
253
254
  if (parsed.clamped) {
254
- // 越界但可夹取:按夹取值提交并回显,同时给出行内提示
255
+ // 越界但可夹取:按夹取值提交并回显,给说明性提示而非报错——值已成功保存,
256
+ // 「请输入合法整数」的报错口径与实际行为矛盾
255
257
  const seq = ++writeSeqRef.current;
256
258
  setPendingLimit(parsed.value);
257
259
  void scope.set('memoryInjectLimit', parsed.value)
@@ -261,7 +263,7 @@ export function SettingsSection(props) {
261
263
  verifyWritten(seq, 'memoryInjectLimit', parsed.value);
262
264
  })
263
265
  .catch((err) => { setPendingLimit(undefined); toastError(err); });
264
- setLimitError(true);
266
+ setLimitError('clamped');
265
267
  return;
266
268
  }
267
269
  if (parsed.value === snap.value?.memoryInjectLimit)
@@ -275,10 +277,6 @@ export function SettingsSection(props) {
275
277
  })
276
278
  .catch((err) => { setPendingLimit(undefined); toastError(err); });
277
279
  };
278
- const coachLabel = (id) => {
279
- const index = COACH_IDS.indexOf(id);
280
- return index >= 0 ? t(COACH_KEYS[index]) : (id ?? '');
281
- };
282
280
  const saveCoach = (style) => {
283
281
  if (saving || style === profile?.coachStyle)
284
282
  return;
@@ -304,16 +302,19 @@ export function SettingsSection(props) {
304
302
  flashSaved(t('settings.profile.saved'));
305
303
  }));
306
304
  };
307
- // 三个分节各自成面板卡(与全站卡片语言一致),字段不再裸堆叠;卡内节奏由样式层统一
305
+ // 分节各自成面板卡(与全站卡片语言一致);开关类设置用 row 语法(标签+说明在左、
306
+ // 控件在右),表单类字段保持 label 在上的纵排——两类各有惯例,不混用
308
307
  return createElement('div', { className: 'xy-settings' }, createElement('section', { className: 'xy-panel' }, createElement('h3', { className: 'xy-panel-head' }, t('settings.coach.title')), createElement('div', { className: 'xy-seg', role: 'group', 'aria-label': t('settings.coach.title') }, ...COACH_IDS.map((id, i) => createElement('button', {
309
308
  key: id,
310
309
  className: `xy-seg-btn${profile?.coachStyle === id ? ' xy-on' : ''}`,
311
310
  'aria-pressed': profile?.coachStyle === id,
312
311
  disabled: saving,
313
312
  onClick: () => saveCoach(id),
314
- }, t(COACH_KEYS[i])))), createElement('p', { className: 'xy-hint' }, profileError !== undefined ? t('settings.coach.loadFailed', { error: profileError })
313
+ }, t(COACH_KEYS[i])))),
314
+ // 分段按钮已表达当前风格,说明行只讲作用不报状态;错误态保留重试入口
315
+ createElement('p', { className: 'xy-hint' }, profileError !== undefined ? t('settings.coach.loadFailed', { error: profileError })
315
316
  : profile === undefined ? t('common.loading') + '…'
316
- : t('settings.coach.current', { label: coachLabel(profile.coachStyle) })), profileError !== undefined
317
+ : t('settings.coach.hint')), profileError !== undefined
317
318
  ? createElement('button', { className: 'xy-btn', onClick: loadProfile }, t('common.retry'))
318
319
  : null),
319
320
  // 画像字段:label 包裹关联控件(可点击标签聚焦输入),小标题在上、示例 placeholder 在下,
@@ -334,11 +335,14 @@ export function SettingsSection(props) {
334
335
  className: 'xy-btn xy-btn-primary', disabled: saving, onClick: saveProfile,
335
336
  }, saving ? t('settings.profile.saving') : t('settings.profile.save')), savedMsg !== '' ? createElement('span', { className: 'xy-saved', role: 'status' },
336
337
  // 勾形装饰对读屏隐藏(语义由文案承担),与卡片完成态同一语法
337
- createElement('span', { 'aria-hidden': 'true' }, '✓ '), savedMsg) : null), createElement('p', { className: 'xy-hint' }, t('settings.profile.sharedHint'))), createElement('section', { className: 'xy-panel' }, createElement('h3', { className: 'xy-panel-head' }, t('settings.pref.title')),
338
- // 整页 section 没有官方卡片那套「按命名空间自动显隐」的保护,失败呈现归注册方
338
+ createElement('span', { 'aria-hidden': 'true' }, '✓ '), savedMsg) : null), createElement('p', { className: 'xy-hint' }, t('settings.profile.sharedHint'))),
339
+ // 整页 section 没有官方卡片那套「按命名空间自动显隐」的保护,失败呈现归注册方。
340
+ // 命名空间级通知作用于下方两卡(写操作确认/对话偏好),页级一次说清不逐卡重复
339
341
  prefNoticeKey !== undefined
340
342
  ? createElement('p', { className: 'xy-hint' }, t(prefNoticeKey))
341
- : null, createElement('label', { className: 'xy-field' }, createElement('span', { className: 'xy-field-head' }, createElement('input', {
343
+ : null,
344
+ // 写操作确认独立成卡:安全类设置自成一组,与一般行为参数分离
345
+ createElement('section', { className: 'xy-panel' }, createElement('h3', { className: 'xy-panel-head' }, t('settings.confirm.title')), createElement('label', { className: 'xy-setrow' }, createElement('span', { className: 'xy-setrow-main' }, createElement('span', { className: 'xy-setrow-label' }, t('settings.confirm.master')), createElement('span', { className: 'xy-setrow-desc' }, t('settings.pref.confirmWritesHint'))), createElement('input', {
342
346
  type: 'checkbox',
343
347
  className: 'xy-toggle',
344
348
  name: 'confirmWrites',
@@ -358,60 +362,57 @@ export function SettingsSection(props) {
358
362
  toastError(err);
359
363
  });
360
364
  },
361
- }), t('settings.pref.confirmWrites')), createElement('p', { className: 'xy-hint' }, t('settings.pref.confirmWritesHint'))),
365
+ })),
362
366
  // 确认类目明细(锁定删除行恒展示):总开关关闭时整组禁用置灰——不弹卡由总开关
363
367
  // 决定;禁用原因由组尾 hint 承担(aria-describedby 关联),不在每行重复
364
368
  createElement('div', {
365
- className: 'xy-confirm-ops',
369
+ className: `xy-confirm-ops${confirmWrites ? '' : ' xy-confirm-ops-off'}`,
366
370
  role: 'group',
367
371
  'aria-labelledby': 'xy-confirm-ops-head',
368
372
  'aria-describedby': 'xy-confirm-ops-hint',
369
- }, createElement('span', { className: 'xy-op-group-head', id: 'xy-confirm-ops-head' }, t('settings.pref.confirmOps.group')), ...CONFIRM_OPS.map((op) => createElement('label', { className: 'xy-op-row', key: op }, createElement('input', {
373
+ }, createElement('span', { className: 'xy-op-group-head', id: 'xy-confirm-ops-head' }, t('settings.pref.confirmOps.group')), createElement('div', { className: 'xy-setrows' }, ...CONFIRM_OPS.map((op) => createElement('label', { className: 'xy-setrow', key: op }, createElement('span', { className: 'xy-setrow-main' }, createElement('span', { className: 'xy-setrow-label' }, t(CONFIRM_OP_LABEL_KEYS[op]))), createElement('input', {
370
374
  type: 'checkbox',
371
375
  className: 'xy-toggle',
372
376
  name: `confirmOps.${op}`,
373
377
  checked: confirmOps[op],
374
378
  disabled: !writable || pendingOps !== undefined || !confirmWrites,
375
379
  onChange: (e) => toggleConfirmOp(op, e.target.checked),
376
- }), t(CONFIRM_OP_LABEL_KEYS[op]))),
377
- // 锁定类目:div + 只读开关(不可交互故不用 label),说明单独一行与文字对齐
378
- createElement('div', { className: 'xy-op-row xy-op-row-locked' }, createElement('input', {
379
- type: 'checkbox',
380
- className: 'xy-toggle',
381
- name: 'confirmOps.deleteLocked',
382
- checked: true,
383
- readOnly: true,
384
- disabled: true,
385
- 'aria-label': t('settings.pref.confirmOps.delete'),
386
- }), createElement('span', null, t('settings.pref.confirmOps.delete'))), createElement('span', { className: 'xy-hint xy-op-locked-hint' }, t('settings.pref.confirmOps.deleteHint')), createElement('span', { className: 'xy-hint', id: 'xy-confirm-ops-hint' }, t('settings.pref.confirmOps.hint'))), createElement('label', { className: 'xy-field' }, createElement('span', { className: 'xy-field-head' }, t('settings.pref.memoryLimit')), createElement('input', {
380
+ }))),
381
+ // 锁定类目:div + 「始终开启」徽章(不可交互,不用禁用开关表达恒开语义)
382
+ createElement('div', { className: 'xy-setrow' }, createElement('span', { className: 'xy-setrow-main' }, createElement('span', { className: 'xy-setrow-label' }, t('settings.pref.confirmOps.delete')), createElement('span', { className: 'xy-setrow-desc' }, t('settings.pref.confirmOps.deleteHint'))), createElement('span', { className: 'xy-locked' }, t('settings.pref.confirmOps.locked'))))), createElement('span', { className: 'xy-hint', id: 'xy-confirm-ops-hint' }, t('settings.pref.confirmOps.hint'))),
383
+ // 一般对话行为参数:记忆注入上限 + 确认卡语言
384
+ createElement('section', { className: 'xy-panel' }, createElement('h3', { className: 'xy-panel-head' }, t('settings.pref.title')), createElement('div', { className: 'xy-setrows' }, createElement('label', { className: 'xy-setrow' }, createElement('span', { className: 'xy-setrow-main' }, createElement('span', { className: 'xy-setrow-label' }, t('settings.pref.memoryLimit')), createElement('span', { className: 'xy-setrow-desc' }, t('settings.pref.memoryLimitHint')), limitError === 'invalid'
385
+ ? createElement('span', { id: 'xy-limit-error', className: 'xy-field-err', role: 'alert' }, t('settings.pref.limitInvalid'))
386
+ : limitError === 'clamped'
387
+ ? createElement('span', { id: 'xy-limit-error', className: 'xy-hint', role: 'status' }, t('settings.pref.limitClamped'))
388
+ : null), createElement('input', {
387
389
  type: 'number', min: MEMORY_LIMIT_MIN, max: MEMORY_LIMIT_MAX,
388
390
  className: 'xy-input xy-input-num', name: 'memoryInjectLimit', inputMode: 'numeric',
391
+ autoComplete: 'off',
389
392
  'aria-label': t('settings.pref.memoryLimit'),
390
- 'aria-invalid': limitError || undefined,
393
+ 'aria-invalid': limitError === 'invalid' || undefined,
391
394
  ...(limitError ? { 'aria-describedby': 'xy-limit-error' } : {}),
392
395
  // 写入在途时顶住乐观值并禁用(与开关同款),避免闪回旧值与并发写交错
393
396
  value: limitDraft ?? (pendingLimit !== undefined ? String(pendingLimit) : limit),
394
397
  disabled: !writable || pendingLimit !== undefined,
395
- onChange: (e) => { setLimitDraft(e.target.value); setLimitError(false); },
398
+ onChange: (e) => { setLimitDraft(e.target.value); setLimitError(undefined); },
396
399
  onBlur: commitLimit,
397
400
  onKeyDown: (e) => {
398
401
  if (e.key === 'Enter')
399
402
  e.currentTarget.blur();
400
403
  },
401
- }), createElement('span', { className: 'xy-hint' }, t('settings.pref.memoryLimitHint')), limitError
402
- ? createElement('span', { id: 'xy-limit-error', className: 'xy-field-err', role: 'alert' }, t('settings.pref.limitInvalid'))
403
- : null),
404
+ })),
404
405
  // 确认卡语言:平台不向 host 侧暴露界面语言(rc.2 实测),对话侧确认卡文案无法
405
- // 自动跟随界面语言——由此处显式选择,即时热生效(hitl/tools 每次执行读 thunk)
406
- createElement('label', { className: 'xy-field' }, createElement('span', { className: 'xy-field-head' }, t('settings.pref.confirmLang')), createElement('select', {
407
- className: 'xy-input', value: confirmLang, name: 'confirmLang',
408
- 'aria-label': t('settings.pref.confirmLang'),
406
+ // 自动跟随界面语言——由此处显式选择,即时热生效(hitl/tools 每次执行读 thunk)。
407
+ // 两档枚举与教练风格共用分段控件(下拉对小枚举过重);行内是按钮组故不用 label
408
+ createElement('div', { className: 'xy-setrow' }, createElement('span', { className: 'xy-setrow-main' }, createElement('span', { className: 'xy-setrow-label' }, t('settings.pref.confirmLang')), createElement('span', { className: 'xy-setrow-desc' }, t('settings.pref.confirmLangHint'))), createElement('span', { className: 'xy-seg', role: 'group', 'aria-label': t('settings.pref.confirmLang') }, ...['zh', 'en'].map((lang) => createElement('button', {
409
+ key: lang,
410
+ type: 'button',
411
+ className: `xy-seg-btn${confirmLang === lang ? ' xy-on' : ''}`,
412
+ 'aria-pressed': confirmLang === lang,
409
413
  disabled: !writable || pendingLang !== undefined,
410
- onChange: (e) => {
411
- if (e.target.value === 'zh' || e.target.value === 'en')
412
- switchConfirmLang(e.target.value);
413
- },
414
- }, createElement('option', { value: 'zh' }, t('settings.pref.confirmLang.zh')), createElement('option', { value: 'en' }, t('settings.pref.confirmLang.en'))), createElement('span', { className: 'xy-hint' }, t('settings.pref.confirmLangHint')))),
414
+ onClick: () => switchConfirmLang(lang),
415
+ }, t(lang === 'zh' ? 'settings.pref.confirmLang.zh' : 'settings.pref.confirmLang.en'))))))),
415
416
  // 标签页显示:模式三态(跟随会话/始终显示/始终隐藏)+ 六个标签勾选 chips。
416
417
  // 与教练风格卡同一 xy-seg 视觉语法;「始终隐藏」时勾选区整组禁用置灰。
417
418
  // 命名空间常驻于 bundle 层(未选星愿预设也可调),见 src/ui-settings.ts 头注。
@@ -429,12 +430,14 @@ export function SettingsSection(props) {
429
430
  'aria-label': t('settings.tabs.chooseTab'),
430
431
  }, ...TAB_IDS.map((id) => {
431
432
  const shown = !hiddenTabs.includes(id);
433
+ // 多选勾选态加勾形装饰(对读屏隐藏,状态由 aria-pressed 承担):
434
+ // 与上方单选的模式分段在视觉上区分「可多选」
432
435
  return createElement('button', {
433
436
  key: id,
434
437
  className: `xy-seg-btn${shown ? ' xy-on' : ''}`,
435
438
  'aria-pressed': shown,
436
439
  disabled: !uiWritable || pendingHidden !== undefined || tabMode === 'hide',
437
440
  onClick: () => toggleTab(id, !shown),
438
- }, t(TAB_LABEL_KEYS[id]));
441
+ }, shown ? createElement('span', { 'aria-hidden': 'true' }, '✓ ') : null, t(TAB_LABEL_KEYS[id]));
439
442
  })), createElement('p', { className: 'xy-hint' }, t('settings.tabs.hint'))), createElement('p', { className: 'xy-hint' }, t('settings.dataHint')));
440
443
  }
@@ -264,7 +264,7 @@ body[data-ds-dark-theme] .xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(
264
264
  .xy-input:disabled{opacity:.55;cursor:not-allowed}
265
265
  .xy-field-err{color:var(--xyd-danger);font-size:12px;margin-top:4px}
266
266
  /* 数字微输入(设置页注入上限等):按内容长度定宽,不随浏览器默认 size 拉成宽条 */
267
- .xy-input-num{width:96px}
267
+ .xy-input-num{width:96px;font-variant-numeric:tabular-nums}
268
268
 
269
269
  /* 列表行 */
270
270
  .xy-rowmain{display:flex;flex-direction:column;gap:2px;min-width:0}
@@ -506,35 +506,54 @@ button.xy-growth-col.xy-hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}
506
506
 
507
507
  /* ===== 设置页 ===== */
508
508
  .xy-settings{display:flex;flex-direction:column;gap:16px;max-width:560px;color:var(--dsw-alias-label-primary);font-size:14px}
509
- /* 设置三个分节各自成面板卡;间距交给 xy-settings 的 gap,卡内子元素统一 10px 纵向节奏 */
509
+ /* 游离于卡片外的说明行(页级命名空间通知/页尾数据说明)随卡内文字对齐
510
+ * (xy-panel 横向内边距 14px),不得贴容器左缘悬在列外 */
511
+ .xy-settings>.xy-hint{padding:0 14px}
512
+ /* 设置各分节自成面板卡;间距交给 xy-settings 的 gap,卡内子元素统一 10px 纵向节奏 */
510
513
  .xy-settings .xy-panel{margin-top:0}
511
514
  .xy-settings .xy-panel>*+*{margin-top:10px}
512
515
  .xy-field{display:flex;flex-direction:column;gap:6px}
513
- .xy-field-head{display:flex;align-items:center;gap:8px;font-weight:600}
516
+ /* 设置行(业界设置页 row 惯例):标签+说明在左、控件在右,扫描线对齐;说明文字
517
+ * flex:1 收缩换行、控件 flex:none 不被挤压,窄面板下控件换行左对齐。
518
+ * label 行整行可点(label 包裹控件);div 行(分段按钮组/锁定行)不可点。 */
519
+ .xy-setrow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
520
+ label.xy-setrow{cursor:pointer}
521
+ .xy-setrow-main{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 220px}
522
+ .xy-setrow-label{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}
523
+ .xy-setrow-desc{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0;overflow-wrap:anywhere}
524
+ /* 行列表:行间 hairline 分隔(与分组卡 xy-grouprow 同一语法),首行不画线 */
525
+ .xy-setrows{display:flex;flex-direction:column}
526
+ .xy-setrows>.xy-setrow{padding:8px 0}
527
+ .xy-setrows>.xy-setrow+.xy-setrow{border-top:1px solid var(--dsw-alias-border-l1)}
528
+ .xy-setrow>.xy-toggle,.xy-setrow>.xy-input-num,.xy-setrow>.xy-seg{flex:none}
514
529
  .xy-input-wide{width:100%;max-width:360px;box-sizing:border-box}
515
530
  .xy-seg{display:flex;gap:6px;flex-wrap:wrap}
516
531
  .xy-seg-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:999px;padding:5px 14px;font-size:13px;cursor:pointer;transition:border-color .15s ease,background-color .15s ease,color .15s ease}
532
+ .xy-seg-btn:disabled{opacity:.55;cursor:not-allowed}
517
533
  @media (hover:hover) and (pointer:fine){
518
- .xy-seg-btn:hover{border-color:var(--xyd-accent)}
534
+ .xy-seg-btn:hover:not(:disabled){border-color:var(--xyd-accent)}
519
535
  }
520
536
  /* 选中态双选择器:类名与 aria-pressed 属性等价(组件侧用属性表达状态语义) */
521
537
  .xy-seg-btn.xy-on,.xy-seg-btn[aria-pressed='true']{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}
522
538
  .xy-save-row{display:flex;align-items:center;gap:10px;margin-top:2px}
523
539
  .xy-toggle{width:38px;height:22px;appearance:none;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);position:relative;cursor:pointer;transition:background .15s}
540
+ /* 禁用即置灰(与 xy-btn/xy-input 同语法):只读命名空间/写入在途的控件不得看起来仍可交互 */
541
+ .xy-toggle:disabled{opacity:.4;cursor:not-allowed}
524
542
  .xy-toggle:checked{background:var(--xyd-accent);border-color:transparent}
525
543
  .xy-toggle::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .15s}
526
544
  .xy-toggle:checked::after{transform:translateX(16px);background:var(--xyd-on-accent)}
527
545
  .xy-hint{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0}
528
- /* 确认类目明细:缩进嵌在总开关下(与「总开关 + 明细」分层同构),行 = 开关 + 名称;
529
- * 锁定行(删除)为只读展示,其说明行缩进与文字对齐(开关 38px + 间距 8px) */
530
- .xy-confirm-ops{display:flex;flex-direction:column;gap:8px;margin-left:22px}
531
- /* 禁用弱化必须显式写:自定义外观的 toggle 不吃原生禁用变灰,总开关关闭时明细行
532
- * 否则与可用态无法区分;锁定的删除行恒禁用,常态弱化即「冻结在开启态」的语义 */
533
- .xy-confirm-ops .xy-toggle:disabled{opacity:.4;cursor:default}
534
- .xy-op-group-head{font-weight:600;font-size:13px}
535
- .xy-op-row{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:13px}
536
- .xy-op-row-locked{color:var(--dsw-alias-label-secondary);cursor:default}
537
- .xy-op-locked-hint{padding-left:46px}
546
+ /* 确认类目明细:总开关行下平铺(row 语法 + 组头),不再缩进嵌套;
547
+ * 总开关关闭时整组禁用弱化必须显式写(自定义 toggle 不吃原生禁用变灰),
548
+ * 行文字同步降权;禁用原因由组尾 hint 承担(aria-describedby 关联) */
549
+ .xy-confirm-ops{display:flex;flex-direction:column;gap:4px}
550
+ /* 关闭态只降权可切换的类目行(label 行):锁定删除行不受总开关支配(始终确认),
551
+ * 置灰会让「始终开启」徽章与灰字自相矛盾 */
552
+ .xy-confirm-ops-off label.xy-setrow .xy-setrow-label{color:var(--dsw-alias-label-secondary)}
553
+ .xy-op-group-head{font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary)}
554
+ /* 锁定类目(删除恒确认):「始终开启」徽章表达冻结语义——禁用开关看着像坏了,
555
+ * 徽章即状态;胶囊 999 符合形状纪律 */
556
+ .xy-locked{flex:none;font-size:12px;line-height:1.4;padding:3px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--xyd-label-on-2)}
538
557
 
539
558
  /* ===== 详情聚合视图 ===== */
540
559
  /* 段间 10px 呼吸;每段内部「标签 → 内容」固定 5px 纵向节奏(label 不再与内容文字挤行)。
package/lib/client.js CHANGED
@@ -248,27 +248,28 @@ const ZH_DICT = {
248
248
  "settings.coach.gentle": "温柔型",
249
249
  "settings.coach.strict": "严格型",
250
250
  "settings.coach.humorous": "幽默型",
251
- "settings.coach.current": "当前:{label}。决定对话语气与人设,也可在对话中说「对我严格一点」。",
251
+ "settings.coach.hint": "决定对话语气与人设,也可在对话中说「对我严格一点」。",
252
252
  "settings.coach.saved": "教练风格已更新,对后续对话生效",
253
253
  "settings.coach.loadFailed": "加载失败:{error}",
254
254
  "settings.profile.title": "昵称与画像",
255
255
  "settings.profile.nickname": "昵称",
256
256
  "settings.profile.occupation": "职业",
257
257
  "settings.profile.interests": "兴趣",
258
- "settings.profile.nicknamePlaceholder": "昵称:希望被怎么称呼(留空清除)",
259
- "settings.profile.occupationPlaceholder": "职业(留空清除)",
260
- "settings.profile.interestsPlaceholder": "兴趣:用顿号或逗号分隔(如 阅读、跑步)",
258
+ "settings.profile.nicknamePlaceholder": "希望被怎么称呼",
259
+ "settings.profile.occupationPlaceholder": "如:教师、产品经理",
260
+ "settings.profile.interestsPlaceholder": "如:阅读、跑步",
261
261
  "settings.profile.save": "保存画像",
262
262
  "settings.profile.saving": "保存中…",
263
263
  "settings.profile.saved": "画像已保存",
264
- "settings.profile.sharedHint": "与对话侧共享同一份档案;对话里说「叫我小星」也会更新。",
264
+ "settings.profile.sharedHint": "留空的字段会被清除;画像与对话侧共享,对话里说「叫我小星」也会更新。",
265
265
  "settings.pref.title": "对话偏好",
266
266
  "settings.pref.unavailable": "当前连接不支持持久化偏好(远程或临时模式),以下选项不可用。",
267
267
  "settings.pref.loading": "偏好加载中…",
268
268
  "settings.pref.notRegistered": "偏好暂不可用(组件未就绪),请稍后重试。",
269
269
  "settings.pref.readOnly": "当前设置为只读,无法保存修改。",
270
- "settings.pref.confirmWrites": "写操作二次确认",
271
- "settings.pref.confirmWritesHint": "总开关:开启后按下方类目决定是否弹确认卡,关闭后除删除(始终确认)外一律直接执行。",
270
+ "settings.confirm.title": "写操作确认",
271
+ "settings.confirm.master": "总开关",
272
+ "settings.pref.confirmWritesHint": "开启后按下方类目决定是否弹确认卡;关闭后除删除(始终确认)外一律直接执行。",
272
273
  "settings.pref.confirmOps.group": "确认类目",
273
274
  "settings.pref.confirmOps.create": "创建愿望/任务(含微行动拆解)",
274
275
  "settings.pref.confirmOps.checkin": "打卡",
@@ -277,11 +278,13 @@ const ZH_DICT = {
277
278
  "settings.pref.confirmOps.update": "修改愿望/任务/分类",
278
279
  "settings.pref.confirmOps.memorySave": "保存记忆",
279
280
  "settings.pref.confirmOps.delete": "删除(含批量、微行动重开)",
281
+ "settings.pref.confirmOps.locked": "始终开启",
280
282
  "settings.pref.confirmOps.deleteHint": "始终确认,不可关闭:删除不可恢复。",
281
283
  "settings.pref.confirmOps.hint": "类目明细在总开关开启时生效;默认与之前版本一致。",
282
284
  "settings.pref.memoryLimit": "记忆注入上限",
283
285
  "settings.pref.memoryLimitHint": "每次对话自动注入上下文的记忆条数上限(5-200,默认 40);失焦后保存。",
284
286
  "settings.pref.limitInvalid": "请输入 5-200 的整数",
287
+ "settings.pref.limitClamped": "超出 5-200 范围,已按最近的边界值保存",
285
288
  "settings.pref.writeFailed": "保存未生效,请重试。",
286
289
  "settings.pref.confirmLang": "确认卡语言",
287
290
  "settings.pref.confirmLangHint": "对话中写操作确认卡与问题的显示语言。确认卡无法自动跟随界面语言,需在此选择;默认中文。",
@@ -665,27 +668,28 @@ const EN_DICT = {
665
668
  "settings.coach.gentle": "Gentle",
666
669
  "settings.coach.strict": "Strict",
667
670
  "settings.coach.humorous": "Humorous",
668
- "settings.coach.current": "Current: {label}. Shapes the coaching tone; you can also say “be tougher on me” in chat.",
671
+ "settings.coach.hint": "Shapes the coaching tone; you can also say “be tougher on me” in chat.",
669
672
  "settings.coach.saved": "Coach style updated; applies to future chats",
670
673
  "settings.coach.loadFailed": "Failed to load: {error}",
671
674
  "settings.profile.title": "Nickname & profile",
672
675
  "settings.profile.nickname": "Nickname",
673
676
  "settings.profile.occupation": "Occupation",
674
677
  "settings.profile.interests": "Interests",
675
- "settings.profile.nicknamePlaceholder": "Nickname: how should I call you? (empty clears)",
676
- "settings.profile.occupationPlaceholder": "Occupation (empty clears)",
677
- "settings.profile.interestsPlaceholder": "Interests: separate with commas (e.g. reading, running)",
678
+ "settings.profile.nicknamePlaceholder": "How should I call you?",
679
+ "settings.profile.occupationPlaceholder": "e.g. teacher, product manager",
680
+ "settings.profile.interestsPlaceholder": "e.g. reading, running",
678
681
  "settings.profile.save": "Save profile",
679
682
  "settings.profile.saving": "Saving…",
680
683
  "settings.profile.saved": "Profile saved",
681
- "settings.profile.sharedHint": "Shared with the chat side; saying “call me Star” in chat updates it too.",
684
+ "settings.profile.sharedHint": "Empty fields are cleared. The profile is shared with chat; saying “call me Star” updates it too.",
682
685
  "settings.pref.title": "Chat preferences",
683
686
  "settings.pref.unavailable": "This connection cannot persist preferences (remote or temporary mode); the options below are disabled.",
684
687
  "settings.pref.loading": "Loading preferences…",
685
688
  "settings.pref.notRegistered": "Preferences are unavailable right now (component not ready); please retry later.",
686
689
  "settings.pref.readOnly": "Settings are read-only; changes cannot be saved.",
687
- "settings.pref.confirmWrites": "Confirm write actions",
688
- "settings.pref.confirmWritesHint": "Master switch: when on, confirmations follow the categories below; when off, everything except deletes (always confirmed) runs directly.",
690
+ "settings.confirm.title": "Confirmation before writes",
691
+ "settings.confirm.master": "Master switch",
692
+ "settings.pref.confirmWritesHint": "When on, confirmations follow the categories below; when off, everything except deletes (always confirmed) runs directly.",
689
693
  "settings.pref.confirmOps.group": "Confirmation categories",
690
694
  "settings.pref.confirmOps.create": "Create wishes/tasks (incl. micro-action plans)",
691
695
  "settings.pref.confirmOps.checkin": "Check-ins",
@@ -694,11 +698,13 @@ const EN_DICT = {
694
698
  "settings.pref.confirmOps.update": "Editing wishes/tasks/categories",
695
699
  "settings.pref.confirmOps.memorySave": "Saving memories",
696
700
  "settings.pref.confirmOps.delete": "Deletes (incl. batch & restarts)",
701
+ "settings.pref.confirmOps.locked": "Always on",
697
702
  "settings.pref.confirmOps.deleteHint": "Always confirms and cannot be turned off; deletes are irreversible.",
698
703
  "settings.pref.confirmOps.hint": "Category switches apply while the master switch is on; defaults match previous versions.",
699
704
  "settings.pref.memoryLimit": "Memory injection limit",
700
705
  "settings.pref.memoryLimitHint": "Max memories auto-injected per chat (5-200, default 40); saved when you leave the field.",
701
706
  "settings.pref.limitInvalid": "Enter an integer between 5 and 200",
707
+ "settings.pref.limitClamped": "Out of the 5-200 range; saved as the nearest allowed value.",
702
708
  "settings.pref.writeFailed": "The change did not save; please try again.",
703
709
  "settings.pref.confirmLang": "Confirm card language",
704
710
  "settings.pref.confirmLangHint": "Language of the in-chat confirmation card and its question. The card cannot follow the interface language automatically, so pick it here; defaults to Chinese.",
@@ -1592,7 +1598,7 @@ body[data-ds-dark-theme] .xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(
1592
1598
  .xy-input:disabled{opacity:.55;cursor:not-allowed}
1593
1599
  .xy-field-err{color:var(--xyd-danger);font-size:12px;margin-top:4px}
1594
1600
  /* 数字微输入(设置页注入上限等):按内容长度定宽,不随浏览器默认 size 拉成宽条 */
1595
- .xy-input-num{width:96px}
1601
+ .xy-input-num{width:96px;font-variant-numeric:tabular-nums}
1596
1602
 
1597
1603
  /* 列表行 */
1598
1604
  .xy-rowmain{display:flex;flex-direction:column;gap:2px;min-width:0}
@@ -1834,35 +1840,54 @@ button.xy-growth-col.xy-hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}
1834
1840
 
1835
1841
  /* ===== 设置页 ===== */
1836
1842
  .xy-settings{display:flex;flex-direction:column;gap:16px;max-width:560px;color:var(--dsw-alias-label-primary);font-size:14px}
1837
- /* 设置三个分节各自成面板卡;间距交给 xy-settings 的 gap,卡内子元素统一 10px 纵向节奏 */
1843
+ /* 游离于卡片外的说明行(页级命名空间通知/页尾数据说明)随卡内文字对齐
1844
+ * (xy-panel 横向内边距 14px),不得贴容器左缘悬在列外 */
1845
+ .xy-settings>.xy-hint{padding:0 14px}
1846
+ /* 设置各分节自成面板卡;间距交给 xy-settings 的 gap,卡内子元素统一 10px 纵向节奏 */
1838
1847
  .xy-settings .xy-panel{margin-top:0}
1839
1848
  .xy-settings .xy-panel>*+*{margin-top:10px}
1840
1849
  .xy-field{display:flex;flex-direction:column;gap:6px}
1841
- .xy-field-head{display:flex;align-items:center;gap:8px;font-weight:600}
1850
+ /* 设置行(业界设置页 row 惯例):标签+说明在左、控件在右,扫描线对齐;说明文字
1851
+ * flex:1 收缩换行、控件 flex:none 不被挤压,窄面板下控件换行左对齐。
1852
+ * label 行整行可点(label 包裹控件);div 行(分段按钮组/锁定行)不可点。 */
1853
+ .xy-setrow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
1854
+ label.xy-setrow{cursor:pointer}
1855
+ .xy-setrow-main{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 220px}
1856
+ .xy-setrow-label{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}
1857
+ .xy-setrow-desc{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0;overflow-wrap:anywhere}
1858
+ /* 行列表:行间 hairline 分隔(与分组卡 xy-grouprow 同一语法),首行不画线 */
1859
+ .xy-setrows{display:flex;flex-direction:column}
1860
+ .xy-setrows>.xy-setrow{padding:8px 0}
1861
+ .xy-setrows>.xy-setrow+.xy-setrow{border-top:1px solid var(--dsw-alias-border-l1)}
1862
+ .xy-setrow>.xy-toggle,.xy-setrow>.xy-input-num,.xy-setrow>.xy-seg{flex:none}
1842
1863
  .xy-input-wide{width:100%;max-width:360px;box-sizing:border-box}
1843
1864
  .xy-seg{display:flex;gap:6px;flex-wrap:wrap}
1844
1865
  .xy-seg-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:999px;padding:5px 14px;font-size:13px;cursor:pointer;transition:border-color .15s ease,background-color .15s ease,color .15s ease}
1866
+ .xy-seg-btn:disabled{opacity:.55;cursor:not-allowed}
1845
1867
  @media (hover:hover) and (pointer:fine){
1846
- .xy-seg-btn:hover{border-color:var(--xyd-accent)}
1868
+ .xy-seg-btn:hover:not(:disabled){border-color:var(--xyd-accent)}
1847
1869
  }
1848
1870
  /* 选中态双选择器:类名与 aria-pressed 属性等价(组件侧用属性表达状态语义) */
1849
1871
  .xy-seg-btn.xy-on,.xy-seg-btn[aria-pressed='true']{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}
1850
1872
  .xy-save-row{display:flex;align-items:center;gap:10px;margin-top:2px}
1851
1873
  .xy-toggle{width:38px;height:22px;appearance:none;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);position:relative;cursor:pointer;transition:background .15s}
1874
+ /* 禁用即置灰(与 xy-btn/xy-input 同语法):只读命名空间/写入在途的控件不得看起来仍可交互 */
1875
+ .xy-toggle:disabled{opacity:.4;cursor:not-allowed}
1852
1876
  .xy-toggle:checked{background:var(--xyd-accent);border-color:transparent}
1853
1877
  .xy-toggle::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .15s}
1854
1878
  .xy-toggle:checked::after{transform:translateX(16px);background:var(--xyd-on-accent)}
1855
1879
  .xy-hint{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0}
1856
- /* 确认类目明细:缩进嵌在总开关下(与「总开关 + 明细」分层同构),行 = 开关 + 名称;
1857
- * 锁定行(删除)为只读展示,其说明行缩进与文字对齐(开关 38px + 间距 8px) */
1858
- .xy-confirm-ops{display:flex;flex-direction:column;gap:8px;margin-left:22px}
1859
- /* 禁用弱化必须显式写:自定义外观的 toggle 不吃原生禁用变灰,总开关关闭时明细行
1860
- * 否则与可用态无法区分;锁定的删除行恒禁用,常态弱化即「冻结在开启态」的语义 */
1861
- .xy-confirm-ops .xy-toggle:disabled{opacity:.4;cursor:default}
1862
- .xy-op-group-head{font-weight:600;font-size:13px}
1863
- .xy-op-row{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:13px}
1864
- .xy-op-row-locked{color:var(--dsw-alias-label-secondary);cursor:default}
1865
- .xy-op-locked-hint{padding-left:46px}
1880
+ /* 确认类目明细:总开关行下平铺(row 语法 + 组头),不再缩进嵌套;
1881
+ * 总开关关闭时整组禁用弱化必须显式写(自定义 toggle 不吃原生禁用变灰),
1882
+ * 行文字同步降权;禁用原因由组尾 hint 承担(aria-describedby 关联) */
1883
+ .xy-confirm-ops{display:flex;flex-direction:column;gap:4px}
1884
+ /* 关闭态只降权可切换的类目行(label 行):锁定删除行不受总开关支配(始终确认),
1885
+ * 置灰会让「始终开启」徽章与灰字自相矛盾 */
1886
+ .xy-confirm-ops-off label.xy-setrow .xy-setrow-label{color:var(--dsw-alias-label-secondary)}
1887
+ .xy-op-group-head{font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary)}
1888
+ /* 锁定类目(删除恒确认):「始终开启」徽章表达冻结语义——禁用开关看着像坏了,
1889
+ * 徽章即状态;胶囊 999 符合形状纪律 */
1890
+ .xy-locked{flex:none;font-size:12px;line-height:1.4;padding:3px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--xyd-label-on-2)}
1866
1891
 
1867
1892
  /* ===== 详情聚合视图 ===== */
1868
1893
  /* 段间 10px 呼吸;每段内部「标签 → 内容」固定 5px 纵向节奏(label 不再与内容文字挤行)。
@@ -5011,7 +5036,7 @@ function SettingsSection(props) {
5011
5036
  const [occupationDraft, setOccupationDraft] = (0, react.useState)("");
5012
5037
  const [interestsDraft, setInterestsDraft] = (0, react.useState)("");
5013
5038
  const [limitDraft, setLimitDraft] = (0, react.useState)(null);
5014
- const [limitError, setLimitError] = (0, react.useState)(false);
5039
+ const [limitError, setLimitError] = (0, react.useState)(void 0);
5015
5040
  const [pendingLimit, setPendingLimit] = (0, react.useState)(void 0);
5016
5041
  const [pendingLang, setPendingLang] = (0, react.useState)(void 0);
5017
5042
  const [saving, setSaving] = (0, react.useState)(false);
@@ -5140,12 +5165,12 @@ function SettingsSection(props) {
5140
5165
  const commitLimit = () => {
5141
5166
  const raw = limitDraft;
5142
5167
  setLimitDraft(null);
5143
- setLimitError(false);
5168
+ setLimitError(void 0);
5144
5169
  if (raw === null || !writable) return;
5145
5170
  if (raw.trim() === "") return;
5146
5171
  const parsed = parseMemoryLimit(raw);
5147
5172
  if (parsed === void 0) {
5148
- setLimitError(true);
5173
+ setLimitError("invalid");
5149
5174
  return;
5150
5175
  }
5151
5176
  if (parsed.clamped) {
@@ -5159,7 +5184,7 @@ function SettingsSection(props) {
5159
5184
  setPendingLimit(void 0);
5160
5185
  toastError(err);
5161
5186
  });
5162
- setLimitError(true);
5187
+ setLimitError("clamped");
5163
5188
  return;
5164
5189
  }
5165
5190
  if (parsed.value === snap.value?.memoryInjectLimit) return;
@@ -5173,10 +5198,6 @@ function SettingsSection(props) {
5173
5198
  toastError(err);
5174
5199
  });
5175
5200
  };
5176
- const coachLabel = (id) => {
5177
- const index = COACH_IDS.indexOf(id);
5178
- return index >= 0 ? t(COACH_KEYS[index]) : id ?? "";
5179
- };
5180
5201
  const saveCoach = (style) => {
5181
5202
  if (saving || style === profile?.coachStyle) return;
5182
5203
  runSave(() => postJson("/xingyuan/api/profile", { coachStyle: style }).then((p) => {
@@ -5211,7 +5232,7 @@ function SettingsSection(props) {
5211
5232
  "aria-pressed": profile?.coachStyle === id,
5212
5233
  disabled: saving,
5213
5234
  onClick: () => saveCoach(id)
5214
- }, t(COACH_KEYS[i])))), (0, react.createElement)("p", { className: "xy-hint" }, profileError !== void 0 ? t("settings.coach.loadFailed", { error: profileError }) : profile === void 0 ? t("common.loading") + "…" : t("settings.coach.current", { label: coachLabel(profile.coachStyle) })), profileError !== void 0 ? (0, react.createElement)("button", {
5235
+ }, t(COACH_KEYS[i])))), (0, react.createElement)("p", { className: "xy-hint" }, profileError !== void 0 ? t("settings.coach.loadFailed", { error: profileError }) : profile === void 0 ? t("common.loading") + "…" : t("settings.coach.hint")), profileError !== void 0 ? (0, react.createElement)("button", {
5215
5236
  className: "xy-btn",
5216
5237
  onClick: loadProfile
5217
5238
  }, t("common.retry")) : null), (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.profile.title")), (0, react.createElement)("label", { className: "xy-field" }, (0, react.createElement)("span", { className: "xy-quick-label" }, t("settings.profile.nickname")), (0, react.createElement)("input", {
@@ -5244,7 +5265,7 @@ function SettingsSection(props) {
5244
5265
  }, saving ? t("settings.profile.saving") : t("settings.profile.save")), savedMsg !== "" ? (0, react.createElement)("span", {
5245
5266
  className: "xy-saved",
5246
5267
  role: "status"
5247
- }, (0, react.createElement)("span", { "aria-hidden": "true" }, "✓ "), savedMsg) : null), (0, react.createElement)("p", { className: "xy-hint" }, t("settings.profile.sharedHint"))), (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.pref.title")), prefNoticeKey !== void 0 ? (0, react.createElement)("p", { className: "xy-hint" }, t(prefNoticeKey)) : null, (0, react.createElement)("label", { className: "xy-field" }, (0, react.createElement)("span", { className: "xy-field-head" }, (0, react.createElement)("input", {
5268
+ }, (0, react.createElement)("span", { "aria-hidden": "true" }, "✓ "), savedMsg) : null), (0, react.createElement)("p", { className: "xy-hint" }, t("settings.profile.sharedHint"))), prefNoticeKey !== void 0 ? (0, react.createElement)("p", { className: "xy-hint" }, t(prefNoticeKey)) : null, (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.confirm.title")), (0, react.createElement)("label", { className: "xy-setrow" }, (0, react.createElement)("span", { className: "xy-setrow-main" }, (0, react.createElement)("span", { className: "xy-setrow-label" }, t("settings.confirm.master")), (0, react.createElement)("span", { className: "xy-setrow-desc" }, t("settings.pref.confirmWritesHint"))), (0, react.createElement)("input", {
5248
5269
  type: "checkbox",
5249
5270
  className: "xy-toggle",
5250
5271
  name: "confirmWrites",
@@ -5263,69 +5284,68 @@ function SettingsSection(props) {
5263
5284
  toastError(err);
5264
5285
  });
5265
5286
  }
5266
- }), t("settings.pref.confirmWrites")), (0, react.createElement)("p", { className: "xy-hint" }, t("settings.pref.confirmWritesHint"))), (0, react.createElement)("div", {
5267
- className: "xy-confirm-ops",
5287
+ })), (0, react.createElement)("div", {
5288
+ className: `xy-confirm-ops${confirmWrites ? "" : " xy-confirm-ops-off"}`,
5268
5289
  role: "group",
5269
5290
  "aria-labelledby": "xy-confirm-ops-head",
5270
5291
  "aria-describedby": "xy-confirm-ops-hint"
5271
5292
  }, (0, react.createElement)("span", {
5272
5293
  className: "xy-op-group-head",
5273
5294
  id: "xy-confirm-ops-head"
5274
- }, t("settings.pref.confirmOps.group")), ...CONFIRM_OPS.map((op) => (0, react.createElement)("label", {
5275
- className: "xy-op-row",
5295
+ }, t("settings.pref.confirmOps.group")), (0, react.createElement)("div", { className: "xy-setrows" }, ...CONFIRM_OPS.map((op) => (0, react.createElement)("label", {
5296
+ className: "xy-setrow",
5276
5297
  key: op
5277
- }, (0, react.createElement)("input", {
5298
+ }, (0, react.createElement)("span", { className: "xy-setrow-main" }, (0, react.createElement)("span", { className: "xy-setrow-label" }, t(CONFIRM_OP_LABEL_KEYS[op]))), (0, react.createElement)("input", {
5278
5299
  type: "checkbox",
5279
5300
  className: "xy-toggle",
5280
5301
  name: `confirmOps.${op}`,
5281
5302
  checked: confirmOps[op],
5282
5303
  disabled: !writable || pendingOps !== void 0 || !confirmWrites,
5283
5304
  onChange: (e) => toggleConfirmOp(op, e.target.checked)
5284
- }), t(CONFIRM_OP_LABEL_KEYS[op]))), (0, react.createElement)("div", { className: "xy-op-row xy-op-row-locked" }, (0, react.createElement)("input", {
5285
- type: "checkbox",
5286
- className: "xy-toggle",
5287
- name: "confirmOps.deleteLocked",
5288
- checked: true,
5289
- readOnly: true,
5290
- disabled: true,
5291
- "aria-label": t("settings.pref.confirmOps.delete")
5292
- }), (0, react.createElement)("span", null, t("settings.pref.confirmOps.delete"))), (0, react.createElement)("span", { className: "xy-hint xy-op-locked-hint" }, t("settings.pref.confirmOps.deleteHint")), (0, react.createElement)("span", {
5305
+ }))), (0, react.createElement)("div", { className: "xy-setrow" }, (0, react.createElement)("span", { className: "xy-setrow-main" }, (0, react.createElement)("span", { className: "xy-setrow-label" }, t("settings.pref.confirmOps.delete")), (0, react.createElement)("span", { className: "xy-setrow-desc" }, t("settings.pref.confirmOps.deleteHint"))), (0, react.createElement)("span", { className: "xy-locked" }, t("settings.pref.confirmOps.locked"))))), (0, react.createElement)("span", {
5293
5306
  className: "xy-hint",
5294
5307
  id: "xy-confirm-ops-hint"
5295
- }, t("settings.pref.confirmOps.hint"))), (0, react.createElement)("label", { className: "xy-field" }, (0, react.createElement)("span", { className: "xy-field-head" }, t("settings.pref.memoryLimit")), (0, react.createElement)("input", {
5308
+ }, t("settings.pref.confirmOps.hint"))), (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.pref.title")), (0, react.createElement)("div", { className: "xy-setrows" }, (0, react.createElement)("label", { className: "xy-setrow" }, (0, react.createElement)("span", { className: "xy-setrow-main" }, (0, react.createElement)("span", { className: "xy-setrow-label" }, t("settings.pref.memoryLimit")), (0, react.createElement)("span", { className: "xy-setrow-desc" }, t("settings.pref.memoryLimitHint")), limitError === "invalid" ? (0, react.createElement)("span", {
5309
+ id: "xy-limit-error",
5310
+ className: "xy-field-err",
5311
+ role: "alert"
5312
+ }, t("settings.pref.limitInvalid")) : limitError === "clamped" ? (0, react.createElement)("span", {
5313
+ id: "xy-limit-error",
5314
+ className: "xy-hint",
5315
+ role: "status"
5316
+ }, t("settings.pref.limitClamped")) : null), (0, react.createElement)("input", {
5296
5317
  type: "number",
5297
5318
  min: 5,
5298
5319
  max: 200,
5299
5320
  className: "xy-input xy-input-num",
5300
5321
  name: "memoryInjectLimit",
5301
5322
  inputMode: "numeric",
5323
+ autoComplete: "off",
5302
5324
  "aria-label": t("settings.pref.memoryLimit"),
5303
- "aria-invalid": limitError || void 0,
5325
+ "aria-invalid": limitError === "invalid" || void 0,
5304
5326
  ...limitError ? { "aria-describedby": "xy-limit-error" } : {},
5305
5327
  value: limitDraft ?? (pendingLimit !== void 0 ? String(pendingLimit) : limit),
5306
5328
  disabled: !writable || pendingLimit !== void 0,
5307
5329
  onChange: (e) => {
5308
5330
  setLimitDraft(e.target.value);
5309
- setLimitError(false);
5331
+ setLimitError(void 0);
5310
5332
  },
5311
5333
  onBlur: commitLimit,
5312
5334
  onKeyDown: (e) => {
5313
5335
  if (e.key === "Enter") e.currentTarget.blur();
5314
5336
  }
5315
- }), (0, react.createElement)("span", { className: "xy-hint" }, t("settings.pref.memoryLimitHint")), limitError ? (0, react.createElement)("span", {
5316
- id: "xy-limit-error",
5317
- className: "xy-field-err",
5318
- role: "alert"
5319
- }, t("settings.pref.limitInvalid")) : null), (0, react.createElement)("label", { className: "xy-field" }, (0, react.createElement)("span", { className: "xy-field-head" }, t("settings.pref.confirmLang")), (0, react.createElement)("select", {
5320
- className: "xy-input",
5321
- value: confirmLang,
5322
- name: "confirmLang",
5323
- "aria-label": t("settings.pref.confirmLang"),
5337
+ })), (0, react.createElement)("div", { className: "xy-setrow" }, (0, react.createElement)("span", { className: "xy-setrow-main" }, (0, react.createElement)("span", { className: "xy-setrow-label" }, t("settings.pref.confirmLang")), (0, react.createElement)("span", { className: "xy-setrow-desc" }, t("settings.pref.confirmLangHint"))), (0, react.createElement)("span", {
5338
+ className: "xy-seg",
5339
+ role: "group",
5340
+ "aria-label": t("settings.pref.confirmLang")
5341
+ }, ...["zh", "en"].map((lang) => (0, react.createElement)("button", {
5342
+ key: lang,
5343
+ type: "button",
5344
+ className: `xy-seg-btn${confirmLang === lang ? " xy-on" : ""}`,
5345
+ "aria-pressed": confirmLang === lang,
5324
5346
  disabled: !writable || pendingLang !== void 0,
5325
- onChange: (e) => {
5326
- if (e.target.value === "zh" || e.target.value === "en") switchConfirmLang(e.target.value);
5327
- }
5328
- }, (0, react.createElement)("option", { value: "zh" }, t("settings.pref.confirmLang.zh")), (0, react.createElement)("option", { value: "en" }, t("settings.pref.confirmLang.en"))), (0, react.createElement)("span", { className: "xy-hint" }, t("settings.pref.confirmLangHint")))), (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.tabs.title")), uiNoticeKey !== void 0 ? (0, react.createElement)("p", { className: "xy-hint" }, t(uiNoticeKey)) : null, (0, react.createElement)("div", {
5347
+ onClick: () => switchConfirmLang(lang)
5348
+ }, t(lang === "zh" ? "settings.pref.confirmLang.zh" : "settings.pref.confirmLang.en"))))))), (0, react.createElement)("section", { className: "xy-panel" }, (0, react.createElement)("h3", { className: "xy-panel-head" }, t("settings.tabs.title")), uiNoticeKey !== void 0 ? (0, react.createElement)("p", { className: "xy-hint" }, t(uiNoticeKey)) : null, (0, react.createElement)("div", {
5329
5349
  className: "xy-seg",
5330
5350
  role: "group",
5331
5351
  "aria-label": t("settings.tabs.title")
@@ -5347,7 +5367,7 @@ function SettingsSection(props) {
5347
5367
  "aria-pressed": shown,
5348
5368
  disabled: !uiWritable || pendingHidden !== void 0 || tabMode === "hide",
5349
5369
  onClick: () => toggleTab(id, !shown)
5350
- }, t(TAB_LABEL_KEYS[id]));
5370
+ }, shown ? (0, react.createElement)("span", { "aria-hidden": "true" }, "✓ ") : null, t(TAB_LABEL_KEYS[id]));
5351
5371
  })), (0, react.createElement)("p", { className: "xy-hint" }, t("settings.tabs.hint"))), (0, react.createElement)("p", { className: "xy-hint" }, t("settings.dataHint")));
5352
5372
  }
5353
5373
 
@@ -225,27 +225,28 @@ export declare const ZH_DICT: {
225
225
  readonly 'settings.coach.gentle': "温柔型";
226
226
  readonly 'settings.coach.strict': "严格型";
227
227
  readonly 'settings.coach.humorous': "幽默型";
228
- readonly 'settings.coach.current': "当前:{label}。决定对话语气与人设,也可在对话中说「对我严格一点」。";
228
+ readonly 'settings.coach.hint': "决定对话语气与人设,也可在对话中说「对我严格一点」。";
229
229
  readonly 'settings.coach.saved': "教练风格已更新,对后续对话生效";
230
230
  readonly 'settings.coach.loadFailed': "加载失败:{error}";
231
231
  readonly 'settings.profile.title': "昵称与画像";
232
232
  readonly 'settings.profile.nickname': "昵称";
233
233
  readonly 'settings.profile.occupation': "职业";
234
234
  readonly 'settings.profile.interests': "兴趣";
235
- readonly 'settings.profile.nicknamePlaceholder': "昵称:希望被怎么称呼(留空清除)";
236
- readonly 'settings.profile.occupationPlaceholder': "职业(留空清除)";
237
- readonly 'settings.profile.interestsPlaceholder': "兴趣:用顿号或逗号分隔(如 阅读、跑步)";
235
+ readonly 'settings.profile.nicknamePlaceholder': "希望被怎么称呼";
236
+ readonly 'settings.profile.occupationPlaceholder': "如:教师、产品经理";
237
+ readonly 'settings.profile.interestsPlaceholder': "如:阅读、跑步";
238
238
  readonly 'settings.profile.save': "保存画像";
239
239
  readonly 'settings.profile.saving': "保存中…";
240
240
  readonly 'settings.profile.saved': "画像已保存";
241
- readonly 'settings.profile.sharedHint': "与对话侧共享同一份档案;对话里说「叫我小星」也会更新。";
241
+ readonly 'settings.profile.sharedHint': "留空的字段会被清除;画像与对话侧共享,对话里说「叫我小星」也会更新。";
242
242
  readonly 'settings.pref.title': "对话偏好";
243
243
  readonly 'settings.pref.unavailable': "当前连接不支持持久化偏好(远程或临时模式),以下选项不可用。";
244
244
  readonly 'settings.pref.loading': "偏好加载中…";
245
245
  readonly 'settings.pref.notRegistered': "偏好暂不可用(组件未就绪),请稍后重试。";
246
246
  readonly 'settings.pref.readOnly': "当前设置为只读,无法保存修改。";
247
- readonly 'settings.pref.confirmWrites': "写操作二次确认";
248
- readonly 'settings.pref.confirmWritesHint': "总开关:开启后按下方类目决定是否弹确认卡,关闭后除删除(始终确认)外一律直接执行。";
247
+ readonly 'settings.confirm.title': "写操作确认";
248
+ readonly 'settings.confirm.master': "总开关";
249
+ readonly 'settings.pref.confirmWritesHint': "开启后按下方类目决定是否弹确认卡;关闭后除删除(始终确认)外一律直接执行。";
249
250
  readonly 'settings.pref.confirmOps.group': "确认类目";
250
251
  readonly 'settings.pref.confirmOps.create': "创建愿望/任务(含微行动拆解)";
251
252
  readonly 'settings.pref.confirmOps.checkin': "打卡";
@@ -254,11 +255,13 @@ export declare const ZH_DICT: {
254
255
  readonly 'settings.pref.confirmOps.update': "修改愿望/任务/分类";
255
256
  readonly 'settings.pref.confirmOps.memorySave': "保存记忆";
256
257
  readonly 'settings.pref.confirmOps.delete': "删除(含批量、微行动重开)";
258
+ readonly 'settings.pref.confirmOps.locked': "始终开启";
257
259
  readonly 'settings.pref.confirmOps.deleteHint': "始终确认,不可关闭:删除不可恢复。";
258
260
  readonly 'settings.pref.confirmOps.hint': "类目明细在总开关开启时生效;默认与之前版本一致。";
259
261
  readonly 'settings.pref.memoryLimit': "记忆注入上限";
260
262
  readonly 'settings.pref.memoryLimitHint': "每次对话自动注入上下文的记忆条数上限(5-200,默认 40);失焦后保存。";
261
263
  readonly 'settings.pref.limitInvalid': "请输入 5-200 的整数";
264
+ readonly 'settings.pref.limitClamped': "超出 5-200 范围,已按最近的边界值保存";
262
265
  readonly 'settings.pref.writeFailed': "保存未生效,请重试。";
263
266
  readonly 'settings.pref.confirmLang': "确认卡语言";
264
267
  readonly 'settings.pref.confirmLangHint': "对话中写操作确认卡与问题的显示语言。确认卡无法自动跟随界面语言,需在此选择;默认中文。";
@@ -16,4 +16,4 @@
16
16
  * 令牌区**(:root 与深色覆盖块,即「会话卡片」分段注释之前),正文区一律引用
17
17
  * 令牌;该约束由 test/style-contract.test.ts 机械锁定(含 gen-mock 产物)。
18
18
  */
19
- export declare const STYLE_TEXT = "\n/* ===== \u54C1\u724C\u4E0E\u8BED\u4E49\u4EE4\u724C ===== */\n:root{\n --xyd-accent:#1a6fe0;\n --xyd-on-accent:#ffffff;\n --xyd-accent-strong:#1e40af;\n --xyd-accent-soft:rgba(26,111,224,.12);\n --xyd-danger:#c0392b;\n --xyd-danger-bg:#c0392b;\n --xyd-warn:#b45309;\n --xyd-ok:#0f766e;\n /* \u5F69\u5E95\u5C0F\u5706\u6807\u7684\u524D\u666F\u5BF9\uFF1A\u6309\u4E3B\u9898\u914D\u5BF9\u4FDD\u8BC1 \u22654.5:1\uFF08\u6DF1\u8272\u4EAE\u5E95\u914D\u6DF1\u5B57\uFF09 */\n --xyd-on-ok:#ffffff;\n --xyd-on-danger:#ffffff;\n /* \u6B21\u8981\u6587\u5B57\u5728\u6B21\u7EA7\u9762\u677F\u5E95\uFF08layer-2\uFF09\u4E0A\u7684\u4E13\u7528\u5BF9\uFF1A\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9 layer-2 \u53EA\u6709\n * \u22484.3:1\uFF0C\u672C\u5BF9\u6309 5.0+:1 \u6821\u51C6\uFF08\u9884\u89C8\u6761/\u7EC4\u8BA1\u6570/\u7B49\u7EA7\u7F16\u53F7/\u672A\u6765\u683C/\u6210\u957F\u8F74\u523B\u5EA6\uFF09 */\n --xyd-label-on-2:#5d6a7d;\n /* \u534A\u900F\u660E\u884D\u751F\u8272\uFF08\u7981 color-mix\uFF0C\u6309\u4E3B\u9898\u663E\u5F0F rgba\uFF09\uFF1A\u5F3A\u8C03\u63CF\u8FB9 / \u5F3A\u8C03\u60AC\u505C\u73AF /\n \u5371\u9669\u63CF\u8FB9 / \u5371\u9669\u60AC\u505C\u5E95 / \u4E2D\u6027\u884C\u60AC\u505C\u5E95 / \u659C\u7EB9\u7EB9\u7406\u4E0E\u5F31\u5316\u5E95 */\n --xyd-accent-border:rgba(26,111,224,.38);\n --xyd-accent-ring:rgba(26,111,224,.72);\n --xyd-accent-ring-soft:rgba(26,111,224,.55);\n --xyd-danger-border:rgba(192,57,43,.4);\n --xyd-danger-soft:rgba(192,57,43,.09);\n --xyd-hover:rgba(15,23,42,.05);\n --xyd-hatch:rgba(100,116,139,.36);\n --xyd-hatch-faint:rgba(100,116,139,.14);\n /* \u6210\u529F/\u8B66\u793A\u8BED\u4E49\u67D4\u548C\u5E95\u4E0E\u63CF\u8FB9\u5BF9\uFF08\u6253\u5361\u5361/\u5FAE\u884C\u52A8\u5361/\u6210\u529F\u6A2A\u5E45/\u56FE\u8868\u5FBD\u7AE0\uFF09\uFF1A\n * \u6B64\u524D\u5355\u503C\u900F\u660E\u5EA6\u4E24\u4E3B\u9898\u5171\u7528\uFF0C\u6DF1\u8272\u4E0B .08 \u7EFF\u6D17\u51E0\u4E4E\u4E0D\u53EF\u89C1 */\n --xyd-ok-soft:rgba(56,217,169,.09);\n --xyd-ok-border:rgba(56,217,169,.4);\n --xyd-ok-badge:rgba(56,217,169,.18);\n --xyd-warn-soft:rgba(255,169,77,.2);\n --xyd-warn-border:rgba(255,169,77,.4);\n /* \u65E5\u5386\u72B6\u6001\u5E95\uFF08\u90E8\u5206/\u5168\u90E8\u5B8C\u6210\uFF09\u4E0E\u6253\u5361\u8BB0\u5F55\u683C\uFF08\u5DF2\u6253\u5361\uFF09\u7684\u6210\u5BF9\u5E95\u8272 */\n --xyd-c2-soft:rgba(255,169,77,.32);\n --xyd-c3-soft:rgba(16,185,129,.22);\n --xyd-c3-soft-dot:rgba(16,185,129,.30);\n --xyd-dcell-checked:rgba(56,217,169,.42);\n --xyd-dcell-checked-dot:rgba(56,217,169,.55);\n /* \u4E0A\u8FF0\u6210\u5BF9\u5E95\u8272\u7684\u524D\u666F\u4F19\u4F34\uFF08\u540C\u4F7F\u7528\u70B9\u6536\u8FDB\u4EE4\u724C\u533A\uFF0C\u6F02\u79FB\u5373\u7EA2\uFF09 */\n --xyd-on-c2:#7c4a03;\n --xyd-on-c3:#065f46;\n --xyd-on-dcell:#0b3d26;\n /* warn-soft \u5E95\u7684\u524D\u666F\u4F19\u4F34\uFF08StaleBanner \u6587\u5B57\uFF09\uFF1A\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9\u7425\u73C0\u67D4\u5E95\u6D45 4.19 /\n \u6DF1 2.95\uFF0C\u8DCC\u7834 WCAG 1.4.3 AA\u2014\u2014\u6309 \u22654.5:1 \u6821\u51C6\u7684\u4E13\u7528\u5BF9\uFF08on-c2 \u540C\u65CF\u6696\u7425\u73C0\u524D\u666F\uFF09 */\n --xyd-on-warn:#7c4a03;\n /* \u9634\u5F71\u5BF9\uFF08\u5361\u7247\u60AC\u505C/toast/\u5F39\u7A97/\u82F1\u96C4\u5361\uFF09\uFF1A\u6DF1\u6D45\u5404\u81EA\u914D\u6863\uFF0C\u7981\u6B62\u6B63\u6587\u533A\u88F8\u5199 rgba */\n --xyd-shadow-card:0 2px 10px rgba(15,23,42,.07);\n --xyd-shadow-toast:0 8px 24px -8px rgba(15,23,42,.2),0 2px 8px -2px rgba(15,23,42,.1);\n --xyd-shadow-modal:0 24px 48px -16px rgba(15,23,42,.35),0 4px 12px -4px rgba(15,23,42,.2);\n --xyd-shadow-hero:0 2px 10px rgba(30,25,60,.16);\n --xyd-hero-border:rgba(255,255,255,.16);\n --xyd-on-hero:rgba(255,255,255,.92);\n --xyd-bar-on-hero:rgba(255,255,255,.28);\n --xyd-swatch-ring:rgba(255,255,255,.85);\n --xyd-swatch-glyph-shadow:0 0 2px rgba(0,0,0,.85),0 1px 3px rgba(0,0,0,.6);\n --xyd-herobadge-glyph-shadow:0 1px 2px rgba(0,0,0,.18);\n /* \u58F3\u906E\u7F69\u4EE4\u724C\u7F3A\u5E2D\u65F6\u7684\u515C\u5E95\uFF08\u4E0D\u518D\u5728\u89C4\u5219\u884C\u5185\u88F8\u5199 rgba \u515C\u5E95\u503C\uFF09 */\n --xyd-mask:rgba(15,23,42,.45);\n /* \u5706\u89D2\u523B\u5EA6 */\n --xyd-r-card:12px;--xyd-r-inner:9px;--xyd-r-ctl:8px;\n}\nbody[data-ds-dark-theme]{\n --xyd-accent:#60a5fa;\n --xyd-on-accent:#0f172a;\n --xyd-accent-strong:#93c5fd;\n --xyd-accent-soft:rgba(96,165,250,.16);\n --xyd-danger:#ff9b8f;\n --xyd-danger-bg:#e2635a;\n --xyd-warn:#fbbf24;\n --xyd-ok:#34d399;\n --xyd-on-ok:#052e21;\n --xyd-on-danger:#3f1008;\n --xyd-label-on-2:#9aa6b7;\n --xyd-accent-border:rgba(96,165,250,.38);\n --xyd-accent-ring:rgba(96,165,250,.72);\n --xyd-accent-ring-soft:rgba(96,165,250,.55);\n --xyd-danger-border:rgba(255,155,143,.4);\n --xyd-danger-soft:rgba(255,155,143,.12);\n --xyd-hover:rgba(148,163,184,.1);\n --xyd-hatch:rgba(139,152,171,.4);\n --xyd-hatch-faint:rgba(139,152,171,.16);\n --xyd-ok-soft:rgba(52,211,153,.14);\n --xyd-ok-border:rgba(52,211,153,.55);\n --xyd-ok-badge:rgba(52,211,153,.22);\n --xyd-warn-soft:rgba(255,169,77,.26);\n --xyd-warn-border:rgba(255,169,77,.5);\n --xyd-c2-soft:rgba(255,169,77,.24);\n --xyd-c3-soft:rgba(52,211,153,.22);\n --xyd-c3-soft-dot:rgba(52,211,153,.30);\n --xyd-dcell-checked:rgba(46,160,105,.32);\n --xyd-dcell-checked-dot:rgba(46,160,105,.45);\n --xyd-on-c2:#ffd9a8;\n --xyd-on-c3:#a7f3c9;\n --xyd-on-dcell:#a7f3c9;\n --xyd-on-warn:#ffd9a8;\n --xyd-shadow-card:0 2px 10px rgba(0,0,0,.32);\n --xyd-shadow-toast:0 8px 24px -8px rgba(0,0,0,.5),0 2px 8px -2px rgba(0,0,0,.35);\n --xyd-shadow-modal:0 24px 48px -16px rgba(0,0,0,.55),0 4px 12px -4px rgba(0,0,0,.4);\n --xyd-shadow-hero:0 2px 10px rgba(0,0,0,.4);\n --xyd-hero-border:rgba(255,255,255,.16);\n --xyd-on-hero:rgba(255,255,255,.92);\n --xyd-bar-on-hero:rgba(255,255,255,.28);\n --xyd-swatch-ring:rgba(255,255,255,.85);\n --xyd-swatch-glyph-shadow:0 0 2px rgba(0,0,0,.85),0 1px 3px rgba(0,0,0,.6);\n --xyd-herobadge-glyph-shadow:0 1px 2px rgba(0,0,0,.18);\n --xyd-mask:rgba(0,0,0,.5);\n}\n\n.xy-visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n\n/* ===== \u4F1A\u8BDD\u5361\u7247 ===== */\n.xy-card{border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:11px 14px;margin:6px 0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:14px}\n.xy-card-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\n/* \u957F\u5185\u5BB9\u7EAA\u5F8B\uFF1A\u5FBD\u7AE0\u4E0D\u6536\u7F29\uFF1B\u6807\u9898\u5141\u8BB8\u65AD\u884C\u6536\u7F29\u2014\u2014\u675C\u7EDD\u957F\u82F1\u6587\u8BCD\u6A2A\u5411\u6EA2\u51FA\u4E0E\u6574\u884C\u6296\u52A8 */\n.xy-badge{flex:none;font-size:12px;border-radius:6px;padding:1px 7px;color:var(--dsw-alias-label-primary)}\n/* \u5206\u7C7B\u5FBD\u7AE0\uFF1AHSL \u53D8\u91CF\u4F9B\u8272\uFF0C\u4EAE\u5EA6\u6309\u4E3B\u9898\u5206\u5C42\uFF08\u5BF9\u9F50 Web wish-category \u7684 .dark \u8986\u76D6\u53E3\u5F84\uFF09 */\n.xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(--cat-sbg,58)*1%) 92%);color:hsl(var(--cat-h,275) calc(var(--cat-sfg,46)*1%) 30%);border:1px solid hsl(var(--cat-h,275) calc(var(--cat-sbd,46)*1%) 55% / .12)}\nbody[data-ds-dark-theme] .xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(--cat-sbg,58)*1%) 22%);color:hsl(var(--cat-h,275) calc(var(--cat-sfg,46)*1%) 80%);border-color:hsl(var(--cat-h,275) calc(var(--cat-sbd,46)*1%) 70% / .2)}\n.xy-badge-task{background:var(--xyd-accent-soft)}\n.xy-badge-chart{background:var(--xyd-ok-badge)}\n.xy-badge-micro{background:var(--xyd-warn-soft)}\n.xy-title{min-width:0;font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}\n.xy-deleted{opacity:.65}\n.xy-deleted .xy-title{text-decoration:line-through}\n.xy-meta{color:var(--dsw-alias-label-secondary);font-size:12px;margin-top:4px;overflow-wrap:anywhere}\n/* \u6B21\u7EA7\u9762\u677F\u5E95\u4E0A\u7684\u6B21\u8981\u6587\u5B57\u7528\u4E13\u7528\u5BF9\uFF08\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9 layer-2 \u4EC5 \u22484.3:1\uFF0C\u53CC\u4E3B\u9898\u540C\u75C5\uFF09 */\n.xy-preview{margin-top:6px;font-size:12px;color:var(--xyd-label-on-2);background:var(--dsw-alias-bg-layer-2);border-radius:var(--xyd-r-inner);padding:6px 8px}\n.xy-checkin{border-color:var(--xyd-ok-border);background:var(--xyd-ok-soft)}\n.xy-glyph{font-size:15px;font-weight:700;line-height:1}\n.xy-glyph-ok{color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-glyph-back{color:var(--dsw-alias-label-secondary)}\n.xy-actioned{margin-left:auto;color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n\n/* \u5FAE\u884C\u52A8\u5361 */\n.xy-micro{border-color:var(--xyd-warn-border)}\n.xy-microsteps{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}\n.xy-microstep{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-inner);background:var(--dsw-alias-bg-layer-2)}\n.xy-microstep.xy-done .xy-microsteptext{text-decoration:line-through}\n/* \u5B8C\u6210/\u8DF3\u8FC7\u6B65\u7684\u6587\u5B57\u964D\u6743\u8D70\u6B21\u8981\u8272\u800C\u975E\u6574\u884C opacity\uFF08\u5BF9\u6BD4\u5EA6\u4F9D\u636E\u540C\u4E0A .xy-done \u6CE8\uFF09 */\n.xy-microstep.xy-done .xy-microsteptext,.xy-microstep.xy-skipped .xy-microsteptext{color:var(--dsw-alias-label-secondary)}\n.xy-microstepnum{flex:none;width:20px;height:20px;border-radius:50%;background:var(--xyd-accent);color:var(--xyd-on-accent);display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;margin-top:1px}\n.xy-microsteptext{font-size:13px;display:flex;flex-direction:column;min-width:0}\n/* \u5361\u5185\u6B65\u9AA4\u8BF4\u660E/\u72B6\u6001\u8BCD\u7684\u80CC\u666F\u662F layer-2\uFF1A\u6B21\u8981\u6587\u5B57\u7528 label-on-2 \u4E13\u7528\u5BF9\uFF08\u58F3\u901A\u7528\n * \u6B21\u8981\u8272\u5BF9 layer-2 \u4EC5 \u22484.3:1\uFF0C\u53CC\u4E3B\u9898\u540C\u75C5\u2014\u2014\u4E0E xy-preview \u540C\u4E00\u6CBB\u7406\u7EBF\uFF09 */\n.xy-microstep .xy-meta{color:var(--xyd-label-on-2)}\n.xy-microstate{margin-left:auto;flex:none}\n\n/* \u56FE\u8868\u5361 */\n.xy-chart{background:var(--dsw-alias-bg-layer-1)}\n.xy-chart-legend{display:flex;gap:12px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary);align-items:center}\n.xy-arcwrap{margin-top:8px}\n.xy-arcnum{font-size:22px;font-weight:700;color:var(--xyd-accent);font-variant-numeric:tabular-nums}\n.xy-bar{height:8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);margin-top:6px;overflow:hidden}\n/* \u586B\u5145\u8D70 scaleX\uFF08\u5408\u6210\u5668\u52A8\u753B\uFF09\uFF1Awidth \u8FC7\u6E21\u4F1A\u9010\u5E27\u89E6\u53D1\u5E03\u5C40\uFF0Ctransform \u53EA\u8FDB\u5408\u6210\u5668 */\n.xy-bar-fill{height:100%;border-radius:inherit;background:var(--xyd-accent);transform-origin:0 50%;transition:transform .35s cubic-bezier(.22,1,.36,1)}\n.xy-rows{list-style:none;margin-top:6px;display:flex;flex-direction:column;gap:4px;padding:0}\n.xy-row{display:flex;justify-content:space-between;font-size:13px}\n.xy-rowval{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}\n.xy-heat{display:grid;grid-template-columns:repeat(auto-fill,minmax(14px,1fr));gap:2px;margin-top:8px}\n.xy-heatcell{aspect-ratio:1;border-radius:3px;background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-svg{width:100%;height:auto;margin-top:6px}\n\n/* ===== Toast \u8F7B\u63D0\u793A ===== */\n.xy-toasts{position:fixed;top:14px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:8px;z-index:9999;pointer-events:none;max-width:min(92vw,460px)}\n.xy-toast{pointer-events:auto;display:flex;align-items:center;gap:9px;padding:9px 14px;border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);font-size:13px;box-shadow:var(--xyd-shadow-toast);animation:xy-toast-in .24s cubic-bezier(.22,1,.36,1);cursor:pointer}\n.xy-toast-out{opacity:0;transform:translateY(-6px);transition:opacity .22s ease,transform .22s ease}\n@keyframes xy-toast-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}\n.xy-toast-glyph{flex:none;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}\n.xy-toast-ok .xy-toast-glyph{background:var(--dsw-alias-state-success-primary,var(--xyd-ok));color:var(--xyd-on-ok)}\n.xy-toast-info .xy-toast-glyph{background:var(--xyd-accent);color:var(--xyd-on-accent)}\n.xy-toast-error .xy-toast-glyph{background:var(--xyd-danger-bg);color:var(--xyd-on-danger)}\n.xy-toast-text{min-width:0;overflow-wrap:anywhere}\n\n/* ===== \u5E94\u7528\u5185\u786E\u8BA4\u5F39\u7A97 =====\n * \u539F\u751F window.confirm \u7684\u66FF\u4EE3\uFF1A\u906E\u7F69 + \u9762\u677F\u5361\uFF0C\u5168\u90E8\u8D70\u4E3B\u9898\u4EE4\u724C\uFF08\u6DF1\u6D45\u8272\u81EA\u9002\u5E94\uFF09\u3002\n * \u52A8\u6548\u53EA\u7528 opacity/transform\uFF1Bz-index \u538B\u8FC7 toast \u5C42\uFF0C\u907F\u514D\u8F7B\u63D0\u793A\u6D6E\u5728\u5F39\u7A97\u4E4B\u4E0A\u3002 */\n.xy-modal-backdrop{position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;padding:20px;background:var(--dsw-alias-bg-mask-1,var(--xyd-mask));animation:xy-fade-in .16s ease-out}\n.xy-modal-backdrop.xy-modal-out{opacity:0;transition:opacity .15s ease}\n.xy-modal{width:min(400px,100%);background:var(--dsw-alias-bg-overlay,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);padding:16px 18px;box-shadow:var(--xyd-shadow-modal);animation:xy-pop-in .18s cubic-bezier(.22,1,.36,1)}\n.xy-modal-out .xy-modal{transform:scale(.98);transition:transform .15s ease}\n.xy-modal-msg{margin:0;font-size:14px;line-height:1.65;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;max-height:min(56vh,440px);overflow-y:auto}\n.xy-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n@keyframes xy-fade-in{from{opacity:0}to{opacity:1}}\n@keyframes xy-pop-in{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n/* \u5B9E\u5FC3\u5371\u9669\u786E\u8BA4\u952E\uFF08\u5220\u9664\u7C7B\u52A8\u4F5C\u4E13\u7528\uFF09\uFF1A\u4E0E\u63CF\u8FB9\u5371\u9669\u952E\u533A\u5206\u300C\u5DF2\u786E\u8BA4\u5C06\u6267\u884C\u300D\u7684\u91CD\u91CF */\n.xy-btn-danger-solid{background:var(--xyd-danger-bg);border-color:transparent;color:var(--xyd-on-danger)}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger-solid:hover:not(:disabled){filter:brightness(1.08);color:var(--xyd-on-danger)}\n}\n\n/* ===== \u9AA8\u67B6\u5C4F\u52A0\u8F7D\u6001 ===== */\n.xy-skel{border-radius:var(--xyd-r-inner);background:linear-gradient(90deg,var(--dsw-alias-bg-layer-2) 25%,var(--dsw-alias-bg-layer-1) 45%,var(--dsw-alias-bg-layer-2) 65%);background-size:200% 100%;animation:xy-shimmer 1.4s ease infinite}\n.xy-skel-title{height:22px;width:38%;margin-bottom:14px}\n.xy-skel-row{height:64px;margin-top:10px}\n@keyframes xy-shimmer{from{background-position:180% 0}to{background-position:-20% 0}}\n\n/* ===== \u7A7A\u6001\uFF08\u7EAF\u6587\u5B57\u7248\u5F0F\uFF0C\u63D2\u753B\u5DF2\u79FB\u9664\uFF1A\u89C1 PageEmpty \u6CE8\u91CA\uFF09===== */\n.xy-page-center{display:flex;flex-direction:column;align-items:center;gap:6px;padding:44px 0;text-align:center}\n.xy-empty-title{font-weight:600;color:var(--dsw-alias-label-primary);margin-top:4px}\n.xy-empty-hint{margin-top:2px;max-width:360px}\n\n/* ===== \u4F1A\u8BDD\u89C6\u56FE\u9875\u9AA8\u67B6 ===== */\n/* \u8282\u594F\u9501\uFF1A\u9875 padding 18/20 \u00B7 \u533A\u5757\u95F4 14\uFF08section-title \u4E0A\u8FB9\u8DDD\uFF09\u00B7 \u884C\u95F4\u8DDD 6/10 */\n.xy-page{box-sizing:border-box;width:100%;max-width:min(780px,100%);min-width:0;margin:0 auto;padding:18px 20px 26px;color:var(--dsw-alias-label-primary);font-size:14px;overflow-x:clip}\n.xy-page-head{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}\n/* \u5C45\u4E2D\u884C\u5185\u7684 .xy-meta \u5173\u95ED\u9ED8\u8BA4 4px \u4E0A\u8FB9\u8DDD\uFF1Aflex \u6309\u542B margin \u7684\u76D2\u5B50\u5C45\u4E2D\uFF0C\u9876\u8DDD\u4F1A\u8BA9\n * \u6B21\u8981\u6587\u5B57\u6052\u5B9A\u4F4E 2px\uFF08\u4E0E .xy-detail>div>.xy-meta \u540C\u4E00\u6761\u6CBB\u7406\u7EBF\uFF0C\u5934\u90E8\u6F0F\u6CBB\u70B9\u5728\u6B64\u6536\u53E3\uFF09 */\n.xy-card-head .xy-meta,.xy-page-head .xy-meta{margin-top:0}\n.xy-page-title{font-size:17px;font-weight:700;margin:0;color:var(--dsw-alias-label-primary)}\n.xy-section-title{font-size:12px;color:var(--dsw-alias-label-secondary);margin:14px 0 6px;font-weight:600;letter-spacing:.02em}\n/* \u9875\u5934\u52A8\u4F5C\u7EC4\uFF1A\u5355\u4E00 margin-left:auto \u6574\u4F53\u53F3\u7F6E\u2014\u2014\u591A\u6309\u94AE\u5404\u81EA auto \u4F1A\u5E73\u5206\u5269\u4F59\u7A7A\u95F4 */\n.xy-page-actions{display:flex;align-items:center;gap:8px;margin-left:auto;flex-wrap:wrap}\n\n/* \u63A7\u4EF6\u4F53\u7CFB */\n.xy-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border-radius:var(--xyd-r-ctl);padding:5px 12px;min-height:28px;font-size:13px;cursor:pointer;line-height:1.5;transition:border-color .15s ease,background-color .15s ease,color .15s ease,filter .15s ease,transform .12s ease}\n/* \u60AC\u505C\u53CD\u9988\u4EC5\u5728\u300C\u771F\u60AC\u505C\u300D\u8BBE\u5907\u751F\u6548\uFF1A\u89E6\u5C4F\u6CA1\u6709\u53EF\u9760\u7684 hover \u9000\u51FA\uFF0C\u884C/\u683C/\u6309\u94AE\u7684\n * \u60AC\u505C\u5E95\u8272\u4F1A\u7C98\u6EDE\u5230\u4E0B\u4E00\u6B21\u70B9\u6309\uFF08hover \u95E8\u63A7 = (hover:hover) and (pointer:fine)\uFF09 */\n@media (hover:hover) and (pointer:fine){\n .xy-btn:hover:not(:disabled){border-color:var(--xyd-accent);color:var(--xyd-accent-strong)}\n}\n.xy-btn:active:not(:disabled){transform:scale(.97)}\n.xy-btn:disabled{opacity:.55;cursor:not-allowed}\n.xy-btn:focus-visible,.xy-input:focus-visible,.xy-cell:focus-visible,.xy-seg-btn:focus-visible,.xy-toggle:focus-visible,.xy-swatch:focus-visible,.xy-growth-col:focus-visible,.xy-wishtoggle:focus-visible{outline:2px solid var(--xyd-accent);outline-offset:2px}\n/* \u89E6\u63A7\u57FA\u7EBF\uFF1A\u6D88\u9664\u79FB\u52A8\u7AEF\u53CC\u51FB\u7F29\u653E\u5EF6\u8FDF\u4E0E\u7CFB\u7EDF\u70B9\u6309\u9AD8\u4EAE\uFF08\u4EA4\u4E92\u53CD\u9988\u7EDF\u4E00\u7531 hover/active \u627F\u62C5\uFF09 */\n.xy-btn,.xy-seg-btn,.xy-cell,.xy-swatch,.xy-toggle,.xy-growth-col,.xy-wishtoggle{touch-action:manipulation;-webkit-tap-highlight-color:transparent}\n/* \u884C\u5185\u6309\u94AE\uFF1A\u226526px \u547D\u4E2D\u76EE\u6807\uFF08\u5361\u7247\u5934/\u64CD\u4F5C\u884C\u7684\u7D27\u51D1\u4E3B\u6218\u6309\u94AE\uFF09 */\n.xy-btn-inline{margin-left:auto;padding:3px 10px;font-size:12px;min-height:26px;display:inline-flex;align-items:center}\n/* \u56FE\u6807\u5E7D\u7075\u952E\uFF08\u226526px \u65B9\u5F62\u547D\u4E2D\u76EE\u6807\uFF09\uFF1A\u7F16\u8F91/\u5220\u9664\u8FD9\u7C7B\u9AD8\u9891\u91CD\u590D\u7684\u884C\u5185\u4F4E\u9891\u52A8\u4F5C\u964D\u566A\u2014\u2014\n * \u56FE\u6807\u7EBF\u7A3F\u627F\u8BB8\u53EF\u4E49\u3001\u6587\u5B57\u8BED\u4E49\u8D70 aria-label\uFF1Bhover/focus \u624D\u663E\u5E95\u8272\u3002 */\n.xy-btn-icon{width:26px;height:26px;min-height:26px;padding:0;display:inline-flex;align-items:center;justify-content:center;flex:none}\n.xy-btn-primary{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-primary:hover:not(:disabled){filter:brightness(1.06);color:var(--xyd-on-accent)}\n}\n.xy-btn-danger{color:var(--xyd-danger);border-color:var(--xyd-danger-border);background:transparent}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger:hover:not(:disabled){background:var(--xyd-danger-soft);color:var(--xyd-danger)}\n}\n.xy-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:var(--xyd-r-ctl);padding:5px 8px;font-size:13px;font-family:inherit;transition:border-color .15s ease}\n@media (hover:hover) and (pointer:fine){\n .xy-input:hover:not(:disabled){border-color:var(--dsw-alias-border-l3)}\n}\n.xy-input::placeholder{color:var(--dsw-alias-label-secondary)}\n.xy-input:disabled{opacity:.55;cursor:not-allowed}\n.xy-field-err{color:var(--xyd-danger);font-size:12px;margin-top:4px}\n/* \u6570\u5B57\u5FAE\u8F93\u5165\uFF08\u8BBE\u7F6E\u9875\u6CE8\u5165\u4E0A\u9650\u7B49\uFF09\uFF1A\u6309\u5185\u5BB9\u957F\u5EA6\u5B9A\u5BBD\uFF0C\u4E0D\u968F\u6D4F\u89C8\u5668\u9ED8\u8BA4 size \u62C9\u6210\u5BBD\u6761 */\n.xy-input-num{width:96px}\n\n/* \u5217\u8868\u884C */\n.xy-rowmain{display:flex;flex-direction:column;gap:2px;min-width:0}\n.xy-rowtitle{font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}\n/* \u5B8C\u6210\u6001\u884C\u9996\u88C5\u9970\u52FE\uFF08aria-hidden\uFF0C\u8BED\u4E49\u7531\u884C\u6587\u6848\u627F\u62C5\uFF09 */\n.xy-done-glyph{color:var(--dsw-alias-state-success-primary,var(--xyd-ok));margin-right:2px}\n/* \u9AD8\u91CD\u8981\u5EA6\u661F\u6807\uFF1A\u7425\u73C0\u8B66\u793A\u8272\uFF08\u4E0D\u590D\u7528\u5B8C\u6210\u52FE\u7684\u7EFF\u8272\uFF0C\u8BED\u4E49\u4E0D\u649E\u8F66\uFF09 */\n.xy-star-hi{color:var(--xyd-warn);margin-right:2px}\n/* \u5B8C\u6210\u6001\u884C\uFF1A\u6807\u9898\u7528\u6B21\u8981\u8272\u964D\u6743\uFF08secondary \u5B9E\u6D4B\u6D45 4.76 / \u6DF1 5.15 \u22654.5:1\uFF09\u2014\u2014\u4E0D\u7528\u6574\u884C\n * opacity\uFF1A0.78 \u6DF7\u5E95\u540E\u6587\u5B57\u6709\u6548\u5BF9\u6BD4\u4EC5 \u22483.1:1\uFF0C\u8DCC\u7834 WCAG 1.4.3 AA\uFF08opacity \u53EA\u7559\u7ED9\n * aria-hidden \u7684\u88C5\u9970\u5143\u7D20\uFF0C\u884C\u5185\u53EF\u8BFB\u6587\u5B57\u4E00\u5F8B\u8D70\u989C\u8272\u964D\u6743\uFF09 */\n.xy-done .xy-rowtitle{color:var(--dsw-alias-label-secondary)}\n.xy-banner-ok{margin-top:10px;padding:10px 12px;border-radius:var(--xyd-r-inner);background:var(--xyd-ok-soft);border:1px solid var(--xyd-ok-border);font-size:13px}\n/* \u5237\u65B0\u5931\u8D25\u4F46\u65E7\u6570\u636E\u4ECD\u5728\u7684\u8BDA\u5B9E\u964D\u7EA7\u6A2A\u5E45\uFF1A\u7425\u73C0\u865A\u7EBF\u9762\u677F\uFF08\u8B66\u793A\u4F46\u4E0D\u6050\u5413\u2014\u2014\u52A8\u4F5C\u5DF2\u6210\u529F\uFF09 */\n.xy-stalerow{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px;padding:8px 12px;border:1px dashed var(--xyd-warn-border);border-radius:var(--xyd-r-inner);background:var(--xyd-warn-soft)}\n/* \u63D0\u793A\u6587\u5B57\u7528\u7425\u73C0\u67D4\u5E95\u7684\u4E13\u7528\u524D\u666F\u5BF9\uFF08--xyd-on-warn\uFF09\uFF1A\u6B21\u8981\u901A\u7528\u8272\u5728\u6B64\u5E95\u4E0A\u6D45 4.19 / \u6DF1\n * 2.95\uFF0C\u6DF1\u8272\u8FDC\u4F4E\u4E8E AA\uFF1B\u91CD\u8BD5\u952E\u4FDD\u6301 label-primary\uFF08\u5BF9\u7425\u73C0\u67D4\u5E95 >10:1\uFF09\uFF0C\u65E0\u9700\u5904\u7406 */\n.xy-stalerow .xy-meta{color:var(--xyd-on-warn)}\n.xy-stalerow .xy-btn-inline{margin-left:0}\n\n/* ===== \u5206\u7EC4\u5361\uFF08\u4EFB\u52A1\u9875\u72B6\u6001\u5206\u6876 / \u4ECA\u65E5\u9875\u5F85\u6253\u5361\u00B7\u5DF2\u5B8C\u6210\u5171\u7528\uFF09=====\n * \u5361\u7247\u5BB9\u5668 + \u72B6\u6001\u70B9\u6807\u9898\u884C + \u5206\u9694\u7EBF\u884C\u5217\u8868\uFF1A\u66FF\u4EE3\u88F8\u5806\u53E0\u7684 section-title+wishtasks\uFF1B\n * \u7EC4\u95F4\u8DDD 12 \u4E0E\u9875\u5934 margin-bottom 12 \u540C\u62CD\uFF0C\u884C\u5185\u8FB9\u8DDD 11/14 \u5BF9\u9F50\u5361\u7247\u4F53\u7CFB\u8282\u594F\u9501\u3002 */\n.xy-group{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);overflow:hidden}\n.xy-group-head{display:flex;align-items:center;gap:8px;margin:0;padding:9px 14px;font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1)}\n.xy-group-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-secondary)}\n.xy-group-dot-accent{background:var(--xyd-accent)}\n.xy-group-dot-warn{background:var(--xyd-warn)}\n.xy-group-dot-ok{background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-group-count{margin-left:auto;flex:none;font-size:12px;line-height:1.7;padding:0 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);font-variant-numeric:tabular-nums}\n.xy-grouplist{list-style:none;display:flex;flex-direction:column;margin:0;padding:0}\n.xy-grouprow{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 14px;border-top:1px solid var(--dsw-alias-border-l1);transition:background-color .15s ease}\n.xy-grouprow:first-child{border-top:none}\n@media (hover:hover) and (pointer:fine){\n .xy-grouprow:hover{background:var(--xyd-hover)}\n}\n/* \u5206\u7EC4\u5361\u7684\u5757\u7EA7\u884C\u53D8\u4F53\uFF08\u4EFB\u52A1\u884C + \u53EF\u9009\u5185\u8054\u8BE6\u60C5\uFF09\uFF1BTaskLine \u57FA\u7C7B\u672C\u8EAB\u5373\u4E24\u680F\u7F51\u683C\uFF08\u89C1\u613F\u671B\u5361\u6BB5\uFF09 */\n.xy-taskrow{display:block}\n.xy-taskrow .xy-detail{margin-bottom:2px}\n\n/* ===== \u9762\u677F\u5361\uFF08\u65E5\u5386/\u6210\u957F\u56FE\u8868/\u8BBE\u7F6E\u5206\u8282\u7B49\u901A\u7528\u5BB9\u5668\uFF09=====\n * \u4E0E\u613F\u671B\u5361\u540C\u4E00\u5361\u7247\u8BED\u6CD5\u4F46\u65E0 hover \u6001\uFF1A\u7EAF\u5BB9\u5668\u3002\u5B50\u5143\u7D20\u95F4\u8DDD\u7531\u5404\u9875\u65E2\u6709 margin \u8D1F\u8D23\u3002 */\n.xy-panel{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px}\n.xy-panel>.xy-skel:first-child{margin-top:0}\n.xy-panel-head{margin:0;font-size:14px;font-weight:600;display:flex;align-items:center;gap:8px;color:var(--dsw-alias-label-primary)}\n\n/* ===== \u4ECA\u65E5\u6982\u89C8\u5361 =====\n * \u6807\u9898\u3001\u5B8C\u6210\u8BA1\u6570\u4E0E\u8FDB\u5EA6\u6761\u540C\u5361\u5448\u73B0\uFF1A\u8FDB\u5EA6\u6761\u4E0D\u518D\u4F5C\u4E3A\u88F8\u6761\u60AC\u5728\u9875\u5934\u4E0B\u65B9\n * \uFF080% \u65F6\u5373\u7528\u6237\u6240\u89C1\u300C\u7A7A\u767D\u6A2A\u6761\u300D\uFF09\uFF1B\u54C1\u724C\u8272\u8F7B\u6655\u67D3\u63D0\u4F9B\u4ECA\u65E5\u9875\u7684\u89C6\u89C9\u951A\u70B9\u3002 */\n.xy-todayhero{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:13px 16px;display:flex;flex-direction:column;gap:9px;background:linear-gradient(135deg,var(--xyd-accent-soft),transparent 55%),var(--dsw-alias-bg-layer-1)}\n.xy-todayhero-top{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}\n/* \u5B8C\u6210\u8BA1\u6570\u662F\u4ECA\u65E5\u9875\u7684\u89C6\u89C9\u951A\u70B9\uFF08habit \u7C7B App \u5934\u90E8\u60EF\u4F8B\uFF09\uFF1A\u5347\u5927\u53F7 tabular \u6570\u5B57 */\n.xy-todayhero-num{margin-left:auto;font-size:22px;font-weight:700;color:var(--xyd-accent);font-variant-numeric:tabular-nums;line-height:1.2}\n.xy-todayhero-all .xy-todayhero-num{color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-todayhero .xy-bar{height:10px;margin-top:0}\n.xy-todayhero .xy-banner-ok{margin-top:0}\n\n/* \u613F\u671B\u5361\uFF08\u9875\u9762\uFF09 */\n.xy-wishcard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:var(--xyd-r-card);padding:12px 14px;margin-top:10px;transition:border-color .15s ease,box-shadow .15s ease}\n@media (hover:hover) and (pointer:fine){\n .xy-wishcard:hover{border-color:var(--dsw-alias-border-l2);box-shadow:var(--xyd-shadow-card)}\n}\n.xy-progress-num{margin-left:auto;flex:none;color:var(--dsw-alias-label-secondary);font-size:12px;font-variant-numeric:tabular-nums}\n/* \u4EFB\u52A1\u533A\u62AB\u9732\u5F00\u5173\uFF08\u9ED8\u8BA4\u6536\u8D77\uFF0C\u5C55\u5F00\u96C6\u5408\u8D70 view-state\uFF09\uFF1A\u6574\u884C\u6309\u94AE\u7EE7\u627F\u865A\u7EBF\u5206\u9694\uFF08\u539F\u5C5E\n * .xy-wishtasks \u7684\u5361\u5185\u5206\u754C\uFF09\uFF0C\u7BAD\u5934\u65CB\u8F6C\u53EA\u52A8 transform\uFF1B\u6309\u94AE\u6587\u672C\u542B\u4EFB\u52A1\u6570\uFF08\u53E3\u8BED\u5316\uFF0C\u65E0\u72B6\u6001\u8BCD\uFF09\u3002 */\n.xy-wishtoggle{margin-top:8px;display:flex;align-items:center;gap:5px;width:100%;padding:8px 0 5px;background:none;border:0;border-top:1px dashed var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;cursor:pointer;text-align:left}\n@media (hover:hover) and (pointer:fine){\n .xy-wishtoggle:hover{color:var(--dsw-alias-label-primary)}\n}\n.xy-wishtoggle svg{flex:none;transition:transform .15s ease}\n.xy-wishtoggle[aria-expanded='true'] svg{transform:rotate(180deg)}\n/* \u5361\u5185\u5B50\u4EFB\u52A1\u5217\u8868\uFF1A\u5206\u9694\u7EBF\u5DF2\u4E0A\u79FB\u5230\u62AB\u9732\u5F00\u5173\uFF0C\u884C\u7559\u767D\u7531\u4EFB\u52A1\u884C\u81EA\u8EAB padding \u627F\u62C5\u3002\n * \u7ED3\u6784\u4E3A [taskline, detail?, taskline, detail?] \u2014\u2014 \u76F8\u90BB\u9009\u62E9\u5668\u7CBE\u786E\u547D\u4E2D\u300C\u65B0\u4EFB\u52A1\u884C\u300D\u8FB9\u754C\u3002 */\n.xy-wishtasks{display:flex;flex-direction:column}\n.xy-wishtasks>.xy-taskline+.xy-taskline,.xy-wishtasks>.xy-detail+.xy-taskline{border-top:1px solid var(--dsw-alias-border-l1)}\n.xy-wishtasks>.xy-taskline{padding:9px 0}\n/* \u5C55\u5F00\u8BE6\u60C5\u662F\u5361\u5185\u6700\u540E\u4E00\u4E2A\u5143\u7D20\u65F6\u6536\u6389\u5E95\u90E8\u7559\u767D\uFF1A\u5361\u7247\u81EA\u8EAB padding \u5DF2\u627F\u62C5\u6536\u5C3E */\n.xy-wishtasks>.xy-detail:last-child{margin-bottom:0}\n/* TaskLine \u57FA\u7C7B = \u4E24\u680F\u7F51\u683C\uFF1A\u540D\u79F0/\u5143\u4FE1\u606F\u5C45\u5DE6\u6536\u7F29\u6362\u884C\uFF0C\u52A8\u4F5C\u7C07\uFF08\u9886\u53D6/\u6253\u5361 + \u8BE6\u60C5\u5F00\u5173\uFF09\u53F3\u7F6E\u5782\u76F4\u5C45\u4E2D\uFF1B\n * \u613F\u671B\u5361\u5B50\u4EFB\u52A1\u4E0E\u4EFB\u52A1\u9875\u5171\u7528\u540C\u4E00\u884C\u8BED\u6CD5\u3002 */\n.xy-taskline{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;row-gap:2px;align-items:center}\n.xy-taskname{grid-column:1;grid-row:1;font-weight:600;font-size:13px;overflow-wrap:anywhere}\n.xy-taskline>.xy-meta{grid-column:1;grid-row:2;margin-top:0}\n.xy-taskline>div:last-child{grid-column:2;grid-row:1/span 2;justify-self:end}\n/* \u5371\u9669\u56FE\u6807\u952E\u7EDF\u4E00\u9759\u9ED8\u6863\uFF08\u957F\u5217\u8868\u9010\u884C\u91CD\u590D\u7684\u4F4E\u9891\u9AD8\u5371\u52A8\u4F5C\uFF1A\u613F\u671B\u5361\u5934\u5220\u9664 / \u8BB0\u5FC6\u884C\u5220\u9664\uFF09\uFF1A\n * \u57FA\u7840\u900F\u660E\u5EA6 0.78\u2014\u2014\u6DF7\u5E95\u540E\u56FE\u6807\u63CF\u8FB9\u5BF9\u6BD4\u6D45\u8272 3.73 / \u6DF1\u8272 5.06\uFF0C\u6EE1\u8DB3 WCAG 1.4.11\n * \u975E\u6587\u5B57 \u22653:1\uFF08\u539F\u6CE8\u300C\u22654.5:1\u300D\u4EC5\u6DF1\u8272\u6210\u7ACB\uFF0C\u5DF2\u6309\u975E\u6587\u5B57\u53E3\u5F84\u66F4\u6B63\uFF09\uFF0Chover/focus \u6062\u590D\n * \u6EE1\u5F3A\u5EA6\uFF1B\u6587\u5B57\u5371\u9669\u952E\uFF08.xy-btn-danger \u65E0 .xy-btn-icon\uFF09\u4FDD\u6301\u6EE1\u5F3A\u5EA6\u4E0D\u53D7\u6B64\u6863\u3002 */\n.xy-btn-danger.xy-btn-icon{opacity:.78}\n.xy-btn-danger.xy-btn-icon:focus-visible{opacity:1}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger.xy-btn-icon:hover:not(:disabled){opacity:1}\n}\n\n/* ===== \u65E5\u5386 ===== */\n/* \u73B0\u4EE3\u65E5\u5386\u8BED\u6CD5\uFF08Apple/Google Calendar \u60EF\u4F8B\uFF09\uFF1A\u65E0\u8FB9\u6846\u8FDE\u7EED\u7F51\u683C\uFF0C\u65E5\u671F\u53F7\u5750\u5728\u5706\u7AE0\u4E0A\uFF0C\n * \u72B6\u6001\u8BED\u4E49\u5168\u90E8\u7531\u5706\u7AE0\u627F\u8F7D\uFF08\u5F85\u6253\u5361=\u4E2D\u6027\u8BA1\u5212\u5E95\u3001\u90E8\u5206\u5B8C\u6210=\u7425\u73C0\u3001\u5168\u90E8\u5B8C\u6210=\u7EFF\uFF09\uFF0C\n * today/picked \u8D70\u5706\u7AE0\u7684\u73AF\u4E0E\u5B9E\u5E95\uFF0C\u4E0D\u518D\u6574\u683C\u5237\u8272/\u6574\u683C\u63CF\u8FB9\u3002\n * \u90BB\u6708\u8865\u4F4D\u65E5 = \u4F4E\u900F\u660E\u5EA6\u6570\u5B57\uFF08\u7EAF\u89C6\u89C9\u5EF6\u7EED\uFF0C\u5207\u6708\u6B8B\u884C\u4E0D\u788E\u7247\u5316\uFF09\u3002 */\n.xy-calcard{padding:0;overflow:hidden}\n/* \u6708\u4EFD\u5BFC\u822A\u6210\u7EC4\u5C45\u4E2D\uFF1B\u300C\u56DE\u5230\u672C\u6708\u300D\u7EDD\u5BF9\u5B9A\u4F4D\u8D34\u53F3\u7F18\uFF0C\u4E0D\u6324\u5360\u4E2D\u8F74\uFF08\u7A84\u5C4F\u6539\u968F\u6D41\u907F\u514D\u76F8\u649E\uFF09 */\n.xy-calnav{position:relative;justify-content:center}\n.xy-calnav-back{position:absolute;right:0}\n@media (max-width:520px){.xy-calnav-back{position:static;margin-left:4px}}\n.xy-calhead{display:grid;grid-template-columns:repeat(7,1fr);padding:11px 0 8px}\n.xy-calhead-cell{text-align:center;font-size:12px;color:var(--dsw-alias-label-secondary)}\n.xy-cal{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l1)}\n.xy-week{display:grid;grid-template-columns:repeat(7,1fr)}\n.xy-cell{height:42px;border:none;background:transparent;cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;padding:0;font-family:inherit;color:var(--dsw-alias-label-primary)}\n/* \u5706\u7AE0\uFF1A32px \u5706\u5F62\uFF0C\u72B6\u6001\u5E95\u8272/\u73AF/\u5B9E\u5E95\u90FD\u6302\u8FD9\u91CC */\n.xy-daynum{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;font-variant-numeric:tabular-nums;transition:background-color .15s ease,box-shadow .15s ease,color .15s ease}\n.xy-cell:focus-visible{outline-offset:-3px}\n/* \u90BB\u6708\u8865\u4F4D\u65E5\uFF1A\u5F31\u5316\u6570\u5B57\uFF08\u4E0D\u53EF\u805A\u7126\u4E0D\u53EF\u70B9\uFF09\u3002opacity .45 \u5728\u6D45\u8272\u4E0B\u4EC5 1.8:1\uFF0C\n * \u63D0\u5230 .55 \u4FDD\u6301\u300C\u4F4E\u4E00\u6863\u300D\u7684\u89C6\u89C9\u6B21\u5E8F\u540C\u65F6\u4E0D\u518D\u8FD1\u4E4E\u9690\u5F62 */\n.xy-outside{cursor:default}\n.xy-outside .xy-daynum{color:var(--dsw-alias-label-secondary);opacity:.55}\n/* \u65E0\u5B89\u6392 = \u7559\u767D + \u6B21\u8981\u5B57 */\n.xy-c0{cursor:default}\n.xy-c0 .xy-daynum{color:var(--dsw-alias-label-secondary)}\n/* \u5F85\u6253\u5361 = \u4E2D\u6027\u8BA1\u5212\u5E95\uFF08\u9AD8\u9891\u72B6\u6001\u4E0D\u4F5C\u8B66\u793A\u8272\uFF09\uFF1Binset \u63CF\u8FB9\u8BA9 c1 \u5706\u7AE0\u4E0E\u56FE\u4F8B\u70B9\u540C\u6784\n * \uFF08c1 \u5E95\u8272\u5BF9\u5361\u5E95\u4EC5 \u22481.1:1\uFF0C\u56FE\u4F8B\u70B9\u6709\u63CF\u8FB9\u800C\u5706\u7AE0\u6CA1\u6709\u2014\u2014\u4E24\u4FA7\u89C2\u611F\u4E0D\u4E00\u81F4\uFF09 */\n.xy-c1 .xy-daynum{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2)}\n/* \u90E8\u5206\u5B8C\u6210 / \u5168\u90E8\u5B8C\u6210 = \u67D4\u548C\u8BED\u4E49\u5E95\uFF0C\u5B57\u8272\u6309\u4E3B\u9898\u914D\u5BF9\u4FDD\u8BC1 \u22654.5:1 */\n.xy-c2 .xy-daynum{background:var(--xyd-c2-soft);color:var(--xyd-on-c2)}\n.xy-c3 .xy-daynum{background:var(--xyd-c3-soft);color:var(--xyd-on-c3)}\nbody[data-ds-dark-theme] .xy-c2 .xy-daynum{color:var(--xyd-on-c2)}\nbody[data-ds-dark-theme] .xy-c3 .xy-daynum{color:var(--xyd-on-c3)}\n/* hover \u6655\u5E95\u6392\u9664\u5DF2\u9009\u4E2D\u683C\u4E0E\u8BED\u4E49\u72B6\u6001\u683C\uFF1Aspecificity \u9AD8\u4E8E\u5355\u7C7B\u9009\u62E9\u5668\uFF0C\u4E0D\u6392\u9664\u7684\u8BDD\n * \u60AC\u505C\u5728\u5DF2\u9009\u65E5\u4E0A\u4F1A\u7528\u6655\u5E95\u76D6\u6389\u9009\u4E2D\u5B9E\u5E95\uFF08\u89C6\u89C9\u4E0A\u300C\u53D6\u6D88\u9009\u4E2D\u300D\uFF09\uFF1Bc2/c3 \u540C\u7406\u2014\u2014\n * \u72B6\u6001\u5E95\u8272\u6B63\u662F\u7528\u6237\u60AC\u505C\u6838\u5BF9\u7684\u90A3\u4E2A\u4FE1\u606F\uFF0C\u4E0D\u80FD\u5728\u60AC\u505C\u77AC\u95F4\u88AB\u6655\u5E95\u62B9\u6389 */\n@media (hover:hover) and (pointer:fine){\n .xy-cell:not(.xy-outside):not(.xy-picked):not(.xy-c2):not(.xy-c3):hover .xy-daynum{background:var(--xyd-accent-soft)}\n}\n/* \u4ECA\u65E5 = accent \u73AF\u5305\u5706\u7AE0\uFF1A\u4E0D\u8986\u76D6\u72B6\u6001\u5E95\u8272\uFF08\u300C\u4ECA\u5929\u8BE5\u6253\u5361\u300D\u7684\u63D0\u793A\u4E0D\u80FD\u88AB\u5403\u6389\uFF09 */\n.xy-today .xy-daynum{box-shadow:0 0 0 2px var(--xyd-accent)}\n/* \u9009\u4E2D = accent \u5B9E\u5E95\u5706\u7AE0\uFF08\u5373\u65F6\u53CD\u9988\u77ED\u6682\u6001\uFF0C\u8986\u76D6\u72B6\u6001\u8272\u53EF\u63A5\u53D7\uFF0C\u8BE6\u60C5\u9762\u677F\u7D27\u968F\u5176\u4E0B\uFF09 */\n.xy-picked .xy-daynum{background:var(--xyd-accent);color:var(--xyd-on-accent)}\n.xy-legend{display:flex;gap:14px;margin-top:10px;font-size:12px;color:var(--dsw-alias-label-secondary);align-items:center;flex-wrap:wrap}\n.xy-dot{width:10px;height:10px;border-radius:3px;display:inline-block;margin-right:4px;vertical-align:-1px}\n.xy-dot.xy-dot-checked{background:var(--xyd-accent)}\n/* \u56FE\u4F8B\u7F3A\u53E3\u70B9\uFF1A\u4E0E\u67F1\u4F53\u540C\u4E00\u659C\u7EB9\u8BED\u6CD5\uFF08\u5355\u4E00\u4E8B\u5B9E\u6E90\uFF0C\u4E24\u5904\u6C38\u4E0D\u6F02\u79FB\uFF09 */\n.xy-dot.xy-dot-gap{border:1px solid var(--dsw-alias-border-l2);background:repeating-linear-gradient(135deg,var(--xyd-hatch) 0 2px,transparent 2px 4px)}\n/* \u56FE\u4F8B\u4E0E\u5706\u7AE0\u540C\u6784\uFF1A\u65E0\u5B89\u6392=\u63CF\u8FB9\u7A7A\u5FC3\u3001\u5F85\u6253\u5361=\u4E2D\u6027\u5E95\u3001\u90E8\u5206/\u5168\u90E8\u5B8C\u6210=\u8BED\u4E49\u67D4\u548C\u5E95 */\n.xy-dot.xy-c0{background:transparent;border:1px solid var(--dsw-alias-border-l2)}\n.xy-dot.xy-c1{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2)}\n.xy-dot.xy-c2{background:var(--xyd-c2-soft)}\n.xy-dot.xy-c3{background:var(--xyd-c3-soft-dot)}\n/* \u5361\u5373\u8868\u540E\uFF1A\u56FE\u4F8B\u8D34\u5361\u5E95\u5E76\u4EE5 hairline \u4E0E\u7F51\u683C\u5206\u754C */\n.xy-calcard .xy-legend{margin-top:0;padding:10px 14px 12px;border-top:1px solid var(--dsw-alias-border-l1)}\n/* \u8BE6\u60C5\u9762\u677F\u5E38\u9A7B\u5E76\u5347\u7EA7\u4E3A\u9644\u5361\uFF1A\u56FA\u5B9A\u6700\u5C0F\u9AD8\u5EA6 + \u8D85\u957F\u5185\u90E8\u6EDA\u52A8\uFF0C\u70B9\u51FB\u4E0D\u540C\u65E5\u671F\u4E0D\u518D\u5F15\u8D77\u6574\u9875\u9AD8\u5EA6\u6296\u52A8 */\n.xy-daypanel{margin-top:10px;min-height:112px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:11px 14px}\n.xy-daypanel .xy-daydetail{max-height:300px;overflow-y:auto;scrollbar-gutter:stable}\n/* \u8BE6\u60C5\u4EFB\u52A1\u884C\u590D\u7528\u5206\u7EC4\u5361\u884C\u8BED\u6CD5\uFF1A\u8D34\u9762\u677F\u5185\u8FB9\u8DDD\uFF0C\u4E0D\u7559\u53CC\u91CD\u5927\u8FB9\u8DDD */\n.xy-daypanel .xy-grouprow{padding:9px 0}\n.xy-daypanel .xy-section-title{margin-top:2px}\n.xy-dayhint{padding-top:0}\n/* \u62FE\u53D6\u52A0\u8F7D\u884C\uFF1A\u70B9\u51FB\u65E5\u671F\u53D6\u8BE6\u60C5\u671F\u95F4\u7684\u7EC6\u6761\u9AA8\u67B6\uFF08\u5360\u4F4D\u9AD8\u5EA6\u6052\u5B9A\uFF0C\u9762\u677F\u4E0D\u8DF3\uFF09 */\n.xy-pickline{height:12px;width:46%;margin-top:2px}\n\n/* ===== \u7EDF\u8BA1\u5361 & \u6210\u957F ===== */\n.xy-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-top:8px}\n.xy-statcard{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:14px;text-align:center}\n/* \u5C42\u7EA7\uFF1A\u666E\u901A\u7EDF\u8BA1\u6570\u5B57\u7528\u4E3B\u6587\u5B57\u8272\uFF08\u9875\u9762\u66F4\u5B89\u9759\uFF09\uFF0C\u4EC5\u300C\u5F53\u524D\u8FDE\u7EED\u300D\u8FD9\u5F20\u5361\u4EE5\u54C1\u724C\u8272+\u6D45\u6655\u5E95\u7A81\u51FA\n * \uFF08habit \u7C7B App \u628A streak \u4F5C\u4E3A\u82F1\u96C4\u6307\u6807\u7F6E\u4E8E\u70ED\u529B\u56FE\u65C1\u7684\u60EF\u4F8B\uFF09 */\n.xy-statnum{font-size:24px;font-weight:700;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums}\n.xy-statcard-hot{border-color:var(--xyd-accent-border);background:linear-gradient(160deg,var(--xyd-accent-soft),transparent 62%),var(--dsw-alias-bg-layer-1)}\n.xy-statcard-hot .xy-statnum{color:var(--xyd-accent)}\n/* \u7F3A\u7701\u503C\uFF08\u6682\u65E0/N/A\uFF09\uFF1A\u6B21\u8981\u8272\u5C0F\u4E00\u53F7\uFF0C\u7F3A\u5931\u4FE1\u606F\u4E0D\u5F97\u6BD4\u771F\u5B9E\u6570\u636E\u66F4\u54CD */\n.xy-statcard-muted .xy-statnum{color:var(--dsw-alias-label-secondary);font-size:18px}\n/* \u7A84\u9762\u677F\uFF08\u4F1A\u8BDD\u89C6\u56FE\u9875\u968F\u58F3\u6536\u7F29\uFF09\u4E0B 30 \u6839\u67F1\u88AB flex \u6324\u538B\u5230 ~10px \u5BBD\uFF0C\u89E6\u5C4F\u96BE\u4EE5\u547D\u4E2D\uFF1A\n * \u5BB9\u5668\u6A2A\u5411\u6EDA\u52A8 + \u6700\u5C0F\u5BBD\u515C\u5E95\uFF08\u2264520px \u4E0E\u65E5\u5386\u65AD\u70B9\u540C\u53E3\u5F84\uFF09\u628A\u67F1\u5BBD\u62AC\u5230 ~13px\u2014\u2014\n * \u662F\u547D\u4E2D\u4F53\u9A8C\u7684\u6539\u5584\u4F46\u672A\u8FBE WCAG 2.5.8 \u7684 24px\uFF08\u8FBE\u6807\u9700 min-width ~810px\uFF0C\u6EDA\u52A8\u6210\u672C\n * \u8FDC\u8D85\u8BEF\u89E6\u4EE3\u4EF7\uFF0C\u56FE\u8868 tooltip \u5C5E\u4F4E\u98CE\u9669\u4FE1\u606F\u67E5\u8BE2\uFF0C\u6709\u610F\u53D6\u820D\uFF09\uFF1B\u5BBD\u9762\u677F\uFF08\u72EC\u7ACB\n * /xingyuan/growth \u9875\uFF09\u5185\u5BB9\u4E0D\u8D85\u5BBD\u3001\u6EDA\u52A8\u5BB9\u5668\u65E0\u611F\u77E5 */\n.xy-growth-scroll{overflow-x:auto}\n.xy-growth{display:flex;gap:3px;align-items:stretch;height:120px;margin-top:10px}\n.xy-growth-col{flex:1;display:flex;flex-direction:column;height:100%;min-width:0;border:none;background:transparent;padding:0;cursor:default;border-radius:3px 3px 0 0}\n.xy-growth-stack{flex:1;display:flex;flex-direction:column;justify-content:flex-end;width:100%}\n.xy-growth-bar{background:var(--xyd-accent);border-radius:2px 2px 0 0;width:100%}\n.xy-growth-col.xy-full .xy-growth-bar{background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n/* \u672A\u5B8C\u6210\u7F3A\u53E3\uFF1A\u659C\u7EB9\u5197\u4F59\u7F16\u7801\uFF08\u8DDF\u968F\u4E3B\u9898\u6587\u5B57\u8272\u6DF7\u5408\uFF09\u2014\u2014layer-2 \u5B9E\u8272\u5728\u6DF1\u8272\u58F3\u4E0E\u9762\u677F\u5E95\n * \u51E0\u4E4E\u540C\u4EAE\u5EA6\u800C\u9690\u5F62\uFF0C\u659C\u7EB9\u5728\u4E24\u79CD\u4E3B\u9898\u4E0B\u90FD\u6709\u7A33\u5B9A\u7684\u7EB9\u7406\u53EF\u89C1\u5EA6\uFF0C\u4E14\u4E0E\u5B9E\u5FC3\u5B8C\u6210\u67F1\u5F62\u6210\n * \u300C\u5F62\u72B6 \u00D7 \u989C\u8272\u300D\u53CC\u901A\u9053\u533A\u5206\uFF0C\u4E0D\u4F9D\u8D56\u8272\u89C9\u5355\u901A\u9053 */\n.xy-growth-missed{width:100%;border-radius:2px 2px 0 0;background:repeating-linear-gradient(135deg,var(--xyd-hatch) 0 2px,transparent 2px 5px),var(--xyd-hatch-faint)}\nbutton.xy-growth-col{cursor:pointer}\nbutton.xy-growth-col.xy-hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}\n@media (hover:hover) and (pointer:fine){\n button.xy-growth-col:hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}\n}\n@media (max-width:520px){\n .xy-growth-scroll .xy-growth,.xy-growth-scroll .xy-growth-axis{min-width:480px}\n}\n/* \u57FA\u7EBF\u8D34\u67F1\u5E95\uFF08\u4E0E\u804A\u5929\u56FE\u8868\u5361\u7684 SVG \u57FA\u7EBF\u540C\u4E00\u8BED\u6CD5\uFF09\uFF0C\u523B\u5EA6\u5C42\u4E0B\u79FB\u8BA9\u51FA\u7EBF\u7684\u4F4D\u7F6E */\n.xy-growth-axis{position:relative;height:20px;margin-top:0;border-top:1px solid var(--dsw-alias-border-l2)}\n.xy-growth-tick{position:absolute;top:4px;font-size:12px;line-height:16px;color:var(--xyd-label-on-2);white-space:nowrap;font-variant-numeric:tabular-nums}\n/* \u6210\u957F\u9875\u60AC\u6D6E\u660E\u7EC6 */\n.xy-tip{position:relative;margin-top:0;min-height:20px;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-inner);padding:3px 10px;display:inline-block;font-variant-numeric:tabular-nums}\n.xy-tip:empty{visibility:hidden}\n/* \u56FE\u8868\u52A0\u8F7D\u5360\u4F4D\uFF1A\u4E0E\u6210\u54C1\u56FE\u7B49\u9AD8\uFF0C\u6570\u636E\u5230\u8FBE\u4E0D\u5F15\u8D77\u4E0B\u65B9\u5185\u5BB9\u4F4D\u79FB */\n.xy-chartload{height:150px;margin-top:8px}\n\n/* ===== \u6210\u957F\u9875\uFF1A\u7B49\u7EA7\u82F1\u96C4\u5361 + \u7B49\u7EA7\u8BF4\u660E ===== */\n/* \u6E10\u53D8\u4E24\u7AEF\u5747\u4E3A\u5B9E\u8272\uFF08\u6DF1\u6863\u2192\u57FA\u6863\uFF0Cgrowth.ts \u5185\u8054 darkenHex \u9884\u6DF7\uFF09\uFF0C\u767D\u5B57\u5BF9\u5E95\u8272 \u22654.5:1\n * \u5728\u6D45\u8272\u58F3\u4E0B\u540C\u6837\u6210\u7ACB\u2014\u2014\u534A\u900F\u660E\u6E10\u53D8\u6DF7\u5165\u9875\u9762\u767D\u5E95\u540E\u53F3\u7AEF\u4F1A\u8DCC\u7834 3:1\uFF0C\u5DF2\u5F03\u7528\u3002 */\n.xy-hero{display:flex;gap:14px;align-items:center;border-radius:var(--xyd-r-card);padding:18px;margin-top:12px;border:1px solid var(--xyd-hero-border);box-shadow:var(--xyd-shadow-hero)}\n.xy-herobadge{width:54px;height:54px;border-radius:12px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:16px;flex:none;text-shadow:var(--xyd-herobadge-glyph-shadow)}\n.xy-heromain{flex:1;min-width:0}\n.xy-onhero{color:var(--xyd-on-hero)!important}\n.xy-herotitle{font-size:19px;font-weight:700;margin:3px 0 8px;color:#fff}\n.xy-bar-onhero{background:var(--xyd-bar-on-hero)}\n.xy-bar-fill-solid{background:#fff}\n.xy-heroreward{margin-top:8px}\n.xy-levels{display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:4px 14px}\n/* \u7B49\u7EA7\u884C\u7684\u300C\u672A\u8FBE\u6210\u300D\u964D\u6743\u8D70\u6587\u5B57\u8272\u800C\u975E\u6574\u884C opacity\uFF080.68 \u6DF7\u5E95\u540E label-on-2/secondary\n * \u5747\u8DCC\u7834 AA\uFF0C\u6700\u4F4E \u22482.6:1\uFF09\uFF1A\u540D\u79F0/\u5956\u52B1\u7528 secondary\uFF08\u22654.5:1\uFF09\uFF0C\u5FBD\u7AE0\u672C\u5C31\u662F\u4E2D\u6027\u5E95 +\n * label-on-2\uFF08\u6821\u51C6 5.0:1\uFF09\uFF1B\u547D\u4E2D\u884C\u6062\u590D\u4E3B\u6587\u5B57\u8272 + \u5F69\u8272\u5FBD\u7AE0\uFF0C\u5C42\u7EA7\u611F\u4E0D\u9760\u900F\u660E\u5EA6 */\n.xy-levelrow{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--dsw-alias-border-l1);font-size:13px}\n.xy-levelrow:last-child{border-bottom:none}\n.xy-levelrow .xy-lvname{color:var(--dsw-alias-label-secondary)}\n.xy-levelhit .xy-lvname{color:var(--dsw-alias-label-primary)}\n.xy-lvnum{width:42px;height:24px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none}\n.xy-lvname{font-weight:600;width:64px;color:var(--dsw-alias-label-primary)}\n.xy-lvreward{margin-left:auto;text-align:right}\n\n/* ===== \u8BB0\u5FC6\u9875 ===== */\n/* \u6DFB\u52A0/\u7F16\u8F91\u8BB0\u5FC6\u8868\u5355\uFF1A\u865A\u7EBF\u9762\u677F\u5361\uFF08\u4E0E\u5FEB\u901F\u65B0\u5EFA\u540C\u4E00\u300C\u53EF\u4E66\u5199\u300D\u8BED\u6CD5\uFF09 */\n.xy-compose{margin-top:12px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px;display:flex;gap:8px;flex-wrap:wrap}\n.xy-compose .xy-input-grow{flex:1 1 170px;width:auto;min-width:140px}\n.xy-compose select.xy-input{width:auto}\n.xy-editing{display:flex;align-items:center;gap:10px;margin-top:12px;padding:7px 10px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-inner)}\n.xy-memactions{display:flex;gap:6px;flex:none}\n.xy-membar{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}\n.xy-membar .xy-input-search{width:min(250px,100%)}\n.xy-memcap{margin-top:6px}\n/* \u8D85\u957F\u8BB0\u5FC6\u503C 3 \u884C\u622A\u65AD\uFF08\u22641000 \u5B57\u7B26\u8BB0\u5F55\u4E0D\u518D\u6491\u51FA\u6570\u5C4F\u9AD8\u884C\uFF1B\u5B8C\u6574\u503C\u5728\u5220\u9664\u786E\u8BA4\u5F39\u7A97\u53EF\u89C1\uFF09 */\n.xy-memval{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}\n.xy-saved{color:var(--dsw-alias-state-success-primary,var(--xyd-ok));font-size:13px}\n.xy-memfoot{display:flex;align-items:center;gap:12px;margin-top:14px}\n\n/* ===== \u8BBE\u7F6E\u9875 ===== */\n.xy-settings{display:flex;flex-direction:column;gap:16px;max-width:560px;color:var(--dsw-alias-label-primary);font-size:14px}\n/* \u8BBE\u7F6E\u4E09\u4E2A\u5206\u8282\u5404\u81EA\u6210\u9762\u677F\u5361\uFF1B\u95F4\u8DDD\u4EA4\u7ED9 xy-settings \u7684 gap\uFF0C\u5361\u5185\u5B50\u5143\u7D20\u7EDF\u4E00 10px \u7EB5\u5411\u8282\u594F */\n.xy-settings .xy-panel{margin-top:0}\n.xy-settings .xy-panel>*+*{margin-top:10px}\n.xy-field{display:flex;flex-direction:column;gap:6px}\n.xy-field-head{display:flex;align-items:center;gap:8px;font-weight:600}\n.xy-input-wide{width:100%;max-width:360px;box-sizing:border-box}\n.xy-seg{display:flex;gap:6px;flex-wrap:wrap}\n.xy-seg-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:999px;padding:5px 14px;font-size:13px;cursor:pointer;transition:border-color .15s ease,background-color .15s ease,color .15s ease}\n@media (hover:hover) and (pointer:fine){\n .xy-seg-btn:hover{border-color:var(--xyd-accent)}\n}\n/* \u9009\u4E2D\u6001\u53CC\u9009\u62E9\u5668\uFF1A\u7C7B\u540D\u4E0E aria-pressed \u5C5E\u6027\u7B49\u4EF7\uFF08\u7EC4\u4EF6\u4FA7\u7528\u5C5E\u6027\u8868\u8FBE\u72B6\u6001\u8BED\u4E49\uFF09 */\n.xy-seg-btn.xy-on,.xy-seg-btn[aria-pressed='true']{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}\n.xy-save-row{display:flex;align-items:center;gap:10px;margin-top:2px}\n.xy-toggle{width:38px;height:22px;appearance:none;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);position:relative;cursor:pointer;transition:background .15s}\n.xy-toggle:checked{background:var(--xyd-accent);border-color:transparent}\n.xy-toggle::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .15s}\n.xy-toggle:checked::after{transform:translateX(16px);background:var(--xyd-on-accent)}\n.xy-hint{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0}\n/* \u786E\u8BA4\u7C7B\u76EE\u660E\u7EC6\uFF1A\u7F29\u8FDB\u5D4C\u5728\u603B\u5F00\u5173\u4E0B\uFF08\u4E0E\u300C\u603B\u5F00\u5173 + \u660E\u7EC6\u300D\u5206\u5C42\u540C\u6784\uFF09\uFF0C\u884C = \u5F00\u5173 + \u540D\u79F0\uFF1B\n * \u9501\u5B9A\u884C\uFF08\u5220\u9664\uFF09\u4E3A\u53EA\u8BFB\u5C55\u793A\uFF0C\u5176\u8BF4\u660E\u884C\u7F29\u8FDB\u4E0E\u6587\u5B57\u5BF9\u9F50\uFF08\u5F00\u5173 38px + \u95F4\u8DDD 8px\uFF09 */\n.xy-confirm-ops{display:flex;flex-direction:column;gap:8px;margin-left:22px}\n/* \u7981\u7528\u5F31\u5316\u5FC5\u987B\u663E\u5F0F\u5199\uFF1A\u81EA\u5B9A\u4E49\u5916\u89C2\u7684 toggle \u4E0D\u5403\u539F\u751F\u7981\u7528\u53D8\u7070\uFF0C\u603B\u5F00\u5173\u5173\u95ED\u65F6\u660E\u7EC6\u884C\n * \u5426\u5219\u4E0E\u53EF\u7528\u6001\u65E0\u6CD5\u533A\u5206\uFF1B\u9501\u5B9A\u7684\u5220\u9664\u884C\u6052\u7981\u7528\uFF0C\u5E38\u6001\u5F31\u5316\u5373\u300C\u51BB\u7ED3\u5728\u5F00\u542F\u6001\u300D\u7684\u8BED\u4E49 */\n.xy-confirm-ops .xy-toggle:disabled{opacity:.4;cursor:default}\n.xy-op-group-head{font-weight:600;font-size:13px}\n.xy-op-row{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:13px}\n.xy-op-row-locked{color:var(--dsw-alias-label-secondary);cursor:default}\n.xy-op-locked-hint{padding-left:46px}\n\n/* ===== \u8BE6\u60C5\u805A\u5408\u89C6\u56FE ===== */\n/* \u6BB5\u95F4 10px \u547C\u5438\uFF1B\u6BCF\u6BB5\u5185\u90E8\u300C\u6807\u7B7E \u2192 \u5185\u5BB9\u300D\u56FA\u5B9A 5px \u7EB5\u5411\u8282\u594F\uFF08label \u4E0D\u518D\u4E0E\u5185\u5BB9\u6587\u5B57\u6324\u884C\uFF09\u3002\n * \u5E95\u90E8\u7559 8px\uFF1A\u64CD\u4F5C\u6309\u94AE\u4E0E\u4E0B\u4E00\u6761\u4EFB\u52A1\u7684\u5206\u5272\u7EBF\u4E0D\u5F97\u8D34\u6B7B\uFF08\u613F\u671B\u5361\u91CC\u5206\u5272\u7EBF\u76F4\u63A5\u538B\u5728\u8BE6\u60C5\u4E0B\u7F18\uFF09\uFF0C\n * \u4EFB\u52A1\u9875\u7531 xy-taskrow \u8986\u76D6\u4E3A 2px\uFF08\u5206\u7EC4\u5361\u884C\u81EA\u5E26 11px \u5185\u8FB9\u8DDD\uFF0C\u603B\u91CF\u5DF2\u591F\uFF09\u3002 */\n.xy-detail{margin-top:8px;margin-bottom:8px;border-top:1px dashed var(--dsw-alias-border-l1);padding-top:10px;display:flex;flex-direction:column;gap:10px}\n.xy-detail>div{display:flex;flex-direction:column;gap:5px;align-items:flex-start;min-width:0}\n.xy-detail>div>.xy-meta{margin-top:0}\n.xy-detail-grid{display:grid;grid-template-columns:repeat(7,max-content);gap:4px;padding:2px 0}\n/* \u6253\u5361\u683C\uFF1A22px + 11px \u6570\u5B57\uFF08\u53EF\u8BFB\u6027\u4E0B\u9650\uFF09\uFF1Bradius 6 \u4E3A\u5FBD\u7AE0\u7EA7\u5FAE\u5143\u7D20\u4F8B\u5916\u6863\u3002\n * \u7F51\u683C\u6309\u5468\u5BF9\u9F50\uFF08\u5468\u4E00\u59CB\uFF0C\u4E0E\u65E5\u5386\u9875\u8868\u5934\u540C\u6784\uFF09\uFF1A\u8FDE\u7EED\u6027\u4E00\u773C\u53EF\u8BFB\uFF08GitHub/Streaks \u60EF\u4F8B\uFF09\uFF0C\n * \u9996\u884C\u524D\u7F6E\u7A7A\u4F4D\u7531 .xy-dcell-blank \u5360\u4F4D\u3002 */\n.xy-dcell{width:22px;height:22px;border-radius:6px;font-size:11px;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;padding:0;border:none;cursor:default;font-variant-numeric:tabular-nums}\n.xy-dcell-blank{visibility:hidden}\n/* \u4ECA\u65E5\u683C = accent \u73AF\u5305\u5E95\u8272\uFF1A\u4E0E\u65E5\u5386\u9875\u5706\u7AE0\u7684 today \u73AF\u540C\u4E00\u8BED\u6CD5 */\n.xy-dcell.xy-dcell-today{box-shadow:0 0 0 2px var(--xyd-accent)}\n.xy-dcell-checked{background:var(--xyd-dcell-checked);color:var(--xyd-on-dcell)}\nbody[data-ds-dark-theme] .xy-dcell-checked{color:var(--xyd-on-dcell)}\n.xy-dcell-missed{background:transparent;border:1px dashed var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary)}\n.xy-dcell-future{background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);border:1px solid var(--dsw-alias-border-l1)}\n/* \u56FE\u4F8B\u590D\u7528 xy-dot \u65F6\u501F\u683C\u5B50\u7684\u8BED\u4E49\u5E95\u8272\uFF08\u540C\u8272\u7CFB\u5C0F\u5C3A\u5BF8\uFF09 */\n.xy-dot.xy-dcell-missed{background:transparent;border:1px dashed var(--dsw-alias-border-l3)}\n.xy-dot.xy-dcell-future{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1)}\n.xy-dot.xy-dcell-checked{background:var(--xyd-dcell-checked-dot)}\n.xy-detail-next{font-size:12px;color:var(--dsw-alias-label-secondary)}\n/* \u64CD\u4F5C\u884C\u4E0E\u5168\u7AD9\u6309\u94AE\u7EC4\u540C\u62CD\uFF08gap 8\uFF09\uFF1A\u5220\u9664\u5728\u540C\u4E00\u884C\u6D41\u5185\u9760 danger \u63CF\u8FB9\u533A\u5206\uFF0C\n * \u786E\u8BA4\u5F39\u7A97\u515C\u5E95\u9632\u8BEF\u89E6\u2014\u2014\u4E0D\u518D margin-left:auto \u6F02\u5230\u5361\u7F18\uFF08\u7A84\u9762\u677F\u91CC\u662F\u4E00\u6BB5\u7A81\u5140\u7A7A\u767D\uFF0C\n * \u613F\u671B\u5361\u91CC\u8FD8\u4F1A\u4E0E\u5361\u5934\u7684\u613F\u671B\u7EA7\u5220\u9664\u540C\u4FA7\u5BF9\u9F50\u9020\u6210\u8BED\u4E49\u6DF7\u6DC6\uFF09 */\n.xy-detail-ops{display:flex;gap:8px;flex-wrap:wrap;align-items:center}\n\n/* ===== \u5206\u7C7B\u7BA1\u7406 ===== */\n.xy-catpanel{margin-top:10px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px}\n.xy-catrow{display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l1)}\n.xy-catrow:last-child{border-bottom:none}\n.xy-catcount{margin-left:auto}\n.xy-catops{display:flex;gap:6px}\n.xy-swatchrow{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;align-items:center}\n/* \u8272\u677F\u683C\uFF1A24px \u547D\u4E2D\u76EE\u6807 + hover \u63CF\u8FB9 + \u4E3B\u9898\u4EE4\u724C\u63CF\u8FB9\uFF08\u6DF1\u8272\u4E0B\u4E0D\u518D\u9690\u8EAB\uFF09 */\n.xy-swatch{width:24px;height:24px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);cursor:pointer;padding:0;position:relative;transition:box-shadow .15s ease}\n.xy-swatch:disabled{opacity:.55;cursor:not-allowed}\n@media (hover:hover) and (pointer:fine){\n .xy-swatch:hover:not(:disabled){box-shadow:inset 0 0 0 2px var(--xyd-accent-ring-soft)}\n}\n/* \u9009\u4E2D\u6001\u53CC\u73AF\uFF08\u5185\u767D\u9699 + \u5916\u5F3A\u8C03\u5708\uFF09\uFF1A\u4EFB\u4F55\u8272\u76F8\u4E0B\u90FD\u6E05\u6670\u53EF\u8FA8\uFF0C\u4E0D\u4F9D\u8D56\u5BF9\u52FE\u672C\u8EAB\u7684\u5BF9\u51B2 */\n.xy-swatch.xy-picked{box-shadow:inset 0 0 0 2px var(--xyd-swatch-ring),0 0 0 2px var(--xyd-accent)}\n.xy-swatch.xy-picked::after{content:'\u2713';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-size:12px;font-weight:700;text-shadow:var(--xyd-swatch-glyph-shadow)}\n.xy-catloading{padding:6px 0}\n/* \u884C\u5185\u6539\u540D\u7F16\u8F91\u5668\uFF1A\u8F93\u5165\u5728\u7A84\u9762\u677F\u6536\u7F29\uFF08\u65E0 min-width:0 \u65F6 input \u56FA\u6709\u5BBD\u5EA6\u4F1A\u628A\n * \u4FDD\u5B58/\u53D6\u6D88\u952E\u6324\u51FA 320px \u9762\u677F\u88AB overflow-x:clip \u65E0\u58F0\u88C1\u6389\uFF09 */\n.xy-rename{display:flex;gap:6px;align-items:center;margin-top:8px;flex-wrap:wrap}\n.xy-rename .xy-input{flex:1 1 120px;min-width:0;width:auto}\n\n/* ===== \u5FEB\u901F\u65B0\u5EFA ===== */\n.xy-quick{margin-top:10px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);padding:12px 14px;display:flex;flex-direction:column;gap:10px;background:var(--dsw-alias-bg-layer-1)}\n.xy-quick-row{display:flex;gap:10px;flex-wrap:wrap}\n.xy-quick-field{display:flex;flex-direction:column;gap:4px;min-width:150px;flex:1}\n.xy-quick-label{font-size:12px;color:var(--dsw-alias-label-secondary);font-weight:600}\n.xy-quick-actions{display:flex;gap:10px;align-items:center}\n\n/* ===== \u6EDA\u52A8\u6761\u69FD\u4F4D\u6052\u5B9A\uFF08\u5BBD\u5EA6\u9632\u6296\u7B2C\u4E8C\u9053\u4FDD\u9669\uFF09=====\n * \u58F3\u7684\u4F1A\u8BDD\u6EDA\u52A8\u5BB9\u5668\uFF08CSS Modules\u300C\u54C8\u5E0C\u524D\u7F00_\u8BED\u4E49\u540E\u7F00\u300D\u7A33\u5B9A\u547D\u540D + data-conversation-scroll\n * \u6807\u8BB0\uFF09\u9ED8\u8BA4 gutter stable\uFF0C\u4F46\u8F93\u5165\u6846\u6D6E\u5C42\u6A21\u5F0F\u4F1A\u4E3B\u52A8\u653E\u5F00\u4E3A auto\u2014\u2014\u7ECF\u5178\u6EDA\u52A8\u6761\u6309\u9700\u51FA\u73B0\u4F1A\u62BD\u8D70\n * ~15px \u5BBD\u5EA6\uFF08\u70B9\u300C\u65B0\u5EFA\u300D\u5C55\u5F00\u8868\u5355\u3001\u5C55\u5F00\u8BE6\u60C5\u5373\u89E6\u53D1\uFF09\uFF0C\u5C45\u4E2D\u9875\u9762\u968F\u4E4B\u6574\u5E27\u5DE6\u53F3\u5F39\u8DF3\u3002\n * \u8FD9\u91CC\u5BF9\u6EDA\u52A8\u5BB9\u5668\u672C\u8EAB\u65E0\u6761\u4EF6\u5F3A\u5236\u5E38\u9A7B\u69FD\u4F4D\uFF1B\u4E0E useStableScrollbar \u7684 useLayoutEffect\n * \u8FD0\u884C\u65F6\u9489\u4F4F\u4E92\u4E3A\u5197\u4F59\uFF08\u6837\u5F0F\u5148\u4E8E\u9996\u5E27\uFF0C\u8FD0\u884C\u65F6\u515C\u5E95\u58F3\u4FA7\u8282\u70B9\u66FF\u6362\uFF09\u3002 */\n[class*='_scrollBody'][data-conversation-scroll]{scrollbar-gutter:stable!important}\n\n/* \u5F31\u5316\u52A8\u753B\u504F\u597D\uFF1A\u5C0A\u91CD prefers-reduced-motion\uFF08\u542B\u5F00\u5173\u6ED1\u5757\u3001hover \u8FC7\u6E21\u3001\u63D2\u753B\u65E0\u52A8\u753B\u3001toast \u8FDB\u51FA\u573A\u3001\u786E\u8BA4\u5F39\u7A97\uFF09 */\n@media (prefers-reduced-motion: reduce){\n .xy-skel,.xy-toast,.xy-modal-backdrop,.xy-modal{animation:none}\n .xy-toast-out,.xy-modal-backdrop.xy-modal-out,.xy-modal-out .xy-modal{transition:none}\n .xy-bar-fill,.xy-btn,.xy-toggle,.xy-toggle::after,.xy-wishcard,.xy-cell,.xy-daynum,.xy-seg-btn,.xy-input,.xy-swatch,.xy-grouprow,.xy-wishtoggle svg{transition:none}\n}\n";
19
+ export declare const STYLE_TEXT = "\n/* ===== \u54C1\u724C\u4E0E\u8BED\u4E49\u4EE4\u724C ===== */\n:root{\n --xyd-accent:#1a6fe0;\n --xyd-on-accent:#ffffff;\n --xyd-accent-strong:#1e40af;\n --xyd-accent-soft:rgba(26,111,224,.12);\n --xyd-danger:#c0392b;\n --xyd-danger-bg:#c0392b;\n --xyd-warn:#b45309;\n --xyd-ok:#0f766e;\n /* \u5F69\u5E95\u5C0F\u5706\u6807\u7684\u524D\u666F\u5BF9\uFF1A\u6309\u4E3B\u9898\u914D\u5BF9\u4FDD\u8BC1 \u22654.5:1\uFF08\u6DF1\u8272\u4EAE\u5E95\u914D\u6DF1\u5B57\uFF09 */\n --xyd-on-ok:#ffffff;\n --xyd-on-danger:#ffffff;\n /* \u6B21\u8981\u6587\u5B57\u5728\u6B21\u7EA7\u9762\u677F\u5E95\uFF08layer-2\uFF09\u4E0A\u7684\u4E13\u7528\u5BF9\uFF1A\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9 layer-2 \u53EA\u6709\n * \u22484.3:1\uFF0C\u672C\u5BF9\u6309 5.0+:1 \u6821\u51C6\uFF08\u9884\u89C8\u6761/\u7EC4\u8BA1\u6570/\u7B49\u7EA7\u7F16\u53F7/\u672A\u6765\u683C/\u6210\u957F\u8F74\u523B\u5EA6\uFF09 */\n --xyd-label-on-2:#5d6a7d;\n /* \u534A\u900F\u660E\u884D\u751F\u8272\uFF08\u7981 color-mix\uFF0C\u6309\u4E3B\u9898\u663E\u5F0F rgba\uFF09\uFF1A\u5F3A\u8C03\u63CF\u8FB9 / \u5F3A\u8C03\u60AC\u505C\u73AF /\n \u5371\u9669\u63CF\u8FB9 / \u5371\u9669\u60AC\u505C\u5E95 / \u4E2D\u6027\u884C\u60AC\u505C\u5E95 / \u659C\u7EB9\u7EB9\u7406\u4E0E\u5F31\u5316\u5E95 */\n --xyd-accent-border:rgba(26,111,224,.38);\n --xyd-accent-ring:rgba(26,111,224,.72);\n --xyd-accent-ring-soft:rgba(26,111,224,.55);\n --xyd-danger-border:rgba(192,57,43,.4);\n --xyd-danger-soft:rgba(192,57,43,.09);\n --xyd-hover:rgba(15,23,42,.05);\n --xyd-hatch:rgba(100,116,139,.36);\n --xyd-hatch-faint:rgba(100,116,139,.14);\n /* \u6210\u529F/\u8B66\u793A\u8BED\u4E49\u67D4\u548C\u5E95\u4E0E\u63CF\u8FB9\u5BF9\uFF08\u6253\u5361\u5361/\u5FAE\u884C\u52A8\u5361/\u6210\u529F\u6A2A\u5E45/\u56FE\u8868\u5FBD\u7AE0\uFF09\uFF1A\n * \u6B64\u524D\u5355\u503C\u900F\u660E\u5EA6\u4E24\u4E3B\u9898\u5171\u7528\uFF0C\u6DF1\u8272\u4E0B .08 \u7EFF\u6D17\u51E0\u4E4E\u4E0D\u53EF\u89C1 */\n --xyd-ok-soft:rgba(56,217,169,.09);\n --xyd-ok-border:rgba(56,217,169,.4);\n --xyd-ok-badge:rgba(56,217,169,.18);\n --xyd-warn-soft:rgba(255,169,77,.2);\n --xyd-warn-border:rgba(255,169,77,.4);\n /* \u65E5\u5386\u72B6\u6001\u5E95\uFF08\u90E8\u5206/\u5168\u90E8\u5B8C\u6210\uFF09\u4E0E\u6253\u5361\u8BB0\u5F55\u683C\uFF08\u5DF2\u6253\u5361\uFF09\u7684\u6210\u5BF9\u5E95\u8272 */\n --xyd-c2-soft:rgba(255,169,77,.32);\n --xyd-c3-soft:rgba(16,185,129,.22);\n --xyd-c3-soft-dot:rgba(16,185,129,.30);\n --xyd-dcell-checked:rgba(56,217,169,.42);\n --xyd-dcell-checked-dot:rgba(56,217,169,.55);\n /* \u4E0A\u8FF0\u6210\u5BF9\u5E95\u8272\u7684\u524D\u666F\u4F19\u4F34\uFF08\u540C\u4F7F\u7528\u70B9\u6536\u8FDB\u4EE4\u724C\u533A\uFF0C\u6F02\u79FB\u5373\u7EA2\uFF09 */\n --xyd-on-c2:#7c4a03;\n --xyd-on-c3:#065f46;\n --xyd-on-dcell:#0b3d26;\n /* warn-soft \u5E95\u7684\u524D\u666F\u4F19\u4F34\uFF08StaleBanner \u6587\u5B57\uFF09\uFF1A\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9\u7425\u73C0\u67D4\u5E95\u6D45 4.19 /\n \u6DF1 2.95\uFF0C\u8DCC\u7834 WCAG 1.4.3 AA\u2014\u2014\u6309 \u22654.5:1 \u6821\u51C6\u7684\u4E13\u7528\u5BF9\uFF08on-c2 \u540C\u65CF\u6696\u7425\u73C0\u524D\u666F\uFF09 */\n --xyd-on-warn:#7c4a03;\n /* \u9634\u5F71\u5BF9\uFF08\u5361\u7247\u60AC\u505C/toast/\u5F39\u7A97/\u82F1\u96C4\u5361\uFF09\uFF1A\u6DF1\u6D45\u5404\u81EA\u914D\u6863\uFF0C\u7981\u6B62\u6B63\u6587\u533A\u88F8\u5199 rgba */\n --xyd-shadow-card:0 2px 10px rgba(15,23,42,.07);\n --xyd-shadow-toast:0 8px 24px -8px rgba(15,23,42,.2),0 2px 8px -2px rgba(15,23,42,.1);\n --xyd-shadow-modal:0 24px 48px -16px rgba(15,23,42,.35),0 4px 12px -4px rgba(15,23,42,.2);\n --xyd-shadow-hero:0 2px 10px rgba(30,25,60,.16);\n --xyd-hero-border:rgba(255,255,255,.16);\n --xyd-on-hero:rgba(255,255,255,.92);\n --xyd-bar-on-hero:rgba(255,255,255,.28);\n --xyd-swatch-ring:rgba(255,255,255,.85);\n --xyd-swatch-glyph-shadow:0 0 2px rgba(0,0,0,.85),0 1px 3px rgba(0,0,0,.6);\n --xyd-herobadge-glyph-shadow:0 1px 2px rgba(0,0,0,.18);\n /* \u58F3\u906E\u7F69\u4EE4\u724C\u7F3A\u5E2D\u65F6\u7684\u515C\u5E95\uFF08\u4E0D\u518D\u5728\u89C4\u5219\u884C\u5185\u88F8\u5199 rgba \u515C\u5E95\u503C\uFF09 */\n --xyd-mask:rgba(15,23,42,.45);\n /* \u5706\u89D2\u523B\u5EA6 */\n --xyd-r-card:12px;--xyd-r-inner:9px;--xyd-r-ctl:8px;\n}\nbody[data-ds-dark-theme]{\n --xyd-accent:#60a5fa;\n --xyd-on-accent:#0f172a;\n --xyd-accent-strong:#93c5fd;\n --xyd-accent-soft:rgba(96,165,250,.16);\n --xyd-danger:#ff9b8f;\n --xyd-danger-bg:#e2635a;\n --xyd-warn:#fbbf24;\n --xyd-ok:#34d399;\n --xyd-on-ok:#052e21;\n --xyd-on-danger:#3f1008;\n --xyd-label-on-2:#9aa6b7;\n --xyd-accent-border:rgba(96,165,250,.38);\n --xyd-accent-ring:rgba(96,165,250,.72);\n --xyd-accent-ring-soft:rgba(96,165,250,.55);\n --xyd-danger-border:rgba(255,155,143,.4);\n --xyd-danger-soft:rgba(255,155,143,.12);\n --xyd-hover:rgba(148,163,184,.1);\n --xyd-hatch:rgba(139,152,171,.4);\n --xyd-hatch-faint:rgba(139,152,171,.16);\n --xyd-ok-soft:rgba(52,211,153,.14);\n --xyd-ok-border:rgba(52,211,153,.55);\n --xyd-ok-badge:rgba(52,211,153,.22);\n --xyd-warn-soft:rgba(255,169,77,.26);\n --xyd-warn-border:rgba(255,169,77,.5);\n --xyd-c2-soft:rgba(255,169,77,.24);\n --xyd-c3-soft:rgba(52,211,153,.22);\n --xyd-c3-soft-dot:rgba(52,211,153,.30);\n --xyd-dcell-checked:rgba(46,160,105,.32);\n --xyd-dcell-checked-dot:rgba(46,160,105,.45);\n --xyd-on-c2:#ffd9a8;\n --xyd-on-c3:#a7f3c9;\n --xyd-on-dcell:#a7f3c9;\n --xyd-on-warn:#ffd9a8;\n --xyd-shadow-card:0 2px 10px rgba(0,0,0,.32);\n --xyd-shadow-toast:0 8px 24px -8px rgba(0,0,0,.5),0 2px 8px -2px rgba(0,0,0,.35);\n --xyd-shadow-modal:0 24px 48px -16px rgba(0,0,0,.55),0 4px 12px -4px rgba(0,0,0,.4);\n --xyd-shadow-hero:0 2px 10px rgba(0,0,0,.4);\n --xyd-hero-border:rgba(255,255,255,.16);\n --xyd-on-hero:rgba(255,255,255,.92);\n --xyd-bar-on-hero:rgba(255,255,255,.28);\n --xyd-swatch-ring:rgba(255,255,255,.85);\n --xyd-swatch-glyph-shadow:0 0 2px rgba(0,0,0,.85),0 1px 3px rgba(0,0,0,.6);\n --xyd-herobadge-glyph-shadow:0 1px 2px rgba(0,0,0,.18);\n --xyd-mask:rgba(0,0,0,.5);\n}\n\n.xy-visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n\n/* ===== \u4F1A\u8BDD\u5361\u7247 ===== */\n.xy-card{border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:11px 14px;margin:6px 0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:14px}\n.xy-card-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\n/* \u957F\u5185\u5BB9\u7EAA\u5F8B\uFF1A\u5FBD\u7AE0\u4E0D\u6536\u7F29\uFF1B\u6807\u9898\u5141\u8BB8\u65AD\u884C\u6536\u7F29\u2014\u2014\u675C\u7EDD\u957F\u82F1\u6587\u8BCD\u6A2A\u5411\u6EA2\u51FA\u4E0E\u6574\u884C\u6296\u52A8 */\n.xy-badge{flex:none;font-size:12px;border-radius:6px;padding:1px 7px;color:var(--dsw-alias-label-primary)}\n/* \u5206\u7C7B\u5FBD\u7AE0\uFF1AHSL \u53D8\u91CF\u4F9B\u8272\uFF0C\u4EAE\u5EA6\u6309\u4E3B\u9898\u5206\u5C42\uFF08\u5BF9\u9F50 Web wish-category \u7684 .dark \u8986\u76D6\u53E3\u5F84\uFF09 */\n.xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(--cat-sbg,58)*1%) 92%);color:hsl(var(--cat-h,275) calc(var(--cat-sfg,46)*1%) 30%);border:1px solid hsl(var(--cat-h,275) calc(var(--cat-sbd,46)*1%) 55% / .12)}\nbody[data-ds-dark-theme] .xy-badge-cat{background:hsl(var(--cat-h,275) calc(var(--cat-sbg,58)*1%) 22%);color:hsl(var(--cat-h,275) calc(var(--cat-sfg,46)*1%) 80%);border-color:hsl(var(--cat-h,275) calc(var(--cat-sbd,46)*1%) 70% / .2)}\n.xy-badge-task{background:var(--xyd-accent-soft)}\n.xy-badge-chart{background:var(--xyd-ok-badge)}\n.xy-badge-micro{background:var(--xyd-warn-soft)}\n.xy-title{min-width:0;font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}\n.xy-deleted{opacity:.65}\n.xy-deleted .xy-title{text-decoration:line-through}\n.xy-meta{color:var(--dsw-alias-label-secondary);font-size:12px;margin-top:4px;overflow-wrap:anywhere}\n/* \u6B21\u7EA7\u9762\u677F\u5E95\u4E0A\u7684\u6B21\u8981\u6587\u5B57\u7528\u4E13\u7528\u5BF9\uFF08\u58F3\u901A\u7528\u6B21\u8981\u8272\u5BF9 layer-2 \u4EC5 \u22484.3:1\uFF0C\u53CC\u4E3B\u9898\u540C\u75C5\uFF09 */\n.xy-preview{margin-top:6px;font-size:12px;color:var(--xyd-label-on-2);background:var(--dsw-alias-bg-layer-2);border-radius:var(--xyd-r-inner);padding:6px 8px}\n.xy-checkin{border-color:var(--xyd-ok-border);background:var(--xyd-ok-soft)}\n.xy-glyph{font-size:15px;font-weight:700;line-height:1}\n.xy-glyph-ok{color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-glyph-back{color:var(--dsw-alias-label-secondary)}\n.xy-actioned{margin-left:auto;color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n\n/* \u5FAE\u884C\u52A8\u5361 */\n.xy-micro{border-color:var(--xyd-warn-border)}\n.xy-microsteps{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}\n.xy-microstep{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-inner);background:var(--dsw-alias-bg-layer-2)}\n.xy-microstep.xy-done .xy-microsteptext{text-decoration:line-through}\n/* \u5B8C\u6210/\u8DF3\u8FC7\u6B65\u7684\u6587\u5B57\u964D\u6743\u8D70\u6B21\u8981\u8272\u800C\u975E\u6574\u884C opacity\uFF08\u5BF9\u6BD4\u5EA6\u4F9D\u636E\u540C\u4E0A .xy-done \u6CE8\uFF09 */\n.xy-microstep.xy-done .xy-microsteptext,.xy-microstep.xy-skipped .xy-microsteptext{color:var(--dsw-alias-label-secondary)}\n.xy-microstepnum{flex:none;width:20px;height:20px;border-radius:50%;background:var(--xyd-accent);color:var(--xyd-on-accent);display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;margin-top:1px}\n.xy-microsteptext{font-size:13px;display:flex;flex-direction:column;min-width:0}\n/* \u5361\u5185\u6B65\u9AA4\u8BF4\u660E/\u72B6\u6001\u8BCD\u7684\u80CC\u666F\u662F layer-2\uFF1A\u6B21\u8981\u6587\u5B57\u7528 label-on-2 \u4E13\u7528\u5BF9\uFF08\u58F3\u901A\u7528\n * \u6B21\u8981\u8272\u5BF9 layer-2 \u4EC5 \u22484.3:1\uFF0C\u53CC\u4E3B\u9898\u540C\u75C5\u2014\u2014\u4E0E xy-preview \u540C\u4E00\u6CBB\u7406\u7EBF\uFF09 */\n.xy-microstep .xy-meta{color:var(--xyd-label-on-2)}\n.xy-microstate{margin-left:auto;flex:none}\n\n/* \u56FE\u8868\u5361 */\n.xy-chart{background:var(--dsw-alias-bg-layer-1)}\n.xy-chart-legend{display:flex;gap:12px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary);align-items:center}\n.xy-arcwrap{margin-top:8px}\n.xy-arcnum{font-size:22px;font-weight:700;color:var(--xyd-accent);font-variant-numeric:tabular-nums}\n.xy-bar{height:8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);margin-top:6px;overflow:hidden}\n/* \u586B\u5145\u8D70 scaleX\uFF08\u5408\u6210\u5668\u52A8\u753B\uFF09\uFF1Awidth \u8FC7\u6E21\u4F1A\u9010\u5E27\u89E6\u53D1\u5E03\u5C40\uFF0Ctransform \u53EA\u8FDB\u5408\u6210\u5668 */\n.xy-bar-fill{height:100%;border-radius:inherit;background:var(--xyd-accent);transform-origin:0 50%;transition:transform .35s cubic-bezier(.22,1,.36,1)}\n.xy-rows{list-style:none;margin-top:6px;display:flex;flex-direction:column;gap:4px;padding:0}\n.xy-row{display:flex;justify-content:space-between;font-size:13px}\n.xy-rowval{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}\n.xy-heat{display:grid;grid-template-columns:repeat(auto-fill,minmax(14px,1fr));gap:2px;margin-top:8px}\n.xy-heatcell{aspect-ratio:1;border-radius:3px;background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-svg{width:100%;height:auto;margin-top:6px}\n\n/* ===== Toast \u8F7B\u63D0\u793A ===== */\n.xy-toasts{position:fixed;top:14px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:8px;z-index:9999;pointer-events:none;max-width:min(92vw,460px)}\n.xy-toast{pointer-events:auto;display:flex;align-items:center;gap:9px;padding:9px 14px;border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);font-size:13px;box-shadow:var(--xyd-shadow-toast);animation:xy-toast-in .24s cubic-bezier(.22,1,.36,1);cursor:pointer}\n.xy-toast-out{opacity:0;transform:translateY(-6px);transition:opacity .22s ease,transform .22s ease}\n@keyframes xy-toast-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}\n.xy-toast-glyph{flex:none;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}\n.xy-toast-ok .xy-toast-glyph{background:var(--dsw-alias-state-success-primary,var(--xyd-ok));color:var(--xyd-on-ok)}\n.xy-toast-info .xy-toast-glyph{background:var(--xyd-accent);color:var(--xyd-on-accent)}\n.xy-toast-error .xy-toast-glyph{background:var(--xyd-danger-bg);color:var(--xyd-on-danger)}\n.xy-toast-text{min-width:0;overflow-wrap:anywhere}\n\n/* ===== \u5E94\u7528\u5185\u786E\u8BA4\u5F39\u7A97 =====\n * \u539F\u751F window.confirm \u7684\u66FF\u4EE3\uFF1A\u906E\u7F69 + \u9762\u677F\u5361\uFF0C\u5168\u90E8\u8D70\u4E3B\u9898\u4EE4\u724C\uFF08\u6DF1\u6D45\u8272\u81EA\u9002\u5E94\uFF09\u3002\n * \u52A8\u6548\u53EA\u7528 opacity/transform\uFF1Bz-index \u538B\u8FC7 toast \u5C42\uFF0C\u907F\u514D\u8F7B\u63D0\u793A\u6D6E\u5728\u5F39\u7A97\u4E4B\u4E0A\u3002 */\n.xy-modal-backdrop{position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;padding:20px;background:var(--dsw-alias-bg-mask-1,var(--xyd-mask));animation:xy-fade-in .16s ease-out}\n.xy-modal-backdrop.xy-modal-out{opacity:0;transition:opacity .15s ease}\n.xy-modal{width:min(400px,100%);background:var(--dsw-alias-bg-overlay,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);padding:16px 18px;box-shadow:var(--xyd-shadow-modal);animation:xy-pop-in .18s cubic-bezier(.22,1,.36,1)}\n.xy-modal-out .xy-modal{transform:scale(.98);transition:transform .15s ease}\n.xy-modal-msg{margin:0;font-size:14px;line-height:1.65;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;max-height:min(56vh,440px);overflow-y:auto}\n.xy-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n@keyframes xy-fade-in{from{opacity:0}to{opacity:1}}\n@keyframes xy-pop-in{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n/* \u5B9E\u5FC3\u5371\u9669\u786E\u8BA4\u952E\uFF08\u5220\u9664\u7C7B\u52A8\u4F5C\u4E13\u7528\uFF09\uFF1A\u4E0E\u63CF\u8FB9\u5371\u9669\u952E\u533A\u5206\u300C\u5DF2\u786E\u8BA4\u5C06\u6267\u884C\u300D\u7684\u91CD\u91CF */\n.xy-btn-danger-solid{background:var(--xyd-danger-bg);border-color:transparent;color:var(--xyd-on-danger)}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger-solid:hover:not(:disabled){filter:brightness(1.08);color:var(--xyd-on-danger)}\n}\n\n/* ===== \u9AA8\u67B6\u5C4F\u52A0\u8F7D\u6001 ===== */\n.xy-skel{border-radius:var(--xyd-r-inner);background:linear-gradient(90deg,var(--dsw-alias-bg-layer-2) 25%,var(--dsw-alias-bg-layer-1) 45%,var(--dsw-alias-bg-layer-2) 65%);background-size:200% 100%;animation:xy-shimmer 1.4s ease infinite}\n.xy-skel-title{height:22px;width:38%;margin-bottom:14px}\n.xy-skel-row{height:64px;margin-top:10px}\n@keyframes xy-shimmer{from{background-position:180% 0}to{background-position:-20% 0}}\n\n/* ===== \u7A7A\u6001\uFF08\u7EAF\u6587\u5B57\u7248\u5F0F\uFF0C\u63D2\u753B\u5DF2\u79FB\u9664\uFF1A\u89C1 PageEmpty \u6CE8\u91CA\uFF09===== */\n.xy-page-center{display:flex;flex-direction:column;align-items:center;gap:6px;padding:44px 0;text-align:center}\n.xy-empty-title{font-weight:600;color:var(--dsw-alias-label-primary);margin-top:4px}\n.xy-empty-hint{margin-top:2px;max-width:360px}\n\n/* ===== \u4F1A\u8BDD\u89C6\u56FE\u9875\u9AA8\u67B6 ===== */\n/* \u8282\u594F\u9501\uFF1A\u9875 padding 18/20 \u00B7 \u533A\u5757\u95F4 14\uFF08section-title \u4E0A\u8FB9\u8DDD\uFF09\u00B7 \u884C\u95F4\u8DDD 6/10 */\n.xy-page{box-sizing:border-box;width:100%;max-width:min(780px,100%);min-width:0;margin:0 auto;padding:18px 20px 26px;color:var(--dsw-alias-label-primary);font-size:14px;overflow-x:clip}\n.xy-page-head{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}\n/* \u5C45\u4E2D\u884C\u5185\u7684 .xy-meta \u5173\u95ED\u9ED8\u8BA4 4px \u4E0A\u8FB9\u8DDD\uFF1Aflex \u6309\u542B margin \u7684\u76D2\u5B50\u5C45\u4E2D\uFF0C\u9876\u8DDD\u4F1A\u8BA9\n * \u6B21\u8981\u6587\u5B57\u6052\u5B9A\u4F4E 2px\uFF08\u4E0E .xy-detail>div>.xy-meta \u540C\u4E00\u6761\u6CBB\u7406\u7EBF\uFF0C\u5934\u90E8\u6F0F\u6CBB\u70B9\u5728\u6B64\u6536\u53E3\uFF09 */\n.xy-card-head .xy-meta,.xy-page-head .xy-meta{margin-top:0}\n.xy-page-title{font-size:17px;font-weight:700;margin:0;color:var(--dsw-alias-label-primary)}\n.xy-section-title{font-size:12px;color:var(--dsw-alias-label-secondary);margin:14px 0 6px;font-weight:600;letter-spacing:.02em}\n/* \u9875\u5934\u52A8\u4F5C\u7EC4\uFF1A\u5355\u4E00 margin-left:auto \u6574\u4F53\u53F3\u7F6E\u2014\u2014\u591A\u6309\u94AE\u5404\u81EA auto \u4F1A\u5E73\u5206\u5269\u4F59\u7A7A\u95F4 */\n.xy-page-actions{display:flex;align-items:center;gap:8px;margin-left:auto;flex-wrap:wrap}\n\n/* \u63A7\u4EF6\u4F53\u7CFB */\n.xy-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border-radius:var(--xyd-r-ctl);padding:5px 12px;min-height:28px;font-size:13px;cursor:pointer;line-height:1.5;transition:border-color .15s ease,background-color .15s ease,color .15s ease,filter .15s ease,transform .12s ease}\n/* \u60AC\u505C\u53CD\u9988\u4EC5\u5728\u300C\u771F\u60AC\u505C\u300D\u8BBE\u5907\u751F\u6548\uFF1A\u89E6\u5C4F\u6CA1\u6709\u53EF\u9760\u7684 hover \u9000\u51FA\uFF0C\u884C/\u683C/\u6309\u94AE\u7684\n * \u60AC\u505C\u5E95\u8272\u4F1A\u7C98\u6EDE\u5230\u4E0B\u4E00\u6B21\u70B9\u6309\uFF08hover \u95E8\u63A7 = (hover:hover) and (pointer:fine)\uFF09 */\n@media (hover:hover) and (pointer:fine){\n .xy-btn:hover:not(:disabled){border-color:var(--xyd-accent);color:var(--xyd-accent-strong)}\n}\n.xy-btn:active:not(:disabled){transform:scale(.97)}\n.xy-btn:disabled{opacity:.55;cursor:not-allowed}\n.xy-btn:focus-visible,.xy-input:focus-visible,.xy-cell:focus-visible,.xy-seg-btn:focus-visible,.xy-toggle:focus-visible,.xy-swatch:focus-visible,.xy-growth-col:focus-visible,.xy-wishtoggle:focus-visible{outline:2px solid var(--xyd-accent);outline-offset:2px}\n/* \u89E6\u63A7\u57FA\u7EBF\uFF1A\u6D88\u9664\u79FB\u52A8\u7AEF\u53CC\u51FB\u7F29\u653E\u5EF6\u8FDF\u4E0E\u7CFB\u7EDF\u70B9\u6309\u9AD8\u4EAE\uFF08\u4EA4\u4E92\u53CD\u9988\u7EDF\u4E00\u7531 hover/active \u627F\u62C5\uFF09 */\n.xy-btn,.xy-seg-btn,.xy-cell,.xy-swatch,.xy-toggle,.xy-growth-col,.xy-wishtoggle{touch-action:manipulation;-webkit-tap-highlight-color:transparent}\n/* \u884C\u5185\u6309\u94AE\uFF1A\u226526px \u547D\u4E2D\u76EE\u6807\uFF08\u5361\u7247\u5934/\u64CD\u4F5C\u884C\u7684\u7D27\u51D1\u4E3B\u6218\u6309\u94AE\uFF09 */\n.xy-btn-inline{margin-left:auto;padding:3px 10px;font-size:12px;min-height:26px;display:inline-flex;align-items:center}\n/* \u56FE\u6807\u5E7D\u7075\u952E\uFF08\u226526px \u65B9\u5F62\u547D\u4E2D\u76EE\u6807\uFF09\uFF1A\u7F16\u8F91/\u5220\u9664\u8FD9\u7C7B\u9AD8\u9891\u91CD\u590D\u7684\u884C\u5185\u4F4E\u9891\u52A8\u4F5C\u964D\u566A\u2014\u2014\n * \u56FE\u6807\u7EBF\u7A3F\u627F\u8BB8\u53EF\u4E49\u3001\u6587\u5B57\u8BED\u4E49\u8D70 aria-label\uFF1Bhover/focus \u624D\u663E\u5E95\u8272\u3002 */\n.xy-btn-icon{width:26px;height:26px;min-height:26px;padding:0;display:inline-flex;align-items:center;justify-content:center;flex:none}\n.xy-btn-primary{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-primary:hover:not(:disabled){filter:brightness(1.06);color:var(--xyd-on-accent)}\n}\n.xy-btn-danger{color:var(--xyd-danger);border-color:var(--xyd-danger-border);background:transparent}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger:hover:not(:disabled){background:var(--xyd-danger-soft);color:var(--xyd-danger)}\n}\n.xy-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:var(--xyd-r-ctl);padding:5px 8px;font-size:13px;font-family:inherit;transition:border-color .15s ease}\n@media (hover:hover) and (pointer:fine){\n .xy-input:hover:not(:disabled){border-color:var(--dsw-alias-border-l3)}\n}\n.xy-input::placeholder{color:var(--dsw-alias-label-secondary)}\n.xy-input:disabled{opacity:.55;cursor:not-allowed}\n.xy-field-err{color:var(--xyd-danger);font-size:12px;margin-top:4px}\n/* \u6570\u5B57\u5FAE\u8F93\u5165\uFF08\u8BBE\u7F6E\u9875\u6CE8\u5165\u4E0A\u9650\u7B49\uFF09\uFF1A\u6309\u5185\u5BB9\u957F\u5EA6\u5B9A\u5BBD\uFF0C\u4E0D\u968F\u6D4F\u89C8\u5668\u9ED8\u8BA4 size \u62C9\u6210\u5BBD\u6761 */\n.xy-input-num{width:96px;font-variant-numeric:tabular-nums}\n\n/* \u5217\u8868\u884C */\n.xy-rowmain{display:flex;flex-direction:column;gap:2px;min-width:0}\n.xy-rowtitle{font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}\n/* \u5B8C\u6210\u6001\u884C\u9996\u88C5\u9970\u52FE\uFF08aria-hidden\uFF0C\u8BED\u4E49\u7531\u884C\u6587\u6848\u627F\u62C5\uFF09 */\n.xy-done-glyph{color:var(--dsw-alias-state-success-primary,var(--xyd-ok));margin-right:2px}\n/* \u9AD8\u91CD\u8981\u5EA6\u661F\u6807\uFF1A\u7425\u73C0\u8B66\u793A\u8272\uFF08\u4E0D\u590D\u7528\u5B8C\u6210\u52FE\u7684\u7EFF\u8272\uFF0C\u8BED\u4E49\u4E0D\u649E\u8F66\uFF09 */\n.xy-star-hi{color:var(--xyd-warn);margin-right:2px}\n/* \u5B8C\u6210\u6001\u884C\uFF1A\u6807\u9898\u7528\u6B21\u8981\u8272\u964D\u6743\uFF08secondary \u5B9E\u6D4B\u6D45 4.76 / \u6DF1 5.15 \u22654.5:1\uFF09\u2014\u2014\u4E0D\u7528\u6574\u884C\n * opacity\uFF1A0.78 \u6DF7\u5E95\u540E\u6587\u5B57\u6709\u6548\u5BF9\u6BD4\u4EC5 \u22483.1:1\uFF0C\u8DCC\u7834 WCAG 1.4.3 AA\uFF08opacity \u53EA\u7559\u7ED9\n * aria-hidden \u7684\u88C5\u9970\u5143\u7D20\uFF0C\u884C\u5185\u53EF\u8BFB\u6587\u5B57\u4E00\u5F8B\u8D70\u989C\u8272\u964D\u6743\uFF09 */\n.xy-done .xy-rowtitle{color:var(--dsw-alias-label-secondary)}\n.xy-banner-ok{margin-top:10px;padding:10px 12px;border-radius:var(--xyd-r-inner);background:var(--xyd-ok-soft);border:1px solid var(--xyd-ok-border);font-size:13px}\n/* \u5237\u65B0\u5931\u8D25\u4F46\u65E7\u6570\u636E\u4ECD\u5728\u7684\u8BDA\u5B9E\u964D\u7EA7\u6A2A\u5E45\uFF1A\u7425\u73C0\u865A\u7EBF\u9762\u677F\uFF08\u8B66\u793A\u4F46\u4E0D\u6050\u5413\u2014\u2014\u52A8\u4F5C\u5DF2\u6210\u529F\uFF09 */\n.xy-stalerow{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px;padding:8px 12px;border:1px dashed var(--xyd-warn-border);border-radius:var(--xyd-r-inner);background:var(--xyd-warn-soft)}\n/* \u63D0\u793A\u6587\u5B57\u7528\u7425\u73C0\u67D4\u5E95\u7684\u4E13\u7528\u524D\u666F\u5BF9\uFF08--xyd-on-warn\uFF09\uFF1A\u6B21\u8981\u901A\u7528\u8272\u5728\u6B64\u5E95\u4E0A\u6D45 4.19 / \u6DF1\n * 2.95\uFF0C\u6DF1\u8272\u8FDC\u4F4E\u4E8E AA\uFF1B\u91CD\u8BD5\u952E\u4FDD\u6301 label-primary\uFF08\u5BF9\u7425\u73C0\u67D4\u5E95 >10:1\uFF09\uFF0C\u65E0\u9700\u5904\u7406 */\n.xy-stalerow .xy-meta{color:var(--xyd-on-warn)}\n.xy-stalerow .xy-btn-inline{margin-left:0}\n\n/* ===== \u5206\u7EC4\u5361\uFF08\u4EFB\u52A1\u9875\u72B6\u6001\u5206\u6876 / \u4ECA\u65E5\u9875\u5F85\u6253\u5361\u00B7\u5DF2\u5B8C\u6210\u5171\u7528\uFF09=====\n * \u5361\u7247\u5BB9\u5668 + \u72B6\u6001\u70B9\u6807\u9898\u884C + \u5206\u9694\u7EBF\u884C\u5217\u8868\uFF1A\u66FF\u4EE3\u88F8\u5806\u53E0\u7684 section-title+wishtasks\uFF1B\n * \u7EC4\u95F4\u8DDD 12 \u4E0E\u9875\u5934 margin-bottom 12 \u540C\u62CD\uFF0C\u884C\u5185\u8FB9\u8DDD 11/14 \u5BF9\u9F50\u5361\u7247\u4F53\u7CFB\u8282\u594F\u9501\u3002 */\n.xy-group{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);overflow:hidden}\n.xy-group-head{display:flex;align-items:center;gap:8px;margin:0;padding:9px 14px;font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1)}\n.xy-group-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-secondary)}\n.xy-group-dot-accent{background:var(--xyd-accent)}\n.xy-group-dot-warn{background:var(--xyd-warn)}\n.xy-group-dot-ok{background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-group-count{margin-left:auto;flex:none;font-size:12px;line-height:1.7;padding:0 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);font-variant-numeric:tabular-nums}\n.xy-grouplist{list-style:none;display:flex;flex-direction:column;margin:0;padding:0}\n.xy-grouprow{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 14px;border-top:1px solid var(--dsw-alias-border-l1);transition:background-color .15s ease}\n.xy-grouprow:first-child{border-top:none}\n@media (hover:hover) and (pointer:fine){\n .xy-grouprow:hover{background:var(--xyd-hover)}\n}\n/* \u5206\u7EC4\u5361\u7684\u5757\u7EA7\u884C\u53D8\u4F53\uFF08\u4EFB\u52A1\u884C + \u53EF\u9009\u5185\u8054\u8BE6\u60C5\uFF09\uFF1BTaskLine \u57FA\u7C7B\u672C\u8EAB\u5373\u4E24\u680F\u7F51\u683C\uFF08\u89C1\u613F\u671B\u5361\u6BB5\uFF09 */\n.xy-taskrow{display:block}\n.xy-taskrow .xy-detail{margin-bottom:2px}\n\n/* ===== \u9762\u677F\u5361\uFF08\u65E5\u5386/\u6210\u957F\u56FE\u8868/\u8BBE\u7F6E\u5206\u8282\u7B49\u901A\u7528\u5BB9\u5668\uFF09=====\n * \u4E0E\u613F\u671B\u5361\u540C\u4E00\u5361\u7247\u8BED\u6CD5\u4F46\u65E0 hover \u6001\uFF1A\u7EAF\u5BB9\u5668\u3002\u5B50\u5143\u7D20\u95F4\u8DDD\u7531\u5404\u9875\u65E2\u6709 margin \u8D1F\u8D23\u3002 */\n.xy-panel{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px}\n.xy-panel>.xy-skel:first-child{margin-top:0}\n.xy-panel-head{margin:0;font-size:14px;font-weight:600;display:flex;align-items:center;gap:8px;color:var(--dsw-alias-label-primary)}\n\n/* ===== \u4ECA\u65E5\u6982\u89C8\u5361 =====\n * \u6807\u9898\u3001\u5B8C\u6210\u8BA1\u6570\u4E0E\u8FDB\u5EA6\u6761\u540C\u5361\u5448\u73B0\uFF1A\u8FDB\u5EA6\u6761\u4E0D\u518D\u4F5C\u4E3A\u88F8\u6761\u60AC\u5728\u9875\u5934\u4E0B\u65B9\n * \uFF080% \u65F6\u5373\u7528\u6237\u6240\u89C1\u300C\u7A7A\u767D\u6A2A\u6761\u300D\uFF09\uFF1B\u54C1\u724C\u8272\u8F7B\u6655\u67D3\u63D0\u4F9B\u4ECA\u65E5\u9875\u7684\u89C6\u89C9\u951A\u70B9\u3002 */\n.xy-todayhero{margin-top:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:13px 16px;display:flex;flex-direction:column;gap:9px;background:linear-gradient(135deg,var(--xyd-accent-soft),transparent 55%),var(--dsw-alias-bg-layer-1)}\n.xy-todayhero-top{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}\n/* \u5B8C\u6210\u8BA1\u6570\u662F\u4ECA\u65E5\u9875\u7684\u89C6\u89C9\u951A\u70B9\uFF08habit \u7C7B App \u5934\u90E8\u60EF\u4F8B\uFF09\uFF1A\u5347\u5927\u53F7 tabular \u6570\u5B57 */\n.xy-todayhero-num{margin-left:auto;font-size:22px;font-weight:700;color:var(--xyd-accent);font-variant-numeric:tabular-nums;line-height:1.2}\n.xy-todayhero-all .xy-todayhero-num{color:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n.xy-todayhero .xy-bar{height:10px;margin-top:0}\n.xy-todayhero .xy-banner-ok{margin-top:0}\n\n/* \u613F\u671B\u5361\uFF08\u9875\u9762\uFF09 */\n.xy-wishcard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:var(--xyd-r-card);padding:12px 14px;margin-top:10px;transition:border-color .15s ease,box-shadow .15s ease}\n@media (hover:hover) and (pointer:fine){\n .xy-wishcard:hover{border-color:var(--dsw-alias-border-l2);box-shadow:var(--xyd-shadow-card)}\n}\n.xy-progress-num{margin-left:auto;flex:none;color:var(--dsw-alias-label-secondary);font-size:12px;font-variant-numeric:tabular-nums}\n/* \u4EFB\u52A1\u533A\u62AB\u9732\u5F00\u5173\uFF08\u9ED8\u8BA4\u6536\u8D77\uFF0C\u5C55\u5F00\u96C6\u5408\u8D70 view-state\uFF09\uFF1A\u6574\u884C\u6309\u94AE\u7EE7\u627F\u865A\u7EBF\u5206\u9694\uFF08\u539F\u5C5E\n * .xy-wishtasks \u7684\u5361\u5185\u5206\u754C\uFF09\uFF0C\u7BAD\u5934\u65CB\u8F6C\u53EA\u52A8 transform\uFF1B\u6309\u94AE\u6587\u672C\u542B\u4EFB\u52A1\u6570\uFF08\u53E3\u8BED\u5316\uFF0C\u65E0\u72B6\u6001\u8BCD\uFF09\u3002 */\n.xy-wishtoggle{margin-top:8px;display:flex;align-items:center;gap:5px;width:100%;padding:8px 0 5px;background:none;border:0;border-top:1px dashed var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;cursor:pointer;text-align:left}\n@media (hover:hover) and (pointer:fine){\n .xy-wishtoggle:hover{color:var(--dsw-alias-label-primary)}\n}\n.xy-wishtoggle svg{flex:none;transition:transform .15s ease}\n.xy-wishtoggle[aria-expanded='true'] svg{transform:rotate(180deg)}\n/* \u5361\u5185\u5B50\u4EFB\u52A1\u5217\u8868\uFF1A\u5206\u9694\u7EBF\u5DF2\u4E0A\u79FB\u5230\u62AB\u9732\u5F00\u5173\uFF0C\u884C\u7559\u767D\u7531\u4EFB\u52A1\u884C\u81EA\u8EAB padding \u627F\u62C5\u3002\n * \u7ED3\u6784\u4E3A [taskline, detail?, taskline, detail?] \u2014\u2014 \u76F8\u90BB\u9009\u62E9\u5668\u7CBE\u786E\u547D\u4E2D\u300C\u65B0\u4EFB\u52A1\u884C\u300D\u8FB9\u754C\u3002 */\n.xy-wishtasks{display:flex;flex-direction:column}\n.xy-wishtasks>.xy-taskline+.xy-taskline,.xy-wishtasks>.xy-detail+.xy-taskline{border-top:1px solid var(--dsw-alias-border-l1)}\n.xy-wishtasks>.xy-taskline{padding:9px 0}\n/* \u5C55\u5F00\u8BE6\u60C5\u662F\u5361\u5185\u6700\u540E\u4E00\u4E2A\u5143\u7D20\u65F6\u6536\u6389\u5E95\u90E8\u7559\u767D\uFF1A\u5361\u7247\u81EA\u8EAB padding \u5DF2\u627F\u62C5\u6536\u5C3E */\n.xy-wishtasks>.xy-detail:last-child{margin-bottom:0}\n/* TaskLine \u57FA\u7C7B = \u4E24\u680F\u7F51\u683C\uFF1A\u540D\u79F0/\u5143\u4FE1\u606F\u5C45\u5DE6\u6536\u7F29\u6362\u884C\uFF0C\u52A8\u4F5C\u7C07\uFF08\u9886\u53D6/\u6253\u5361 + \u8BE6\u60C5\u5F00\u5173\uFF09\u53F3\u7F6E\u5782\u76F4\u5C45\u4E2D\uFF1B\n * \u613F\u671B\u5361\u5B50\u4EFB\u52A1\u4E0E\u4EFB\u52A1\u9875\u5171\u7528\u540C\u4E00\u884C\u8BED\u6CD5\u3002 */\n.xy-taskline{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;row-gap:2px;align-items:center}\n.xy-taskname{grid-column:1;grid-row:1;font-weight:600;font-size:13px;overflow-wrap:anywhere}\n.xy-taskline>.xy-meta{grid-column:1;grid-row:2;margin-top:0}\n.xy-taskline>div:last-child{grid-column:2;grid-row:1/span 2;justify-self:end}\n/* \u5371\u9669\u56FE\u6807\u952E\u7EDF\u4E00\u9759\u9ED8\u6863\uFF08\u957F\u5217\u8868\u9010\u884C\u91CD\u590D\u7684\u4F4E\u9891\u9AD8\u5371\u52A8\u4F5C\uFF1A\u613F\u671B\u5361\u5934\u5220\u9664 / \u8BB0\u5FC6\u884C\u5220\u9664\uFF09\uFF1A\n * \u57FA\u7840\u900F\u660E\u5EA6 0.78\u2014\u2014\u6DF7\u5E95\u540E\u56FE\u6807\u63CF\u8FB9\u5BF9\u6BD4\u6D45\u8272 3.73 / \u6DF1\u8272 5.06\uFF0C\u6EE1\u8DB3 WCAG 1.4.11\n * \u975E\u6587\u5B57 \u22653:1\uFF08\u539F\u6CE8\u300C\u22654.5:1\u300D\u4EC5\u6DF1\u8272\u6210\u7ACB\uFF0C\u5DF2\u6309\u975E\u6587\u5B57\u53E3\u5F84\u66F4\u6B63\uFF09\uFF0Chover/focus \u6062\u590D\n * \u6EE1\u5F3A\u5EA6\uFF1B\u6587\u5B57\u5371\u9669\u952E\uFF08.xy-btn-danger \u65E0 .xy-btn-icon\uFF09\u4FDD\u6301\u6EE1\u5F3A\u5EA6\u4E0D\u53D7\u6B64\u6863\u3002 */\n.xy-btn-danger.xy-btn-icon{opacity:.78}\n.xy-btn-danger.xy-btn-icon:focus-visible{opacity:1}\n@media (hover:hover) and (pointer:fine){\n .xy-btn-danger.xy-btn-icon:hover:not(:disabled){opacity:1}\n}\n\n/* ===== \u65E5\u5386 ===== */\n/* \u73B0\u4EE3\u65E5\u5386\u8BED\u6CD5\uFF08Apple/Google Calendar \u60EF\u4F8B\uFF09\uFF1A\u65E0\u8FB9\u6846\u8FDE\u7EED\u7F51\u683C\uFF0C\u65E5\u671F\u53F7\u5750\u5728\u5706\u7AE0\u4E0A\uFF0C\n * \u72B6\u6001\u8BED\u4E49\u5168\u90E8\u7531\u5706\u7AE0\u627F\u8F7D\uFF08\u5F85\u6253\u5361=\u4E2D\u6027\u8BA1\u5212\u5E95\u3001\u90E8\u5206\u5B8C\u6210=\u7425\u73C0\u3001\u5168\u90E8\u5B8C\u6210=\u7EFF\uFF09\uFF0C\n * today/picked \u8D70\u5706\u7AE0\u7684\u73AF\u4E0E\u5B9E\u5E95\uFF0C\u4E0D\u518D\u6574\u683C\u5237\u8272/\u6574\u683C\u63CF\u8FB9\u3002\n * \u90BB\u6708\u8865\u4F4D\u65E5 = \u4F4E\u900F\u660E\u5EA6\u6570\u5B57\uFF08\u7EAF\u89C6\u89C9\u5EF6\u7EED\uFF0C\u5207\u6708\u6B8B\u884C\u4E0D\u788E\u7247\u5316\uFF09\u3002 */\n.xy-calcard{padding:0;overflow:hidden}\n/* \u6708\u4EFD\u5BFC\u822A\u6210\u7EC4\u5C45\u4E2D\uFF1B\u300C\u56DE\u5230\u672C\u6708\u300D\u7EDD\u5BF9\u5B9A\u4F4D\u8D34\u53F3\u7F18\uFF0C\u4E0D\u6324\u5360\u4E2D\u8F74\uFF08\u7A84\u5C4F\u6539\u968F\u6D41\u907F\u514D\u76F8\u649E\uFF09 */\n.xy-calnav{position:relative;justify-content:center}\n.xy-calnav-back{position:absolute;right:0}\n@media (max-width:520px){.xy-calnav-back{position:static;margin-left:4px}}\n.xy-calhead{display:grid;grid-template-columns:repeat(7,1fr);padding:11px 0 8px}\n.xy-calhead-cell{text-align:center;font-size:12px;color:var(--dsw-alias-label-secondary)}\n.xy-cal{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l1)}\n.xy-week{display:grid;grid-template-columns:repeat(7,1fr)}\n.xy-cell{height:42px;border:none;background:transparent;cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;padding:0;font-family:inherit;color:var(--dsw-alias-label-primary)}\n/* \u5706\u7AE0\uFF1A32px \u5706\u5F62\uFF0C\u72B6\u6001\u5E95\u8272/\u73AF/\u5B9E\u5E95\u90FD\u6302\u8FD9\u91CC */\n.xy-daynum{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;font-variant-numeric:tabular-nums;transition:background-color .15s ease,box-shadow .15s ease,color .15s ease}\n.xy-cell:focus-visible{outline-offset:-3px}\n/* \u90BB\u6708\u8865\u4F4D\u65E5\uFF1A\u5F31\u5316\u6570\u5B57\uFF08\u4E0D\u53EF\u805A\u7126\u4E0D\u53EF\u70B9\uFF09\u3002opacity .45 \u5728\u6D45\u8272\u4E0B\u4EC5 1.8:1\uFF0C\n * \u63D0\u5230 .55 \u4FDD\u6301\u300C\u4F4E\u4E00\u6863\u300D\u7684\u89C6\u89C9\u6B21\u5E8F\u540C\u65F6\u4E0D\u518D\u8FD1\u4E4E\u9690\u5F62 */\n.xy-outside{cursor:default}\n.xy-outside .xy-daynum{color:var(--dsw-alias-label-secondary);opacity:.55}\n/* \u65E0\u5B89\u6392 = \u7559\u767D + \u6B21\u8981\u5B57 */\n.xy-c0{cursor:default}\n.xy-c0 .xy-daynum{color:var(--dsw-alias-label-secondary)}\n/* \u5F85\u6253\u5361 = \u4E2D\u6027\u8BA1\u5212\u5E95\uFF08\u9AD8\u9891\u72B6\u6001\u4E0D\u4F5C\u8B66\u793A\u8272\uFF09\uFF1Binset \u63CF\u8FB9\u8BA9 c1 \u5706\u7AE0\u4E0E\u56FE\u4F8B\u70B9\u540C\u6784\n * \uFF08c1 \u5E95\u8272\u5BF9\u5361\u5E95\u4EC5 \u22481.1:1\uFF0C\u56FE\u4F8B\u70B9\u6709\u63CF\u8FB9\u800C\u5706\u7AE0\u6CA1\u6709\u2014\u2014\u4E24\u4FA7\u89C2\u611F\u4E0D\u4E00\u81F4\uFF09 */\n.xy-c1 .xy-daynum{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2)}\n/* \u90E8\u5206\u5B8C\u6210 / \u5168\u90E8\u5B8C\u6210 = \u67D4\u548C\u8BED\u4E49\u5E95\uFF0C\u5B57\u8272\u6309\u4E3B\u9898\u914D\u5BF9\u4FDD\u8BC1 \u22654.5:1 */\n.xy-c2 .xy-daynum{background:var(--xyd-c2-soft);color:var(--xyd-on-c2)}\n.xy-c3 .xy-daynum{background:var(--xyd-c3-soft);color:var(--xyd-on-c3)}\nbody[data-ds-dark-theme] .xy-c2 .xy-daynum{color:var(--xyd-on-c2)}\nbody[data-ds-dark-theme] .xy-c3 .xy-daynum{color:var(--xyd-on-c3)}\n/* hover \u6655\u5E95\u6392\u9664\u5DF2\u9009\u4E2D\u683C\u4E0E\u8BED\u4E49\u72B6\u6001\u683C\uFF1Aspecificity \u9AD8\u4E8E\u5355\u7C7B\u9009\u62E9\u5668\uFF0C\u4E0D\u6392\u9664\u7684\u8BDD\n * \u60AC\u505C\u5728\u5DF2\u9009\u65E5\u4E0A\u4F1A\u7528\u6655\u5E95\u76D6\u6389\u9009\u4E2D\u5B9E\u5E95\uFF08\u89C6\u89C9\u4E0A\u300C\u53D6\u6D88\u9009\u4E2D\u300D\uFF09\uFF1Bc2/c3 \u540C\u7406\u2014\u2014\n * \u72B6\u6001\u5E95\u8272\u6B63\u662F\u7528\u6237\u60AC\u505C\u6838\u5BF9\u7684\u90A3\u4E2A\u4FE1\u606F\uFF0C\u4E0D\u80FD\u5728\u60AC\u505C\u77AC\u95F4\u88AB\u6655\u5E95\u62B9\u6389 */\n@media (hover:hover) and (pointer:fine){\n .xy-cell:not(.xy-outside):not(.xy-picked):not(.xy-c2):not(.xy-c3):hover .xy-daynum{background:var(--xyd-accent-soft)}\n}\n/* \u4ECA\u65E5 = accent \u73AF\u5305\u5706\u7AE0\uFF1A\u4E0D\u8986\u76D6\u72B6\u6001\u5E95\u8272\uFF08\u300C\u4ECA\u5929\u8BE5\u6253\u5361\u300D\u7684\u63D0\u793A\u4E0D\u80FD\u88AB\u5403\u6389\uFF09 */\n.xy-today .xy-daynum{box-shadow:0 0 0 2px var(--xyd-accent)}\n/* \u9009\u4E2D = accent \u5B9E\u5E95\u5706\u7AE0\uFF08\u5373\u65F6\u53CD\u9988\u77ED\u6682\u6001\uFF0C\u8986\u76D6\u72B6\u6001\u8272\u53EF\u63A5\u53D7\uFF0C\u8BE6\u60C5\u9762\u677F\u7D27\u968F\u5176\u4E0B\uFF09 */\n.xy-picked .xy-daynum{background:var(--xyd-accent);color:var(--xyd-on-accent)}\n.xy-legend{display:flex;gap:14px;margin-top:10px;font-size:12px;color:var(--dsw-alias-label-secondary);align-items:center;flex-wrap:wrap}\n.xy-dot{width:10px;height:10px;border-radius:3px;display:inline-block;margin-right:4px;vertical-align:-1px}\n.xy-dot.xy-dot-checked{background:var(--xyd-accent)}\n/* \u56FE\u4F8B\u7F3A\u53E3\u70B9\uFF1A\u4E0E\u67F1\u4F53\u540C\u4E00\u659C\u7EB9\u8BED\u6CD5\uFF08\u5355\u4E00\u4E8B\u5B9E\u6E90\uFF0C\u4E24\u5904\u6C38\u4E0D\u6F02\u79FB\uFF09 */\n.xy-dot.xy-dot-gap{border:1px solid var(--dsw-alias-border-l2);background:repeating-linear-gradient(135deg,var(--xyd-hatch) 0 2px,transparent 2px 4px)}\n/* \u56FE\u4F8B\u4E0E\u5706\u7AE0\u540C\u6784\uFF1A\u65E0\u5B89\u6392=\u63CF\u8FB9\u7A7A\u5FC3\u3001\u5F85\u6253\u5361=\u4E2D\u6027\u5E95\u3001\u90E8\u5206/\u5168\u90E8\u5B8C\u6210=\u8BED\u4E49\u67D4\u548C\u5E95 */\n.xy-dot.xy-c0{background:transparent;border:1px solid var(--dsw-alias-border-l2)}\n.xy-dot.xy-c1{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2)}\n.xy-dot.xy-c2{background:var(--xyd-c2-soft)}\n.xy-dot.xy-c3{background:var(--xyd-c3-soft-dot)}\n/* \u5361\u5373\u8868\u540E\uFF1A\u56FE\u4F8B\u8D34\u5361\u5E95\u5E76\u4EE5 hairline \u4E0E\u7F51\u683C\u5206\u754C */\n.xy-calcard .xy-legend{margin-top:0;padding:10px 14px 12px;border-top:1px solid var(--dsw-alias-border-l1)}\n/* \u8BE6\u60C5\u9762\u677F\u5E38\u9A7B\u5E76\u5347\u7EA7\u4E3A\u9644\u5361\uFF1A\u56FA\u5B9A\u6700\u5C0F\u9AD8\u5EA6 + \u8D85\u957F\u5185\u90E8\u6EDA\u52A8\uFF0C\u70B9\u51FB\u4E0D\u540C\u65E5\u671F\u4E0D\u518D\u5F15\u8D77\u6574\u9875\u9AD8\u5EA6\u6296\u52A8 */\n.xy-daypanel{margin-top:10px;min-height:112px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:11px 14px}\n.xy-daypanel .xy-daydetail{max-height:300px;overflow-y:auto;scrollbar-gutter:stable}\n/* \u8BE6\u60C5\u4EFB\u52A1\u884C\u590D\u7528\u5206\u7EC4\u5361\u884C\u8BED\u6CD5\uFF1A\u8D34\u9762\u677F\u5185\u8FB9\u8DDD\uFF0C\u4E0D\u7559\u53CC\u91CD\u5927\u8FB9\u8DDD */\n.xy-daypanel .xy-grouprow{padding:9px 0}\n.xy-daypanel .xy-section-title{margin-top:2px}\n.xy-dayhint{padding-top:0}\n/* \u62FE\u53D6\u52A0\u8F7D\u884C\uFF1A\u70B9\u51FB\u65E5\u671F\u53D6\u8BE6\u60C5\u671F\u95F4\u7684\u7EC6\u6761\u9AA8\u67B6\uFF08\u5360\u4F4D\u9AD8\u5EA6\u6052\u5B9A\uFF0C\u9762\u677F\u4E0D\u8DF3\uFF09 */\n.xy-pickline{height:12px;width:46%;margin-top:2px}\n\n/* ===== \u7EDF\u8BA1\u5361 & \u6210\u957F ===== */\n.xy-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-top:8px}\n.xy-statcard{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:14px;text-align:center}\n/* \u5C42\u7EA7\uFF1A\u666E\u901A\u7EDF\u8BA1\u6570\u5B57\u7528\u4E3B\u6587\u5B57\u8272\uFF08\u9875\u9762\u66F4\u5B89\u9759\uFF09\uFF0C\u4EC5\u300C\u5F53\u524D\u8FDE\u7EED\u300D\u8FD9\u5F20\u5361\u4EE5\u54C1\u724C\u8272+\u6D45\u6655\u5E95\u7A81\u51FA\n * \uFF08habit \u7C7B App \u628A streak \u4F5C\u4E3A\u82F1\u96C4\u6307\u6807\u7F6E\u4E8E\u70ED\u529B\u56FE\u65C1\u7684\u60EF\u4F8B\uFF09 */\n.xy-statnum{font-size:24px;font-weight:700;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums}\n.xy-statcard-hot{border-color:var(--xyd-accent-border);background:linear-gradient(160deg,var(--xyd-accent-soft),transparent 62%),var(--dsw-alias-bg-layer-1)}\n.xy-statcard-hot .xy-statnum{color:var(--xyd-accent)}\n/* \u7F3A\u7701\u503C\uFF08\u6682\u65E0/N/A\uFF09\uFF1A\u6B21\u8981\u8272\u5C0F\u4E00\u53F7\uFF0C\u7F3A\u5931\u4FE1\u606F\u4E0D\u5F97\u6BD4\u771F\u5B9E\u6570\u636E\u66F4\u54CD */\n.xy-statcard-muted .xy-statnum{color:var(--dsw-alias-label-secondary);font-size:18px}\n/* \u7A84\u9762\u677F\uFF08\u4F1A\u8BDD\u89C6\u56FE\u9875\u968F\u58F3\u6536\u7F29\uFF09\u4E0B 30 \u6839\u67F1\u88AB flex \u6324\u538B\u5230 ~10px \u5BBD\uFF0C\u89E6\u5C4F\u96BE\u4EE5\u547D\u4E2D\uFF1A\n * \u5BB9\u5668\u6A2A\u5411\u6EDA\u52A8 + \u6700\u5C0F\u5BBD\u515C\u5E95\uFF08\u2264520px \u4E0E\u65E5\u5386\u65AD\u70B9\u540C\u53E3\u5F84\uFF09\u628A\u67F1\u5BBD\u62AC\u5230 ~13px\u2014\u2014\n * \u662F\u547D\u4E2D\u4F53\u9A8C\u7684\u6539\u5584\u4F46\u672A\u8FBE WCAG 2.5.8 \u7684 24px\uFF08\u8FBE\u6807\u9700 min-width ~810px\uFF0C\u6EDA\u52A8\u6210\u672C\n * \u8FDC\u8D85\u8BEF\u89E6\u4EE3\u4EF7\uFF0C\u56FE\u8868 tooltip \u5C5E\u4F4E\u98CE\u9669\u4FE1\u606F\u67E5\u8BE2\uFF0C\u6709\u610F\u53D6\u820D\uFF09\uFF1B\u5BBD\u9762\u677F\uFF08\u72EC\u7ACB\n * /xingyuan/growth \u9875\uFF09\u5185\u5BB9\u4E0D\u8D85\u5BBD\u3001\u6EDA\u52A8\u5BB9\u5668\u65E0\u611F\u77E5 */\n.xy-growth-scroll{overflow-x:auto}\n.xy-growth{display:flex;gap:3px;align-items:stretch;height:120px;margin-top:10px}\n.xy-growth-col{flex:1;display:flex;flex-direction:column;height:100%;min-width:0;border:none;background:transparent;padding:0;cursor:default;border-radius:3px 3px 0 0}\n.xy-growth-stack{flex:1;display:flex;flex-direction:column;justify-content:flex-end;width:100%}\n.xy-growth-bar{background:var(--xyd-accent);border-radius:2px 2px 0 0;width:100%}\n.xy-growth-col.xy-full .xy-growth-bar{background:var(--dsw-alias-state-success-primary,var(--xyd-ok))}\n/* \u672A\u5B8C\u6210\u7F3A\u53E3\uFF1A\u659C\u7EB9\u5197\u4F59\u7F16\u7801\uFF08\u8DDF\u968F\u4E3B\u9898\u6587\u5B57\u8272\u6DF7\u5408\uFF09\u2014\u2014layer-2 \u5B9E\u8272\u5728\u6DF1\u8272\u58F3\u4E0E\u9762\u677F\u5E95\n * \u51E0\u4E4E\u540C\u4EAE\u5EA6\u800C\u9690\u5F62\uFF0C\u659C\u7EB9\u5728\u4E24\u79CD\u4E3B\u9898\u4E0B\u90FD\u6709\u7A33\u5B9A\u7684\u7EB9\u7406\u53EF\u89C1\u5EA6\uFF0C\u4E14\u4E0E\u5B9E\u5FC3\u5B8C\u6210\u67F1\u5F62\u6210\n * \u300C\u5F62\u72B6 \u00D7 \u989C\u8272\u300D\u53CC\u901A\u9053\u533A\u5206\uFF0C\u4E0D\u4F9D\u8D56\u8272\u89C9\u5355\u901A\u9053 */\n.xy-growth-missed{width:100%;border-radius:2px 2px 0 0;background:repeating-linear-gradient(135deg,var(--xyd-hatch) 0 2px,transparent 2px 5px),var(--xyd-hatch-faint)}\nbutton.xy-growth-col{cursor:pointer}\nbutton.xy-growth-col.xy-hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}\n@media (hover:hover) and (pointer:fine){\n button.xy-growth-col:hover{box-shadow:inset 0 0 0 2px var(--xyd-accent-ring)}\n}\n@media (max-width:520px){\n .xy-growth-scroll .xy-growth,.xy-growth-scroll .xy-growth-axis{min-width:480px}\n}\n/* \u57FA\u7EBF\u8D34\u67F1\u5E95\uFF08\u4E0E\u804A\u5929\u56FE\u8868\u5361\u7684 SVG \u57FA\u7EBF\u540C\u4E00\u8BED\u6CD5\uFF09\uFF0C\u523B\u5EA6\u5C42\u4E0B\u79FB\u8BA9\u51FA\u7EBF\u7684\u4F4D\u7F6E */\n.xy-growth-axis{position:relative;height:20px;margin-top:0;border-top:1px solid var(--dsw-alias-border-l2)}\n.xy-growth-tick{position:absolute;top:4px;font-size:12px;line-height:16px;color:var(--xyd-label-on-2);white-space:nowrap;font-variant-numeric:tabular-nums}\n/* \u6210\u957F\u9875\u60AC\u6D6E\u660E\u7EC6 */\n.xy-tip{position:relative;margin-top:0;min-height:20px;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-inner);padding:3px 10px;display:inline-block;font-variant-numeric:tabular-nums}\n.xy-tip:empty{visibility:hidden}\n/* \u56FE\u8868\u52A0\u8F7D\u5360\u4F4D\uFF1A\u4E0E\u6210\u54C1\u56FE\u7B49\u9AD8\uFF0C\u6570\u636E\u5230\u8FBE\u4E0D\u5F15\u8D77\u4E0B\u65B9\u5185\u5BB9\u4F4D\u79FB */\n.xy-chartload{height:150px;margin-top:8px}\n\n/* ===== \u6210\u957F\u9875\uFF1A\u7B49\u7EA7\u82F1\u96C4\u5361 + \u7B49\u7EA7\u8BF4\u660E ===== */\n/* \u6E10\u53D8\u4E24\u7AEF\u5747\u4E3A\u5B9E\u8272\uFF08\u6DF1\u6863\u2192\u57FA\u6863\uFF0Cgrowth.ts \u5185\u8054 darkenHex \u9884\u6DF7\uFF09\uFF0C\u767D\u5B57\u5BF9\u5E95\u8272 \u22654.5:1\n * \u5728\u6D45\u8272\u58F3\u4E0B\u540C\u6837\u6210\u7ACB\u2014\u2014\u534A\u900F\u660E\u6E10\u53D8\u6DF7\u5165\u9875\u9762\u767D\u5E95\u540E\u53F3\u7AEF\u4F1A\u8DCC\u7834 3:1\uFF0C\u5DF2\u5F03\u7528\u3002 */\n.xy-hero{display:flex;gap:14px;align-items:center;border-radius:var(--xyd-r-card);padding:18px;margin-top:12px;border:1px solid var(--xyd-hero-border);box-shadow:var(--xyd-shadow-hero)}\n.xy-herobadge{width:54px;height:54px;border-radius:12px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:16px;flex:none;text-shadow:var(--xyd-herobadge-glyph-shadow)}\n.xy-heromain{flex:1;min-width:0}\n.xy-onhero{color:var(--xyd-on-hero)!important}\n.xy-herotitle{font-size:19px;font-weight:700;margin:3px 0 8px;color:#fff}\n.xy-bar-onhero{background:var(--xyd-bar-on-hero)}\n.xy-bar-fill-solid{background:#fff}\n.xy-heroreward{margin-top:8px}\n.xy-levels{display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);padding:4px 14px}\n/* \u7B49\u7EA7\u884C\u7684\u300C\u672A\u8FBE\u6210\u300D\u964D\u6743\u8D70\u6587\u5B57\u8272\u800C\u975E\u6574\u884C opacity\uFF080.68 \u6DF7\u5E95\u540E label-on-2/secondary\n * \u5747\u8DCC\u7834 AA\uFF0C\u6700\u4F4E \u22482.6:1\uFF09\uFF1A\u540D\u79F0/\u5956\u52B1\u7528 secondary\uFF08\u22654.5:1\uFF09\uFF0C\u5FBD\u7AE0\u672C\u5C31\u662F\u4E2D\u6027\u5E95 +\n * label-on-2\uFF08\u6821\u51C6 5.0:1\uFF09\uFF1B\u547D\u4E2D\u884C\u6062\u590D\u4E3B\u6587\u5B57\u8272 + \u5F69\u8272\u5FBD\u7AE0\uFF0C\u5C42\u7EA7\u611F\u4E0D\u9760\u900F\u660E\u5EA6 */\n.xy-levelrow{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--dsw-alias-border-l1);font-size:13px}\n.xy-levelrow:last-child{border-bottom:none}\n.xy-levelrow .xy-lvname{color:var(--dsw-alias-label-secondary)}\n.xy-levelhit .xy-lvname{color:var(--dsw-alias-label-primary)}\n.xy-lvnum{width:42px;height:24px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none}\n.xy-lvname{font-weight:600;width:64px;color:var(--dsw-alias-label-primary)}\n.xy-lvreward{margin-left:auto;text-align:right}\n\n/* ===== \u8BB0\u5FC6\u9875 ===== */\n/* \u6DFB\u52A0/\u7F16\u8F91\u8BB0\u5FC6\u8868\u5355\uFF1A\u865A\u7EBF\u9762\u677F\u5361\uFF08\u4E0E\u5FEB\u901F\u65B0\u5EFA\u540C\u4E00\u300C\u53EF\u4E66\u5199\u300D\u8BED\u6CD5\uFF09 */\n.xy-compose{margin-top:12px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px;display:flex;gap:8px;flex-wrap:wrap}\n.xy-compose .xy-input-grow{flex:1 1 170px;width:auto;min-width:140px}\n.xy-compose select.xy-input{width:auto}\n.xy-editing{display:flex;align-items:center;gap:10px;margin-top:12px;padding:7px 10px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-inner)}\n.xy-memactions{display:flex;gap:6px;flex:none}\n.xy-membar{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}\n.xy-membar .xy-input-search{width:min(250px,100%)}\n.xy-memcap{margin-top:6px}\n/* \u8D85\u957F\u8BB0\u5FC6\u503C 3 \u884C\u622A\u65AD\uFF08\u22641000 \u5B57\u7B26\u8BB0\u5F55\u4E0D\u518D\u6491\u51FA\u6570\u5C4F\u9AD8\u884C\uFF1B\u5B8C\u6574\u503C\u5728\u5220\u9664\u786E\u8BA4\u5F39\u7A97\u53EF\u89C1\uFF09 */\n.xy-memval{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}\n.xy-saved{color:var(--dsw-alias-state-success-primary,var(--xyd-ok));font-size:13px}\n.xy-memfoot{display:flex;align-items:center;gap:12px;margin-top:14px}\n\n/* ===== \u8BBE\u7F6E\u9875 ===== */\n.xy-settings{display:flex;flex-direction:column;gap:16px;max-width:560px;color:var(--dsw-alias-label-primary);font-size:14px}\n/* \u6E38\u79BB\u4E8E\u5361\u7247\u5916\u7684\u8BF4\u660E\u884C\uFF08\u9875\u7EA7\u547D\u540D\u7A7A\u95F4\u901A\u77E5/\u9875\u5C3E\u6570\u636E\u8BF4\u660E\uFF09\u968F\u5361\u5185\u6587\u5B57\u5BF9\u9F50\n * \uFF08xy-panel \u6A2A\u5411\u5185\u8FB9\u8DDD 14px\uFF09\uFF0C\u4E0D\u5F97\u8D34\u5BB9\u5668\u5DE6\u7F18\u60AC\u5728\u5217\u5916 */\n.xy-settings>.xy-hint{padding:0 14px}\n/* \u8BBE\u7F6E\u5404\u5206\u8282\u81EA\u6210\u9762\u677F\u5361\uFF1B\u95F4\u8DDD\u4EA4\u7ED9 xy-settings \u7684 gap\uFF0C\u5361\u5185\u5B50\u5143\u7D20\u7EDF\u4E00 10px \u7EB5\u5411\u8282\u594F */\n.xy-settings .xy-panel{margin-top:0}\n.xy-settings .xy-panel>*+*{margin-top:10px}\n.xy-field{display:flex;flex-direction:column;gap:6px}\n/* \u8BBE\u7F6E\u884C\uFF08\u4E1A\u754C\u8BBE\u7F6E\u9875 row \u60EF\u4F8B\uFF09\uFF1A\u6807\u7B7E+\u8BF4\u660E\u5728\u5DE6\u3001\u63A7\u4EF6\u5728\u53F3\uFF0C\u626B\u63CF\u7EBF\u5BF9\u9F50\uFF1B\u8BF4\u660E\u6587\u5B57\n * flex:1 \u6536\u7F29\u6362\u884C\u3001\u63A7\u4EF6 flex:none \u4E0D\u88AB\u6324\u538B\uFF0C\u7A84\u9762\u677F\u4E0B\u63A7\u4EF6\u6362\u884C\u5DE6\u5BF9\u9F50\u3002\n * label \u884C\u6574\u884C\u53EF\u70B9\uFF08label \u5305\u88F9\u63A7\u4EF6\uFF09\uFF1Bdiv \u884C\uFF08\u5206\u6BB5\u6309\u94AE\u7EC4/\u9501\u5B9A\u884C\uFF09\u4E0D\u53EF\u70B9\u3002 */\n.xy-setrow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}\nlabel.xy-setrow{cursor:pointer}\n.xy-setrow-main{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 220px}\n.xy-setrow-label{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}\n.xy-setrow-desc{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0;overflow-wrap:anywhere}\n/* \u884C\u5217\u8868\uFF1A\u884C\u95F4 hairline \u5206\u9694\uFF08\u4E0E\u5206\u7EC4\u5361 xy-grouprow \u540C\u4E00\u8BED\u6CD5\uFF09\uFF0C\u9996\u884C\u4E0D\u753B\u7EBF */\n.xy-setrows{display:flex;flex-direction:column}\n.xy-setrows>.xy-setrow{padding:8px 0}\n.xy-setrows>.xy-setrow+.xy-setrow{border-top:1px solid var(--dsw-alias-border-l1)}\n.xy-setrow>.xy-toggle,.xy-setrow>.xy-input-num,.xy-setrow>.xy-seg{flex:none}\n.xy-input-wide{width:100%;max-width:360px;box-sizing:border-box}\n.xy-seg{display:flex;gap:6px;flex-wrap:wrap}\n.xy-seg-btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:999px;padding:5px 14px;font-size:13px;cursor:pointer;transition:border-color .15s ease,background-color .15s ease,color .15s ease}\n.xy-seg-btn:disabled{opacity:.55;cursor:not-allowed}\n@media (hover:hover) and (pointer:fine){\n .xy-seg-btn:hover:not(:disabled){border-color:var(--xyd-accent)}\n}\n/* \u9009\u4E2D\u6001\u53CC\u9009\u62E9\u5668\uFF1A\u7C7B\u540D\u4E0E aria-pressed \u5C5E\u6027\u7B49\u4EF7\uFF08\u7EC4\u4EF6\u4FA7\u7528\u5C5E\u6027\u8868\u8FBE\u72B6\u6001\u8BED\u4E49\uFF09 */\n.xy-seg-btn.xy-on,.xy-seg-btn[aria-pressed='true']{background:var(--xyd-accent);border-color:transparent;color:var(--xyd-on-accent)}\n.xy-save-row{display:flex;align-items:center;gap:10px;margin-top:2px}\n.xy-toggle{width:38px;height:22px;appearance:none;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);position:relative;cursor:pointer;transition:background .15s}\n/* \u7981\u7528\u5373\u7F6E\u7070\uFF08\u4E0E xy-btn/xy-input \u540C\u8BED\u6CD5\uFF09\uFF1A\u53EA\u8BFB\u547D\u540D\u7A7A\u95F4/\u5199\u5165\u5728\u9014\u7684\u63A7\u4EF6\u4E0D\u5F97\u770B\u8D77\u6765\u4ECD\u53EF\u4EA4\u4E92 */\n.xy-toggle:disabled{opacity:.4;cursor:not-allowed}\n.xy-toggle:checked{background:var(--xyd-accent);border-color:transparent}\n.xy-toggle::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .15s}\n.xy-toggle:checked::after{transform:translateX(16px);background:var(--xyd-on-accent)}\n.xy-hint{color:var(--dsw-alias-label-secondary);font-size:12px;margin:0}\n/* \u786E\u8BA4\u7C7B\u76EE\u660E\u7EC6\uFF1A\u603B\u5F00\u5173\u884C\u4E0B\u5E73\u94FA\uFF08row \u8BED\u6CD5 + \u7EC4\u5934\uFF09\uFF0C\u4E0D\u518D\u7F29\u8FDB\u5D4C\u5957\uFF1B\n * \u603B\u5F00\u5173\u5173\u95ED\u65F6\u6574\u7EC4\u7981\u7528\u5F31\u5316\u5FC5\u987B\u663E\u5F0F\u5199\uFF08\u81EA\u5B9A\u4E49 toggle \u4E0D\u5403\u539F\u751F\u7981\u7528\u53D8\u7070\uFF09\uFF0C\n * \u884C\u6587\u5B57\u540C\u6B65\u964D\u6743\uFF1B\u7981\u7528\u539F\u56E0\u7531\u7EC4\u5C3E hint \u627F\u62C5\uFF08aria-describedby \u5173\u8054\uFF09 */\n.xy-confirm-ops{display:flex;flex-direction:column;gap:4px}\n/* \u5173\u95ED\u6001\u53EA\u964D\u6743\u53EF\u5207\u6362\u7684\u7C7B\u76EE\u884C\uFF08label \u884C\uFF09\uFF1A\u9501\u5B9A\u5220\u9664\u884C\u4E0D\u53D7\u603B\u5F00\u5173\u652F\u914D\uFF08\u59CB\u7EC8\u786E\u8BA4\uFF09\uFF0C\n * \u7F6E\u7070\u4F1A\u8BA9\u300C\u59CB\u7EC8\u5F00\u542F\u300D\u5FBD\u7AE0\u4E0E\u7070\u5B57\u81EA\u76F8\u77DB\u76FE */\n.xy-confirm-ops-off label.xy-setrow .xy-setrow-label{color:var(--dsw-alias-label-secondary)}\n.xy-op-group-head{font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary)}\n/* \u9501\u5B9A\u7C7B\u76EE\uFF08\u5220\u9664\u6052\u786E\u8BA4\uFF09\uFF1A\u300C\u59CB\u7EC8\u5F00\u542F\u300D\u5FBD\u7AE0\u8868\u8FBE\u51BB\u7ED3\u8BED\u4E49\u2014\u2014\u7981\u7528\u5F00\u5173\u770B\u7740\u50CF\u574F\u4E86\uFF0C\n * \u5FBD\u7AE0\u5373\u72B6\u6001\uFF1B\u80F6\u56CA 999 \u7B26\u5408\u5F62\u72B6\u7EAA\u5F8B */\n.xy-locked{flex:none;font-size:12px;line-height:1.4;padding:3px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--xyd-label-on-2)}\n\n/* ===== \u8BE6\u60C5\u805A\u5408\u89C6\u56FE ===== */\n/* \u6BB5\u95F4 10px \u547C\u5438\uFF1B\u6BCF\u6BB5\u5185\u90E8\u300C\u6807\u7B7E \u2192 \u5185\u5BB9\u300D\u56FA\u5B9A 5px \u7EB5\u5411\u8282\u594F\uFF08label \u4E0D\u518D\u4E0E\u5185\u5BB9\u6587\u5B57\u6324\u884C\uFF09\u3002\n * \u5E95\u90E8\u7559 8px\uFF1A\u64CD\u4F5C\u6309\u94AE\u4E0E\u4E0B\u4E00\u6761\u4EFB\u52A1\u7684\u5206\u5272\u7EBF\u4E0D\u5F97\u8D34\u6B7B\uFF08\u613F\u671B\u5361\u91CC\u5206\u5272\u7EBF\u76F4\u63A5\u538B\u5728\u8BE6\u60C5\u4E0B\u7F18\uFF09\uFF0C\n * \u4EFB\u52A1\u9875\u7531 xy-taskrow \u8986\u76D6\u4E3A 2px\uFF08\u5206\u7EC4\u5361\u884C\u81EA\u5E26 11px \u5185\u8FB9\u8DDD\uFF0C\u603B\u91CF\u5DF2\u591F\uFF09\u3002 */\n.xy-detail{margin-top:8px;margin-bottom:8px;border-top:1px dashed var(--dsw-alias-border-l1);padding-top:10px;display:flex;flex-direction:column;gap:10px}\n.xy-detail>div{display:flex;flex-direction:column;gap:5px;align-items:flex-start;min-width:0}\n.xy-detail>div>.xy-meta{margin-top:0}\n.xy-detail-grid{display:grid;grid-template-columns:repeat(7,max-content);gap:4px;padding:2px 0}\n/* \u6253\u5361\u683C\uFF1A22px + 11px \u6570\u5B57\uFF08\u53EF\u8BFB\u6027\u4E0B\u9650\uFF09\uFF1Bradius 6 \u4E3A\u5FBD\u7AE0\u7EA7\u5FAE\u5143\u7D20\u4F8B\u5916\u6863\u3002\n * \u7F51\u683C\u6309\u5468\u5BF9\u9F50\uFF08\u5468\u4E00\u59CB\uFF0C\u4E0E\u65E5\u5386\u9875\u8868\u5934\u540C\u6784\uFF09\uFF1A\u8FDE\u7EED\u6027\u4E00\u773C\u53EF\u8BFB\uFF08GitHub/Streaks \u60EF\u4F8B\uFF09\uFF0C\n * \u9996\u884C\u524D\u7F6E\u7A7A\u4F4D\u7531 .xy-dcell-blank \u5360\u4F4D\u3002 */\n.xy-dcell{width:22px;height:22px;border-radius:6px;font-size:11px;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;padding:0;border:none;cursor:default;font-variant-numeric:tabular-nums}\n.xy-dcell-blank{visibility:hidden}\n/* \u4ECA\u65E5\u683C = accent \u73AF\u5305\u5E95\u8272\uFF1A\u4E0E\u65E5\u5386\u9875\u5706\u7AE0\u7684 today \u73AF\u540C\u4E00\u8BED\u6CD5 */\n.xy-dcell.xy-dcell-today{box-shadow:0 0 0 2px var(--xyd-accent)}\n.xy-dcell-checked{background:var(--xyd-dcell-checked);color:var(--xyd-on-dcell)}\nbody[data-ds-dark-theme] .xy-dcell-checked{color:var(--xyd-on-dcell)}\n.xy-dcell-missed{background:transparent;border:1px dashed var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary)}\n.xy-dcell-future{background:var(--dsw-alias-bg-layer-2);color:var(--xyd-label-on-2);border:1px solid var(--dsw-alias-border-l1)}\n/* \u56FE\u4F8B\u590D\u7528 xy-dot \u65F6\u501F\u683C\u5B50\u7684\u8BED\u4E49\u5E95\u8272\uFF08\u540C\u8272\u7CFB\u5C0F\u5C3A\u5BF8\uFF09 */\n.xy-dot.xy-dcell-missed{background:transparent;border:1px dashed var(--dsw-alias-border-l3)}\n.xy-dot.xy-dcell-future{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1)}\n.xy-dot.xy-dcell-checked{background:var(--xyd-dcell-checked-dot)}\n.xy-detail-next{font-size:12px;color:var(--dsw-alias-label-secondary)}\n/* \u64CD\u4F5C\u884C\u4E0E\u5168\u7AD9\u6309\u94AE\u7EC4\u540C\u62CD\uFF08gap 8\uFF09\uFF1A\u5220\u9664\u5728\u540C\u4E00\u884C\u6D41\u5185\u9760 danger \u63CF\u8FB9\u533A\u5206\uFF0C\n * \u786E\u8BA4\u5F39\u7A97\u515C\u5E95\u9632\u8BEF\u89E6\u2014\u2014\u4E0D\u518D margin-left:auto \u6F02\u5230\u5361\u7F18\uFF08\u7A84\u9762\u677F\u91CC\u662F\u4E00\u6BB5\u7A81\u5140\u7A7A\u767D\uFF0C\n * \u613F\u671B\u5361\u91CC\u8FD8\u4F1A\u4E0E\u5361\u5934\u7684\u613F\u671B\u7EA7\u5220\u9664\u540C\u4FA7\u5BF9\u9F50\u9020\u6210\u8BED\u4E49\u6DF7\u6DC6\uFF09 */\n.xy-detail-ops{display:flex;gap:8px;flex-wrap:wrap;align-items:center}\n\n/* ===== \u5206\u7C7B\u7BA1\u7406 ===== */\n.xy-catpanel{margin-top:10px;border:1px solid var(--dsw-alias-border-l1);border-radius:var(--xyd-r-card);background:var(--dsw-alias-bg-layer-1);padding:12px 14px}\n.xy-catrow{display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l1)}\n.xy-catrow:last-child{border-bottom:none}\n.xy-catcount{margin-left:auto}\n.xy-catops{display:flex;gap:6px}\n.xy-swatchrow{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;align-items:center}\n/* \u8272\u677F\u683C\uFF1A24px \u547D\u4E2D\u76EE\u6807 + hover \u63CF\u8FB9 + \u4E3B\u9898\u4EE4\u724C\u63CF\u8FB9\uFF08\u6DF1\u8272\u4E0B\u4E0D\u518D\u9690\u8EAB\uFF09 */\n.xy-swatch{width:24px;height:24px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);cursor:pointer;padding:0;position:relative;transition:box-shadow .15s ease}\n.xy-swatch:disabled{opacity:.55;cursor:not-allowed}\n@media (hover:hover) and (pointer:fine){\n .xy-swatch:hover:not(:disabled){box-shadow:inset 0 0 0 2px var(--xyd-accent-ring-soft)}\n}\n/* \u9009\u4E2D\u6001\u53CC\u73AF\uFF08\u5185\u767D\u9699 + \u5916\u5F3A\u8C03\u5708\uFF09\uFF1A\u4EFB\u4F55\u8272\u76F8\u4E0B\u90FD\u6E05\u6670\u53EF\u8FA8\uFF0C\u4E0D\u4F9D\u8D56\u5BF9\u52FE\u672C\u8EAB\u7684\u5BF9\u51B2 */\n.xy-swatch.xy-picked{box-shadow:inset 0 0 0 2px var(--xyd-swatch-ring),0 0 0 2px var(--xyd-accent)}\n.xy-swatch.xy-picked::after{content:'\u2713';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-size:12px;font-weight:700;text-shadow:var(--xyd-swatch-glyph-shadow)}\n.xy-catloading{padding:6px 0}\n/* \u884C\u5185\u6539\u540D\u7F16\u8F91\u5668\uFF1A\u8F93\u5165\u5728\u7A84\u9762\u677F\u6536\u7F29\uFF08\u65E0 min-width:0 \u65F6 input \u56FA\u6709\u5BBD\u5EA6\u4F1A\u628A\n * \u4FDD\u5B58/\u53D6\u6D88\u952E\u6324\u51FA 320px \u9762\u677F\u88AB overflow-x:clip \u65E0\u58F0\u88C1\u6389\uFF09 */\n.xy-rename{display:flex;gap:6px;align-items:center;margin-top:8px;flex-wrap:wrap}\n.xy-rename .xy-input{flex:1 1 120px;min-width:0;width:auto}\n\n/* ===== \u5FEB\u901F\u65B0\u5EFA ===== */\n.xy-quick{margin-top:10px;border:1px dashed var(--dsw-alias-border-l2);border-radius:var(--xyd-r-card);padding:12px 14px;display:flex;flex-direction:column;gap:10px;background:var(--dsw-alias-bg-layer-1)}\n.xy-quick-row{display:flex;gap:10px;flex-wrap:wrap}\n.xy-quick-field{display:flex;flex-direction:column;gap:4px;min-width:150px;flex:1}\n.xy-quick-label{font-size:12px;color:var(--dsw-alias-label-secondary);font-weight:600}\n.xy-quick-actions{display:flex;gap:10px;align-items:center}\n\n/* ===== \u6EDA\u52A8\u6761\u69FD\u4F4D\u6052\u5B9A\uFF08\u5BBD\u5EA6\u9632\u6296\u7B2C\u4E8C\u9053\u4FDD\u9669\uFF09=====\n * \u58F3\u7684\u4F1A\u8BDD\u6EDA\u52A8\u5BB9\u5668\uFF08CSS Modules\u300C\u54C8\u5E0C\u524D\u7F00_\u8BED\u4E49\u540E\u7F00\u300D\u7A33\u5B9A\u547D\u540D + data-conversation-scroll\n * \u6807\u8BB0\uFF09\u9ED8\u8BA4 gutter stable\uFF0C\u4F46\u8F93\u5165\u6846\u6D6E\u5C42\u6A21\u5F0F\u4F1A\u4E3B\u52A8\u653E\u5F00\u4E3A auto\u2014\u2014\u7ECF\u5178\u6EDA\u52A8\u6761\u6309\u9700\u51FA\u73B0\u4F1A\u62BD\u8D70\n * ~15px \u5BBD\u5EA6\uFF08\u70B9\u300C\u65B0\u5EFA\u300D\u5C55\u5F00\u8868\u5355\u3001\u5C55\u5F00\u8BE6\u60C5\u5373\u89E6\u53D1\uFF09\uFF0C\u5C45\u4E2D\u9875\u9762\u968F\u4E4B\u6574\u5E27\u5DE6\u53F3\u5F39\u8DF3\u3002\n * \u8FD9\u91CC\u5BF9\u6EDA\u52A8\u5BB9\u5668\u672C\u8EAB\u65E0\u6761\u4EF6\u5F3A\u5236\u5E38\u9A7B\u69FD\u4F4D\uFF1B\u4E0E useStableScrollbar \u7684 useLayoutEffect\n * \u8FD0\u884C\u65F6\u9489\u4F4F\u4E92\u4E3A\u5197\u4F59\uFF08\u6837\u5F0F\u5148\u4E8E\u9996\u5E27\uFF0C\u8FD0\u884C\u65F6\u515C\u5E95\u58F3\u4FA7\u8282\u70B9\u66FF\u6362\uFF09\u3002 */\n[class*='_scrollBody'][data-conversation-scroll]{scrollbar-gutter:stable!important}\n\n/* \u5F31\u5316\u52A8\u753B\u504F\u597D\uFF1A\u5C0A\u91CD prefers-reduced-motion\uFF08\u542B\u5F00\u5173\u6ED1\u5757\u3001hover \u8FC7\u6E21\u3001\u63D2\u753B\u65E0\u52A8\u753B\u3001toast \u8FDB\u51FA\u573A\u3001\u786E\u8BA4\u5F39\u7A97\uFF09 */\n@media (prefers-reduced-motion: reduce){\n .xy-skel,.xy-toast,.xy-modal-backdrop,.xy-modal{animation:none}\n .xy-toast-out,.xy-modal-backdrop.xy-modal-out,.xy-modal-out .xy-modal{transition:none}\n .xy-bar-fill,.xy-btn,.xy-toggle,.xy-toggle::after,.xy-wishcard,.xy-cell,.xy-daynum,.xy-seg-btn,.xy-input,.xy-swatch,.xy-grouprow,.xy-wishtoggle svg{transition:none}\n}\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starwish-ai/xingyuan-dsh",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "星愿 XingYuan for DeepSeek Harness: 对话创建愿望/任务、机会日打卡、微行动、记忆与图表的 Agent Preset 组合包",
5
5
  "type": "module",
6
6
  "license": "MIT",