dsh-ds-balance 2.1.1 → 2.1.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/lib/client.js CHANGED
@@ -198,7 +198,10 @@ var en = {
198
198
  "dev.hint": "UI development only; does not affect real configuration."
199
199
  };
200
200
  function interpolate(template, params) {
201
- return template.replace(/\{(\w+)\}/g, (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole);
201
+ return template.replace(
202
+ /\{(\w+)\}/g,
203
+ (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole
204
+ );
202
205
  }
203
206
 
204
207
  // src/client/settings/fields.tsx
@@ -230,7 +233,6 @@ var fields_default = {
230
233
  groupNote: "fields_groupNote",
231
234
  fields: "fields_fields",
232
235
  details: "fields_details",
233
- detailsSummary: "fields_detailsSummary",
234
236
  detailsBody: "fields_detailsBody",
235
237
  field: "fields_field",
236
238
  row: "fields_row",
@@ -241,10 +243,10 @@ var fields_default = {
241
243
  label: "fields_label",
242
244
  badges: "fields_badges",
243
245
  reset: "fields_reset",
244
- input: "fields_input",
245
246
  inputStatic: "fields_inputStatic",
246
247
  inputInvalid: "fields_inputInvalid",
247
248
  inputWithAction: "fields_inputWithAction",
249
+ input: "fields_input",
248
250
  reveal: "fields_reveal",
249
251
  revealOn: "fields_revealOn",
250
252
  selectorAnchor: "fields_selectorAnchor",
@@ -254,7 +256,6 @@ var fields_default = {
254
256
  pairNote: "fields_pairNote",
255
257
  invalid: "fields_invalid",
256
258
  actions: "fields_actions",
257
- actionButton: "fields_actionButton",
258
259
  resultOk: "fields_resultOk",
259
260
  resultFail: "fields_resultFail"
260
261
  };
@@ -322,10 +323,10 @@ function FieldFrame(props) {
322
323
  }
323
324
  function TextControl(props) {
324
325
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
325
- "input",
326
+ import_dsh_client_ui_primitives.Input,
326
327
  {
327
328
  id: props.id,
328
- className: props.invalid ? fields_default.inputInvalid : fields_default.input,
329
+ className: props.invalid ? fields_default.inputInvalid : void 0,
329
330
  type: "text",
330
331
  ...props.numeric ? { inputMode: "numeric" } : {},
331
332
  ...props.invalid ? { "aria-invalid": true } : {},
@@ -340,10 +341,10 @@ function TextControl(props) {
340
341
  }
341
342
  function ReadOnlyControl(props) {
342
343
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
343
- "input",
344
+ import_dsh_client_ui_primitives.Input,
344
345
  {
345
346
  id: props.id,
346
- className: clsx_default(fields_default.input, fields_default.inputStatic),
347
+ className: fields_default.inputStatic,
347
348
  type: "text",
348
349
  value: "",
349
350
  readOnly: true
@@ -352,20 +353,20 @@ function ReadOnlyControl(props) {
352
353
  }
353
354
  function DetailsGroup(props) {
354
355
  const [open, setOpen] = (0, import_react.useState)(props.defaultOpen === true);
355
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
356
- "details",
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.details, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
357
+ import_dsh_client_ui_primitives.DisclosureRow,
357
358
  {
358
- className: fields_default.details,
359
+ icon: null,
360
+ title: props.title,
359
361
  open,
360
- onToggle: (event) => {
361
- setOpen(event.currentTarget.open);
362
+ expandable: true,
363
+ expandOnRowClick: true,
364
+ onToggle: () => {
365
+ setOpen((value) => !value);
362
366
  },
363
- children: [
364
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { className: fields_default.detailsSummary, children: props.title }),
365
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
366
- ]
367
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
367
368
  }
368
- );
369
+ ) });
369
370
  }
370
371
  function SelectorControl(props) {
371
372
  const [open, setOpen] = (0, import_react.useState)(false);
@@ -410,16 +411,7 @@ function SelectorControl(props) {
410
411
  }
411
412
  function ActionRow(props) {
412
413
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
413
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
414
- "button",
415
- {
416
- type: "button",
417
- className: fields_default.actionButton,
418
- disabled: props.disabled,
419
- onClick: props.onClick,
420
- children: props.label
421
- }
422
- ) }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { type: "button", variant: "outline", disabled: props.disabled, onClick: props.onClick, children: props.label }) }),
423
415
  props.result === null ? null : (
424
416
  // 成功只是通报,用 polite 的 status;失败需要用户处理,按 06 §6.7 的「行内错误」用 alert。
425
417
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -469,7 +461,13 @@ function selectField(field) {
469
461
  var AUTO_CURRENCY = "auto";
470
462
  var KNOWN_CURRENCIES = ["CNY", "USD"];
471
463
  var THRESHOLD_PAIRS = [
472
- { currency: "CNY", warn: "cnyWarn", critical: "cnyCritical", defaultWarn: 10, defaultCritical: 5 },
464
+ {
465
+ currency: "CNY",
466
+ warn: "cnyWarn",
467
+ critical: "cnyCritical",
468
+ defaultWarn: 10,
469
+ defaultCritical: 5
470
+ },
473
471
  { currency: "USD", warn: "usdWarn", critical: "usdCritical", defaultWarn: 2, defaultCritical: 1 }
474
472
  ];
475
473
  function pairNumber(state, fallback) {
@@ -512,8 +510,10 @@ var SPEC_BY_FIELD = new Map(
512
510
  var TEST_LATENCY_MS = 800;
513
511
  function probeFailure(baseUrl, apiKey, apiKeyRef) {
514
512
  const url = baseUrl.trim();
515
- if (url !== "" && !/^https?:\/\//i.test(url)) return "base URL must start with http:// or https://";
516
- if (apiKey.trim() === "" && apiKeyRef.trim() === "") return "no API key or credential reference configured";
513
+ if (url !== "" && !/^https?:\/\//i.test(url))
514
+ return "base URL must start with http:// or https://";
515
+ if (apiKey.trim() === "" && apiKeyRef.trim() === "")
516
+ return "no API key or credential reference configured";
517
517
  return null;
518
518
  }
519
519
  function isRecord(input) {
@@ -564,16 +564,72 @@ function fieldStateOf(snapshot, spec, edit) {
564
564
  const effective = snapshot.value[spec.field];
565
565
  const stored = Object.hasOwn(snapshot.user, spec.field);
566
566
  if (edit === void 0) {
567
- return isTextSpec(spec) ? { text: spec.format(effective), value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
567
+ return isTextSpec(spec) ? {
568
+ text: spec.format(effective),
569
+ value: void 0,
570
+ effective,
571
+ stored,
572
+ overridden: stored,
573
+ dirty: false,
574
+ invalid: false
575
+ } : {
576
+ text: "",
577
+ value: effective,
578
+ effective,
579
+ stored,
580
+ overridden: stored,
581
+ dirty: false,
582
+ invalid: false
583
+ };
568
584
  }
569
585
  if (edit.kind === "clear") {
570
- return isTextSpec(spec) ? { text: "", value: void 0, effective, stored, overridden: false, dirty: stored, invalid: false } : { text: "", value: effective, effective, stored, overridden: false, dirty: stored, invalid: false };
586
+ return isTextSpec(spec) ? {
587
+ text: "",
588
+ value: void 0,
589
+ effective,
590
+ stored,
591
+ overridden: false,
592
+ dirty: stored,
593
+ invalid: false
594
+ } : {
595
+ text: "",
596
+ value: effective,
597
+ effective,
598
+ stored,
599
+ overridden: false,
600
+ dirty: stored,
601
+ invalid: false
602
+ };
571
603
  }
572
604
  if (!isTextSpec(spec)) {
573
- return edit.kind === "value" ? { text: "", value: edit.value, effective, stored, overridden: true, dirty: edit.value !== effective, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
605
+ return edit.kind === "value" ? {
606
+ text: "",
607
+ value: edit.value,
608
+ effective,
609
+ stored,
610
+ overridden: true,
611
+ dirty: edit.value !== effective,
612
+ invalid: false
613
+ } : {
614
+ text: "",
615
+ value: effective,
616
+ effective,
617
+ stored,
618
+ overridden: stored,
619
+ dirty: false,
620
+ invalid: false
621
+ };
574
622
  }
575
623
  if (edit.kind !== "text") {
576
- return { text: "", value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false };
624
+ return {
625
+ text: "",
626
+ value: void 0,
627
+ effective,
628
+ stored,
629
+ overridden: stored,
630
+ dirty: false,
631
+ invalid: false
632
+ };
577
633
  }
578
634
  const write = spec.parse(edit.text);
579
635
  const dirty = write === void 0 ? true : write.kind === "clear" ? stored : edit.text !== spec.format(effective);
@@ -618,10 +674,7 @@ function useConfigForm(form) {
618
674
  cacheRef.current = { value, user, writable, available, snapshot: snapshot2 };
619
675
  return snapshot2;
620
676
  }, [form]);
621
- const subscribe = (0, import_react2.useCallback)(
622
- (listener) => form.subscribe(listener),
623
- [form]
624
- );
677
+ const subscribe = (0, import_react2.useCallback)((listener) => form.subscribe(listener), [form]);
625
678
  const snapshot = (0, import_react2.useSyncExternalStore)(subscribe, readSnapshot);
626
679
  const [staged, setStaged] = (0, import_react2.useState)(() => /* @__PURE__ */ new Map());
627
680
  const [saving, setSaving] = (0, import_react2.useState)(false);
@@ -631,18 +684,23 @@ function useConfigForm(form) {
631
684
  const [test, setTest] = (0, import_react2.useState)({ running: false, ok: null, message: "" });
632
685
  const testTimerRef = (0, import_react2.useRef)(null);
633
686
  const testRunningRef = (0, import_react2.useRef)(false);
634
- (0, import_react2.useEffect)(() => () => {
635
- if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
636
- testTimerRef.current = null;
637
- testRunningRef.current = false;
638
- }, []);
687
+ (0, import_react2.useEffect)(
688
+ () => () => {
689
+ if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
690
+ testTimerRef.current = null;
691
+ testRunningRef.current = false;
692
+ },
693
+ []
694
+ );
639
695
  const plan = (0, import_react2.useMemo)(() => planWrites(snapshot, staged), [snapshot, staged]);
640
696
  const pairsInvalid = (0, import_react2.useMemo)(
641
- () => THRESHOLD_PAIRS.some((pair) => !thresholdsOk(
642
- pair,
643
- fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
644
- fieldOf(snapshot, pair.critical, staged.get(pair.critical))
645
- )),
697
+ () => THRESHOLD_PAIRS.some(
698
+ (pair) => !thresholdsOk(
699
+ pair,
700
+ fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
701
+ fieldOf(snapshot, pair.critical, staged.get(pair.critical))
702
+ )
703
+ ),
646
704
  [snapshot, staged]
647
705
  );
648
706
  const invalid = plan.some((item) => item.write === void 0) || pairsInvalid;
@@ -659,17 +717,28 @@ function useConfigForm(form) {
659
717
  testTimerRef.current = null;
660
718
  }
661
719
  testRunningRef.current = false;
662
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
720
+ setTest(
721
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
722
+ );
663
723
  }, []);
664
- const edit = (0, import_react2.useCallback)((field2, text) => {
665
- stage(field2, { kind: "text", text });
666
- }, [stage]);
667
- const setValue = (0, import_react2.useCallback)((field2, value) => {
668
- stage(field2, { kind: "value", value });
669
- }, [stage]);
670
- const resetField = (0, import_react2.useCallback)((field2) => {
671
- stage(field2, { kind: "clear" });
672
- }, [stage]);
724
+ const edit = (0, import_react2.useCallback)(
725
+ (field2, text) => {
726
+ stage(field2, { kind: "text", text });
727
+ },
728
+ [stage]
729
+ );
730
+ const setValue = (0, import_react2.useCallback)(
731
+ (field2, value) => {
732
+ stage(field2, { kind: "value", value });
733
+ },
734
+ [stage]
735
+ );
736
+ const resetField = (0, import_react2.useCallback)(
737
+ (field2) => {
738
+ stage(field2, { kind: "clear" });
739
+ },
740
+ [stage]
741
+ );
673
742
  const discard = (0, import_react2.useCallback)(() => {
674
743
  setStaged((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
675
744
  setFailed(false);
@@ -678,7 +747,9 @@ function useConfigForm(form) {
678
747
  testTimerRef.current = null;
679
748
  }
680
749
  testRunningRef.current = false;
681
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
750
+ setTest(
751
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
752
+ );
682
753
  }, []);
683
754
  const save = (0, import_react2.useCallback)(async () => {
684
755
  if (savingRef.current) return;
@@ -692,9 +763,11 @@ function useConfigForm(form) {
692
763
  for (const item of writes) {
693
764
  const write = item.write;
694
765
  if (write === void 0) continue;
695
- ops.push(write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value });
766
+ ops.push(
767
+ write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value }
768
+ );
696
769
  }
697
- let landed = false;
770
+ let landed;
698
771
  try {
699
772
  landed = await form.mutate(ops, form.getSnapshot().revision);
700
773
  } catch {
@@ -720,7 +793,9 @@ function useConfigForm(form) {
720
793
  testTimerRef.current = setTimeout(() => {
721
794
  testTimerRef.current = null;
722
795
  testRunningRef.current = false;
723
- setTest(failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure });
796
+ setTest(
797
+ failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure }
798
+ );
724
799
  }, TEST_LATENCY_MS);
725
800
  }, [readSnapshot, staged]);
726
801
  const field = (0, import_react2.useCallback)(
@@ -871,8 +946,7 @@ var BalanceSettingsCard_default = {
871
946
  readOnly: "BalanceSettingsCard_readOnly",
872
947
  footer: "BalanceSettingsCard_footer",
873
948
  failed: "BalanceSettingsCard_failed",
874
- notice: "BalanceSettingsCard_notice",
875
- save: "BalanceSettingsCard_save"
949
+ notice: "BalanceSettingsCard_notice"
876
950
  };
877
951
 
878
952
  // src/client/settings/BalanceSettingsCard.tsx
@@ -922,7 +996,8 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
922
996
  const toggleGroup = (key) => {
923
997
  setGroupOpen((current) => ({ ...current, [key]: !current[key] }));
924
998
  };
925
- const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
999
+ const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || // 成对校验不是字段级 invalid,得单独问一次:否则收起的阈值组会挡住「保存为什么是灰的」。
1000
+ key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
926
1001
  const { available, writable, dirty, invalid, saving, failed } = form.state;
927
1002
  const disabled = !writable || saving;
928
1003
  const credentialStatus = (name) => {
@@ -1079,7 +1154,10 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1079
1154
  {
1080
1155
  id: FIELD_IDS.apiKeyState ?? "apiKeyState",
1081
1156
  label: t("settings.field.apiKey"),
1082
- status: { label: t(CREDENTIAL_BADGE[credentialView]), tone: credentialView === "notConfigured" ? "quiet" : "neutral" },
1157
+ status: {
1158
+ label: t(CREDENTIAL_BADGE[credentialView]),
1159
+ tone: credentialView === "notConfigured" ? "quiet" : "neutral"
1160
+ },
1083
1161
  pending: false,
1084
1162
  resettable: false,
1085
1163
  pendingLabel: t("settings.unsaved"),
@@ -1089,12 +1167,7 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1089
1167
  disabled: true,
1090
1168
  onReset: () => {
1091
1169
  },
1092
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1093
- ReadOnlyControl,
1094
- {
1095
- id: FIELD_IDS.apiKeyState ?? "apiKeyState"
1096
- }
1097
- )
1170
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadOnlyControl, { id: FIELD_IDS.apiKeyState ?? "apiKeyState" })
1098
1171
  }
1099
1172
  ),
1100
1173
  textRow("baseUrl", "settings.field.baseUrl", "settings.hint.baseUrl", false),
@@ -1153,19 +1226,31 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1153
1226
  },
1154
1227
  last: true,
1155
1228
  children: [
1156
- numberRow("serverRefreshSeconds", "settings.field.serverRefreshSeconds", "settings.hint.serverRefreshSeconds"),
1157
- numberRow("clientPollSeconds", "settings.field.clientPollSeconds", "settings.hint.clientPollSeconds"),
1158
- numberRow("manualRefreshCooldownSeconds", "settings.field.manualRefreshCooldownSeconds", "settings.hint.manualRefreshCooldownSeconds")
1229
+ numberRow(
1230
+ "serverRefreshSeconds",
1231
+ "settings.field.serverRefreshSeconds",
1232
+ "settings.hint.serverRefreshSeconds"
1233
+ ),
1234
+ numberRow(
1235
+ "clientPollSeconds",
1236
+ "settings.field.clientPollSeconds",
1237
+ "settings.hint.clientPollSeconds"
1238
+ ),
1239
+ numberRow(
1240
+ "manualRefreshCooldownSeconds",
1241
+ "settings.field.manualRefreshCooldownSeconds",
1242
+ "settings.hint.manualRefreshCooldownSeconds"
1243
+ )
1159
1244
  ]
1160
1245
  }
1161
1246
  ),
1162
1247
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: BalanceSettingsCard_default.footer, children: [
1163
1248
  footerNote === null ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: footerNote.className, role: "status", children: footerNote.text }),
1164
1249
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1165
- "button",
1250
+ import_dsh_client_ui_primitives2.Button,
1166
1251
  {
1167
1252
  type: "button",
1168
- className: BalanceSettingsCard_default.save,
1253
+ variant: "primary",
1169
1254
  disabled: !dirty || invalid || saving || !writable,
1170
1255
  onClick: () => {
1171
1256
  void form.save();
@@ -1283,6 +1368,14 @@ function currentAgeMs(seenAt, seenAgeMs, now) {
1283
1368
  const base = Number.isFinite(seenAgeMs) ? Math.max(0, seenAgeMs) : 0;
1284
1369
  return Math.max(0, base + (now - seenAt));
1285
1370
  }
1371
+ var MS_PER_SECOND = 1e3;
1372
+ function cooldownUntilOf(now, configuredSeconds, rejectedRemainingMs) {
1373
+ const span = rejectedRemainingMs === null ? Math.max(0, configuredSeconds) * MS_PER_SECOND : Math.max(0, rejectedRemainingMs);
1374
+ return now + span;
1375
+ }
1376
+ function cooldownSecondsOf(until, now) {
1377
+ return Math.max(0, Math.ceil((until - now) / MS_PER_SECOND));
1378
+ }
1286
1379
 
1287
1380
  // src/client/mock/scenarios.ts
1288
1381
  var T0 = 176e10;
@@ -1315,9 +1408,17 @@ var scenarios = {
1315
1408
  /** 正常。 */
1316
1409
  ok: make({}),
1317
1410
  /** 余额偏低但可用。 */
1318
- warn: make({ severity: "warn", balances: [cny("8.00000000", "0.00000000", "8.00000000")], selected: { currency: "CNY", total: "8.00000000" } }),
1411
+ warn: make({
1412
+ severity: "warn",
1413
+ balances: [cny("8.00000000", "0.00000000", "8.00000000")],
1414
+ selected: { currency: "CNY", total: "8.00000000" }
1415
+ }),
1319
1416
  /** 余额告急。 */
1320
- critical: make({ severity: "critical", balances: [cny("3.00000000", "0.00000000", "3.00000000")], selected: { currency: "CNY", total: "3.00000000" } }),
1417
+ critical: make({
1418
+ severity: "critical",
1419
+ balances: [cny("3.00000000", "0.00000000", "3.00000000")],
1420
+ selected: { currency: "CNY", total: "3.00000000" }
1421
+ }),
1321
1422
  /** 账户不可用(余额耗尽 / 欠费)。 */
1322
1423
  unavailable: make({
1323
1424
  severity: "unavailable",
@@ -1326,7 +1427,14 @@ var scenarios = {
1326
1427
  selected: { currency: "CNY", total: "0.00000000" }
1327
1428
  }),
1328
1429
  /** 有旧值但本次刷新失败。 */
1329
- stale: make({ state: "stale", stale: true, severity: "unknown", ageMs: 36e5, fetchedAt: T0 - 36e5, error: { code: "NO_NETWORK", message: "fetch failed" } }),
1430
+ stale: make({
1431
+ state: "stale",
1432
+ stale: true,
1433
+ severity: "unknown",
1434
+ ageMs: 36e5,
1435
+ fetchedAt: T0 - 36e5,
1436
+ error: { code: "NO_NETWORK", message: "fetch failed" }
1437
+ }),
1330
1438
  /** 无值失败。 */
1331
1439
  error: make({
1332
1440
  state: "error",
@@ -1339,14 +1447,35 @@ var scenarios = {
1339
1447
  error: { code: "UPSTREAM_5XX", message: "upstream returned 500" }
1340
1448
  }),
1341
1449
  /** 未配置。 */
1342
- empty: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0 }),
1450
+ empty: make({
1451
+ state: "empty",
1452
+ severity: "unknown",
1453
+ isAvailable: false,
1454
+ balances: [],
1455
+ selected: null,
1456
+ ageMs: 0
1457
+ }),
1343
1458
  /** 未配置且带 NO_KEY 错误。 */
1344
- noKey: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0, error: { code: "NO_KEY", message: "no API key configured" } }),
1459
+ noKey: make({
1460
+ state: "empty",
1461
+ severity: "unknown",
1462
+ isAvailable: false,
1463
+ balances: [],
1464
+ selected: null,
1465
+ ageMs: 0,
1466
+ error: { code: "NO_KEY", message: "no API key configured" }
1467
+ }),
1345
1468
  /** 多币种。`selected` 显式写出,不靠 `make()` 的默认值兜。 */
1346
1469
  multiCurrency: make({
1347
- balances: [cny("110.00000000", "10.00000000", "100.00000000"), { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }],
1470
+ balances: [
1471
+ cny("110.00000000", "10.00000000", "100.00000000"),
1472
+ { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }
1473
+ ],
1348
1474
  selected: { currency: "CNY", total: "110.00000000" },
1349
- thresholds: { CNY: { warn: "10.00000000", critical: "5.00000000" }, USD: { warn: "2.00000000", critical: "1.00000000" } }
1475
+ thresholds: {
1476
+ CNY: { warn: "10.00000000", critical: "5.00000000" },
1477
+ USD: { warn: "2.00000000", critical: "1.00000000" }
1478
+ }
1350
1479
  }),
1351
1480
  /**
1352
1481
  * 选定了账户里没有的币种(USD),账户只有 CNY。
@@ -1561,9 +1690,12 @@ function BalancePopover(props) {
1561
1690
  const cooling = cooldownSeconds > 0;
1562
1691
  let statusText = "";
1563
1692
  if (refreshing) statusText = t("popover.refreshing");
1564
- else if (cooling) statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1693
+ else if (cooling)
1694
+ statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1565
1695
  const refreshLabel = t("sidebar.aria.refresh");
1566
- const pluginsLabel = t(pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins");
1696
+ const pluginsLabel = t(
1697
+ pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins"
1698
+ );
1567
1699
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1568
1700
  "section",
1569
1701
  {
@@ -1609,7 +1741,16 @@ function BalancePopover(props) {
1609
1741
  ] }),
1610
1742
  shown !== null && !selection.matchesPreference ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.notice, children: [
1611
1743
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: interpolate(t("popover.mismatch"), { wanted: displayCurrency, shown: shown.currency }) }),
1612
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { size: "sm", variant: "outline", disabled: useShownDisabled === true, onClick: onUseShown, children: interpolate(t("popover.action.useShown"), { shown: shown.currency }) }) })
1744
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1745
+ import_dsh_client_ui_primitives3.Button,
1746
+ {
1747
+ size: "sm",
1748
+ variant: "outline",
1749
+ disabled: useShownDisabled === true,
1750
+ onClick: onUseShown,
1751
+ children: interpolate(t("popover.action.useShown"), { shown: shown.currency })
1752
+ }
1753
+ ) })
1613
1754
  ] }) : null,
1614
1755
  configSlotWarning === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.notice, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: configSlotWarning }) }),
1615
1756
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.footer, children: [
@@ -1654,7 +1795,13 @@ var CROSS_ARM = (2 * RADIUS - STROKE) / 2 / Math.SQRT2;
1654
1795
  function round3(value) {
1655
1796
  return Math.round(value * 1e3) / 1e3;
1656
1797
  }
1657
- function PercentRing({ state, marker = null, ratio = 1, size = 18, title }) {
1798
+ function PercentRing({
1799
+ state,
1800
+ marker = null,
1801
+ ratio = 1,
1802
+ size = 18,
1803
+ title
1804
+ }) {
1658
1805
  const clamped = Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1;
1659
1806
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1660
1807
  "svg",
@@ -1720,8 +1867,8 @@ var REFRESH_SIMULATION_MS = 600;
1720
1867
  var PANEL_GAP = 8;
1721
1868
  var PANEL_MARGIN = 12;
1722
1869
  var MEASURE_STYLE = { visibility: "hidden", left: 0, top: 0 };
1723
- var MS_PER_SECOND = 1e3;
1724
- var TICK_MS = MS_PER_SECOND;
1870
+ var MS_PER_SECOND2 = 1e3;
1871
+ var TICK_MS = MS_PER_SECOND2;
1725
1872
  function useConfigSlotState(probe) {
1726
1873
  const [state, setState] = (0, import_react5.useState)(() => probe.getSnapshot());
1727
1874
  (0, import_react5.useEffect)(() => {
@@ -1747,8 +1894,10 @@ function usePluginsNavigation(navigation) {
1747
1894
  return action;
1748
1895
  }
1749
1896
  function stateLabelKey(response, selection) {
1750
- if (response.state === "error") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
1751
- if (response.state === "empty") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
1897
+ if (response.state === "error")
1898
+ return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
1899
+ if (response.state === "empty")
1900
+ return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
1752
1901
  if (response.state === "stale") return "state.stale";
1753
1902
  if (!response.isAvailable) return "state.unavailable";
1754
1903
  if (selection.shown === null) return "state.noBalance";
@@ -1793,16 +1942,19 @@ function SidebarBalance({
1793
1942
  }, []);
1794
1943
  const preference = config.displayCurrency;
1795
1944
  const selection = (0, import_react5.useMemo)(() => selectionOf(response, preference), [response, preference]);
1796
- (0, import_react5.useEffect)(() => subscribeScenario((key) => {
1797
- const active = resolveScenario() !== null;
1798
- setMock(active);
1799
- if (!active || lastScenario.current === key) return;
1800
- lastScenario.current = key;
1801
- acceptBalance(currentBalance());
1802
- setRefreshing(false);
1803
- setCooldownUntil(0);
1804
- setOpen(false);
1805
- }), [acceptBalance]);
1945
+ (0, import_react5.useEffect)(
1946
+ () => subscribeScenario((key) => {
1947
+ const active = resolveScenario() !== null;
1948
+ setMock(active);
1949
+ if (!active || lastScenario.current === key) return;
1950
+ lastScenario.current = key;
1951
+ acceptBalance(currentBalance());
1952
+ setRefreshing(false);
1953
+ setCooldownUntil(0);
1954
+ setOpen(false);
1955
+ }),
1956
+ [acceptBalance]
1957
+ );
1806
1958
  (0, import_react5.useEffect)(() => {
1807
1959
  if (mock) return;
1808
1960
  let cancelled = false;
@@ -1818,17 +1970,30 @@ function SidebarBalance({
1818
1970
  }
1819
1971
  };
1820
1972
  void load();
1821
- const id = window.setInterval(() => {
1822
- void load();
1823
- }, Math.max(5, config.clientPollSeconds) * MS_PER_SECOND);
1973
+ const id = window.setInterval(
1974
+ () => {
1975
+ void load();
1976
+ },
1977
+ Math.max(5, config.clientPollSeconds) * MS_PER_SECOND2
1978
+ );
1824
1979
  return () => {
1825
1980
  cancelled = true;
1826
1981
  window.clearInterval(id);
1827
1982
  };
1828
- }, [mock, preference, config.clientPollSeconds, config.configSignature, acceptBalance, showUnreachable]);
1829
- (0, import_react5.useEffect)(() => () => {
1830
- if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1831
- }, []);
1983
+ }, [
1984
+ mock,
1985
+ preference,
1986
+ config.clientPollSeconds,
1987
+ config.configSignature,
1988
+ acceptBalance,
1989
+ showUnreachable
1990
+ ]);
1991
+ (0, import_react5.useEffect)(
1992
+ () => () => {
1993
+ if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1994
+ },
1995
+ []
1996
+ );
1832
1997
  const closeNow = (0, import_react5.useCallback)(() => {
1833
1998
  setOpen(false);
1834
1999
  }, []);
@@ -1843,9 +2008,12 @@ function SidebarBalance({
1843
2008
  gap: PANEL_GAP,
1844
2009
  margin: PANEL_MARGIN
1845
2010
  });
1846
- (0, import_react5.useEffect)(() => {
2011
+ (0, import_react5.useLayoutEffect)(() => {
1847
2012
  if (!open) return;
1848
2013
  setNow(Date.now());
2014
+ }, [open]);
2015
+ (0, import_react5.useEffect)(() => {
2016
+ if (!open) return;
1849
2017
  const id = window.setInterval(() => {
1850
2018
  setNow(Date.now());
1851
2019
  }, TICK_MS);
@@ -1853,6 +2021,17 @@ function SidebarBalance({
1853
2021
  window.clearInterval(id);
1854
2022
  };
1855
2023
  }, [open]);
2024
+ (0, import_react5.useEffect)(() => {
2025
+ if (cooldownUntil === 0) return;
2026
+ const remaining = cooldownUntil - Date.now();
2027
+ if (remaining <= 0) return;
2028
+ const id = window.setTimeout(() => {
2029
+ setNow(Date.now());
2030
+ }, remaining);
2031
+ return () => {
2032
+ window.clearTimeout(id);
2033
+ };
2034
+ }, [cooldownUntil]);
1856
2035
  (0, import_react5.useEffect)(() => {
1857
2036
  if (!open) return;
1858
2037
  const onKeyDown = (event) => {
@@ -1868,31 +2047,46 @@ function SidebarBalance({
1868
2047
  if (refreshing) return;
1869
2048
  if (Date.now() < cooldownUntil) return;
1870
2049
  setRefreshing(true);
1871
- const finish = () => {
2050
+ const finish = (rejectedRemainingMs) => {
2051
+ const at = Date.now();
1872
2052
  setRefreshing(false);
1873
- setCooldownUntil(Date.now() + Math.max(0, config.manualRefreshCooldownSeconds) * MS_PER_SECOND);
2053
+ setCooldownUntil(
2054
+ cooldownUntilOf(at, config.manualRefreshCooldownSeconds, rejectedRemainingMs)
2055
+ );
2056
+ setNow(at);
1874
2057
  };
1875
2058
  if (mock) {
1876
2059
  refreshTimer.current = window.setTimeout(() => {
1877
2060
  refreshTimer.current = void 0;
1878
2061
  markFresh();
1879
- finish();
2062
+ finish(null);
1880
2063
  }, REFRESH_SIMULATION_MS);
1881
2064
  return;
1882
2065
  }
1883
2066
  void (async () => {
2067
+ let rejectedRemainingMs = null;
1884
2068
  try {
1885
- await requestRefresh({ reason: "manual" });
2069
+ const result = await requestRefresh({ reason: "manual" });
2070
+ if (!result.triggered) rejectedRemainingMs = Math.max(0, result.cooldownMs);
1886
2071
  const next = await requestBalance({ currency: preference });
1887
2072
  loadedRef.current = true;
1888
2073
  acceptBalance(next);
1889
2074
  } catch (error) {
1890
2075
  if (!loadedRef.current) showUnreachable(error);
1891
2076
  } finally {
1892
- finish();
2077
+ finish(rejectedRemainingMs);
1893
2078
  }
1894
2079
  })();
1895
- }, [cooldownUntil, config.manualRefreshCooldownSeconds, mock, preference, refreshing, acceptBalance, showUnreachable, markFresh]);
2080
+ }, [
2081
+ cooldownUntil,
2082
+ config.manualRefreshCooldownSeconds,
2083
+ mock,
2084
+ preference,
2085
+ refreshing,
2086
+ acceptBalance,
2087
+ showUnreachable,
2088
+ markFresh
2089
+ ]);
1896
2090
  const handleUseShown = (0, import_react5.useCallback)(() => {
1897
2091
  const current = selection.shown;
1898
2092
  if (current === null) return;
@@ -1933,7 +2127,7 @@ function SidebarBalance({
1933
2127
  if (stateText !== null && stateText !== markerLabel) ariaParts.push(stateText);
1934
2128
  if (markerLabel !== null) ariaParts.push(markerLabel);
1935
2129
  const ariaLabel = ariaParts.join(" ");
1936
- const cooldownSeconds = Math.max(0, Math.ceil((cooldownUntil - now) / MS_PER_SECOND));
2130
+ const cooldownSeconds = cooldownSecondsOf(cooldownUntil, now);
1937
2131
  const ageMs = currentAgeMs(view.seenAt, view.seenAgeMs, now);
1938
2132
  const ringTitle = !wide && stateText !== null ? `${t("sidebar.aria.ring")} ${stateText}` : void 0;
1939
2133
  const hoverLabel = shown === null ? stateText : formatMoney(shown.total, shown.currency);
@@ -1949,42 +2143,42 @@ function SidebarBalance({
1949
2143
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.icon, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 16 }) }),
1950
2144
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.label, children: t("sidebar.label") }),
1951
2145
  markerLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: markerHint, side: "bottom", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.marker, role: "img", "aria-label": markerLabel, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.IconWarningOutlineRegular, { size: 12 }) }) })
1952
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 18, title: ringTitle })
1953
- }
1954
- );
1955
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1956
- "div",
1957
- {
1958
- ref: rootRef,
1959
- className: SidebarBalance_default.root,
1960
- "data-mode": wide ? "wide" : "rail",
1961
- tabIndex: -1,
1962
- children: [
1963
- wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
1964
- open ? (0, import_react_dom.createPortal)(
1965
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1966
- BalancePopover,
1967
- {
1968
- t,
1969
- selection,
1970
- displayCurrency: preference,
1971
- ageMs,
1972
- refreshing,
1973
- cooldownSeconds,
1974
- configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
1975
- panelRef,
1976
- style: pos ?? MEASURE_STYLE,
1977
- onRefresh: handleRefresh,
1978
- onUseShown: handleUseShown,
1979
- useShownDisabled: !config.writable,
1980
- pluginsAction: popoverPluginsAction
1981
- }
1982
- ),
1983
- document.body
1984
- ) : null
1985
- ]
2146
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2147
+ PercentRing,
2148
+ {
2149
+ state: ring.state,
2150
+ marker: ring.marker,
2151
+ ratio: ringRatio,
2152
+ size: 18,
2153
+ title: ringTitle
2154
+ }
2155
+ )
1986
2156
  }
1987
2157
  );
2158
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: rootRef, className: SidebarBalance_default.root, "data-mode": wide ? "wide" : "rail", tabIndex: -1, children: [
2159
+ wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
2160
+ open ? (0, import_react_dom.createPortal)(
2161
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2162
+ BalancePopover,
2163
+ {
2164
+ t,
2165
+ selection,
2166
+ displayCurrency: preference,
2167
+ ageMs,
2168
+ refreshing,
2169
+ cooldownSeconds,
2170
+ configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
2171
+ panelRef,
2172
+ style: pos ?? MEASURE_STYLE,
2173
+ onRefresh: handleRefresh,
2174
+ onUseShown: handleUseShown,
2175
+ useShownDisabled: !config.writable,
2176
+ pluginsAction: popoverPluginsAction
2177
+ }
2178
+ ),
2179
+ document.body
2180
+ ) : null
2181
+ ] });
1988
2182
  }
1989
2183
 
1990
2184
  // src/client/index.tsx
@@ -2142,7 +2336,10 @@ function apply(ctx) {
2142
2336
  const candidate = face["openBundle"];
2143
2337
  if (typeof candidate !== "function") return;
2144
2338
  const openBundle = candidate.bind(face);
2145
- navCtx.effect(() => pluginsNavigation.attachDeepLink(openBundle), "ds-balance: bundle config deep link");
2339
+ navCtx.effect(
2340
+ () => pluginsNavigation.attachDeepLink(openBundle),
2341
+ "ds-balance: bundle config deep link"
2342
+ );
2146
2343
  });
2147
2344
  ctx.inject(["layout"], (layoutCtx) => {
2148
2345
  if (!("layout" in layoutCtx)) return;
@@ -2160,25 +2357,31 @@ function apply(ctx) {
2160
2357
  ctx.inject(["configForms"], (configCtx) => {
2161
2358
  configSlotProbe.markDeclared();
2162
2359
  const form = configCtx.configForms.get(ENTRY_ID);
2163
- ctx.slots.inject(CONFIG_SLOT, () => ctx.slots.register(
2164
- { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2165
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2166
- ));
2167
- ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
2168
- { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2169
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2170
- SidebarSeatComponent,
2171
- {
2172
- seat,
2173
- form,
2174
- configSlotProbe,
2175
- pluginsNavigation
2176
- }
2360
+ ctx.slots.inject(
2361
+ CONFIG_SLOT,
2362
+ () => ctx.slots.register(
2363
+ { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2364
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2365
+ )
2366
+ );
2367
+ ctx.slots.inject(
2368
+ "sidebar.footer.action",
2369
+ () => ctx.slots.register(
2370
+ { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2371
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2372
+ SidebarSeatComponent,
2373
+ {
2374
+ seat,
2375
+ form,
2376
+ configSlotProbe,
2377
+ pluginsNavigation
2378
+ }
2379
+ )
2177
2380
  )
2178
- ));
2381
+ );
2179
2382
  });
2180
2383
  }
2181
- var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsSummary {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n list-style: none;\n}\n.fields_detailsSummary::-webkit-details-marker {\n display: none;\n}\n.fields_detailsSummary::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n transform: translate(-0.5px, -1px) rotate(-45deg);\n transition: transform 120ms ease;\n}\n.fields_details[open] > .fields_detailsSummary::before {\n transform: translate(-0.5px, -1px) rotate(45deg);\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n opacity: 0.6;\n cursor: default;\n}\ninput.fields_inputStatic,\ninput.fields_inputStatic:hover,\ninput.fields_inputStatic:focus,\ninput.fields_inputStatic:focus-visible,\ninput.fields_inputStatic:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n pointer-events: none;\n}\n.fields_inputInvalid {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_inputInvalid:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputInvalid:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 999px;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_actionButton {\n appearance: none;\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n.fields_actionButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.fields_actionButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.fields_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_save {\n appearance: none;\n border: 0.5px solid transparent;\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n.BalanceSettingsCard_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalanceSettingsCard_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: 12px;\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_cross {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: 12px;\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: 12px;\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
2384
+ var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 999px;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: 12px;\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_cross {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: 12px;\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: 12px;\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
2182
2385
  var __dsbTagId = "dsh-ds-balance/client.css";
2183
2386
  if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="' + __dsbTagId + '"]') === null) {
2184
2387
  var __dsbTag = document.createElement('style');