@cassius0924/dsh-usage-dashboard 0.9.0 → 0.9.2

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.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/client/index.tsx", "../src/client/boundary.tsx", "../src/client/cache.ts", "../src/contract.ts", "../src/client/api.ts", "../src/client/dashboard.tsx", "../src/client/budget.ts", "../src/client/charts.tsx", "../src/client/chart-focus.ts", "../src/client/i18n.tsx", "../src/client/locales.ts", "../src/client/dom.ts", "../src/client/export.ts", "../src/client/freshness.ts", "../src/client/metric.ts", "../src/client/prefs.ts", "../src/client/store.ts", "../src/client/layout-prefs.ts", "../src/client/top-up.ts", "../src/client/message-cost.tsx", "../src/client/session-cost-pill.tsx", "../src/pricing.ts", "../src/client/styles.ts", "../src/client/widget.tsx", "../src/client/sessions.ts", "../src/client/views.ts"],
4
- "sourcesContent": ["/**\n * dsh-usage-dashboard client half: mounts the floating balance widget\n * (`shell.overlay`), the \u300C\u989D\u5EA6\u300D view tab (`conversation.view`), an optional\n * sidebar entry / account-wide panel, and the per-turn cost chip.\n * Data arrives through the package's own host API via same-origin fetch.\n */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport { ErrorBoundary } from './boundary.tsx'\nimport type { ClientContext } from './context.ts'\nimport { fetchBalance, fetchUsage } from './api.ts'\nimport { BalanceDashboard } from './dashboard.tsx'\nimport { LocaleProvider, type Translate } from './i18n.tsx'\nimport { QUOTA_PANEL_ID, quotaTabIndexStore, sidebarEntryStore, viewOrderForIndex } from './layout-prefs.ts'\nimport { en, NS, zh } from './locales.ts'\nimport { MessageCost } from './message-cost.tsx'\nimport { SessionCostPill } from './session-cost-pill.tsx'\nimport { css } from './styles.ts'\nimport { quotaViewActiveStore } from './store.ts'\nimport { QuotaWidget, type UseSessionsHook } from './widget.tsx'\nimport { conversationViewsSource } from './views.ts'\n\n/** Plugin identity for the client bundle. */\nexport const name = 'dsh-usage-dashboard'\n\n/** Services required before load. */\nexport const inject = ['slots', 'locale', 'layout']\n\n/** The host's `conversation.view` props include a session-addressable view\n * switcher; the tab-position setting uses it to come back to \u989D\u5EA6 after the\n * registration is replaced with a new `order`. */\ntype OpenView = (view: string, focus: string) => void\n\n/** Kept outside React so the registration half can restore the tab after a\n * dispose/re-register cycle, even when that cycle unmounts the dashboard. */\nlet openQuotaTab: OpenView | null = null\n\n/**\n * Mount the plugin surfaces.\n * @param ctx - client Cordis context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-usage-dashboard: browser dictionaries')\n const t = ctx.locale.bind(NS)\n const views = conversationViewsSource(ctx.slots)\n // One stylesheet for the whole plugin; the module loader claims and removes\n // plugin-owned style tags on unload.\n if (typeof document !== 'undefined') {\n // A hot reload can leave the previous version's tag behind; two sheets would\n // then mix old and new rules, so drop any stale copy before adding ours.\n document.querySelectorAll('style[data-plugin=\"dsh-usage-dashboard\"]').forEach(node => node.remove())\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-usage-dashboard'\n tag.textContent = css\n document.head.appendChild(tag)\n }\n\n // Warm both caches the moment the client bundle loads, rather than waiting\n // for the \u300C\u989D\u5EA6\u300D tab to mount. Usage aggregation alone takes seconds (it\n // replays every session log), so without this the tab's first open always\n // paid that latency; with it, by the time someone actually clicks the tab\n // the fetch has usually already landed and the tab renders from cache. Not\n // awaited and not surfaced: a failure here just leaves the widget/tab to\n // fetch (and report) it themselves on mount, same as before this existed.\n void fetchBalance().catch(() => {})\n void fetchUsage().catch(() => {})\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register(\n { name: 'shell.overlay', id: 'deepseek-quota', order: 1000, locale: NS, label: () => t('widget.title') },\n ({ t: slotT, useSessions }: { t: Translate; useSessions: UseSessionsHook }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent><QuotaWidget useSessions={useSessions} views={views} /></ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n // Composer-dock session reading: one more pill beside the host's own\n // \u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300D/\u300CToken \u7528\u91CF\u300Dentries (same slot, same skin), showing the\n // whole conversation's estimated spend and opening a detail dialog.\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n { name: 'conversation.composer.dock', id: 'quota-cost', order: 2, locale: NS },\n ({ t: slotT, sessionId }: { t: Translate; sessionId?: string }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent><SessionCostPill sessionId={sessionId} /></ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n ctx.slots.inject('conversation.chat.assistant-actions', () => ctx.slots.register(\n {\n name: 'conversation.chat.assistant-actions',\n id: 'dsh-usage-turn-cost',\n order: 5,\n locale: NS,\n label: () => t('messageCost.label'),\n },\n ({ t: slotT, sessionId, messageId }: { t: Translate; sessionId: string; messageId: string }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent>\n <MessageCost sessionId={sessionId} messageId={messageId} />\n </ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n // --- \u300C\u989D\u5EA6\u300Dconversation tab, with a user-configurable position -----------\n //\n // The host orders view tabs by the slot entry's `order` (then registration\n // sequence), and the registration options are immutable once registered. A\n // position change therefore replaces the registration: the persisted index\n // is turned into an order between the neighbouring live entries, so it still\n // means the same thing when another plugin adds/removes a tab. Disposing the\n // entry makes the host fall back to Chat for a moment; the captured\n // `openView` switches back to \u989D\u5EA6 right after the new entry exists.\n const QuotaView = ({ t: slotT, sessionId, openView }: {\n t: Translate\n sessionId?: string\n openView?: OpenView\n }): ReactElement => {\n useEffect(() => { if (openView !== undefined) openQuotaTab = openView }, [openView])\n return (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT}><BalanceDashboard sessionId={sessionId} views={views} /></ErrorBoundary>\n </LocaleProvider>\n )\n }\n\n ctx.effect(() => {\n let disposeView: (() => void) | null = null\n const mount = (): void => {\n disposeView?.()\n disposeView = ctx.slots.inject('conversation.view', () => ctx.slots.register(\n {\n name: 'conversation.view',\n id: 'balance',\n order: viewOrderForIndex(ctx.slots.entries('conversation.view'), quotaTabIndexStore.get()),\n locale: NS,\n label: () => t('nav.quota'),\n },\n // `conversation.view` is a session-scoped slot, so the host injects its\n // standard session props (including `sessionId`) alongside `t`; only the\n // fields this plugin needs are destructured, per the existing\n // \"hand-write the minimal structural type\" convention (see context.ts).\n // `sessionId` stays optional: BalanceDashboard renders the current-\n // session card only when it actually has one, never throws either way.\n QuotaView,\n ))\n }\n mount()\n const unsubscribe = quotaTabIndexStore.subscribe(() => {\n // Only a conversation-mounted dashboard needs the view restored; in the\n // global panel the attribute is absent and the panel stays selected.\n const restore = document !== undefined\n && document.documentElement.hasAttribute('data-dq-quota-view')\n disposeView?.()\n disposeView = null\n mount()\n if (restore) queueMicrotask(() => openQuotaTab?.('balance', 'dsh-usage-dashboard:tab-order'))\n })\n return () => {\n unsubscribe()\n disposeView?.()\n }\n }, 'dsh-usage-dashboard: quota tab registration')\n\n // --- account-wide \u989D\u5EA6 panel + optional sidebar entry ---------------------\n const QuotaPanel = ({ t: slotT }: { t: Translate }): ReactElement => (\n <div className=\"dq-panel\">\n <div className=\"dq-panel-head\" data-window-drag>\n <h1 className=\"dq-panel-title\">{slotT('nav.quota')}</h1>\n <span className=\"dq-panel-caption\">{slotT('panel.caption')}</span>\n </div>\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT}><BalanceDashboard views={views} /></ErrorBoundary>\n </LocaleProvider>\n </div>\n )\n\n /** The \u00A5 glyph drawn as a 16-unit stroke icon so it occupies the same box as\n * the host's own sidebar icons (a text glyph is only ~8px wide, which pushed\n * this row's label ~8px left of every other row). */\n const QuotaGlyph = ({ size, active }: { size: number; active?: boolean }): ReactElement => (\n <svg\n className=\"dq-side-icon\"\n data-active={active === true ? 'true' : 'false'}\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.1}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M3.5 3.3 8 8.7l4.5-5.4\" />\n <path d=\"M8 8.7V13.2\" />\n <path d=\"M3.5 10.2h9\" />\n <path d=\"M3.5 12.1h9\" />\n </svg>\n )\n\n const QuotaFooterButton = ({ wide, t: slotT }: { wide: boolean; t: Translate }): ReactElement => {\n const [active, setActive] = useState(() => ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID)\n useEffect(() => {\n const sync = (): void => {\n setActive(ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID)\n }\n sync()\n return ctx.layout.panelInfo.subscribe(sync)\n }, [])\n return (\n <button\n type=\"button\"\n className={`dq-side-entry${wide ? '' : ' dq-side-entry--rail'}`}\n title={slotT('panel.openAria')}\n aria-label={slotT('nav.quota')}\n aria-pressed={active}\n onClick={() => { ctx.layout.selectPanel(active ? null : QUOTA_PANEL_ID) }}\n >\n <span className=\"dq-side-entry-icon\"><QuotaGlyph size={16} /></span>\n {wide && <span className=\"dq-side-entry-label\">{slotT('nav.quota')}</span>}\n </button>\n )\n }\n\n // The panel itself always exists (its sidebar entry may be off); the entry\n // that reaches it is what the setting turns on and off.\n ctx.effect(() => ctx.slots.inject('main', () => ctx.slots.register(\n { name: 'main', key: QUOTA_PANEL_ID, locale: NS },\n QuotaPanel,\n )), 'dsh-usage-dashboard: quota panel')\n\n ctx.effect(() => {\n let disposeEntry: (() => void) | null = null\n const sync = (): void => {\n disposeEntry?.()\n disposeEntry = null\n const placement = sidebarEntryStore.get()\n if (placement === 'top') {\n // Append after the host's global panels (Plugins / Scheduled tasks /\n // Context insights) instead of taking the first row: the entry is an\n // addition to the existing navigation, not a replacement for its\n // order. A high order keeps that true even for plugins that register\n // after this one (the host sorts the list by order).\n disposeEntry = ctx.slots.inject('sidebar.panellist', () => ctx.slots.register(\n { name: 'sidebar.panellist', id: QUOTA_PANEL_ID, order: 1000, label: () => t('nav.quota'), locale: NS },\n QuotaGlyph,\n ))\n return\n }\n if (placement === 'bottom') {\n disposeEntry = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register(\n { name: 'sidebar.footer.action', id: 'quota', order: 10, locale: NS },\n QuotaFooterButton,\n ))\n return\n }\n // Turning the entry off while its panel is open must not strand the\n // user on a panel with no visible entry: return to the conversation.\n if (ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID) ctx.layout.selectPanel(null)\n }\n sync()\n const unsubscribe = sidebarEntryStore.subscribe(sync)\n return () => {\n unsubscribe()\n disposeEntry?.()\n }\n }, 'dsh-usage-dashboard: sidebar entry')\n\n // --- hide the composer while the \u300C\u989D\u5EA6\u300Dconversation view is active -------\n //\n // The dashboard does not need the chat input, and hiding it gives the long\n // page the full column height. The attribute is only set when the mount is\n // inside the conversation scrollport, so the account-wide panel (which has\n // no composer) never touches host chrome. `quotaViewActiveStore` is the\n // already-existing \"the dashboard is mounted\" signal the widget reacts to.\n ctx.effect(() => {\n let applied = false\n const sync = (): void => {\n const root = document.querySelector('.dq-balance')\n const should = quotaViewActiveStore.get()\n && root !== null\n && root.closest('[data-conversation-scroll]') !== null\n if (should === applied) return\n applied = should\n if (should) document.documentElement.setAttribute('data-dq-quota-view', '')\n else document.documentElement.removeAttribute('data-dq-quota-view')\n }\n sync()\n const unsubscribe = quotaViewActiveStore.subscribe(sync)\n return () => {\n unsubscribe()\n if (applied) document.documentElement.removeAttribute('data-dq-quota-view')\n }\n }, 'dsh-usage-dashboard: composer visibility')\n}\n", "/**\n * Error boundary for the plugin's two slot entries.\n *\n * A slot component that throws while rendering takes its whole subtree down \u2014\n * for the \u300C\u989D\u5EA6\u300D view that meant a blank tab, and the only thing that fixed it\n * was a browser profile with no localStorage. A crash should degrade to\n * something the user can act on, and it should never be the tab's silent\n * default state.\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react'\nimport type { Translate } from './i18n.tsx'\n\nconst PREFIX = 'dsh-usage-dashboard:'\n\n/** Drop every key this plugin owns \u2014 caches and preferences alike. */\nfunction clearPluginStorage(): void {\n if (typeof localStorage === 'undefined') return\n try {\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(PREFIX)) localStorage.removeItem(key)\n }\n } catch {\n // Nothing better to do; the reload below is still worth attempting.\n }\n}\n\ninterface Props {\n /** Shown instead of the fallback UI when the surface has no room for it. */\n silent?: boolean\n t: Translate\n children: ReactNode\n}\n\ninterface State {\n message: string | null\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n state: State = { message: null }\n\n static getDerivedStateFromError(error: unknown): State {\n return { message: (error as { message?: string } | null)?.message ?? String(error) }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo): void {\n console.error('[dsh-usage-dashboard] render failed', error, info.componentStack)\n }\n\n private readonly reset = (): void => {\n clearPluginStorage()\n location.reload()\n }\n\n render(): ReactNode {\n const { message } = this.state\n if (message === null) return this.props.children\n if (this.props.silent === true) return null\n const { t } = this.props\n return (\n <div className=\"dq-balance\">\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">{t('boundary.title')}</div>\n <p className=\"dq-empty\">{t('boundary.body')}</p>\n <pre className=\"dq-crash\">{message}</pre>\n <button type=\"button\" className=\"dq-refresh-btn\" onClick={this.reset}>\n {t('boundary.reset')}\n </button>\n </div>\n </div>\n )\n }\n}\n", "/**\n * Package-local TTL caches shared by the widget, the dashboard, and every\n * tab switch. Cached values outlive the TTL: `get()` still returns them\n * (marked by `at`) so a reopening tab can render instantly and refresh in\n * the background, while `getFresh()` is the cache-aware fetch path.\n *\n * When a `storageKey` is given, every `put()` also mirrors the entry to\n * localStorage so a page refresh keeps the instant first paint (the data\n * shown is the last known good value; a background refresh updates it).\n */\n\n/** Bump whenever the persisted shape changes in a way `isUsable` cannot catch. */\nconst LS_VERSION = 2\n\nexport interface CacheHit<T> {\n data: T\n at: number\n}\n\nexport interface ResourceCache<T> {\n /** Last cached value even when stale; null when never cached. */\n get(): CacheHit<T> | null\n /** Value only when it is still within the TTL. */\n getFresh(): T | null\n put(data: T): void\n}\n\n/**\n * Read a persisted entry, but only trust it if it still matches the shape the\n * current code reads. A payload written by an older build can be missing fields\n * this one dereferences, and because the first render is seeded straight from\n * here, an unchecked stale entry crashes the view \u2014 for the user it looks like\n * a blank tab that only a fresh browser profile fixes.\n */\nfunction loadPersisted<T>(storageKey: string, isUsable?: (data: T) => boolean): CacheHit<T> | null {\n if (typeof localStorage === 'undefined') return null\n const key = `${storageKey}:v${LS_VERSION}`\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return null\n const parsed = JSON.parse(raw) as { data?: T; at?: number }\n if (parsed.data === undefined || typeof parsed.at !== 'number') return null\n if (isUsable !== undefined && !isUsable(parsed.data)) {\n localStorage.removeItem(key)\n return null\n }\n return { data: parsed.data, at: parsed.at }\n } catch {\n return null\n }\n}\n\n/** Drop entries this key wrote under earlier versions; nothing reads them again. */\nfunction pruneOldVersions(storageKey: string): void {\n if (typeof localStorage === 'undefined') return\n try {\n const current = `${storageKey}:v${LS_VERSION}`\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(`${storageKey}:v`) && key !== current) localStorage.removeItem(key)\n }\n } catch {\n // Leaving stale keys behind is harmless; they are never read.\n }\n}\n\nfunction persist<T>(storageKey: string, hit: CacheHit<T>): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(`${storageKey}:v${LS_VERSION}`, JSON.stringify(hit))\n } catch {\n // Quota / private-mode failures must never break the in-memory path.\n }\n}\n\nexport function createCache<T>(ttlMs: number, storageKey?: string, isUsable?: (data: T) => boolean): ResourceCache<T> {\n if (storageKey !== undefined) pruneOldVersions(storageKey)\n let hit: CacheHit<T> | null = storageKey === undefined ? null : loadPersisted<T>(storageKey, isUsable)\n return {\n get: () => hit,\n getFresh: () => (hit !== null && Date.now() - hit.at < ttlMs ? hit.data : null),\n put: (data) => {\n hit = { data, at: Date.now() }\n if (storageKey !== undefined) persist(storageKey, hit)\n },\n }\n}\n", "/** Wire contracts shared by the host API and the client fetchers. */\n\nexport interface BalanceInfo {\n currency: string\n total: string\n granted: string\n toppedUp: string\n}\n\nexport interface BalanceData {\n isAvailable: boolean\n balances: BalanceInfo[]\n}\n\nexport interface BalanceResponse {\n ok: boolean\n error?: string\n data?: BalanceData\n}\n\nexport interface DailyUsage {\n date: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n}\n\nexport interface HourlyUsage {\n hour: number\n total: number\n cost: number\n calls: number\n}\n\nexport interface HeatmapUsage {\n date: string\n total: number\n cost: number\n calls: number\n}\n\nexport interface UsageTotals {\n input: number\n output: number\n cache: number\n reasoning: number\n total: number\n cost: number\n calls: number\n /**\n * What the cache-hit tokens would have cost at cache-miss rates, minus what\n * they actually cost \u2014 i.e. the money prefix caching saved. Folded per\n * record so it respects each record's model and time-of-day rates.\n */\n cacheSavings: number\n}\n\n/** One per-day / per-hour point of a single model's series. */\nexport interface ModelSeriesPoint {\n total: number\n cost: number\n calls: number\n}\n\n/** Per-model usage aggregation: overall totals plus 30-day and 24-hour series. */\nexport interface ModelUsage {\n provider: string\n model: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n daily: ModelSeriesPoint[]\n hourly: ModelSeriesPoint[]\n}\n\n/** Usage rolled up over one time window. */\nexport interface PeriodUsage {\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Time-anchored rollups. \"Accumulated since forever\" answers no question a\n * user actually has; these do: what did today cost, what has this month cost,\n * and is that more or less than the comparable window before it.\n */\nexport interface UsageSummary {\n today: PeriodUsage\n yesterday: PeriodUsage\n /** Current calendar month, to date. */\n month: PeriodUsage\n /** Previous calendar month up to the same day-of-month, so a mid-month\n * comparison is against a same-length window rather than a full month. */\n lastMonthToDate: PeriodUsage\n}\n\n/** CNY per 1M tokens for one model tier. */\nexport interface PricingRates {\n cacheHit: number\n input: number\n output: number\n}\n\nexport interface PricingTier {\n model: string\n peak: PricingRates\n offPeak: PricingRates\n}\n\n/** What the cost column was computed with, so the estimate can be audited. */\nexport interface PricingInfo {\n currency: string\n /** Date peak/off-peak pricing took effect; earlier usage is costed at the\n * flat rates that were actually charged then. */\n switchDate: string\n inPeakNow: boolean\n peakWindows: string[]\n tiers: PricingTier[]\n}\n\n/**\n * How usage divides between DeepSeek's peak and off-peak windows, plus the\n * same usage re-priced as if everything had landed off-peak \u2014 answering\n * \"what would shifting batch work off-peak save me\" under the peak/off-peak\n * table in effect since 2026-08-17.\n */\nexport interface PeakSplit {\n peak: PeriodUsage\n offPeak: PeriodUsage\n /** Every record priced under the peak/off-peak table, as actually classified. */\n peakEraCost: number\n /** Every record priced under that table as if it had landed off-peak. */\n offPeakEraCost: number\n}\n\n/** One session's share of the bill. */\nexport interface SessionCost {\n id: string\n /** The session's title from its log; falls back to a short id. */\n title: string\n total: number\n cost: number\n calls: number\n /** Epoch ms of the last usage record in this session. */\n lastActive: number\n}\n\n/**\n * Multimodal (image) usage, folded from the same log replay: image blocks in\n * user messages and tool results are counted and sized, then estimated with\n * the official resizing rule (see `estimateImageTokens`). Each image is\n * attributed to the next usage record \u2014 the model call whose prompt carried\n * it \u2014 and priced at that call's input (cache-miss) rate, so the share answer\n * \"how much of the bill came from pictures\" has a real number.\n */\nexport interface VisionStats {\n /** Image blocks counted in the scope. */\n images: number\n /** Estimated image tokens under the official conversion rule. */\n imageTokens: number\n /** Estimated CNY cost of those image tokens at the consuming calls' rates. */\n cost: number\n /** Total image payload bytes when the attachment refs carried a size. */\n bytes: number\n}\n\n/** One day's image usage for the per-window / per-day series. */\nexport interface VisionDayPoint {\n date: string\n images: number\n imageTokens: number\n cost: number\n}\n\n/** One session's image usage, ranked for \"which run kept sending pictures\". */\nexport interface VisionSession {\n id: string\n title: string\n images: number\n imageTokens: number\n cost: number\n}\n\n/**\n * What the local log replay could actually inspect. Totals can otherwise look\n * authoritative even when one corrupt session was skipped, so this metadata\n * travels with every usage response and lets the UI disclose partial results.\n */\nexport interface UsageCoverage {\n scope: 'local-dsh-session-logs'\n /** Session headers with a usable id returned by the local persistence. */\n listedSessions: number\n /** Session logs read successfully, including logs with no usage. */\n scannedSessions: number\n /** Valid assistant usage records folded into the totals. */\n usageRecords: number\n /** Usage records rejected because their time or token data was invalid. */\n skippedRecords: number\n /** Session logs that could not be read at all. */\n failedSessions: number\n /** Epoch ms of the first/last valid usage record across all local logs. */\n earliestAt: number | null\n latestAt: number | null\n}\n\nexport const USAGE_WINDOW_DAYS = [7, 30, 90, 365] as const\nexport type UsageWindowDays = (typeof USAGE_WINDOW_DAYS)[number]\n\n/**\n * Session ids observed in this codebase (host-issued, e.g.\n * `session-484a1c14-c6fe-4d6a-abfd-a2d8d2f664d5`) are always plain\n * ASCII-safe tokens \u2014 no documented format contract exists for them outside\n * this repo (`SessionPersistenceFace` is implemented by the DSH host, not\n * here), so this is a defensive charset whitelist rather than an\n * exact-format check: letters, digits, `-`, `_` only, with a generous length\n * cap. It exists specifically to stop path-separator / `..` / null-byte\n * payloads from ever reaching the session-log read \u2014 `id` on the\n * `/session` route arrives verbatim from the browser-controlled `?id=` query\n * parameter, unlike `fetchUsage()`'s session ids, which the host itself\n * enumerates via `persistence.list()`.\n */\nexport const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/\n\nexport const isValidSessionId = (id: string): boolean => SESSION_ID_PATTERN.test(id)\n\n/** One internally consistent view of the same local logs over a calendar window. */\nexport interface UsageWindow {\n days: UsageWindowDays\n daily: DailyUsage[]\n hourly: HourlyUsage[]\n totals: UsageTotals\n models: ModelUsage[]\n /** Most expensive sessions inside this window, capped at SESSION_TOP_N. */\n sessions: SessionCost[]\n /** All sessions that contributed usage inside this window. */\n sessionCount: number\n vision: VisionStats\n visionDaily: VisionDayPoint[]\n /** Sessions that sent the most images inside this window, capped. */\n visionSessions: VisionSession[]\n}\n\nexport interface UsageData {\n daily: DailyUsage[]\n hourly: HourlyUsage[]\n heatmap: HeatmapUsage[]\n totals: UsageTotals\n models: ModelUsage[]\n summary: UsageSummary\n pricing: PricingInfo\n peakSplit: PeakSplit\n /** Most expensive sessions first, capped \u2014 see SESSION_TOP_N. */\n sessions: SessionCost[]\n /** How many sessions contributed usage in total. */\n sessionCount: number\n coverage: UsageCoverage\n windows: UsageWindow[]\n vision: VisionStats\n visionDaily: VisionDayPoint[]\n /** Sessions that sent the most images, capped \u2014 see SESSION_TOP_N. */\n visionSessions: VisionSession[]\n}\n\nexport interface UsageResponse {\n ok: boolean\n error?: string\n data?: UsageData\n}\n\n/**\n * One model's contribution to a single session's bill \u2014 the same field\n * shape as `ModelUsage` minus the `daily`/`hourly` series, which only make\n * sense aggregated across many sessions.\n */\nexport interface SessionModelUsage {\n provider: string\n model: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n}\n\n/** One completed conversation turn's usage. `messageId` is the durable id of\n * the turn's final assistant message \u2014 the same identity the chat action-strip\n * slot exposes to client plugins. Tool-call steps inside the turn are folded\n * into this one figure rather than shown as misleading separate charges. */\nexport interface TurnUsage {\n messageId: string\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Usage for exactly one session \u2014 what the \u300C\u989D\u5EA6\u300Dtab's own conversation\n * is costing, as opposed to `UsageData`'s account-wide totals. Fetched on\n * demand (see `fetchSessionUsage`), not part of the 5-minute `usage` memo:\n * a single session read is cheap and must reflect the session's live state.\n */\nexport interface SessionUsageData {\n sessionId: string\n /** The session's own title from its log; falls back to a short id. */\n title: string\n total: number\n cost: number\n calls: number\n /** Epoch ms of the first/last valid usage record in this session, or null\n * when the session has produced no usage yet. */\n firstActive: number | null\n lastActive: number | null\n /** Most expensive model first. */\n models: SessionModelUsage[]\n /** Completed turns, in log order, addressed by their final message id. */\n turns: TurnUsage[]\n}\n\nexport interface SessionUsageResponse {\n ok: boolean\n error?: string\n data?: SessionUsageData\n}\n", "/**\n * Same-origin fetchers for the host half's JSON API, backed by package-local\n * TTL caches (see ./cache.ts). A fresh cache hit resolves without any network\n * work, so tab switches render instantly; `force` bypasses both the memory\n * cache and the HTTP cache (fetch cache: 'no-store') and asks the host to\n * bypass its own memo via `?refresh=1`.\n */\nimport { createCache } from './cache.ts'\nimport { USAGE_WINDOW_DAYS } from '../contract.ts'\nimport type { BalanceResponse, SessionUsageResponse, UsageResponse } from '../contract.ts'\n\n/** Mirror the host memos: balance 60s, usage 5min. */\nconst BALANCE_TTL_MS = 60_000\nconst USAGE_TTL_MS = 5 * 60_000\n\nasync function getJson<T>(path: string, cache: RequestCache): Promise<T> {\n const res = await fetch(path, { headers: { accept: 'application/json' }, cache })\n if (!res.ok) {\n return { ok: false, error: `HTTP ${res.status}` } as unknown as T\n }\n return res.json() as Promise<T>\n}\n\n/**\n * Every field the UI dereferences off a cached payload. A persisted entry that\n * predates one of them would otherwise be rendered as if it were current and\n * take the whole view down; listing them here keeps that failure impossible\n * instead of merely unlikely. Add a line whenever the UI starts reading a new\n * top-level field.\n */\nconst usageIsUsable = (res: UsageResponse): boolean => {\n if (res.ok !== true) return false\n const data = res.data\n return data !== undefined\n && Array.isArray(data.daily) && Array.isArray(data.hourly) && Array.isArray(data.heatmap)\n && Array.isArray(data.models) && Array.isArray(data.sessions)\n && typeof data.sessionCount === 'number'\n && data.coverage?.scope === 'local-dsh-session-logs'\n && typeof data.coverage.scannedSessions === 'number'\n && typeof data.coverage.skippedRecords === 'number'\n && Array.isArray(data.windows) && data.windows.length === USAGE_WINDOW_DAYS.length\n && USAGE_WINDOW_DAYS.every(days => data.windows.some(window => window.days === days))\n && data.windows.every(window => Array.isArray(window.daily)\n && Array.isArray(window.hourly) && Array.isArray(window.models) && Array.isArray(window.sessions))\n && data.vision !== undefined && typeof data.vision.images === 'number'\n && typeof data.vision.imageTokens === 'number' && typeof data.vision.cost === 'number'\n && Array.isArray(data.visionDaily) && Array.isArray(data.visionSessions)\n && data.windows.every(window => window.vision !== undefined\n && Array.isArray(window.visionDaily) && Array.isArray(window.visionSessions))\n && data.totals !== undefined && typeof data.totals.cacheSavings === 'number'\n && data.summary?.today !== undefined\n && Array.isArray(data.pricing?.tiers)\n && data.peakSplit?.peak !== undefined\n}\n\nconst balanceIsUsable = (res: BalanceResponse): boolean =>\n res.ok === true && Array.isArray(res.data?.balances)\n\nconst balanceCache = createCache<BalanceResponse>(BALANCE_TTL_MS, 'dsh-usage-dashboard:balance', balanceIsUsable)\nconst usageCache = createCache<UsageResponse>(USAGE_TTL_MS, 'dsh-usage-dashboard:usage', usageIsUsable)\n\n/** Last cached value (possibly stale), for an instant first render. */\nexport const getCachedBalance = (): BalanceResponse | null => balanceCache.get()?.data ?? null\nexport const getCachedUsage = (): UsageResponse | null => usageCache.get()?.data ?? null\n/** When the cached usage was fetched, so a consumer can say how old it is. */\nexport const getCachedUsageAt = (): number | null => usageCache.get()?.at ?? null\n\n/**\n * Notified whenever usage is (re)fetched. The floating widget reads usage\n * straight from this cache rather than fetching on its own: aggregating every\n * session log takes seconds, and a background widget must not pay that\n * repeatedly. It subscribes here so it still updates when the dashboard \u2014 or\n * its own refresh button \u2014 brings fresh data in.\n */\nconst usageListeners = new Set<() => void>()\n\nexport const subscribeUsage = (fn: () => void): (() => void) => {\n usageListeners.add(fn)\n return () => {\n usageListeners.delete(fn)\n }\n}\n\n// Non-force calls made while an identical one is already in flight join it\n// instead of firing a second request \u2014 the case that matters is the\n// preload kicked off at plugin load (see index.tsx) landing moments before\n// the widget's or the dashboard's own mount-time fetch. `force` (the\n// refresh button) always fires its own request, since the user asked for a\n// bypass specifically.\nlet balanceInflight: Promise<BalanceResponse> | null = null\nlet usageInflight: Promise<UsageResponse> | null = null\n\nexport async function fetchBalance(force = false): Promise<BalanceResponse> {\n if (!force) {\n const hit = balanceCache.getFresh()\n if (hit !== null) return hit\n if (balanceInflight !== null) return balanceInflight\n }\n const suffix = force ? '?refresh=1' : ''\n const task = getJson<BalanceResponse>(`/api/dsh-usage-dashboard/balance${suffix}`, force ? 'no-store' : 'default')\n .then(res => {\n if (res.ok) balanceCache.put(res)\n return res\n })\n if (!force) {\n balanceInflight = task.finally(() => { balanceInflight = null })\n return balanceInflight\n }\n return task\n}\n\nexport async function fetchUsage(force = false): Promise<UsageResponse> {\n if (!force) {\n const hit = usageCache.getFresh()\n if (hit !== null) return hit\n if (usageInflight !== null) return usageInflight\n }\n const suffix = force ? '?refresh=1' : ''\n // `cache: 'no-store'` on every path, not just force: the host memoizes the\n // expensive replay anyway, and our own TTL cache prevents repeat fetches \u2014\n // but the browser's HTTP cache would happily serve a payload captured before\n // a host upgrade (the old body lacks fields the current UI reads, e.g. the\n // vision block) for up to the max-age it was tagged with.\n const task = getJson<UsageResponse>(`/api/dsh-usage-dashboard/usage${suffix}`, 'no-store')\n .then(res => {\n // Only shapes the current UI dereferences may enter the cache. A host\n // still serving a pre-vision payload (not yet restarted) is therefore\n // never persisted \u2014 the dashboard renders it defensively instead of\n // crashing on the next mount.\n if (res.ok && usageIsUsable(res)) {\n usageCache.put(res)\n for (const listener of [...usageListeners]) listener()\n }\n return res\n })\n if (!force) {\n usageInflight = task.finally(() => { usageInflight = null })\n return usageInflight\n }\n return task\n}\n\n/**\n * Session usage stays memory-only: the widget, dashboard, and every visible\n * turn-cost cell share the latest read without persisting one entry per\n * session. A newly completed turn whose message id is absent from this cache\n * triggers one fresh read; the in-flight map coalesces all cells mounting in\n * the same transcript render.\n */\nconst sessionUsageInflight = new Map<string, Promise<SessionUsageResponse>>()\nconst sessionUsageCache = new Map<string, SessionUsageResponse>()\nconst sessionUsageListeners = new Map<string, Set<() => void>>()\n\nexport const getCachedSessionUsage = (sessionId: string): SessionUsageResponse | null =>\n sessionUsageCache.get(sessionId) ?? null\n\nexport const subscribeSessionUsage = (sessionId: string, fn: () => void): (() => void) => {\n let listeners = sessionUsageListeners.get(sessionId)\n if (listeners === undefined) {\n listeners = new Set()\n sessionUsageListeners.set(sessionId, listeners)\n }\n listeners.add(fn)\n return () => {\n listeners?.delete(fn)\n if (listeners?.size === 0) sessionUsageListeners.delete(sessionId)\n }\n}\n\nconst publishSessionUsage = (sessionId: string, response: SessionUsageResponse): void => {\n if (!response.ok) return\n sessionUsageCache.set(sessionId, response)\n for (const listener of [...(sessionUsageListeners.get(sessionId) ?? [])]) listener()\n}\n\nexport async function fetchSessionUsage(sessionId: string, force = false): Promise<SessionUsageResponse> {\n if (typeof sessionId !== 'string' || sessionId === '') {\n return { ok: false, error: '\u7F3A\u5C11\u4F1A\u8BDD id' }\n }\n if (!force) {\n const inflight = sessionUsageInflight.get(sessionId)\n if (inflight !== undefined) return inflight\n }\n const task = getJson<SessionUsageResponse>(`/api/dsh-usage-dashboard/session?id=${encodeURIComponent(sessionId)}`, 'no-store')\n .then(response => {\n publishSessionUsage(sessionId, response)\n return response\n })\n if (force) return task\n const tracked = task.finally(() => {\n if (sessionUsageInflight.get(sessionId) === tracked) sessionUsageInflight.delete(sessionId)\n })\n sessionUsageInflight.set(sessionId, tracked)\n return tracked\n}\n", "/** The \u300C\u989D\u5EA6\u300D conversation view tab: full balance & usage dashboard.\n *\n * Caching: the first render comes straight from the package-local cache\n * (see ./api.ts), so reopening the tab shows data instantly. A background\n * refresh then updates it without blocking; a full-screen \u52A0\u8F7D\u4E2D only\n * appears when nothing has ever been cached.\n */\nimport { Fragment, useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type DragEvent as ReactDragEvent, type KeyboardEvent as ReactKeyboardEvent, type ReactElement, type ReactNode } from 'react'\nimport { USAGE_WINDOW_DAYS } from '../contract.ts'\nimport { fetchBalance, fetchSessionUsage, fetchUsage, getCachedBalance, getCachedUsage, getCachedUsageAt } from './api.ts'\nimport { budgetSnapshot } from './budget.ts'\nimport { Bars, GroupedBars, Heatmap, MODEL_COLORS, fmt, fmtCompact, fmtInt } from './charts.tsx'\nimport { getComposerElement, getComposerInputElement, getShellFrame } from './dom.ts'\nimport { dailyUsageCsv, downloadText, exportDateStamp, fullUsageJson, modelUsageCsv } from './export.ts'\nimport { syncStatusText, type SyncState } from './freshness.ts'\nimport { fallbackT, intlLocale, localizeApiError, useI18n, type Translate } from './i18n.tsx'\nimport { quotaTabIndexStore, sidebarEntryStore, type SidebarEntryPlacement } from './layout-prefs.ts'\nimport { CHART_METRICS, chartMetricName, chartMetricValue, type ChartMetric } from './metric.ts'\nimport type { BalanceData, ModelUsage, PeakSplit, PeriodUsage, PricingInfo, SessionCost, SessionUsageData, UsageCoverage, UsageData, UsageWindowDays, VisionDayPoint, VisionSession, VisionStats } from '../contract.ts'\nimport { chartMetricStore, lowBalanceStore, monthlyBudgetStore, quotaViewActiveStore, usageWindowStore, widgetTabIdsStore, widgetVisibleStore } from './store.ts'\nimport { TOP_UP_URL, needsTopUp } from './top-up.ts'\nimport type { ConversationViewTab, ConversationViewsSource } from './views.ts'\n\n/** `<package name> v<version>`, injected by build.mjs from package.json so the\n * footer on the \u989D\u5EA6 page reports exactly the version that was built. */\ndeclare const __PLUGIN_LABEL__: string\n\n/** Fallback composer height for the narrow-screen bottom safe area, used only\n * until the real measurement below lands (or if the host markup ever stops\n * exposing the `conversation.composer.dock` slot). DSH has no `--dsw-*`\n * variable for composer height \u2014 this number is not a guess: it is the\n * measured `[data-slot=\"conversation.composer.dock\"]` seat height on a live\n * DSH instance at 620 / 480 / 390px viewports (126px, stable across all\n * three; see LEARNINGS.md). Kept in sync with the small margin added in\n * styles.ts's `.dq-balance` narrow media query. */\nconst COMPOSER_FALLBACK_PX = 126\n\n/** One shimmering placeholder block, sized by the caller. */\nfunction Skel(props: { w: number; h: number }): ReactElement {\n return <div className=\"dq-skel\" style={{ width: `${props.w}px`, height: `${props.h}px` }} />\n}\n\n/** Placeholder for the balance card while the first fetch is in flight. */\nfunction BalanceSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={56} h={11} /><Skel w={150} h={22} /></div>\n <div className=\"dq-stat\"><Skel w={28} h={11} /><Skel w={48} h={22} /></div>\n </div>\n )\n}\n\n/** Placeholder for the current-session card: same three-`Stat` grammar as\n * the balance card's skeleton above, just one more column. */\nfunction SessionUsageSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={64} h={11} /><Skel w={96} h={18} /></div>\n <div className=\"dq-stat\"><Skel w={70} h={11} /><Skel w={80} h={18} /></div>\n <div className=\"dq-stat\"><Skel w={64} h={11} /><Skel w={40} h={18} /></div>\n </div>\n )\n}\n\n/** Placeholder for the usage trend card: replaying every session log takes\n * seconds, and an empty-state string there would read as \"you have no usage\". */\nfunction UsageSkeleton(): ReactElement {\n return (\n <>\n <div className=\"dq-usage-totals\">\n {[44, 44, 62, 62].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={w > 70 ? 84 : 56} h={20} /></div>\n ))}\n </div>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\">\n {Array.from({ length: 30 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${18 + ((i * 37) % 82)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Placeholder for the heatmap card, same loading grammar as the trend card's\n * bar skeleton above \u2014 the heatmap has no separate fetch, it just renders\n * once `usage` lands, so the two cards share one loading vocabulary. */\nfunction HeatmapSkeleton(): ReactElement {\n return (\n <>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\" style={{ height: '88px' }}>\n {Array.from({ length: 52 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${14 + ((i * 29) % 60)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Percentage chip comparing a window against the one before it. */\nfunction Delta(props: { current: number; previous: number; label: string }): ReactElement | null {\n const { t } = useI18n()\n const { current, previous, label } = props\n if (previous <= 0) {\n if (current <= 0) return null\n return <span className=\"dq-delta dq-delta--new\" title={t('delta.noBaselineTitle', { label })}>{t('delta.noBaseline')}</span>\n }\n const percent = Math.round(((current - previous) / previous) * 100)\n const title = `${label} \u00A5${fmt(previous)}`\n if (percent === 0) return <span className=\"dq-delta dq-delta--flat\" title={title}>{t('delta.flat')}</span>\n const up = percent > 0\n // A tiny previous baseline makes the ratio explode (e.g. \u21919176%), which reads\n // like a bug rather than a fact. Cap the displayed magnitude; the title keeps\n // the exact baseline the number was computed from.\n const magnitude = Math.abs(percent) >= 1000 ? '999+' : String(Math.abs(percent))\n return (\n <span className={`dq-delta ${up ? 'dq-delta--up' : 'dq-delta--down'}`} title={title}>\n {up ? '\u2191' : '\u2193'}{magnitude}% <span className=\"dq-delta-label\">{label}</span>\n </span>\n )\n}\n\n/** One window of the \u6D88\u8017\u6982\u89C8 card: cost headline, volume underneath. */\nfunction Period(props: {\n label: string\n period: PeriodUsage\n previous?: PeriodUsage\n compare?: string\n}): ReactElement {\n const { t, locale } = useI18n()\n const { period, previous, compare } = props\n return (\n <div className=\"dq-period\">\n <div className=\"dq-period-head\">\n <span className=\"dq-period-label\">{props.label}</span>\n {previous !== undefined && compare !== undefined && (\n <Delta current={period.cost} previous={previous.cost} label={compare} />\n )}\n </div>\n <div className=\"dq-period-cost\">\u00A5{fmt(period.cost)}</div>\n <div className=\"dq-period-sub\">{t('period.volume', {\n tokens: fmtCompact(period.total, locale),\n calls: t('common.calls', { count: fmtInt(period.calls) }),\n })}</div>\n </div>\n )\n}\n\n/** Monthly guardrail, kept inside the overview rather than adding another card. */\nfunction BudgetMeter(props: { spent: number; budget: number; onConfigure: () => void }): ReactElement {\n const { t } = useI18n()\n if (props.budget <= 0) {\n return (\n <div className=\"dq-budget dq-budget--unset\">\n <span>{t('budget.unset')}</span>\n <button type=\"button\" className=\"dq-budget-action\" onClick={props.onConfigure}>{t('budget.configure')}</button>\n </div>\n )\n }\n\n const snapshot = budgetSnapshot(props.spent, props.budget)\n const usedPercent = snapshot.ratio * 100\n const barPercent = Math.min(100, usedPercent)\n const forecastText = snapshot.status === 'over'\n ? t('budget.over', { amount: fmt(Math.abs(snapshot.remaining)) })\n : snapshot.forecastOver > 0\n ? t('budget.forecastOver', { amount: fmt(snapshot.forecastOver) })\n : t('budget.forecast', { amount: fmt(snapshot.forecast) })\n\n return (\n <div className={`dq-budget dq-budget--${snapshot.status}`}>\n <div className=\"dq-budget-head\">\n <span className=\"dq-budget-title\">{t('budget.title')}</span>\n <span className=\"dq-budget-amount\">\u00A5{fmt(snapshot.spent)} / \u00A5{fmt(snapshot.budget)}</span>\n </div>\n <div\n className=\"dq-budget-track\"\n role=\"progressbar\"\n aria-label={t('budget.progressLabel')}\n aria-valuemin={0}\n aria-valuemax={snapshot.budget}\n aria-valuenow={Math.min(snapshot.spent, snapshot.budget)}\n aria-valuetext={t('budget.used', { percent: usedPercent.toFixed(1), forecast: forecastText })}\n >\n <div className=\"dq-budget-fill\" style={{ transform: `scaleX(${barPercent / 100})` }} />\n </div>\n <div className=\"dq-budget-meta\">\n <span>{snapshot.remaining >= 0\n ? t('budget.remaining', { amount: fmt(snapshot.remaining) })\n : t('budget.exceeded', { amount: fmt(Math.abs(snapshot.remaining)) })}</span>\n <span>{forecastText}</span>\n </div>\n </div>\n )\n}\n\nconst rate = (value: number): string => `\u00A5${value.toLocaleString(undefined, { maximumFractionDigits: 3 })}`\n\n/** Auditable breakdown of the rates the cost estimate was computed with \u2014\n * a `<details>` so it is keyboard-reachable without any extra state. */\nfunction PricingNote(props: { pricing: PricingInfo }): ReactElement {\n const { t } = useI18n()\n const { pricing } = props\n return (\n <details className=\"dq-pricing\">\n <summary className=\"dq-pricing-summary\">\n {t('pricing.title')}\n <span className={`dq-pricing-now${pricing.inPeakNow ? ' dq-pricing-now--peak' : ''}`}>\n {pricing.inPeakNow ? t('pricing.currentPeak') : t('pricing.currentOffPeak')}\n </span>\n </summary>\n <div className=\"dq-pricing-body\">\n <table className=\"dq-pricing-table\">\n <thead>\n <tr>\n <th>{t('pricing.model')}</th>\n <th>{t('pricing.period')}</th>\n <th>{t('pricing.inputCacheHit')}</th>\n <th>{t('pricing.inputCacheMiss')}</th>\n <th>{t('pricing.output')}</th>\n </tr>\n </thead>\n <tbody>\n {pricing.tiers.map(tier => (\n <Fragment key={tier.model}>\n <tr>\n <td rowSpan={2}>{tier.model}</td>\n <td>{t('pricing.peak')}</td>\n <td>{rate(tier.peak.cacheHit)}</td>\n <td>{rate(tier.peak.input)}</td>\n <td>{rate(tier.peak.output)}</td>\n </tr>\n <tr>\n <td>{t('pricing.offPeak')}</td>\n <td>{rate(tier.offPeak.cacheHit)}</td>\n <td>{rate(tier.offPeak.input)}</td>\n <td>{rate(tier.offPeak.output)}</td>\n </tr>\n </Fragment>\n ))}\n </tbody>\n </table>\n <p className=\"dq-pricing-foot\">\n {t('pricing.unit', { currency: pricing.currency })}\n {t('pricing.splitNote', { windows: pricing.peakWindows.join(t('common.listSeparator')) })}\n {t('pricing.visionNote')}\n {t('pricing.unknown')}\n </p>\n </div>\n </details>\n )\n}\n\n/** Make a locally-computed bill honest about which logs it could inspect. */\nfunction CoverageDiagnostics(props: { coverage: UsageCoverage }): ReactElement {\n const { t, locale } = useI18n()\n const { coverage } = props\n const hasGaps = coverage.failedSessions > 0\n || coverage.skippedRecords > 0\n || coverage.scannedSessions < coverage.listedSessions\n const coverageTime = new Intl.DateTimeFormat(intlLocale(locale), {\n timeZone: 'Asia/Shanghai', year: 'numeric', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = coverage.earliestAt === null || coverage.latestAt === null\n ? t('coverage.noRange')\n : `${coverageTime.format(coverage.earliestAt)} \u2013 ${coverageTime.format(coverage.latestAt)}`\n\n return (\n <details className={`dq-coverage${hasGaps ? ' dq-coverage--warn' : ''}`}>\n <summary className=\"dq-coverage-summary\">\n <span className=\"dq-coverage-title\">{t('coverage.title')}</span>\n <span className=\"dq-coverage-status\">{hasGaps ? t('coverage.gaps') : t('coverage.complete')}</span>\n <span className=\"dq-coverage-brief\">{t('coverage.brief', {\n scanned: fmtInt(coverage.scannedSessions), listed: fmtInt(coverage.listedSessions), records: fmtInt(coverage.usageRecords),\n })}</span>\n </summary>\n <div className=\"dq-coverage-body\">\n <dl className=\"dq-coverage-metrics\">\n <div><dt>{t('coverage.scanned')}</dt><dd>{t('common.sessions', { count: fmtInt(coverage.scannedSessions) })}</dd></div>\n <div><dt>{t('coverage.failed')}</dt><dd>{t('common.sessions', { count: fmtInt(coverage.failedSessions) })}</dd></div>\n <div><dt>{t('coverage.skipped')}</dt><dd>{t('common.records', { count: fmtInt(coverage.skippedRecords) })}</dd></div>\n </dl>\n <p className=\"dq-coverage-range\">{t('coverage.time', { range })}</p>\n <p className=\"dq-coverage-note\">{t('coverage.scope')}</p>\n {hasGaps && (\n <p className=\"dq-coverage-warning\">{t('coverage.warning')}</p>\n )}\n </div>\n </details>\n )\n}\n\n/** Section heading: a short title, plus an optional quiet caption on the same line\n * (scope / caveat such as \u300C\u8FD1 30 \u5929\u300D\u300C\u8D39\u7528\u4E3A\u4F30\u7B97\u300D) so the title itself stays short. */\nfunction CardTitle(props: { children: ReactNode; caption?: ReactNode; srOnly?: boolean }): ReactElement {\n return (\n <h2 className={`dq-card-title${props.srOnly === true ? ' dq-sr-only' : ''}`}>\n {props.children}\n {props.caption !== undefined && <span className=\"dq-card-caption\">{props.caption}</span>}\n </h2>\n )\n}\n\n/** In-column section rail: one dot per top-level card, scroll-spy synced, sitting\n * in the centred column's left gutter. Purely additive navigation \u2014 it never\n * reorders or restyles the cards \u2014 and hides when there is no gutter to sit in,\n * so it cannot compete with the host's own sidebar. */\nfunction SectionNav(props: {\n rootRef: { readonly current: HTMLDivElement | null }\n label: string\n sections: Array<{ key: string; label: string }>\n}): ReactElement | null {\n const { rootRef, label, sections } = props\n const [targets, setTargets] = useState<Array<{ el: HTMLElement; label: string }>>([])\n const [active, setActive] = useState(0)\n const [pos, setPos] = useState({ right: 0, visible: false })\n const signature = sections.map(section => `${section.key}:${section.label}`).join('|')\n\n // Pair the label list with the rendered top-level cards in DOM order. The only\n // conditional card is the current-session one, reflected in both lists above.\n useEffect(() => {\n const root = rootRef.current\n if (root === null) return\n const nodes = Array.from(root.querySelectorAll<HTMLElement>(':scope > .dq-card, :scope > .dq-card-pair'))\n setTargets(nodes.map((el, i) => ({ el, label: sections[i]?.label ?? '' })).filter(item => item.label !== ''))\n // `signature` captures the label list; `sections` itself changes identity each render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rootRef, signature])\n\n // Keep the rail in the gutter; hide it when the column is too close to an edge.\n useEffect(() => {\n const root = rootRef.current\n if (root === null) return\n const scrollport = root.closest('[data-conversation-scroll]') as HTMLElement | null\n const measure = (): void => {\n const rect = root.getBoundingClientRect()\n setPos({ right: window.innerWidth - rect.left + 12, visible: window.innerWidth >= 1200 && rect.left >= 170 })\n }\n measure()\n const scroller: HTMLElement | Window = scrollport ?? window\n scroller.addEventListener('scroll', measure, { passive: true })\n window.addEventListener('resize', measure)\n return () => {\n scroller.removeEventListener('scroll', measure)\n window.removeEventListener('resize', measure)\n }\n }, [rootRef])\n\n // Scroll-spy: the last card whose top crossed the top band is \"current\".\n useEffect(() => {\n if (targets.length === 0) return\n const root = rootRef.current\n if (root === null) return\n const scrollport = root.closest('[data-conversation-scroll]') as HTMLElement | null\n const onScroll = (): void => {\n const base = scrollport === null ? 0 : scrollport.getBoundingClientRect().top\n let current = 0\n targets.forEach((target, i) => {\n if (target.el.getBoundingClientRect().top - base <= 120) current = i\n })\n setActive(current)\n }\n onScroll()\n const scroller: HTMLElement | Window = scrollport ?? window\n scroller.addEventListener('scroll', onScroll, { passive: true })\n return () => scroller.removeEventListener('scroll', onScroll)\n }, [targets, rootRef])\n\n if (targets.length < 3) return null\n\n const go = (el: HTMLElement): void => {\n const root = rootRef.current\n const scrollport = root?.closest('[data-conversation-scroll]') as HTMLElement | null\n const reduce = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const behavior: ScrollBehavior = reduce ? 'auto' : 'smooth'\n if (scrollport !== null) {\n const base = scrollport.getBoundingClientRect().top\n scrollport.scrollTo({ top: scrollport.scrollTop + el.getBoundingClientRect().top - base - 12, behavior })\n } else {\n window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 12, behavior })\n }\n }\n\n return (\n <nav className={`dq-sectionnav${pos.visible ? '' : ' dq-sectionnav--hidden'}`} style={{ right: `${pos.right}px` }} aria-label={label}>\n <ol>\n {targets.map((target, i) => (\n <li key={`${target.label}-${String(i)}`}>\n <button\n type=\"button\"\n className={`dq-sectionnav-dot${i === active ? ' dq-sectionnav-dot--active' : ''}`}\n aria-current={i === active ? 'true' : undefined}\n onClick={() => go(target.el)}\n >\n <span className=\"dq-sectionnav-label\">{target.label}</span>\n <span className=\"dq-sectionnav-pip\" aria-hidden=\"true\" />\n </button>\n </li>\n ))}\n </ol>\n </nav>\n )\n}\n\n/** Height reveal + retract for content that stays mounted but toggles visibility\n * (the settings panel). Styles are applied in a layout effect so the panel is\n * already collapsed to height 0 BEFORE the first paint \u2014 no full-height flash,\n * then it eases 0\u2192measured (easeOutExpo). Closing animates back to 0 (ease-in)\n * before display:none. Reduced motion snaps straight to the final state. */\nfunction Collapsible(props: { open: boolean; children: ReactNode }): ReactElement {\n const ref = useRef<HTMLDivElement | null>(null)\n const animationRef = useRef<Animation | null>(null)\n const open = props.open\n useLayoutEffect(() => {\n const el = ref.current\n if (el === null) return\n animationRef.current?.cancel()\n animationRef.current = null\n const reduce = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const canAnimate = typeof el.animate === 'function' && !reduce\n const reset = (): void => { el.style.height = ''; el.style.overflow = ''; el.style.opacity = '' }\n if (open) {\n if (!canAnimate) {\n el.style.display = ''\n reset()\n return\n }\n // Collapse synchronously before paint so measuring the natural height never\n // shows the full panel for a frame.\n el.style.display = 'block'\n el.style.overflow = 'hidden'\n el.style.height = '0px'\n el.style.opacity = '0'\n const height = el.scrollHeight\n const animation = el.animate(\n [{ height: '0px', opacity: 0 }, { height: `${height}px`, opacity: 1 }],\n { duration: 300, easing: 'cubic-bezier(0.16, 1, 0.3, 1)' },\n )\n animationRef.current = animation\n animation.addEventListener('finish', reset)\n return () => animation.cancel()\n }\n if (el.style.display === 'none') return\n if (!canAnimate) {\n reset()\n el.style.display = 'none'\n return\n }\n const height = el.getBoundingClientRect().height || el.scrollHeight\n el.style.overflow = 'hidden'\n el.style.height = `${height}px`\n const animation = el.animate(\n [{ height: `${height}px`, opacity: 1 }, { height: '0px', opacity: 0 }],\n { duration: 220, easing: 'cubic-bezier(0.4, 0, 1, 1)' },\n )\n animationRef.current = animation\n animation.addEventListener('finish', () => { reset(); el.style.display = 'none' })\n return () => animation.cancel()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n return <div ref={ref}>{props.children}</div>\n}\n\nfunction Stat(props: { label: string; children: ReactNode }): ReactElement {\n return (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{props.label}</div>\n {props.children}\n </div>\n )\n}\n\nfunction Link(props: { href: string; children: ReactNode }): ReactElement {\n return (\n <a className=\"dq-link\" href={props.href} target=\"_blank\" rel=\"noreferrer\">{props.children}</a>\n )\n}\n\n/** Download menu kept compact in the usage card header. */\nfunction ExportMenu(props: { usage: UsageData }): ReactElement {\n const { t } = useI18n()\n const [open, setOpen] = useState(false)\n const [done, setDone] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const doneTimerRef = useRef<number | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(event.target as Node)) setOpen(false)\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n setOpen(false)\n triggerRef.current?.focus()\n }\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n window.requestAnimationFrame(() => menuRef.current?.querySelector<HTMLButtonElement>('button')?.focus())\n return () => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n useEffect(() => () => {\n if (doneTimerRef.current !== null) window.clearTimeout(doneTimerRef.current)\n }, [])\n\n const finish = (): void => {\n setOpen(false)\n setDone(true)\n if (doneTimerRef.current !== null) window.clearTimeout(doneTimerRef.current)\n doneTimerRef.current = window.setTimeout(() => setDone(false), 1400)\n }\n\n const exportDaily = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-${stamp}.csv`, dailyUsageCsv(props.usage), 'text/csv;charset=utf-8')\n finish()\n }\n const exportModels = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-models-${stamp}.csv`, modelUsageCsv(props.usage), 'text/csv;charset=utf-8')\n finish()\n }\n const exportJson = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-${stamp}.json`, fullUsageJson(props.usage), 'application/json;charset=utf-8')\n finish()\n }\n\n return (\n <div className=\"dq-export\" ref={rootRef}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={`dq-export-btn${done ? ' dq-export-btn--done' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={open}\n title={t('export.title')}\n onClick={() => setOpen(value => !value)}\n >\n {done ? t('export.done') : t('export.action')}\n </button>\n {open && (\n <div ref={menuRef} className=\"dq-export-menu\" aria-label={t('export.menuLabel')}>\n <button type=\"button\" onClick={exportDaily}>\n <span>{t('export.dailyCsv')}</span><small>{t('common.rows', { count: props.usage.daily.length })}</small>\n </button>\n <button type=\"button\" onClick={exportModels}>\n <span>{t('export.modelCsv')}</span><small>{t('common.rows', { count: props.usage.models.length })}</small>\n </button>\n <button type=\"button\" onClick={exportJson}>\n <span>{t('export.fullJson')}</span><small>{t('export.jsonHint')}</small>\n </button>\n </div>\n )}\n </div>\n )\n}\n\nexport const modelKeyOf = (m: ModelUsage): string => (m.provider !== '' ? `${m.provider}/${m.model}` : m.model)\n\nexport const modelNameOf = (m: ModelUsage, t: Translate = fallbackT): string => (m.model !== '' ? m.model : t('common.unknownModel'))\n\n/**\n * Usage for exactly the session the \u300C\u989D\u5EA6\u300D tab is opened inside \u2014 the one\n * dimension every other card on this page does not answer (they are all\n * account-wide, replayed across every local session log). Deliberately\n * reuses the same `.dq-balance-grid`/`Stat` headline layout as the balance\n * card above it and the same `.dq-rank`/`MODEL_COLORS` breakdown as the\n * model cost ranking card further down, rather than inventing a third\n * visual language for numbers that are structurally the same kind of thing.\n */\nfunction SessionUsageCard(props: { data: SessionUsageData }): ReactElement {\n const { t, locale } = useI18n()\n const { data } = props\n if (data.calls === 0) return <div className=\"dq-empty\">{t('sessionUsage.empty')}</div>\n\n const rangeTime = new Intl.DateTimeFormat(intlLocale(locale), {\n timeZone: 'Asia/Shanghai', year: 'numeric', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = data.firstActive !== null && data.lastActive !== null\n ? (data.firstActive === data.lastActive\n ? rangeTime.format(data.firstActive)\n : `${rangeTime.format(data.firstActive)} \u2013 ${rangeTime.format(data.lastActive)}`)\n : null\n\n return (\n <>\n <div className=\"dq-balance-grid\">\n <Stat label={t('sessionUsage.cost')}><div className=\"dq-stat-value\">\u00A5{fmt(data.cost)}</div></Stat>\n <Stat label={t('sessionUsage.tokens')}><div className=\"dq-stat-value\">{fmtCompact(data.total, locale)}</div></Stat>\n <Stat label={t('sessionUsage.calls')}><div className=\"dq-stat-value\">{fmtInt(data.calls)}</div></Stat>\n </div>\n {/* One model = the breakdown would repeat the totals above; fold it into one meta line. */}\n <div className=\"dq-session-meta\">\n {range !== null && <p className=\"dq-session-sub\">{t('sessionUsage.range', { range })}</p>}\n {data.models.length === 1 && (\n <p className=\"dq-session-sub\">{t('sessionUsage.single', {\n model: data.models[0].model !== '' ? data.models[0].model : t('common.unknownModel'),\n input: fmtCompact(data.models[0].input, locale),\n output: fmtCompact(data.models[0].output, locale),\n cache: fmtCompact(data.models[0].cache, locale),\n })}</p>\n )}\n </div>\n {data.models.length > 1 && (\n <div className=\"dq-rank\">\n {data.models.map((m, index) => {\n const key = m.provider !== '' ? `${m.provider}/${m.model}` : (m.model !== '' ? m.model : `model-${index}`)\n const name = m.model !== '' ? m.model : t('common.unknownModel')\n const color = MODEL_COLORS[index % MODEL_COLORS.length]\n const share = data.cost > 0 ? m.cost / data.cost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: color }} />\n {name}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5{fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={t('models.shareAria', { name, percent: (share * 100).toFixed(1) })}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: color }} />\n </div>\n <div className=\"dq-rank-sub\">\n {t('models.detail', {\n tokens: fmtCompact(m.total, locale),\n calls: t('common.calls', { count: fmtInt(m.calls) }),\n input: fmtCompact(m.input, locale), output: fmtCompact(m.output, locale), cache: fmtCompact(m.cache, locale),\n })}\n </div>\n </div>\n )\n })}\n </div>\n )}\n </>\n )\n}\n\n/**\n * What prefix caching is doing for the bill. Cache-hit tokens are priced at a\n * small fraction of cache-miss tokens, so on a DSH workload this is usually the\n * single biggest lever on cost \u2014 and it was invisible before.\n */\nfunction CacheCard(props: { totals: UsageData['totals'] }): ReactElement {\n const { t, locale } = useI18n()\n const { totals } = props\n const prompt = totals.input + totals.cache\n if (prompt === 0) return <div className=\"dq-empty\">{t('cache.empty')}</div>\n const rate = totals.cache / prompt\n const wouldHaveCost = totals.cost + totals.cacheSavings\n const low = rate < 0.6\n return (\n <div className=\"dq-cache\">\n <div className=\"dq-cache-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.rate')}</div>\n <div className={`dq-stat-value${low ? ' dq-stat-value--warn' : ' dq-stat-value--ok'}`}>\n {(rate * 100).toFixed(1)}%\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.saved')}</div>\n <div className=\"dq-stat-value\">\u00A5{fmt(totals.cacheSavings)}</div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.allMiss')}</div>\n <div className=\"dq-stat-value dq-muted-value\">\u00A5{fmt(wouldHaveCost)}</div>\n </div>\n </div>\n <div className=\"dq-cache-track\" role=\"img\" aria-label={t('cache.aria', { hit: (rate * 100).toFixed(1), miss: ((1 - rate) * 100).toFixed(1) })}>\n <div className=\"dq-cache-fill\" style={{ width: `${rate * 100}%` }} />\n </div>\n <div className=\"dq-cache-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--hit\" />{t('cache.hitLegend', { tokens: fmtCompact(totals.cache, locale) })}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--miss\" />{t('cache.missLegend', { tokens: fmtCompact(totals.input, locale) })}</span>\n </div>\n <p className=\"dq-cache-foot\">{t('cache.basis', { cost: fmt(totals.cost), miss: fmt(wouldHaveCost) })}</p>\n </div>\n )\n}\n\n/** Everything `VisionCard` needs to paint one window's image usage. Captured\n * as a snapshot by the trend card so the closing animation can keep showing\n * the last payload after the live window stops reporting images. */\ninterface VisionSectionProps {\n vision: VisionStats\n daily: VisionDayPoint[]\n sessions: VisionSession[]\n windowLabel: string\n inputTokens: number\n costTotal: number\n}\n\n/**\n * Image / multimodal usage: how much of the bill came from pictures. Image\n * blocks are collected from user messages and tool results during the same\n * log replay that feeds the rest of the dashboard (no attachment bytes are\n * read \u2014 the refs already carry width/height), so this dimension costs the\n * replay nothing extra. Tokens are estimated with the official resizing rule\n * and priced at the consuming call's rates; shares are against the window's\n * reported input tokens and cost.\n */\nfunction VisionCard(props: VisionSectionProps): ReactElement {\n const { t, locale } = useI18n()\n const { vision, daily, sessions, windowLabel, inputTokens, costTotal } = props\n if (vision.images === 0) return <div className=\"dq-empty\">{t('vision.empty', { window: windowLabel })}</div>\n const tokensShare = inputTokens > 0 ? (vision.imageTokens / inputTokens) * 100 : 0\n const costShare = costTotal > 0 ? (vision.cost / costTotal) * 100 : 0\n const labelEvery = daily.length <= 7 ? 1 : daily.length <= 30 ? 5 : daily.length <= 90 ? 15 : 30\n const bars = daily.map(d => ({\n label: d.date.slice(8, 10),\n value: d.images,\n title: t('vision.barTitle', { date: d.date, images: fmtInt(d.images), tokens: fmtCompact(d.imageTokens, locale), cost: fmt(d.cost) }),\n }))\n return (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label={t('vision.images')}><div className=\"dq-stat-value\">{fmtInt(vision.images)}</div></Stat>\n <Stat label={t('vision.tokens')}>\n <div className=\"dq-stat-value\">\n {fmtCompact(vision.imageTokens, locale)}\n {tokensShare > 0 && <span className=\"dq-vision-share\">{t('vision.tokensShare', { percent: tokensShare.toFixed(1) })}</span>}\n </div>\n </Stat>\n <Stat label={t('vision.cost')}>\n <div className=\"dq-stat-value\">\n \u00A5{fmt(vision.cost)}\n {costShare > 0 && <span className=\"dq-vision-share\">{t('vision.costShare', { percent: costShare.toFixed(1) })}</span>}\n </div>\n </Stat>\n </div>\n <div className=\"dq-chart-title\">{t('vision.dailyTitle', { window: windowLabel })}</div>\n <Bars data={bars} height={80} labelEvery={labelEvery} />\n {sessions.length > 0 && (\n <div className=\"dq-vision-sessions\">\n <div className=\"dq-chart-title\">{t('vision.sessionsTitle')}</div>\n {sessions.map(session => (\n <div key={session.id} className=\"dq-session\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={session.id}>{session.title}</span>\n <span className=\"dq-session-cost\">\n {t('vision.sessionRow', { images: fmtInt(session.images), cost: fmt(session.cost) })}\n </span>\n </div>\n </div>\n ))}\n </div>\n )}\n <p className=\"dq-cache-foot\">{t('vision.note')}</p>\n </>\n )\n}\n\n/**\n * Peak vs off-peak: which side of DeepSeek's price windows the usage falls on,\n * and what shifting the peak share off-peak would have saved.\n */\nfunction PeakCard(props: { split: PeakSplit; pricing: PricingInfo }): ReactElement {\n const { t, locale } = useI18n()\n const { split, pricing } = props\n // Live Beijing clock so \"now\" stays honest while the tab is open; one tick a\n // minute is plenty for an hour-resolution strip.\n const [nowMs, setNowMs] = useState(() => Date.now())\n useEffect(() => {\n const id = setInterval(() => setNowMs(Date.now()), 60_000)\n return () => clearInterval(id)\n }, [])\n const total = split.peak.total + split.offPeak.total\n if (total === 0) return <div className=\"dq-empty\">{t('peak.empty')}</div>\n const peakShare = split.peak.total / total\n const shiftSaving = split.peakEraCost - split.offPeakEraCost\n\n // DeepSeek peak windows are Beijing time and weekday-only in the current price\n // era. Derive the schedule from the same strings the pricing note shows, so the\n // clock cannot drift from the table.\n const beijing = new Date(nowMs + 8 * 3_600_000)\n const hour = beijing.getUTCHours()\n const minute = beijing.getUTCMinutes()\n const weekday = beijing.getUTCDay()\n const weekend = weekday === 0 || weekday === 6\n const windows = pricing.peakWindows\n .map(w => w.match(/(\\d{1,2}):\\d{2}\\D+(\\d{1,2}):\\d{2}/))\n .filter((m): m is RegExpMatchArray => m !== null)\n .map(m => [Number(m[1]), Number(m[2])] as const)\n const isPeakNow = !weekend && windows.some(([from, to]) => hour >= from && hour < to)\n const nowPercent = ((hour + minute / 60) / 24) * 100\n const clockCells = Array.from({ length: 24 }, (_, h) => !weekend && windows.some(([from, to]) => h >= from && h < to))\n const nowState = isPeakNow ? t('peak.nowPeak') : t('peak.nowOff')\n return (\n <div className=\"dq-peak\">\n <div className=\"dq-clock\">\n <div className=\"dq-clock-head\">\n <span className=\"dq-clock-title\">{t('peak.clockTitle')}</span>\n <span className={`dq-clock-status ${isPeakNow ? 'dq-clock-status--peak' : 'dq-clock-status--off'}`}>{nowState}</span>\n </div>\n <div className=\"dq-clock-track\" role=\"img\" aria-label={t('peak.clockAria', { state: nowState })}>\n {clockCells.map((peak, h) => (\n <span key={h} className={`dq-clock-cell${peak ? ' dq-clock-cell--peak' : ''}`} />\n ))}\n <span className=\"dq-clock-now\" style={{ left: `${nowPercent}%` }} aria-hidden=\"true\" />\n </div>\n <div className=\"dq-clock-scale\" aria-hidden=\"true\"><span>0</span><span>6</span><span>12</span><span>18</span><span>24</span></div>\n <p className=\"dq-clock-hint\">{t('peak.clockHint')}</p>\n </div>\n <div\n className=\"dq-peak-track\"\n role=\"img\"\n aria-label={t('peak.aria', { peak: (peakShare * 100).toFixed(1), offPeak: ((1 - peakShare) * 100).toFixed(1) })}\n >\n <div className=\"dq-peak-fill\" style={{ width: `${peakShare * 100}%` }} />\n </div>\n <div className=\"dq-peak-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--peak\" />{t('peak.peakLegend', {\n share: (peakShare * 100).toFixed(1), tokens: fmtCompact(split.peak.total, locale), calls: t('common.callsShort', { count: fmtInt(split.peak.calls) }),\n })}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--offpeak\" />{t('peak.offPeakLegend', {\n share: ((1 - peakShare) * 100).toFixed(1), tokens: fmtCompact(split.offPeak.total, locale), calls: t('common.callsShort', { count: fmtInt(split.offPeak.calls) }),\n })}</span>\n </div>\n <div className=\"dq-peak-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('peak.shift')}</div>\n <div className=\"dq-stat-value dq-stat-value--ok\">{t('peak.saving', { amount: fmt(shiftSaving) })}</div>\n </div>\n </div>\n <p className=\"dq-peak-foot\">{t('peak.basis', { total: fmt(split.offPeakEraCost) })}</p>\n </div>\n )\n}\n\n/** Coarse \"how long ago\", enough to tell a live session from last week's. */\nfunction agoText(ms: number, t: Translate): string {\n const minutes = Math.floor((Date.now() - ms) / 60_000)\n if (minutes < 1) return t('common.justNow')\n if (minutes < 60) return t('common.minutesAgo', { count: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('common.hoursAgo', { count: hours })\n return t('common.daysAgo', { count: Math.floor(hours / 24) })\n}\n\n/** Per-row fetch state for the ranking's on-demand expand \u2014 mirrors the\n * three-way {loading, error, data} shape `loadSessionUsage` already uses\n * for the current-session card, just keyed per row instead of per tab. */\ninterface SessionDetailState {\n error: string | null\n data: SessionUsageData | null\n}\n\n/** Body of one expanded ranking row: same loading/error/data three-way as the\n * current-session card, and the same `SessionUsageCard` rendering the data \u2014\n * this is deliberately not a second implementation of that layout. */\nfunction SessionDetail(props: { state: SessionDetailState | undefined }): ReactElement {\n const { t } = useI18n()\n const { state } = props\n if (state === undefined) return <SessionUsageSkeleton />\n if (state.data !== null) return <SessionUsageCard data={state.data} />\n if (state.error !== null) return <div className=\"dq-empty dq-empty--error\">{localizeApiError(state.error, t, 'error.query')}</div>\n return <SessionUsageSkeleton />\n}\n\n/**\n * Which sessions burned the money. Per-model and per-day views say what and\n * when; this says *which run*, which is the one an agent user can act on \u2014\n * a single expensive session is a prompt or a loop worth looking at.\n *\n * Each row is a native `<details>` (same disclosure grammar as `.dq-pricing`/\n * `.dq-coverage` above \u2014 no custom open/close state machine, keyboard and\n * touch come for free). Opening a row for the first time fires an on-demand\n * `fetchSessionUsage(s.id)` and renders the result with the exact same\n * `SessionUsageCard` the \u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300Dcard uses \u2014 the row only has the\n * summary fields (`SessionCost`), the full per-model breakdown only exists\n * once that fetch lands. `startedRef` guards against re-fetching on a\n * collapse/re-expand: once a row's fetch has been kicked off, later toggles\n * just show whatever is already cached in `details`.\n */\nfunction SessionRanking(props: { sessions: SessionCost[]; count: number; totalCost: number }): ReactElement {\n const { t, locale } = useI18n()\n const { sessions, count, totalCost } = props\n const [details, setDetails] = useState<Record<string, SessionDetailState>>({})\n const startedRef = useRef<Set<string>>(new Set())\n\n const loadDetail = (id: string): void => {\n if (startedRef.current.has(id)) return\n startedRef.current.add(id)\n fetchSessionUsage(id).then(res => {\n setDetails(prev => ({\n ...prev,\n [id]: res.ok && res.data !== undefined\n ? { error: null, data: res.data }\n : { error: res.error ?? null, data: null },\n }))\n }, err => {\n const message = (err as { message?: string } | null)?.message ?? String(err)\n setDetails(prev => ({ ...prev, [id]: { error: message, data: null } }))\n })\n }\n\n if (sessions.length === 0) return <div className=\"dq-empty\">{t('sessions.empty')}</div>\n const top = sessions[0].cost\n return (\n <>\n <ol className=\"dq-sessions\">\n {sessions.map(s => (\n <li key={s.id} className=\"dq-session\">\n <details\n className=\"dq-session-details\"\n onToggle={e => { if (e.currentTarget.open) loadDetail(s.id) }}\n >\n <summary className=\"dq-session-summary\">\n <span className=\"dq-session-chevron\" aria-hidden=\"true\" />\n <div className=\"dq-session-summary-body\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={`${s.title}\\n${s.id}`}>{s.title || t('sessions.fallbackTitle', { id: s.id })}</span>\n <span className=\"dq-session-cost\">\u00A5{fmt(s.cost)}</span>\n </div>\n <div className=\"dq-session-track\">\n <div className=\"dq-session-fill\" style={{ width: `${Math.max((s.cost / (top || 1)) * 100, 1.5)}%` }} />\n </div>\n <div className=\"dq-session-sub\">\n {t('sessions.detail', {\n tokens: fmtCompact(s.total, locale),\n calls: t('common.calls', { count: fmtInt(s.calls) }),\n ago: agoText(s.lastActive, t),\n })}\n {totalCost > 0 && <> \u00B7 {t('sessions.share', { percent: ((s.cost / totalCost) * 100).toFixed(1) })}</>}\n </div>\n </div>\n </summary>\n <div className=\"dq-session-expand\">\n <SessionDetail state={details[s.id]} />\n </div>\n </details>\n </li>\n ))}\n </ol>\n {count > sessions.length && (\n <p className=\"dq-session-foot\">{t('sessions.more', { count: fmtInt(count), shown: sessions.length })}</p>\n )}\n </>\n )\n}\n\n/** Which model the money actually goes to, most expensive first. */\nfunction ModelRanking(props: {\n models: ModelUsage[]\n totalCost: number\n colorOf: (key: string) => string\n}): ReactElement {\n const { t, locale } = useI18n()\n const { models, totalCost } = props\n if (models.length === 0) return <div className=\"dq-empty\">{t('models.empty')}</div>\n return (\n <div className=\"dq-rank\">\n {models.map(m => {\n const key = modelKeyOf(m)\n const share = totalCost > 0 ? m.cost / totalCost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n {modelNameOf(m, t)}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5{fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={t('models.shareAria', { name: modelNameOf(m, t), percent: (share * 100).toFixed(1) })}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: props.colorOf(key) }} />\n </div>\n <div className=\"dq-rank-sub\">\n {t('models.detail', {\n tokens: fmtCompact(m.total, locale),\n calls: t('common.calls', { count: fmtInt(m.calls) }),\n input: fmtCompact(m.input, locale), output: fmtCompact(m.output, locale), cache: fmtCompact(m.cache, locale),\n })}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Multi-select model dropdown feeding the grouped bar chart. */\nfunction ModelPicker(props: {\n models: ModelUsage[]\n selected: string[]\n colorOf: (key: string) => string\n onChange: (keys: string[]) => void\n}): ReactElement | null {\n const { t, locale } = useI18n()\n const { models } = props\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape') return\n e.preventDefault()\n setOpen(false)\n triggerRef.current?.focus()\n }\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n window.requestAnimationFrame(() => menuRef.current?.querySelector<HTMLInputElement>('input')?.focus())\n return () => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n if (models.length === 0) return null\n\n const toggle = (key: string): void => {\n props.onChange(\n props.selected.includes(key)\n ? props.selected.filter(k => k !== key)\n : [...props.selected, key],\n )\n }\n\n const label = props.selected.length === 0 ? t('models.all') : t('models.selected', { count: props.selected.length })\n\n return (\n <div className=\"dq-model-picker\" ref={rootRef}>\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"dq-model-btn\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n aria-controls=\"dq-model-menu\"\n title={t('models.filterTitle')}\n onClick={() => setOpen(value => !value)}\n >\n {label}\n </button>\n {open && (\n <div id=\"dq-model-menu\" ref={menuRef} className=\"dq-model-menu\" role=\"group\" aria-label={t('models.filterLabel')}>\n <label className=\"dq-model-item dq-model-item--all\">\n <input\n type=\"checkbox\"\n checked={props.selected.length === 0}\n onChange={() => props.onChange([])}\n />\n <span>{t('models.all')}</span>\n </label>\n {models.map(m => {\n const key = modelKeyOf(m)\n return (\n <label key={key} className=\"dq-model-item\">\n <input type=\"checkbox\" checked={props.selected.includes(key)} onChange={() => toggle(key)} />\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n <span>{modelNameOf(m, t)}</span>\n <span className=\"dq-model-tag\">{fmtCompact(m.total, locale)}</span>\n </label>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nconst windowName = (days: UsageWindowDays, t: Translate = fallbackT): string => days === 365\n ? t('window.year')\n : t('window.days', { days })\n\n/** One range choice controls every metric whose title carries that range. */\nfunction UsageWindowPicker(props: { value: UsageWindowDays; onChange: (days: UsageWindowDays) => void }): ReactElement {\n const { t } = useI18n()\n return (\n <div className=\"dq-window-switch\" role=\"group\" aria-label={t('window.groupLabel')}>\n {USAGE_WINDOW_DAYS.map(days => (\n <button\n key={days}\n type=\"button\"\n className={`dq-window-btn${props.value === days ? ' dq-window-btn--on' : ''}`}\n aria-pressed={props.value === days}\n title={t('window.viewTitle', { window: windowName(days, t) })}\n onClick={() => props.onChange(days)}\n >\n {days === 365 ? t('window.yearButton') : t('window.daysButton', { days })}\n </button>\n ))}\n </div>\n )\n}\n\nconst chartMetricLabel = (metric: ChartMetric, t: Translate = fallbackT): string => metric === 'tokens'\n ? t('metric.tokens')\n : chartMetricName(metric, t)\n\nfunction ChartMetricPicker(props: { value: ChartMetric; onChange: (metric: ChartMetric) => void }): ReactElement {\n const { t } = useI18n()\n return (\n <div className=\"dq-chart-switch\" role=\"group\" aria-label={t('metric.groupLabel')}>\n {CHART_METRICS.map(metric => (\n <button\n key={metric}\n type=\"button\"\n className={`dq-chart-switch-btn${props.value === metric ? ' dq-chart-switch-btn--on' : ''}`}\n aria-pressed={props.value === metric}\n title={t('metric.compareTitle', { metric: chartMetricLabel(metric, t) })}\n onClick={() => props.onChange(metric)}\n >\n {chartMetricLabel(metric, t)}\n </button>\n ))}\n </div>\n )\n}\n\nexport function BalanceDashboard(props: { sessionId?: string; views: ConversationViewsSource }): ReactElement {\n const { t, locale } = useI18n()\n // Seed state from the cache so the tab never waits on the network when\n // data has been fetched before (stale-while-revalidate).\n const cachedBalance = getCachedBalance()\n const cachedUsage = getCachedUsage()\n const cachedUsageAt = getCachedUsageAt()\n const [balance, setBalance] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [usage, setUsage] = useState<UsageData | null>(cachedUsage?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<{ kind: 'all' | 'balance' | 'usage'; error: string } | null>(null)\n // Balance answers in well under a second, usage replays every session log and\n // takes seconds \u2014 so they get their own loading flags and paint independently\n // instead of the fast one waiting on the slow one.\n const [loadingBalance, setLoadingBalance] = useState(cachedBalance === null)\n const [loadingUsage, setLoadingUsage] = useState(cachedUsage === null)\n const [refreshing, setRefreshing] = useState(false)\n const [usageUpdatedAt, setUsageUpdatedAt] = useState<number | null>(cachedUsageAt)\n const [syncState, setSyncState] = useState<SyncState>(cachedUsageAt === null ? 'syncing' : 'cached')\n const [freshnessNow, setFreshnessNow] = useState(Date.now())\n const [settingsOpen, setSettingsOpen] = useState(false)\n const hadDataRef = useRef(cachedBalance !== null || cachedUsage !== null)\n const [widgetOn, setWidgetOn] = useState(widgetVisibleStore.get())\n const [widgetTabIds, setWidgetTabIds] = useState<string[] | null>(widgetTabIdsStore.get())\n const [viewTabs, setViewTabs] = useState<ConversationViewTab[]>(() => props.views.list())\n useEffect(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n const [monthlyBudget, setMonthlyBudget] = useState(monthlyBudgetStore.get())\n const [barMode, setBarMode] = useState<'daily' | 'hourly'>('daily')\n const [selectedModels, setSelectedModels] = useState<string[]>([])\n const [windowDays, setWindowDays] = useState<UsageWindowDays>(usageWindowStore.get())\n const [chartMetric, setChartMetric] = useState<ChartMetric>(chartMetricStore.get())\n // Layout preferences shared with the client registration half (see\n // ./layout-prefs.ts): the sidebar entry is applied there, and the \u300C\u989D\u5EA6\u300Dtab\n // position is mapped onto the host's slot order there. Seed locally and stay\n // subscribed so the row shows whatever actually got applied.\n const [sidebarEntry, setSidebarEntry] = useState<SidebarEntryPlacement>(sidebarEntryStore.get())\n useEffect(() => sidebarEntryStore.subscribe(() => setSidebarEntry(sidebarEntryStore.get())), [])\n // Chip drag state for the tab-position setting. `tabDropTarget` is the chip\n // currently under the pointer while dragging, only to paint the drop target.\n const [tabDragging, setTabDragging] = useState(false)\n const [tabDropTarget, setTabDropTarget] = useState<number | null>(null)\n // The inline image-usage section animates closed when the selected window\n // loses its images; the last payload that had images stays rendered for the\n // ~320ms collapse, so the section always has something to show while shrinking.\n const [retainedVision, setRetainedVision] = useState<VisionSectionProps | null>(null)\n // \"\u9884\u8BA1\u53EF\u7528\" hover preview: an unopened <details> skips rendering its\n // non-summary children in Chromium (a content-visibility-like platform\n // behavior), so CSS-only `:hover{display:block}` never paints anything\n // when the element isn't actually open. Drive `open` from state instead \u2014\n // hovering opens it for a live preview; a manual click/keyboard/touch open\n // keeps it open independent of hover.\n const [runwayHovering, setRunwayHovering] = useState(false)\n const [runwayManuallyOpened, setRunwayManuallyOpened] = useState(false)\n // \u8F6E\u6B21 47: same platform limitation applies to \"\u4F59\u989D\u660E\u7EC6\" \u2014 it used the same\n // CSS-only `:hover{display:flex}` on an uncontrolled <details> since round 29,\n // which never actually painted in current Chromium either. Same fix, same shape.\n const [remainingHovering, setRemainingHovering] = useState(false)\n const [remainingManuallyOpened, setRemainingManuallyOpened] = useState(false)\n const budgetInputRef = useRef<HTMLInputElement | null>(null)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const [composerHeight, setComposerHeight] = useState<number | null>(null)\n // The composer's measured width caps the dashboard column: on narrower\n // viewports the fixed 860px max-width would otherwise overhang the input\n // box the cards visually belong to (user-facing parity requirement).\n const [composerWidth, setComposerWidth] = useState<number | null>(null)\n // The current-session card: fetched per session id, not through the\n // account-wide balance/usage caches (see DESIGN_NOTES \u2014 session-scoped\n // data does not go through the localStorage-persisted cache). No cached\n // seed on first render since there is nothing to seed from.\n const [sessionUsage, setSessionUsage] = useState<SessionUsageData | null>(null)\n const [loadingSessionUsage, setLoadingSessionUsage] = useState(props.sessionId !== undefined && props.sessionId !== '')\n const [sessionUsageError, setSessionUsageError] = useState<string | null>(null)\n const sessionUsageIdRef = useRef<string | null>(null)\n\n // Narrow viewports only: keep the last card scrollable clear of the host's\n // fixed composer, which otherwise overlaps the bottom of a long dashboard\n // (see LEARNINGS.md). Reuses the same `conversation.composer.dock` slot\n // widget.tsx already excludes from its own drag bounds, so both readings of\n // \"where is the composer\" stay in sync. Desktop layout never reads the\n // height \u2014 the CSS variable is only consumed inside the 620px media query;\n // the width is consumed by .dq-balance at every viewport.\n useLayoutEffect(() => {\n const node = rootRef.current\n if (node === null) return\n const measure = (): void => {\n const frame = getShellFrame(node)\n const composer = getComposerElement(frame)\n const rect = composer?.getBoundingClientRect() ?? null\n const nextHeight = rect !== null && rect.height > 0 ? Math.round(rect.height) : null\n setComposerHeight(prev => (prev === nextHeight ? prev : nextHeight))\n // Width parity uses the composer's input card (the rounded panel with\n // the textarea), not the dock seat \u2014 the seat spans the whole pane, so\n // it can never narrow the dashboard column below 860px.\n const input = getComposerInputElement(frame)\n const inputRect = input?.getBoundingClientRect() ?? null\n const nextWidth = inputRect !== null && inputRect.width > 0 ? Math.round(inputRect.width) : null\n setComposerWidth(prev => (prev === nextWidth ? prev : nextWidth))\n }\n measure()\n const frame = getShellFrame(node)\n const composer = getComposerElement(frame)\n const input = getComposerInputElement(frame)\n let observer: ResizeObserver | null = null\n if (typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(measure)\n if (composer !== null) observer.observe(composer)\n if (input !== null) observer.observe(input)\n if (frame !== null) observer.observe(frame)\n }\n window.addEventListener('resize', measure)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', measure)\n }\n }, [])\n\n // All conversation view tabs (Chat / Trajectory / \u989D\u5EA6 \u2026) share one host\n // scrollport (`[data-conversation-scroll]`), and the host keeps scroll\n // memory only for Chat itself \u2014 switching to \u989D\u5EA6 from a scrolled-down Chat\n // otherwise opens the tab near the settings card instead of at the account\n // balance. Reset before paint on every mount; the view is remounted per tab\n // switch, and `sessionId` re-runs it if the host reuses the view for\n // another session.\n useLayoutEffect(() => {\n const node = rootRef.current\n if (node === null) return\n const scrollport = node.closest('[data-conversation-scroll]')\n if (scrollport instanceof HTMLElement) scrollport.scrollTop = 0\n }, [props.sessionId])\n\n // The full dashboard and the floating summary should never compete for the\n // same pixels. This does not touch the persisted widget preference: leaving\n // the tab restores it exactly as the user left it.\n useLayoutEffect(() => {\n quotaViewActiveStore.set(true)\n return () => quotaViewActiveStore.set(false)\n }, [])\n\n const errText = (err: unknown): string => (err as { message?: string } | null)?.message ?? String(err)\n\n /** Load both resources; each resolves to null on success or to its error\n * string on failure, so a partial failure can name the half that broke. */\n const load = async (force: boolean): Promise<void> => {\n const usageAtBefore = getCachedUsageAt()\n setError(null)\n setNotice(null)\n setRefreshing(true)\n setSyncState('syncing')\n const balanceTask = fetchBalance(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setBalance(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingBalance(false)\n return result\n })\n const usageTask = fetchUsage(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setUsage(res.data)\n const updatedAt = getCachedUsageAt()\n setUsageUpdatedAt(updatedAt)\n setFreshnessNow(Date.now())\n setSyncState(updatedAt !== null && updatedAt !== usageAtBefore ? 'fresh' : 'cached')\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingUsage(false)\n return result\n })\n const [balanceError, usageError] = await Promise.all([balanceTask, usageTask])\n setRefreshing(false)\n if (usageError !== null) {\n const fallbackAt = getCachedUsageAt()\n setUsageUpdatedAt(fallbackAt)\n setFreshnessNow(Date.now())\n setSyncState(fallbackAt === null ? 'error' : 'fallback')\n }\n if (balanceError !== null && usageError !== null) {\n // Nothing came back at all: an error only when there is nothing to show.\n if (hadDataRef.current) setNotice({ kind: 'all', error: balanceError })\n else setError(balanceError)\n } else if (balanceError !== null) {\n setNotice({ kind: 'balance', error: balanceError })\n } else if (usageError !== null) {\n setNotice({ kind: 'usage', error: usageError })\n }\n // The current-session card rides along with an explicit force refresh so\n // the one refresh button covers all three data sources; the initial\n // mount-time fetch is handled separately below, keyed on the session id\n // itself, so it is not duplicated here (force=false would otherwise fire\n // twice on first render \u2014 once from this effect, once from that one).\n if (force && props.sessionId !== undefined && props.sessionId !== '') {\n void loadSessionUsage(props.sessionId, true)\n }\n }\n\n /** Stale-while-revalidate for the current-session card: on success, swap\n * in the new data; on failure, keep whatever is already on screen (a\n * refresh going bad should not blank out a card that was working). Guards\n * every state write against the session id having changed mid-flight, so\n * a slow request for a session the user has since navigated away from\n * cannot clobber the next one's numbers. */\n const loadSessionUsage = async (id: string, force: boolean): Promise<void> => {\n if (!force) setLoadingSessionUsage(true)\n try {\n const res = await fetchSessionUsage(id, force)\n if (sessionUsageIdRef.current !== id) return\n if (res.ok && res.data !== undefined) {\n setSessionUsage(res.data)\n setSessionUsageError(null)\n } else {\n setSessionUsageError(res.error ?? null)\n }\n } catch (err) {\n if (sessionUsageIdRef.current === id) setSessionUsageError(errText(err))\n } finally {\n if (sessionUsageIdRef.current === id) setLoadingSessionUsage(false)\n }\n }\n\n useEffect(() => {\n void load(false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Mount-time (and session-switch-time) fetch for the current-session card.\n // Independent of the balance/usage effect above: this data is scoped to\n // whichever session the tab happens to be open inside, not to the account.\n useEffect(() => {\n const id = props.sessionId\n sessionUsageIdRef.current = id ?? null\n if (id === undefined || id === '') {\n setSessionUsage(null)\n setSessionUsageError(null)\n setLoadingSessionUsage(false)\n return\n }\n setSessionUsage(null)\n setSessionUsageError(null)\n setLoadingSessionUsage(true)\n void loadSessionUsage(id, false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.sessionId])\n\n useEffect(() => {\n const timer = window.setInterval(() => setFreshnessNow(Date.now()), 30_000)\n return () => window.clearInterval(timer)\n }, [])\n\n const toggle = (): void => {\n const next = !widgetOn\n setWidgetOn(next)\n widgetVisibleStore.set(next)\n }\n\n const widgetTabs = viewTabs.filter(tab => tab.id !== 'balance')\n const toggleWidgetTab = (id: string): void => {\n const selected = widgetTabIds ?? widgetTabs.map(tab => tab.id)\n const next = selected.includes(id) ? selected.filter(tabId => tabId !== id) : [...selected, id]\n setWidgetTabIds(next)\n widgetTabIdsStore.set(next)\n }\n\n const changeLowBalance = (value: number): void => {\n setLowBalance(value)\n lowBalanceStore.set(value)\n }\n\n const changeMonthlyBudget = (value: number): void => {\n setMonthlyBudget(value)\n monthlyBudgetStore.set(value)\n }\n\n const changeWindowDays = (value: UsageWindowDays): void => {\n setWindowDays(value)\n usageWindowStore.set(value)\n }\n\n const changeChartMetric = (value: ChartMetric): void => {\n setChartMetric(value)\n chartMetricStore.set(value)\n }\n\n const changeSidebarEntry = (value: SidebarEntryPlacement): void => {\n setSidebarEntry(value)\n sidebarEntryStore.set(value)\n }\n\n // \u300C\u989D\u5EA6\u300Dtab position: read from the live roster (never from local state) so\n // the chips show the order the host actually applied, including orders other\n // plugins picked.\n const balanceTabIndex = viewTabs.findIndex(tab => tab.id === 'balance')\n\n /** Final roster position for dropping the quota chip on `target`, before or\n * after that chip's midpoint. The dragged chip leaves the roster before it\n * is reinserted, so a rightward drop lands one slot earlier than the raw\n * target \u2014 `quotaTabIndexStore` stores the final position, not an insertion\n * gap, so the shift has to be undone here. */\n const finalTabIndex = (target: number, after: boolean): number => {\n const gap = after ? target + 1 : target\n const dropped = balanceTabIndex >= 0 && gap > balanceTabIndex ? gap - 1 : gap\n return Math.max(0, Math.min(dropped, Math.max(viewTabs.length - 1, 0)))\n }\n\n const endTabDrag = (): void => {\n setTabDragging(false)\n setTabDropTarget(null)\n }\n\n const previewTabDropTarget = (index: number): void => {\n setTabDropTarget(prev => (prev === index ? prev : index))\n }\n\n const applyQuotaTabIndex = (index: number): void => {\n const next = Math.max(0, Math.min(index, Math.max(viewTabs.length - 1, 0)))\n if (next === balanceTabIndex) return\n quotaTabIndexStore.set(next)\n // Applying the new slot order replaces our registration, which remounts\n // this dashboard: the chip loses DOM focus. Put it back after the remount\n // so holding ArrowLeft/ArrowRight can nudge the tab more than once.\n window.setTimeout(() => {\n const chip = document.querySelector<HTMLElement>('.dq-tab-chip--current')\n chip?.focus()\n }, 80)\n }\n\n const dropQuotaTab = (target: number, after: boolean): void => {\n applyQuotaTabIndex(finalTabIndex(target, after))\n endTabDrag()\n }\n\n const onQuotaTabDragStart = (event: ReactDragEvent<HTMLElement>): void => {\n setTabDragging(true)\n // Firefox refuses to start a drag unless some payload is attached.\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', 'balance')\n }\n\n const onChipDragOver = (event: ReactDragEvent<HTMLElement>, index: number): void => {\n // Only the quota chip's own drag reorders tabs; dragging a file, link or\n // selected text over the strip must not be accepted as a drop target.\n if (!tabDragging) return\n event.preventDefault()\n event.stopPropagation()\n previewTabDropTarget(index)\n }\n\n const onChipDrop = (event: ReactDragEvent<HTMLElement>, index: number): void => {\n if (!tabDragging) return\n event.preventDefault()\n event.stopPropagation()\n const rect = event.currentTarget.getBoundingClientRect()\n dropQuotaTab(index, event.clientX > rect.left + rect.width / 2)\n }\n\n const onOrderDragOver = (event: ReactDragEvent<HTMLDivElement>): void => {\n // The container itself (the chip-free tail) means \"move to the end\"; chips\n // stop propagation and compute a precise before/after slot.\n if (!tabDragging) return\n event.preventDefault()\n if (event.target === event.currentTarget) previewTabDropTarget(viewTabs.length - 1)\n }\n\n const onOrderDrop = (event: ReactDragEvent<HTMLDivElement>): void => {\n if (!tabDragging) return\n event.preventDefault()\n if (event.target !== event.currentTarget) return\n applyQuotaTabIndex(viewTabs.length - 1)\n endTabDrag()\n }\n\n const onQuotaTabKeyDown = (event: ReactKeyboardEvent<HTMLElement>): void => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n event.preventDefault()\n applyQuotaTabIndex(balanceTabIndex + (event.key === 'ArrowLeft' ? -1 : 1))\n }\n\n const primary = balance !== null && balance.balances.length > 0 ? balance.balances[0] : null\n\n // Runway: balance divided by the last 7 calendar days' average spend. Idle\n // days are included on purpose \u2014 that is the burn rate, not the busy-day rate.\n const recentDays = (usage?.daily ?? []).slice(-7)\n const avgDailyCost = recentDays.length > 0\n ? recentDays.reduce((sum, d) => sum + d.cost, 0) / recentDays.length\n : 0\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n // 0 disables the warning; an unreadable balance never triggers it.\n const balanceLow = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n // The top-up shortcut sits outside the configurable warning: either a balance\n // under the fixed floor or one under the user's line is \"time to top up\".\n const topUpPrompt = needsTopUp(balanceValue, lowBalance)\n const daysLeft = avgDailyCost > 0 && Number.isFinite(balanceValue) ? balanceValue / avgDailyCost : null\n const daysLeftText = daysLeft === null\n ? '\u2014'\n : daysLeft >= 365 ? t('balance.overYear') : t('balance.days', { count: daysLeft < 10 ? daysLeft.toFixed(1) : Math.round(daysLeft) })\n const runwayTitle = daysLeft === null\n ? t('balance.noRunway', { days: recentDays.length || 7 })\n : t('balance.runwayTitle', { days: recentDays.length, cost: fmt(avgDailyCost) })\n\n const activeWindow = usage?.windows.find(window => window.days === windowDays) ?? null\n const activeWindowName = windowName(windowDays, t)\n\n // Image / multimodal usage lives inside the \u7528\u91CF\u8D8B\u52BF card now, as a section\n // that opens and closes with the selected window: 0 images means no section\n // at all (a line saying \"no images\" is not worth the space). A host half\n // that has not been restarted yet sends a pre-vision payload, so the shape is\n // re-checked here rather than trusted from the types.\n const visionStats = activeWindow?.vision\n const visionOpen = usage !== null && activeWindow !== null && visionStats !== undefined\n && visionStats.images > 0\n && Array.isArray(activeWindow.visionDaily) && Array.isArray(activeWindow.visionSessions)\n const visionPayload = (window: NonNullable<typeof activeWindow>, stats: VisionStats, label: string): VisionSectionProps => ({\n vision: stats,\n daily: window.visionDaily,\n sessions: window.visionSessions,\n windowLabel: label,\n inputTokens: window.totals.input,\n costTotal: window.totals.cost,\n })\n const liveVision: VisionSectionProps | null = visionOpen && activeWindow !== null && visionStats !== undefined\n ? visionPayload(activeWindow, visionStats, activeWindowName)\n : null\n // Open: paint the live payload immediately. Closed: keep the last payload for\n // 320ms (matching the CSS grid-row collapse) and drop it afterwards. The\n // timer is cleared on every dependency change and on unmount.\n useEffect(() => {\n if (visionOpen && activeWindow !== null && visionStats !== undefined) {\n setRetainedVision(visionPayload(activeWindow, visionStats, activeWindowName))\n return\n }\n const timer = window.setTimeout(() => setRetainedVision(null), 320)\n return () => window.clearTimeout(timer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [visionOpen, activeWindow, activeWindowName])\n const shownVision = visionOpen ? liveVision : retainedVision\n\n const dailyBars = (activeWindow?.daily ?? []).map(d => ({\n label: windowDays === 365 ? d.date.slice(5).replace('-', '/') : d.date.slice(8, 10),\n value: chartMetricValue(chartMetric, d),\n title: t('chart.tooltip', {\n head: d.date, tokens: fmtInt(d.total), cost: fmt(d.cost), calls: t('common.calls', { count: d.calls }),\n }),\n }))\n const hourlyBars = (activeWindow?.hourly ?? []).map(h => ({\n label: String(h.hour),\n value: chartMetricValue(chartMetric, h),\n title: t('chart.tooltip', {\n head: t('chart.hourPoint', { hour: h.hour }), tokens: fmtInt(h.total), cost: fmt(h.cost), calls: t('common.calls', { count: h.calls }),\n }),\n }))\n\n // One canonical model order \u2014 most expensive first \u2014 shared by the ranking\n // card, the picker and the chart, so a model keeps its colour everywhere\n // instead of being coloured by the order it happened to be ticked in.\n // Tallest bar currently on screen \u2014 the chart has no y axis, so this is the\n // only thing giving the bars a magnitude.\n const chartPeak = (barMode === 'daily' ? dailyBars : hourlyBars)\n .reduce((peak, bar) => (bar.value > peak ? bar.value : peak), 0)\n const chartPeakText = chartMetric === 'cost'\n ? `\u00A5${fmt(chartPeak)}`\n : chartMetric === 'calls'\n ? t('common.callsShort', { count: fmtInt(chartPeak) })\n : `${fmtCompact(chartPeak, locale)} tokens`\n\n const modelList = [...(activeWindow?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const canonicalModels = [...(usage?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const availableModelKeys = new Set(modelList.map(modelKeyOf))\n const effectiveSelection = selectedModels.filter(k => availableModelKeys.has(k))\n const colorOf = (key: string): string => {\n const index = canonicalModels.findIndex(m => modelKeyOf(m) === key)\n return MODEL_COLORS[(index < 0 ? 0 : index) % MODEL_COLORS.length]\n }\n const modelCostTotal = modelList.reduce((sum, m) => sum + m.cost, 0)\n\n // Per-model series for the grouped bar chart (only when models are selected).\n const grouped = effectiveSelection.map(key => {\n const m = modelList.find(x => modelKeyOf(x) === key)\n const name = m === undefined ? key : modelNameOf(m, t)\n const color = colorOf(key)\n if (barMode === 'daily') {\n return {\n key,\n name,\n color,\n bars: (m?.daily ?? []).map((p, i) => ({\n label: windowDays === 365\n ? ((activeWindow?.daily ?? [])[i]?.date.slice(5).replace('-', '/') ?? '')\n : ((activeWindow?.daily ?? [])[i]?.date.slice(8, 10) ?? ''),\n value: chartMetricValue(chartMetric, p),\n title: t('chart.tooltip', {\n head: `${name} \u00B7 ${(activeWindow?.daily ?? [])[i]?.date ?? ''}`,\n tokens: fmtInt(p.total), cost: fmt(p.cost), calls: t('common.calls', { count: p.calls }),\n }),\n })),\n }\n }\n return {\n key,\n name,\n color,\n bars: (m?.hourly ?? []).map((p, i) => ({\n label: String(i),\n value: chartMetricValue(chartMetric, p),\n title: t('chart.tooltip', {\n head: `${name} \u00B7 ${t('chart.hourPoint', { hour: i })}`,\n tokens: fmtInt(p.total), cost: fmt(p.cost), calls: t('common.calls', { count: p.calls }),\n }),\n })),\n }\n })\n const dailyLabelEvery = windowDays === 7 ? 1 : windowDays === 30 ? 5 : windowDays === 90 ? 15 : 30\n const dailyMinWidth = windowDays === 365 ? 1825 : undefined\n const noticeText = notice === null ? null : t(\n notice.kind === 'all'\n ? 'error.refreshCached'\n : notice.kind === 'balance' ? 'error.balanceRefreshCached' : 'error.usageRefreshCached',\n { error: localizeApiError(notice.error, t, 'error.query') },\n )\n const errorText = error === null ? null : localizeApiError(error, t, 'error.query')\n\n const composerSafeAreaStyle = {\n '--dq-composer-h': `${composerHeight ?? COMPOSER_FALLBACK_PX}px`,\n // Only set once measured; .dq-balance's max-width falls back to 860px\n // without it (pre-measurement render keeps the settled wide-viewport\n // column, then narrows in place \u2014 no flash of the old width).\n ...(composerWidth !== null ? { '--dq-composer-w': `${composerWidth}px` } : {}),\n } as CSSProperties\n\n const navSections = [\n { key: 'balance', label: t('nav.balance') },\n ...(props.sessionId !== undefined && props.sessionId !== '' ? [{ key: 'session', label: t('nav.session') }] : []),\n { key: 'overview', label: t('nav.overview') },\n { key: 'trend', label: t('nav.trend') },\n { key: 'heatmap', label: t('nav.heatmap') },\n { key: 'models', label: t('nav.models') },\n { key: 'sessions', label: t('nav.sessions') },\n { key: 'peakcache', label: t('nav.peakcache') },\n ]\n\n return (\n <div className=\"dq-balance\" ref={rootRef} style={composerSafeAreaStyle}>\n <SectionNav rootRef={rootRef} label={t('nav.label')} sections={navSections} />\n <div className=\"dq-status-row\">\n <div className=\"dq-status-messages\">\n <span\n className={`dq-sync dq-sync--${syncState}`}\n role=\"status\"\n aria-live=\"polite\"\n title={usageUpdatedAt === null\n ? t('status.neverSynced')\n : t('status.usageTime', { time: new Date(usageUpdatedAt).toLocaleString(intlLocale(locale), { timeZone: 'Asia/Shanghai' }) })}\n >\n <span className=\"dq-sync-dot\" aria-hidden=\"true\" />\n {syncStatusText(syncState, usageUpdatedAt, freshnessNow, t)}\n </span>\n {noticeText !== null && <span className=\"dq-warn\">{noticeText}</span>}\n {errorText !== null && <span className=\"dq-error\">{errorText}</span>}\n </div>\n <div className=\"dq-status-actions\">\n <button\n type=\"button\"\n className=\"dq-settings-btn\"\n aria-expanded={settingsOpen}\n aria-controls=\"dq-settings-panel\"\n onClick={() => setSettingsOpen(open => !open)}\n >\n {t('settings.title')}\n <span className={`dq-settings-caret${settingsOpen ? ' dq-settings-caret--open' : ''}`} aria-hidden=\"true\">\u25BE</span>\n </button>\n <button\n type=\"button\"\n className=\"dq-refresh-btn\"\n title={t('status.forceRefresh')}\n disabled={refreshing}\n aria-busy={refreshing}\n onClick={() => { void load(true) }}\n >\n <span className={`dq-refresh-icon${refreshing ? ' dq-refresh-icon--spin' : ''}`}>\u21BB</span>\n {refreshing ? t('status.refreshing') : t('status.refresh')}\n </button>\n </div>\n </div>\n\n {balanceLow && (\n <div className=\"dq-alert\" role=\"status\">\n <span className=\"dq-alert-icon\" aria-hidden=\"true\">!</span>\n <div>\n <strong>{t('alert.lowTitle', { balance: fmt(balanceValue), currency: primary?.currency, threshold: fmt(lowBalance) })}</strong>\n {daysLeft !== null && t('alert.runway', { days: daysLeftText })}{t('common.period')}\n <a className=\"dq-alert-link\" href={TOP_UP_URL} target=\"_blank\" rel=\"noreferrer\">{t('alert.topUp')}</a>\n </div>\n </div>\n )}\n\n <div className=\"dq-card dq-card--hero\">\n <CardTitle srOnly>{t('balance.title')}</CardTitle>\n {primary !== null ? (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('balance.remaining')}</div>\n <details\n className=\"dq-stat-value dq-remaining\"\n open={remainingHovering || remainingManuallyOpened}\n onPointerEnter={() => setRemainingHovering(true)}\n onPointerLeave={() => setRemainingHovering(false)}\n >\n <summary\n title={t('balance.breakdownTitle')}\n aria-label={`${fmt(primary.total)} ${primary.currency}`}\n onClick={e => {\n // Own the toggle fully instead of the native default action: a controlled\n // <details> can be forced open by hover, and a plain native toggle here\n // would fight that (e.g. it flips to \"closed\" while the mouse is still\n // hovering). Preventing default and flipping our own \"manually opened\"\n // state keeps hover-preview and click/keyboard/tap-to-pin independent.\n e.preventDefault()\n setRemainingManuallyOpened(v => !v)\n }}\n >\n {fmt(primary.total)}<span className=\"dq-hero-unit\">{primary.currency}</span>\n </summary>\n <div className=\"dq-remaining-breakdown\">\n <span>{t('balance.toppedUp', { amount: fmt(primary.toppedUp) })}</span>\n <span className=\"dq-remaining-granted\">{t('balance.granted', { amount: fmt(primary.granted) })}</span>\n </div>\n </details>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('balance.runway')}</div>\n <div className=\"dq-runway-line\">\n <details\n className={`dq-stat-value dq-runway${daysLeft !== null && daysLeft < 3 ? ' dq-stat-value--bad' : ''}`}\n open={runwayHovering || runwayManuallyOpened}\n onPointerEnter={() => setRunwayHovering(true)}\n onPointerLeave={() => setRunwayHovering(false)}\n >\n <summary\n title={t('balance.runwayBreakdownTitle')}\n onClick={e => {\n // Own the toggle fully instead of the native default action: a controlled\n // <details> can be forced open by hover, and a plain native toggle here\n // would fight that (e.g. it flips to \"closed\" while the mouse is still\n // hovering). Preventing default and flipping our own \"manually opened\"\n // state keeps hover-preview and click/keyboard/tap-to-pin independent.\n e.preventDefault()\n setRunwayManuallyOpened(v => !v)\n }}\n >\n {daysLeftText}\n </summary>\n <div className=\"dq-runway-detail\">{runwayTitle}</div>\n </details>\n {topUpPrompt && (\n <a className=\"dq-topup\" href={TOP_UP_URL} target=\"_blank\" rel=\"noreferrer\" title={t('balance.topUpTitle')}>\n {t('alert.topUp')}\n <span className=\"dq-topup-arrow\" aria-hidden=\"true\">\u2197</span>\n </a>\n )}\n </div>\n </div>\n {/* \u300C\u53EF\u7528\u300D\u662F\u5E38\u6001\uFF0C\u4E0D\u5360 hero \u4F4D\uFF1B\u53EA\u6709\u8D26\u6237\u4E0D\u53EF\u7528\u65F6\u624D\u51FA\u73B0\uFF0C\u4E14\u7528\u9519\u8BEF\u8272\u3002 */}\n {balance?.isAvailable === false && (\n <Stat label={t('common.status')}>\n <div className=\"dq-stat-value dq-stat-value--bad\">{t('common.unavailable')}</div>\n </Stat>\n )}\n </div>\n ) : loadingBalance ? (\n <BalanceSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('balance.empty')}</div>\n )}\n </div>\n\n <Collapsible open={settingsOpen}>\n <div className=\"dq-settings-panel\" id=\"dq-settings-panel\" role=\"region\" aria-label={t('settings.title')}>\n <CardTitle>{t('settings.title')}</CardTitle>\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupDisplay')}</div>\n <label className=\"dq-toggle\">\n <input type=\"checkbox\" checked={widgetOn} onChange={toggle} />\n <span>{t('settings.widget')}</span>\n </label>\n <div className=\"dq-toggle-hint\">{t('settings.widgetHint')}</div>\n <div className=\"dq-setting dq-setting--tabs\">\n <div className=\"dq-setting-label\" id=\"dq-widget-tabs-label\">{t('settings.widgetTabs')}</div>\n <div className=\"dq-setting-control dq-widget-tabs\" role=\"group\" aria-labelledby=\"dq-widget-tabs-label\">\n <div className=\"dq-widget-tab-list\">\n {widgetTabs.map(tab => (\n <label className=\"dq-widget-tab\" key={tab.id}>\n <input\n type=\"checkbox\"\n checked={widgetTabIds === null || widgetTabIds.includes(tab.id)}\n onChange={() => toggleWidgetTab(tab.id)}\n />\n <span>{tab.label}</span>\n </label>\n ))}\n </div>\n <span className=\"dq-setting-hint\">\n {widgetTabs.length === 0 ? t('settings.widgetTabsEmpty') : t('settings.widgetTabsHint')}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupAlerts')}</div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-low-balance\">{t('settings.lowBalance')}</label>\n <div className=\"dq-setting-control\">\n <input\n id=\"dq-low-balance\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={1}\n value={lowBalance}\n onChange={e => changeLowBalance(Math.max(0, Number(e.target.value) || 0))}\n />\n <span className=\"dq-setting-hint\">\n {lowBalance > 0\n ? t('settings.lowBalanceOn', { amount: fmt(lowBalance), currency: primary?.currency ?? 'CNY' })\n : t('settings.lowBalanceOff')}\n </span>\n </div>\n </div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-monthly-budget\">{t('settings.monthlyBudget')}</label>\n <div className=\"dq-setting-control\">\n <input\n ref={budgetInputRef}\n id=\"dq-monthly-budget\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={10}\n value={monthlyBudget}\n aria-describedby=\"dq-monthly-budget-hint\"\n onChange={e => changeMonthlyBudget(Math.max(0, Number(e.target.value) || 0))}\n />\n <span id=\"dq-monthly-budget-hint\" className=\"dq-setting-hint\">\n {monthlyBudget > 0\n ? t('settings.monthlyBudgetOn', { amount: fmt(monthlyBudget) })\n : t('settings.monthlyBudgetOff')}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupLayout')}</div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-sidebar-entry\">{t('settings.sidebarEntry')}</label>\n <div className=\"dq-setting-control\">\n <select\n id=\"dq-sidebar-entry\"\n className=\"dq-select\"\n value={sidebarEntry}\n onChange={e => changeSidebarEntry(e.target.value as SidebarEntryPlacement)}\n >\n <option value=\"off\">{t('settings.sidebarEntryOff')}</option>\n <option value=\"top\">{t('settings.sidebarEntryTop')}</option>\n <option value=\"bottom\">{t('settings.sidebarEntryBottom')}</option>\n </select>\n <span className=\"dq-setting-hint\">{t('settings.sidebarEntryHint')}</span>\n </div>\n </div>\n <div className=\"dq-setting\">\n <div className=\"dq-setting-label\" id=\"dq-tab-order-label\">{t('settings.tabPosition')}</div>\n <div className=\"dq-setting-control\">\n <div\n className=\"dq-tab-order\"\n role=\"group\"\n aria-labelledby=\"dq-tab-order-label\"\n aria-describedby=\"dq-tab-order-hint\"\n onDragOver={onOrderDragOver}\n onDrop={onOrderDrop}\n >\n {viewTabs.map((tab, index) => {\n const current = tab.id === 'balance'\n const dropTarget = tabDragging && !current && tabDropTarget === index\n return (\n <span\n key={tab.id}\n className={`dq-tab-chip${current ? ' dq-tab-chip--current' : ''}${current && tabDragging ? ' dq-tab-chip--dragging' : ''}${dropTarget ? ' dq-tab-chip--drop-target' : ''}`}\n draggable={current}\n tabIndex={current ? 0 : undefined}\n role={current ? 'button' : undefined}\n aria-label={current ? t('settings.tabDragAria') : undefined}\n onDragStart={current ? onQuotaTabDragStart : undefined}\n onDragEnd={current ? endTabDrag : undefined}\n onDragOver={event => onChipDragOver(event, index)}\n onDrop={event => onChipDrop(event, index)}\n onKeyDown={current ? onQuotaTabKeyDown : undefined}\n >\n {tab.label}\n </span>\n )\n })}\n </div>\n <span id=\"dq-tab-order-hint\" className=\"dq-setting-hint\">{t('settings.tabPositionHint')}</span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('links.title')}</div>\n <div className=\"dq-links\">\n <Link href=\"https://platform.deepseek.com/usage\">{t('links.usage')}</Link>\n <Link href=\"https://platform.deepseek.com/api_keys\">{t('links.apiKey')}</Link>\n <Link href=\"https://status.deepseek.com\">{t('links.status')}</Link>\n </div>\n </div>\n </div>\n </Collapsible>\n\n {props.sessionId !== undefined && props.sessionId !== '' && (\n <div className=\"dq-card dq-card--primary\">\n <CardTitle caption={t('common.estimated')}>{t('sessionUsage.title')}</CardTitle>\n {sessionUsage !== null ? (\n <SessionUsageCard data={sessionUsage} />\n ) : loadingSessionUsage ? (\n <SessionUsageSkeleton />\n ) : sessionUsageError !== null ? (\n <div className=\"dq-empty dq-empty--error\">{localizeApiError(sessionUsageError, t, 'error.query')}</div>\n ) : (\n <div className=\"dq-empty\">{t('sessionUsage.empty')}</div>\n )}\n </div>\n )}\n\n <div className=\"dq-card dq-card--primary\">\n <CardTitle caption={t('common.estimated')}>{t('overview.title')}</CardTitle>\n {usage !== null ? (\n <div className=\"dq-period-grid\">\n <Period label={t('overview.today')} period={usage.summary.today} previous={usage.summary.yesterday} compare={t('overview.vsYesterday')} />\n <Period label={t('overview.month')} period={usage.summary.month} previous={usage.summary.lastMonthToDate} compare={t('overview.vsLastMonth')} />\n <Period\n label={t('overview.total')}\n period={{ total: usage.totals.total, cost: usage.totals.cost, calls: usage.totals.calls }}\n />\n </div>\n ) : loadingUsage ? (\n\n <div className=\"dq-period-grid\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-period\">\n <Skel w={40} h={11} /><Skel w={104} h={24} /><Skel w={132} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('overview.empty')}</div>\n )}\n {usage !== null && (\n <BudgetMeter\n spent={usage.summary.month.cost}\n budget={monthlyBudget}\n onConfigure={() => { setSettingsOpen(true); window.setTimeout(() => budgetInputRef.current?.focus(), 80) }}\n />\n )}\n {usage !== null && <PricingNote pricing={usage.pricing} />}\n </div>\n\n <div className=\"dq-card dq-card--primary\">\n <div className=\"dq-card-head\">\n <CardTitle>{t('usage.trendTitle')}</CardTitle>\n {usage !== null && (\n <div className=\"dq-card-actions\">\n <UsageWindowPicker value={windowDays} onChange={changeWindowDays} />\n <ExportMenu usage={usage} />\n </div>\n )}\n </div>\n {usage !== null && activeWindow !== null ? (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label={t('usage.windowInput', { window: activeWindowName })}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.input, locale)}</div></Stat>\n <Stat label={t('common.output')}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.output, locale)}</div></Stat>\n <Stat label={t('common.cacheHit')}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.cache, locale)}</div></Stat>\n <Stat label={t('usage.modelCalls')}><div className=\"dq-stat-value\">{fmtInt(activeWindow.totals.calls)}</div></Stat>\n </div>\n <div className=\"dq-chart-block-head\">\n <div className=\"dq-chart-title\">\n {barMode === 'daily'\n ? t('chart.dailyTitle', { window: activeWindowName, metric: chartMetricName(chartMetric, t) })\n : t('chart.hourlyTitle', { window: activeWindowName, metric: chartMetricName(chartMetric, t) })}\n {chartPeak > 0 && <span className=\"dq-chart-peak\">{t('chart.peak', { value: chartPeakText })}</span>}\n </div>\n <div className=\"dq-chart-controls\">\n <ModelPicker models={modelList} selected={effectiveSelection} colorOf={colorOf} onChange={setSelectedModels} />\n <ChartMetricPicker value={chartMetric} onChange={changeChartMetric} />\n <div className=\"dq-chart-switch\" role=\"tablist\" aria-label={t('chart.dimensionLabel')}>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'daily'}\n className={`dq-chart-switch-btn${barMode === 'daily' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('daily')}\n >\n {t('chart.daily')}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'hourly'}\n className={`dq-chart-switch-btn${barMode === 'hourly' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('hourly')}\n >\n {t('chart.hourly')}\n </button>\n </div>\n </div>\n </div>\n {activeWindow.totals.calls === 0 ? (\n <div className=\"dq-empty\">{t('chart.noWindowData', { window: activeWindowName })}</div>\n ) : grouped.length > 0 ? (\n <>\n <GroupedBars\n series={grouped}\n height={barMode === 'daily' ? 160 : 140}\n labelEvery={barMode === 'daily' ? dailyLabelEvery : 3}\n minWidth={barMode === 'daily' ? dailyMinWidth : undefined}\n />\n <div className=\"dq-legend\">\n {grouped.map(s => (\n <span key={s.key} className=\"dq-legend-item\">\n <span className=\"dq-legend-swatch\" style={{ background: s.color }} />\n {s.name}\n </span>\n ))}\n </div>\n </>\n ) : barMode === 'daily' ? (\n <Bars data={dailyBars} height={160} labelEvery={dailyLabelEvery} minWidth={dailyMinWidth} />\n ) : (\n <Bars data={hourlyBars} height={140} labelEvery={3} />\n )}\n </>\n ) : loadingUsage ? (\n <UsageSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('chart.empty')}</div>\n )}\n {/* \u56FE\u7247\u7528\u91CF\u5E76\u5165\u672C\u5361\uFF1A\u7A97\u53E3\u5207\u5230\u6CA1\u6709\u56FE\u7247\u7684\u8303\u56F4\u65F6\u6574\u6BB5\u6536\u8D77\u3002\u5173\u95ED\u671F\u95F4\u4ECD\u6E32\u67D3\n \u6700\u540E\u4E00\u4EFD\u6709\u56FE\u6570\u636E\uFF0C\u8BA9 0fr\u21921fr \u7684\u6536\u8D77\u52A8\u753B\u6709\u5185\u5BB9\u53EF\u52A8\uFF1B\u52A0\u8F7D\u4E2D\u4E5F\u4FDD\u7559\u5173\u95ED\u6001\n \u7684\u7A7A\u58F3\uFF0C\u6570\u636E\u5230\u8FBE\u65F6\u624D\u662F\u771F\u7684\u300C\u5C55\u5F00\u300D\u800C\u4E0D\u662F\u76F4\u63A5\u51FA\u73B0\u3002 */}\n <div className=\"dq-vision-inline\" data-open={visionOpen ? 'true' : 'false'} aria-hidden={!visionOpen}>\n <div className=\"dq-vision-inline-body\">\n {shownVision !== null && (\n <>\n <div className=\"dq-chart-title\">{t('vision.title')}<span className=\"dq-chart-peak\">{shownVision.windowLabel}</span></div>\n <VisionCard\n vision={shownVision.vision}\n daily={shownVision.daily}\n sessions={shownVision.sessions}\n windowLabel={shownVision.windowLabel}\n inputTokens={shownVision.inputTokens}\n costTotal={shownVision.costTotal}\n />\n </>\n )}\n </div>\n </div>\n {usage !== null && <CoverageDiagnostics coverage={usage.coverage} />}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={t('chart.heatmapTitle')}>{t('heatmap.title')}</CardTitle>\n {usage !== null ? (\n <Heatmap data={usage.heatmap} />\n ) : loadingUsage ? (\n <HeatmapSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('chart.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={activeWindowName}>{t('models.title')}</CardTitle>\n {activeWindow !== null ? (\n <ModelRanking models={modelList} totalCost={modelCostTotal} colorOf={colorOf} />\n ) : loadingUsage ? (\n <div className=\"dq-rank\">\n {[0, 1].map(i => (\n <div key={i} className=\"dq-rank-row\">\n <Skel w={148} h={13} />\n <div className=\"dq-rank-track\" />\n <Skel w={230} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('models.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={activeWindowName}>{t('sessions.title')}</CardTitle>\n {activeWindow !== null ? (\n <SessionRanking sessions={activeWindow.sessions} count={activeWindow.sessionCount} totalCost={activeWindow.totals.cost} />\n ) : loadingUsage ? (\n <div className=\"dq-sessions\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-session\">\n <Skel w={200} h={13} />\n <div className=\"dq-session-track\" />\n <Skel w={250} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('sessions.empty')}</div>\n )}\n </div>\n\n {/* The two half-width analysis cards sit side by side while there is\n room; below the pair's own 340px column floor they stack. */}\n <div className=\"dq-card-pair\">\n <div className=\"dq-card\">\n <CardTitle>{t('peak.title')}</CardTitle>\n {usage !== null ? (\n <PeakCard split={usage.peakSplit} pricing={usage.pricing} />\n ) : loadingUsage ? (\n <>\n <div className=\"dq-peak-track\" />\n <div className=\"dq-peak-figures\"><Skel w={120} h={11} /><Skel w={96} h={20} /></div>\n </>\n ) : (\n <div className=\"dq-empty\">{t('peak.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle>{t('cache.title')}</CardTitle>\n {usage !== null ? (\n <CacheCard totals={usage.totals} />\n ) : loadingUsage ? (\n <div className=\"dq-cache-figures\">\n {[60, 96, 72].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={72} h={20} /></div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('cache.empty')}</div>\n )}\n </div>\n </div>\n\n <p className=\"dq-footer\">{__PLUGIN_LABEL__}</p>\n </div>\n )\n}\n", "export type BudgetStatus = 'healthy' | 'risk' | 'over'\n\nexport interface BudgetSnapshot {\n spent: number\n budget: number\n ratio: number\n remaining: number\n forecast: number\n forecastOver: number\n status: BudgetStatus\n}\n\nconst BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000\n\n/**\n * Project the current month's cost to month end. DeepSeek's billing boundary\n * is Beijing time, so this stays deterministic even when the browser runs in\n * another timezone.\n */\nexport function budgetSnapshot(spentValue: number, budgetValue: number, nowMs = Date.now()): BudgetSnapshot {\n const spent = Number.isFinite(spentValue) ? Math.max(0, spentValue) : 0\n const budget = Number.isFinite(budgetValue) ? Math.max(0, budgetValue) : 0\n const beijingNow = new Date(nowMs + BEIJING_OFFSET_MS)\n const year = beijingNow.getUTCFullYear()\n const month = beijingNow.getUTCMonth()\n const start = Date.UTC(year, month, 1) - BEIJING_OFFSET_MS\n const end = Date.UTC(year, month + 1, 1) - BEIJING_OFFSET_MS\n const elapsedRatio = Math.min(1, Math.max(1 / (end - start), (nowMs - start) / (end - start)))\n const forecast = spent / elapsedRatio\n const ratio = budget > 0 ? spent / budget : 0\n const remaining = budget - spent\n const forecastOver = budget > 0 ? Math.max(0, forecast - budget) : 0\n const status: BudgetStatus = ratio >= 1\n ? 'over'\n : (ratio >= 0.8 || forecastOver > 0 ? 'risk' : 'healthy')\n\n return { spent, budget, ratio, remaining, forecast, forecastOver, status }\n}\n", "/** Dependency-free bar chart and heatmap primitives. */\nimport { useEffect, useRef, useState, type FocusEvent as ReactFocusEvent, type KeyboardEvent as ReactKeyboardEvent, type MutableRefObject, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport { isTapGesture, lastPopulatedIndex, maxOrOne, nextChartFocus, nextPinnedIndex, stackedTotals, type ChartFocusKey } from './chart-focus.ts'\nimport { intlLocale, useI18n, type LocaleId } from './i18n.tsx'\nimport type { LocaleKey } from './locales.ts'\n\nexport interface BarDatum {\n label: string\n value: number\n /** Tooltip text, composed as `heading \u00B7 row \u00B7 row`; each ` \u00B7 ` segment is\n * rendered on its own line, the first as the heading. */\n title?: string\n}\n\ninterface TipState {\n x: number\n y: number\n lines: string[]\n above: boolean\n}\n\n/**\n * Cursor-following tooltip shared by every chart. The native `title` attribute\n * this replaces waited about a second, could not be styled to match the shell,\n * and never appeared on touch.\n *\n * Touch has no hover, so a tap pins the tooltip open instead of showing it only\n * while the finger is down (which produced the original one-flicker-then-gone\n * complaint). `pinned` and `hide()` share one `pinnedRef` so a `touchend`\n * followed synchronously by `pointerleave` \u2014 both native events fired in the\n * same tick, before React re-renders \u2014 never reads a stale \"nothing pinned\"\n * state and hides the tooltip it was just asked to pin.\n */\nfunction useChartTip(): {\n wrapRef: MutableRefObject<HTMLDivElement | null>\n tip: TipState | null\n pinned: number | null\n show: (e: ReactPointerEvent<HTMLElement>, text: string | undefined) => void\n showFocused: (e: ReactFocusEvent<HTMLElement>, text: string | undefined) => void\n hide: () => void\n onPointStart: (e: ReactPointerEvent<HTMLElement>) => void\n onPointEnd: (e: ReactPointerEvent<HTMLElement>, index: number, text: string | undefined) => void\n} {\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const [tip, setTip] = useState<TipState | null>(null)\n const [pinned, setPinned] = useState<number | null>(null)\n const pinnedRef = useRef<number | null>(null)\n const touchStart = useRef<{ x: number; y: number; t: number } | null>(null)\n const setPin = (next: number | null): void => {\n pinnedRef.current = next\n setPinned(next)\n }\n const showAt = (target: HTMLElement, text: string | undefined, clientX?: number, clientY?: number): void => {\n const wrap = wrapRef.current\n if (text === undefined || text === '' || wrap === null) return\n const rect = wrap.getBoundingClientRect()\n const targetRect = target.getBoundingClientRect()\n // Keep the (centred) bubble inside the chart's own box.\n const x = Math.min(Math.max((clientX ?? targetRect.left + targetRect.width / 2) - rect.left, 70), Math.max(rect.width - 70, 70))\n const viewportY = clientY ?? targetRect.top\n const y = viewportY - rect.top\n setTip({ x, y, lines: text.split(' \u00B7 '), above: viewportY > window.innerHeight - 160 })\n }\n const show = (e: ReactPointerEvent<HTMLElement>, text: string | undefined): void => {\n // Touch has no hover; a bare `pointermove` while a finger drags across the\n // chart (e.g. scrolling the page) would otherwise flash tooltips at every\n // point it crosses. Touch only opens a tooltip via the deliberate tap\n // handled in `onPointEnd`.\n if (e.pointerType === 'touch') return\n showAt(e.currentTarget, text, e.clientX, e.clientY)\n }\n const showFocused = (e: ReactFocusEvent<HTMLElement>, text: string | undefined): void => {\n showAt(e.currentTarget, text)\n }\n const hide = (): void => {\n if (pinnedRef.current !== null) return\n setTip(null)\n }\n const onPointStart = (e: ReactPointerEvent<HTMLElement>): void => {\n if (e.pointerType === 'touch') touchStart.current = { x: e.clientX, y: e.clientY, t: Date.now() }\n }\n const onPointEnd = (e: ReactPointerEvent<HTMLElement>, index: number, text: string | undefined): void => {\n if (e.pointerType !== 'touch') return\n const start = touchStart.current\n touchStart.current = null\n if (start === null || !isTapGesture(e.clientX - start.x, e.clientY - start.y, Date.now() - start.t)) return\n const next = nextPinnedIndex(pinnedRef.current, index)\n setPin(next)\n if (next === null) setTip(null)\n else showAt(e.currentTarget, text, e.clientX, e.clientY)\n }\n useEffect(() => {\n if (pinned === null) return undefined\n const onDocPointerDown = (e: PointerEvent): void => {\n const wrap = wrapRef.current\n if (wrap !== null && e.target instanceof Node && wrap.contains(e.target)) return\n setPin(null)\n setTip(null)\n }\n document.addEventListener('pointerdown', onDocPointerDown)\n return () => document.removeEventListener('pointerdown', onDocPointerDown)\n }, [pinned])\n return { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd }\n}\n\nfunction useRovingChartPoints(count: number, initial: number, horizontalStep = 1): {\n active: number\n refs: MutableRefObject<Array<HTMLElement | null>>\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>, index: number) => void\n} {\n const refs = useRef<Array<HTMLElement | null>>([])\n const [active, setActive] = useState(initial)\n useEffect(() => setActive(Math.min(Math.max(0, initial), Math.max(0, count - 1))), [count, initial])\n const onKeyDown = (event: ReactKeyboardEvent<HTMLElement>, index: number): void => {\n if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) return\n event.preventDefault()\n const next = nextChartFocus(index, count, event.key as ChartFocusKey, horizontalStep)\n setActive(next)\n const target = refs.current[next]\n target?.focus({ preventScroll: true })\n target?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n }\n return { active, refs, onKeyDown }\n}\n\nfunction ChartTip(props: { tip: TipState | null }): ReactElement | null {\n const { tip } = props\n if (tip === null) return null\n const [head, ...rows] = tip.lines\n return (\n <div className={`dq-tip${tip.above ? ' dq-tip--above' : ''}`} style={{ left: `${tip.x}px`, top: `${tip.y}px` }} role=\"tooltip\">\n <div className=\"dq-tip-head\">{head}</div>\n {rows.map((row, i) => <div key={i} className=\"dq-tip-row\">{row}</div>)}\n </div>\n )\n}\n\n/** Color palette for per-model grouped bars, cycled by model order. */\nexport const MODEL_COLORS = ['#4176e6', '#2da44e', '#e16f24', '#8250df', '#bf8700', '#cf222e', '#1f883d', '#0969da']\n\nexport function Bars(props: { data: BarDatum[]; height?: number; labelEvery?: number; minWidth?: number }): ReactElement {\n const { data, height = 120, labelEvery = 1, minWidth } = props\n const { locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const initialFocus = lastPopulatedIndex(data.map(datum => datum.value))\n const roving = useRovingChartPoints(data.length, initialFocus)\n useEffect(() => {\n const scroll = scrollRef.current\n if (scroll !== null && minWidth !== undefined) scroll.scrollLeft = scroll.scrollWidth\n }, [data.length, minWidth])\n let max = 0\n for (const datum of data) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-plot\">\n <div className=\"dq-yaxis\" style={{ height: `${height}px` }} aria-hidden=\"true\">\n <span>{max > 0 ? fmtCompact(max, locale) : ''}</span>\n <span>0</span>\n </div>\n <div className=\"dq-bars-scroll\" ref={scrollRef}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px`, minWidth: minWidth === undefined ? undefined : `${minWidth}px` }}>\n {data.map((datum, i) => {\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${datum.label}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={i}\n className={`dq-bar-col${pinned === i ? ' dq-bar-col--pinned' : ''}`}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={i === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[i] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, i, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, i)}\n >\n <div className=\"dq-bar\" style={{ height: `${h}px` }} />\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>{datum.label}</div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nexport interface HeatDatum {\n date: string\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Multi-series bar chart: one bar per time slot, each series' value stacked\n * inside it (series[0] at the bottom, later series stacked above, same order\n * in every column). Segment height is scaled against the largest *per-slot\n * total* across all slots (not the largest single value) so the stacked\n * height reflects that slot's combined usage and columns stay comparable to\n * each other. Each segment stays its own focusable/hoverable/tappable point \u2014\n * `pointIndex = i * series.length + seriesIndex` is unchanged from the old\n * side-by-side layout, so `chart-focus.ts`'s roving tabindex (plain \u00B11 /\n * Home / End, no 2-D semantics) needs no changes: arrow keys still move one\n * point at a time, they just now walk bottom-to-top through one column's\n * models before advancing to the next column, instead of left-to-right\n * through side-by-side bars.\n */\nexport function GroupedBars(props: {\n series: Array<{ key: string; color: string; bars: BarDatum[] }>\n height?: number\n labelEvery?: number\n minWidth?: number\n}): ReactElement {\n const { series, height = 120, labelEvery = 1, minWidth } = props\n const { locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const count = series.length > 0 ? series[0].bars.length : 0\n const pointValues = Array.from({ length: count }, (_, i) => series.map(s => s.bars[i]?.value ?? 0)).flat()\n const roving = useRovingChartPoints(pointValues.length, lastPopulatedIndex(pointValues))\n useEffect(() => {\n const scroll = scrollRef.current\n if (scroll !== null && minWidth !== undefined) scroll.scrollLeft = scroll.scrollWidth\n }, [count, minWidth])\n const totals = stackedTotals(series, count)\n const scale = maxOrOne(totals)\n const axisMax = totals.reduce((m, v) => Math.max(m, v), 0)\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-plot\">\n <div className=\"dq-yaxis\" style={{ height: `${height}px` }} aria-hidden=\"true\">\n <span>{axisMax > 0 ? fmtCompact(axisMax, locale) : ''}</span>\n <span>0</span>\n </div>\n <div className=\"dq-bars-scroll\" ref={scrollRef}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px`, minWidth: minWidth === undefined ? undefined : `${minWidth}px` }}>\n {Array.from({ length: count }, (_, i) => (\n <div\n key={i}\n className=\"dq-bar-col\"\n >\n <div className=\"dq-bar-group\">\n {series.map((s, seriesIndex) => {\n const datum = s.bars[i]\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${s.key}: ${datum.value.toLocaleString()}`\n const pointIndex = i * series.length + seriesIndex\n return (\n <div\n key={s.key}\n className={`dq-bar${pinned === pointIndex ? ' dq-bar--pinned' : ''}`}\n style={{ height: `${h}px`, background: s.color }}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={pointIndex === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[pointIndex] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, pointIndex, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, pointIndex)}\n />\n )\n })}\n </div>\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>\n {series[0].bars[i].label}\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nfunction heatColor(level: number): string {\n if (level <= 0) return 'rgba(120,130,150,0.12)'\n if (level === 1) return 'rgba(65,118,230,0.25)'\n if (level === 2) return 'rgba(65,118,230,0.5)'\n if (level === 3) return 'rgba(65,118,230,0.75)'\n return 'rgba(65,118,230,1)'\n}\n\n/**\n * Calendar heatmap: one flex column per week, cells filling the card's full\n * width (rather than a fixed pixel size hugging the left edge), month labels\n * below the grid and a \u5C11\u2192\u591A scale legend \u2014 modelled on Codex's activity\n * graph. No weekday row: at this cell count a day is identified by hovering\n * it, not by which row it sits in.\n */\nexport function Heatmap(props: { data: HeatDatum[] }): ReactElement {\n const { data } = props\n const { t, locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const roving = useRovingChartPoints(data.length, lastPopulatedIndex(data.map(datum => datum.total)), 7)\n let max = 0\n for (const datum of data) if (datum.total > max) max = datum.total\n let firstDow = 0\n if (data.length > 0) {\n const dt = new Date(`${data[0].date}T00:00:00`)\n firstDow = Number.isNaN(dt.getTime()) ? 0 : dt.getDay()\n }\n const cells: Array<HeatDatum | null> = []\n for (let i = 0; i < firstDow; i++) cells.push(null)\n for (const datum of data) cells.push(datum)\n while (cells.length % 7 !== 0) cells.push(null)\n\n const weeks: Array<Array<HeatDatum | null>> = []\n for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7))\n\n // Label a column with its month when it is the first column of that month.\n let lastMonth = ''\n const monthLabels = weeks.map(week => {\n const first = week.find(cell => cell !== null)\n if (first === undefined || first === null) return ''\n const month = first.date.slice(0, 7)\n if (month === lastMonth) return ''\n lastMonth = month\n return t(`chart.month${Number(first.date.slice(5, 7))}` as LocaleKey)\n })\n\n const levelOf = (total: number): number => {\n if (total <= 0) return 0\n const r = max > 0 ? total / max : 0\n return r < 0.25 ? 1 : r < 0.5 ? 2 : r < 0.75 ? 3 : 4\n }\n\n return (\n <div className=\"dq-heat dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-heat-scroll\">\n <div className=\"dq-heatmap\">\n {weeks.map((week, w) => (\n <div key={w} className=\"dq-heat-week\">\n {week.map((datum, d) => {\n if (datum === null) return <div key={d} className=\"dq-heat-cell dq-heat-cell--pad\" />\n const text = t('chart.tooltip', {\n head: datum.date,\n tokens: datum.total.toLocaleString(intlLocale(locale)),\n cost: datum.cost.toFixed(2),\n calls: t('common.calls', { count: datum.calls }),\n })\n const index = w * 7 + d - firstDow\n return (\n <div\n key={d}\n className={`dq-heat-cell${pinned === index ? ' dq-heat-cell--pinned' : ''}`}\n style={{ background: heatColor(levelOf(datum.total)) }}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={index === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[index] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, index, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, index)}\n />\n )\n })}\n </div>\n ))}\n </div>\n <div className=\"dq-heat-months\" aria-hidden=\"true\">\n {monthLabels.map((label, i) => <div key={i} className=\"dq-heat-month\">{label}</div>)}\n </div>\n </div>\n <ChartTip tip={tip} />\n <div className=\"dq-heat-scale\">\n <span>{t('chart.less')}</span>\n {[0, 1, 2, 3, 4].map(level => (\n <span key={level} className=\"dq-heat-key\" style={{ background: heatColor(level) }} />\n ))}\n <span>{t('chart.more')}</span>\n </div>\n </div>\n )\n}\n\nexport const fmt = (v: string | number): string => {\n const n = Number(v)\n if (!Number.isFinite(n)) return String(v)\n return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n}\n\nexport const fmtInt = (v: number | undefined): string => Math.round(Number(v) || 0).toLocaleString()\n\n/**\n * Compact token/count formatting. English delegates to `Intl` compact notation;\n * Simplified Chinese keeps the \u4E07/\u4EBF scale words because \"1.6\u4E07 tokens\" reads\n * faster than \"16K tokens\" to Chinese readers.\n * @param v - raw number of tokens or calls.\n * @param locale - active plugin locale; defaults to Simplified Chinese.\n * @returns the compact string.\n */\nexport const fmtCompact = (v: number | undefined, locale: LocaleId = 'zh'): string => {\n const n = Number(v) || 0\n if (locale === 'en') {\n return new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(n)\n }\n if (n >= 100_000_000) return `${(n / 100_000_000).toFixed(1)}\u4EBF`\n if (n >= 10_000) return `${(n / 10_000).toFixed(1)}\u4E07`\n return Math.round(n).toLocaleString()\n}\n", "export type ChartFocusKey = 'ArrowLeft' | 'ArrowRight' | 'ArrowUp' | 'ArrowDown' | 'Home' | 'End'\n\n/** Resolve roving focus without adding every chart point to the page Tab order. */\nexport function nextChartFocus(\n current: number,\n count: number,\n key: ChartFocusKey,\n horizontalStep = 1,\n): number {\n if (count <= 0) return 0\n const index = Math.min(Math.max(0, current), count - 1)\n if (key === 'Home') return 0\n if (key === 'End') return count - 1\n const step = key === 'ArrowLeft' || key === 'ArrowRight' ? Math.max(1, horizontalStep) : 1\n const direction = key === 'ArrowLeft' || key === 'ArrowUp' ? -1 : 1\n return Math.min(Math.max(0, index + direction * step), count - 1)\n}\n\nexport function lastPopulatedIndex(values: number[]): number {\n for (let index = values.length - 1; index >= 0; index -= 1) {\n if (values[index] > 0) return index\n }\n return Math.max(0, values.length - 1)\n}\n\n/**\n * Touch tap toggles a chart point's tooltip pin: tapping the already-pinned\n * point releases it, tapping any other point (or none pinned yet) pins that\n * one instead. Shared by bar, grouped-bar and heatmap touch handling so pin\n * state never forks into a parallel machine per chart type.\n */\nexport function nextPinnedIndex(current: number | null, tapped: number): number | null {\n return current === tapped ? null : tapped\n}\n\n/**\n * Distinguishes a tap from a scroll/drag using the touch/pointer start-to-end\n * displacement and elapsed time. A page scroll that merely passes over a data\n * point moves well past `moveThreshold` before release; a long press held past\n * `timeThreshold` without lifting is not a quick tap either.\n */\nexport function isTapGesture(dx: number, dy: number, dt: number, moveThreshold = 10, timeThreshold = 500): boolean {\n return Math.hypot(dx, dy) <= moveThreshold && dt <= timeThreshold\n}\n\n/**\n * Per-slot totals across every series of a stacked bar chart: each column's\n * height must reflect the *summed* usage of every selected model at that\n * time slot, not any single model's value \u2014 otherwise a column with many\n * small models would look shorter than a column with one large one even\n * though it represents more total usage.\n */\nexport function stackedTotals(series: Array<{ bars: Array<{ value: number }> }>, count: number): number[] {\n return Array.from({ length: count }, (_, i) => series.reduce((sum, s) => sum + (s.bars[i]?.value ?? 0), 0))\n}\n\n/**\n * Highest value in the list, or 1 when every value is zero \u2014 the shared\n * fallback scale so an all-zero chart still divides safely instead of by 0.\n */\nexport function maxOrOne(values: number[]): number {\n let max = 0\n for (const v of values) if (v > max) max = v\n return max > 0 ? max : 1\n}\n", "import { createContext, useContext, type ReactElement, type ReactNode } from 'react'\nimport { zh, type LocaleKey } from './locales.ts'\n\n/**\n * Locales this plugin ships copy for: DSH's two built-in locales \u2014 Simplified\n * Chinese (`zh`, the host's own id) and English (`en`). The plugin keeps the\n * host's language catalog untouched on purpose: language selection stays a DSH\n * setting, and contributing a plugin-private third language would leave the\n * host UI and this dashboard speaking different languages, because no other\n * package ships a dictionary for it.\n */\nexport type LocaleId = 'zh' | 'en'\n\n/**\n * BCP 47 tags handed to `Intl` for date and number formatting. These are a\n * different vocabulary from {@link LocaleId}: the DSH id also addresses\n * dictionaries and the persisted language preference, while `Intl` wants a tag\n * with settled regional conventions. `zh` maps to `zh-CN`, matching the host's\n * internal document tag for its Simplified dictionary.\n */\nconst INTL_LOCALES: Record<LocaleId, string> = {\n zh: 'zh-CN',\n en: 'en-US',\n}\n\n/**\n * Resolve the `Intl` tag for a plugin locale.\n * @param locale - active plugin locale.\n * @returns the BCP 47 tag to pass to `Intl.*` / `toLocaleString`.\n */\nexport function intlLocale(locale: LocaleId): string {\n return INTL_LOCALES[locale]\n}\n\nexport type Translate = (key: LocaleKey, params?: Record<string, unknown>) => string\n\nexport const fallbackT: Translate = (key, params) => {\n const template = zh[key]\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n}\n\nconst TranslationContext = createContext<Translate>(fallbackT)\n\nexport function LocaleProvider(props: { t: Translate; children: ReactNode }): ReactElement {\n return <TranslationContext.Provider value={props.t}>{props.children}</TranslationContext.Provider>\n}\n\n/**\n * Read the translate function plus the concrete locale it is bound to. The\n * identity rides the dictionary itself (`meta.locale`), because slot components\n * receive only the `t` seat, not the host's locale snapshot; every dictionary\n * stores its own id there, so a language switch moves both together.\n * @returns the active `t` and the plugin locale it resolves to.\n */\nexport function useI18n(): { t: Translate; locale: LocaleId } {\n const t = useContext(TranslationContext)\n return { t, locale: t('meta.locale') === 'en' ? 'en' : 'zh' }\n}\n\n/** Translate host error copy that predates stable machine-readable error codes. */\nexport function localizeApiError(message: string | undefined, t: Translate, fallback: LocaleKey): string {\n if (message === undefined || message === '') return t(fallback)\n if (message === '\u51ED\u8BC1\u670D\u52A1\u4E0D\u53EF\u7528') return t('error.credentialsUnavailable')\n if (message === '\u67E5\u8BE2\u5931\u8D25') return t('error.query')\n if (message === '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25') return t('error.balanceLoad')\n if (message === '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25') return t('error.usageLoad')\n if (message === '\u672A\u914D\u7F6E DEEPSEEK_API_KEY\uFF08\u53EF\u5728\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u4E2D\u586B\u5199\uFF09') return t('error.noApiKey')\n if (message === '\u8D26\u53F7\u4F59\u989D\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u4E14\u672A\u914D\u7F6E DEEPSEEK_API_KEY') return t('error.accountBalanceUnavailable')\n if (message === '\u89E3\u6790\u4F59\u989D\u54CD\u5E94\u5931\u8D25') return t('error.balanceParse')\n if (message === '\u4F1A\u8BDD\u6301\u4E45\u5316\u670D\u52A1\u4E0D\u53EF\u7528') return t('error.persistenceUnavailable')\n if (message === '\u7F3A\u5C11\u4F1A\u8BDD id') return t('error.missingSessionId')\n const mappings: Array<[RegExp, LocaleKey, string]> = [\n [/^\u8BFB\u53D6 API Key \u5931\u8D25\uFF1A(.*)$/, 'error.credentialRead', 'detail'],\n [/^\u8BF7\u6C42\u4F59\u989D\u63A5\u53E3\u5931\u8D25\uFF1A(.*)$/, 'error.balanceRequest', 'detail'],\n [/^\u4F59\u989D\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP (\\d+)\uFF09$/, 'error.balanceHttp', 'status'],\n [/^\u8BFB\u53D6\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF1A(.*)$/, 'error.sessionList', 'detail'],\n [/^\u8BFB\u53D6\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A(.*)$/, 'error.sessionLogRead', 'detail'],\n ]\n for (const [pattern, key, field] of mappings) {\n const match = message.match(pattern)\n if (match !== null) return t(key, { [field]: match[1] })\n }\n return message\n}\n", "/** Locale namespace and complete bilingual copy for the dashboard surfaces. */\nexport const NS = 'dsh-usage-dashboard'\n\nexport const zh = {\n 'meta.locale': 'zh',\n 'nav.quota': '\u989D\u5EA6',\n 'widget.title': 'DeepSeek \u989D\u5EA6',\n 'common.unknownModel': '\u672A\u77E5\u6A21\u578B',\n 'common.calls': '{count} \u6B21\u8C03\u7528',\n 'common.callsShort': '{count} \u6B21',\n 'common.sessions': '{count} \u4E2A\u4F1A\u8BDD',\n 'common.records': '{count} \u6761',\n 'common.rows': '{count} \u884C',\n 'common.input': '\u8F93\u5165',\n 'common.output': '\u8F93\u51FA',\n 'common.cacheHit': '\u7F13\u5B58\u547D\u4E2D',\n 'common.status': '\u72B6\u6001',\n 'common.available': '\u53EF\u7528',\n 'common.unavailable': '\u4E0D\u53EF\u7528',\n 'common.justNow': '\u521A\u521A',\n 'common.minutesAgo': '{count} \u5206\u949F\u524D',\n 'common.hoursAgo': '{count} \u5C0F\u65F6\u524D',\n 'common.daysAgo': '{count} \u5929\u524D',\n 'common.listSeparator': '\u3001',\n 'common.period': '\u3002',\n 'delta.noBaselineTitle': '{label}\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u4ECE\u5BF9\u6BD4',\n 'delta.noBaseline': '\u65E0\u5BF9\u6BD4',\n 'delta.flat': '\u6301\u5E73',\n 'period.volume': '{tokens} tokens \u00B7 {calls}',\n 'budget.unset': '\u672A\u8BBE\u7F6E\u6708\u5EA6\u9884\u7B97\u3002',\n 'budget.configure': '\u8BBE\u7F6E\u9884\u7B97',\n 'budget.over': '\u5DF2\u8D85\u9884\u7B97 \u00A5{amount}',\n 'budget.forecastOver': '\u7167\u5F53\u524D\u901F\u5EA6\uFF0C\u9884\u8BA1\u8D85\u51FA \u00A5{amount}',\n 'budget.forecast': '\u7167\u5F53\u524D\u901F\u5EA6\uFF0C\u9884\u8BA1\u6708\u5E95 \u00A5{amount}',\n 'budget.title': '\u672C\u6708\u9884\u7B97',\n 'budget.progressLabel': '\u672C\u6708\u9884\u7B97\u4F7F\u7528\u8FDB\u5EA6',\n 'budget.used': '\u5DF2\u4F7F\u7528 {percent}%\uFF0C{forecast}',\n 'budget.remaining': '\u5269\u4F59 \u00A5{amount}',\n 'budget.exceeded': '\u8D85\u51FA \u00A5{amount}',\n 'pricing.title': '\u8BA1\u4EF7\u8BF4\u660E',\n 'pricing.currentPeak': '\u5F53\u524D \u9AD8\u5CF0\u65F6\u6BB5',\n 'pricing.currentOffPeak': '\u5F53\u524D \u95F2\u65F6',\n 'pricing.model': '\u6A21\u578B',\n 'pricing.period': '\u65F6\u6BB5',\n 'pricing.inputCacheHit': '\u8F93\u5165\u00B7\u7F13\u5B58\u547D\u4E2D',\n 'pricing.inputCacheMiss': '\u8F93\u5165\u00B7\u672A\u547D\u4E2D',\n 'pricing.output': '\u8F93\u51FA',\n 'pricing.peak': '\u9AD8\u5CF0',\n 'pricing.offPeak': '\u95F2\u65F6',\n 'pricing.unit': '\u5355\u4F4D\uFF1A{currency} / \u767E\u4E07 tokens\u3002',\n 'pricing.splitNote': '\u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 {windows}\uFF08\u5468\u4E00\u81F3\u5468\u4E94\uFF09\uFF0C\u5176\u4F59\u4E3A\u95F2\u65F6\uFF08\u4EF7\u683C\u51CF\u534A\uFF09\uFF1B\u6BCF\u6761\u7528\u91CF\u6309\u53D1\u751F\u65F6\u523B\u751F\u6548\u7684\u5B98\u65B9\u4EF7\u683C\u4F30\u7B97\u3002',\n 'pricing.visionNote': '\u56FE\u7247\u6309\u5C3A\u5BF8\u6298\u7B97 token\uFF0C\u4E0E\u6587\u672C\u4E00\u5E76\u8BA1\u8D39\u3002',\n 'pricing.unknown': '\u672A\u77E5\u6A21\u578B\u6309 deepseek-v4-pro \u8BA1\u4EF7\u3002',\n 'coverage.noRange': '\u6682\u65E0\u6709\u6548\u7528\u91CF\u65F6\u95F4',\n 'coverage.title': '\u7EDF\u8BA1\u8303\u56F4',\n 'coverage.gaps': '\u5B58\u5728\u7F3A\u53E3',\n 'coverage.complete': '\u672C\u673A\u8BFB\u53D6\u5B8C\u6574',\n 'coverage.brief': '\u626B\u63CF {scanned} / {listed} \u4E2A\u4F1A\u8BDD \u00B7 {records} \u6761\u7528\u91CF\u8BB0\u5F55',\n 'coverage.scanned': '\u6210\u529F\u626B\u63CF',\n 'coverage.failed': '\u8BFB\u53D6\u5931\u8D25',\n 'coverage.skipped': '\u8DF3\u8FC7\u8BB0\u5F55',\n 'coverage.time': '\u8BB0\u5F55\u65F6\u95F4\uFF1A{range}',\n 'coverage.scope': '\u8FD9\u91CC\u53EA\u7EDF\u8BA1\u5F53\u524D\u8BBE\u5907\u4E0A\u7684 DSH \u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u4E0D\u5305\u542B\u5176\u4ED6\u8BBE\u5907\u3001DeepSeek \u5E73\u53F0\u76F4\u63A5\u8C03\u7528\u6216\u5DF2\u5220\u9664\u7684\u672C\u5730\u65E5\u5FD7\u3002',\n 'coverage.warning': '\u672C\u6B21\u56DE\u653E\u6709\u65E5\u5FD7\u65E0\u6CD5\u8BFB\u53D6\u6216\u7528\u91CF\u8BB0\u5F55\u683C\u5F0F\u5F02\u5E38\uFF0C\u9875\u9762\u6C47\u603B\u53EF\u80FD\u4F4E\u4E8E\u5B9E\u9645\u6D88\u8017\uFF1B\u53EF\u5237\u65B0\u91CD\u8BD5\uFF0C\u5E76\u4EE5 DeepSeek \u5B98\u65B9\u5E73\u53F0\u8D26\u5355\u4E3A\u51C6\u3002',\n 'export.title': '\u5BFC\u51FA\u5168\u90E8\u672C\u673A DSH \u4F1A\u8BDD\u65E5\u5FD7\u6570\u636E\uFF08\u4E0D\u53D7\u7EDF\u8BA1\u5468\u671F\u5F71\u54CD\uFF09',\n 'export.done': '\u5DF2\u5BFC\u51FA',\n 'export.action': '\u5BFC\u51FA',\n 'export.menuLabel': '\u9009\u62E9\u5BFC\u51FA\u683C\u5F0F',\n 'export.dailyCsv': '\u9010\u5929 CSV',\n 'export.modelCsv': '\u9010\u6A21\u578B CSV',\n 'export.fullJson': '\u5B8C\u6574 JSON',\n 'export.jsonHint': '\u542B\u56FE\u8868\u4E0E\u6392\u884C',\n 'cache.empty': '\u6682\u65E0\u7F13\u5B58\u547D\u4E2D\u6570\u636E\u3002',\n 'cache.rate': '\u7F13\u5B58\u547D\u4E2D\u7387',\n 'cache.saved': '\u8F83\u5168\u672A\u547D\u4E2D\u7701\u4E0B',\n 'cache.allMiss': '\u82E5\u5168\u672A\u547D\u4E2D',\n 'cache.aria': '\u7F13\u5B58\u547D\u4E2D {hit}%\uFF0C\u672A\u547D\u4E2D {miss}%',\n 'cache.hitLegend': '\u7F13\u5B58\u547D\u4E2D {tokens}',\n 'cache.missLegend': '\u672A\u547D\u4E2D {tokens}\uFF08\u6309\u672A\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF09',\n 'cache.basis': '\u5B9E\u4ED8 \u00A5{cost}\uFF1B\u82E5\u5168\u90E8\u672A\u547D\u4E2D\u7EA6 \u00A5{miss}\uFF0C\u4E24\u8005\u5DEE\u989D\u5373\u547D\u4E2D\u7F13\u5B58\u7701\u4E0B\u7684\u8D39\u7528\u3002',\n 'peak.empty': '\u6682\u65E0\u7528\u91CF\u3002',\n 'peak.aria': '\u9AD8\u5CF0\u65F6\u6BB5 {peak}%\uFF0C\u95F2\u65F6 {offPeak}%',\n 'peak.peakLegend': '\u9AD8\u5CF0 {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.offPeakLegend': '\u95F2\u65F6 {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.shift': '\u9AD8\u5CF0\u6539\u8D70\u95F2\u65F6\u53EF\u7701',\n 'peak.saving': '\u00A5{amount}',\n 'peak.basis': '\u5168\u90E8\u6539\u8D70\u95F2\u65F6\u7EA6 \u00A5{total}\uFF1B\u6B64\u5904\u6309\u5F53\u524D\u4EF7\u76EE\u4F30\u7B97\uFF0C\u4E0E\u300C\u6D88\u8017\u6982\u89C8 \u00B7 \u7D2F\u8BA1\u300D\u7684\u5B9E\u9645\u82B1\u8D39\u53E3\u5F84\u4E0D\u540C\u3002',\n 'peak.clockTitle': '\u4ECA\u65E5\u4EF7\u683C\u65F6\u6BB5',\n 'peak.nowPeak': '\u73B0\u5728\u9AD8\u5CF0 \u00B7 \u5168\u4EF7',\n 'peak.nowOff': '\u73B0\u5728\u95F2\u65F6 \u00B7 \u534A\u4EF7',\n 'peak.clockAria': '24 \u5C0F\u65F6\u4EF7\u683C\u65F6\u6BB5\uFF0C{state}',\n 'peak.clockHint': '\u5DE5\u4F5C\u65E5 09\u201312\u300114\u201318 \u4E3A\u9AD8\u5CF0\uFF0C\u5176\u4F59\u65F6\u6BB5\u534A\u4EF7\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09',\n 'vision.empty': '{window}\u6CA1\u6709\u56FE\u7247\u8F93\u5165\u3002',\n 'vision.title': '\u56FE\u7247 / \u591A\u6A21\u6001\u7528\u91CF',\n 'vision.images': '\u56FE\u7247\u5F20\u6570',\n 'vision.tokens': '\u4F30\u7B97\u56FE\u7247 tokens',\n 'vision.cost': '\u4F30\u7B97\u8D39\u7528',\n 'vision.tokensShare': '\u5360\u8F93\u5165 {percent}%',\n 'vision.costShare': '\u5360\u8D39\u7528 {percent}%',\n 'vision.note': '\u6309\u5B98\u65B9\u89C4\u5219\u4F30\u7B97\uFF0C\u5B9E\u9645\u4EE5\u63A5\u53E3\u8FD4\u56DE\u7684\u7528\u91CF\u4E3A\u51C6\u3002',\n 'vision.sessionsTitle': '\u56FE\u7247\u6700\u591A\u7684\u4F1A\u8BDD',\n 'vision.sessionRow': '{images} \u5F20 \u00B7 \u00A5{cost}',\n 'vision.dailyTitle': '{window} \u00B7 \u6BCF\u5929\u56FE\u7247\u6570',\n 'vision.barAria': '{date} \u00B7 {images} \u5F20\u56FE\u7247 \u00B7 \u4F30\u7B97 {tokens} tokens',\n 'vision.barTitle': '{date} \u00B7 {images} \u5F20\u56FE\u7247 \u00B7 \u4F30\u7B97 {tokens} tokens \u00B7 \u00A5{cost}',\n 'sessions.empty': '\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002',\n 'sessions.detail': '{tokens} tokens \u00B7 {calls} \u00B7 {ago}',\n 'sessions.share': '\u5360 {percent}%',\n 'sessions.more': '\u5171 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u663E\u793A\u6700\u8D35\u7684 {shown} \u4E2A\u3002',\n 'sessions.fallbackTitle': '\u4F1A\u8BDD {id}',\n 'models.empty': '\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002',\n 'models.shareAria': '{name} \u5360\u603B\u8D39\u7528 {percent}%',\n 'models.detail': '{tokens} tokens \u00B7 {calls} \u00B7 \u8F93\u5165 {input} / \u8F93\u51FA {output} / \u7F13\u5B58 {cache}',\n 'models.all': '\u5168\u90E8\u6A21\u578B',\n 'models.selected': '\u6A21\u578B \u00D7{count}',\n 'models.filterTitle': '\u7B5B\u9009\u56FE\u8868\u4E2D\u663E\u793A\u7684\u6A21\u578B',\n 'models.filterLabel': '\u7B5B\u9009\u56FE\u8868\u6A21\u578B',\n 'window.year': '\u8FD1 1 \u5E74',\n 'window.days': '\u8FD1 {days} \u5929',\n 'window.groupLabel': '\u7EDF\u8BA1\u5468\u671F',\n 'window.viewTitle': '\u67E5\u770B{window}\u7684\u7528\u91CF\u4E0E\u6392\u884C',\n 'window.yearButton': '1 \u5E74',\n 'window.daysButton': '{days} \u5929',\n 'metric.tokens': 'tokens',\n 'metric.usage': '\u7528\u91CF',\n 'metric.cost': '\u8D39\u7528',\n 'metric.calls': '\u8C03\u7528',\n 'metric.groupLabel': '\u56FE\u8868\u6307\u6807',\n 'metric.compareTitle': '\u6309{metric}\u6BD4\u8F83',\n 'chart.dailyTitle': '{window} \u00B7 \u9010\u5929{metric}',\n 'chart.hourlyTitle': '{window} \u00B7 {metric}\u6309\u5C0F\u65F6\u5206\u5E03\uFF080\u201323 \u70B9\uFF09',\n 'chart.peak': '\u5CF0\u503C {value}',\n 'chart.dimensionLabel': '\u5207\u6362\u56FE\u8868\u7EF4\u5EA6',\n 'chart.daily': '\u9010\u5929',\n 'chart.hourly': '\u9010\u5C0F\u65F6',\n 'chart.noWindowData': '{window}\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002',\n 'chart.heatmapTitle': '\u8FD1\u4E00\u5E74 \u00B7 \u6BCF\u65E5',\n 'chart.empty': '\u8FD8\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002',\n 'chart.hourPoint': '{hour} \u70B9',\n 'chart.tooltip': '{head} \u00B7 {tokens} tokens \u00B7 \u00A5{cost} \u00B7 {calls}',\n 'chart.less': '\u5C11',\n 'chart.more': '\u591A',\n 'chart.month1': '1\u6708',\n 'chart.month2': '2\u6708',\n 'chart.month3': '3\u6708',\n 'chart.month4': '4\u6708',\n 'chart.month5': '5\u6708',\n 'chart.month6': '6\u6708',\n 'chart.month7': '7\u6708',\n 'chart.month8': '8\u6708',\n 'chart.month9': '9\u6708',\n 'chart.month10': '10\u6708',\n 'chart.month11': '11\u6708',\n 'chart.month12': '12\u6708',\n 'number.tenThousand': '{value}\u4E07',\n 'number.hundredMillion': '{value}\u4EBF',\n 'fresh.none': '\u5C1A\u65E0\u6210\u529F\u8BB0\u5F55',\n 'fresh.justNow': '\u521A\u521A\u66F4\u65B0',\n 'fresh.minutes': '\u66F4\u65B0\u4E8E {count} \u5206\u949F\u524D',\n 'fresh.hours': '\u66F4\u65B0\u4E8E {count} \u5C0F\u65F6\u524D',\n 'fresh.days': '\u66F4\u65B0\u4E8E {count} \u5929\u524D',\n 'sync.first': '\u9996\u6B21\u540C\u6B65\u4E2D',\n 'sync.syncing': '\u540C\u6B65\u4E2D \u00B7 \u5F53\u524D\u6570\u636E{age}',\n 'sync.fresh': '\u5DF2\u540C\u6B65 \u00B7 {age}',\n 'sync.cached': '\u672C\u5730\u7F13\u5B58 \u00B7 {age}',\n 'sync.fallback': '\u7F13\u5B58\u56DE\u9000 \u00B7 {age}',\n 'sync.error': '\u540C\u6B65\u5931\u8D25 \u00B7 \u6682\u65E0\u53EF\u663E\u793A\u7684\u7528\u91CF',\n 'status.neverSynced': '\u8FD8\u6CA1\u6709\u6210\u529F\u540C\u6B65\u8FC7\u7528\u91CF\u6570\u636E',\n 'status.usageTime': '\u7528\u91CF\u6570\u636E\u65F6\u95F4\uFF1A{time}',\n 'status.forceRefresh': '\u5F3A\u5236\u5237\u65B0\uFF08\u7ED5\u8FC7\u7F13\u5B58\uFF09',\n 'status.refreshing': '\u5237\u65B0\u4E2D',\n 'status.refresh': '\u5237\u65B0',\n 'error.balanceLoad': '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25',\n 'error.usageLoad': '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25',\n 'error.refreshCached': '\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u6570\u636E\uFF08{error}\uFF09',\n 'error.balanceRefreshCached': '\u4F59\u989D\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u4F59\u989D\uFF08{error}\uFF09',\n 'error.usageRefreshCached': '\u7528\u91CF\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u7528\u91CF\uFF08{error}\uFF09',\n 'error.query': '\u67E5\u8BE2\u5931\u8D25',\n 'error.credentialsUnavailable': '\u51ED\u8BC1\u670D\u52A1\u4E0D\u53EF\u7528',\n 'error.credentialRead': '\u8BFB\u53D6 API Key \u5931\u8D25\uFF1A{detail}',\n 'error.noApiKey': '\u672A\u914D\u7F6E DEEPSEEK_API_KEY\uFF08\u53EF\u5728\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u4E2D\u586B\u5199\uFF09',\n 'error.accountBalanceUnavailable': '\u8D26\u53F7\u4F59\u989D\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u4E14\u672A\u914D\u7F6E DEEPSEEK_API_KEY',\n 'error.balanceRequest': '\u8BF7\u6C42\u4F59\u989D\u63A5\u53E3\u5931\u8D25\uFF1A{detail}',\n 'error.balanceHttp': '\u4F59\u989D\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP {status}\uFF09',\n 'error.balanceParse': '\u89E3\u6790\u4F59\u989D\u54CD\u5E94\u5931\u8D25',\n 'error.persistenceUnavailable': '\u4F1A\u8BDD\u6301\u4E45\u5316\u670D\u52A1\u4E0D\u53EF\u7528',\n 'error.sessionList': '\u8BFB\u53D6\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF1A{detail}',\n 'error.sessionLogRead': '\u8BFB\u53D6\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A{detail}',\n 'error.missingSessionId': '\u7F3A\u5C11\u4F1A\u8BDD id',\n 'alert.lowTitle': '\u4F59\u989D {balance} {currency} \u5DF2\u4F4E\u4E8E\u9884\u8B66\u7EBF {threshold}',\n 'alert.runway': '\uFF0C\u6309\u8FD1\u671F\u7528\u91CF\u4F30\u8BA1\u8FD8\u80FD\u6491 {days}',\n 'alert.topUp': '\u53BB\u5145\u503C',\n 'balance.title': '\u8D26\u6237\u4F59\u989D',\n 'balance.remaining': '\u5269\u4F59\u4F59\u989D',\n 'balance.breakdownTitle': '\u67E5\u770B\u5145\u503C\u4E0E\u8D60\u9001\u989D\u5EA6\u660E\u7EC6',\n 'balance.toppedUp': '\u5145\u503C\u989D\u5EA6 {amount}',\n 'balance.granted': '\u8D60\u9001\u989D\u5EA6 {amount}',\n 'balance.runway': '\u9884\u8BA1\u53EF\u7528',\n 'balance.runwayBreakdownTitle': '\u67E5\u770B\u9884\u8BA1\u53EF\u7528\u5929\u6570\u8BF4\u660E',\n 'balance.topUpTitle': '\u4F59\u989D\u504F\u4F4E\uFF0C\u524D\u5F80 DeepSeek \u5F00\u653E\u5E73\u53F0\u5145\u503C\uFF08\u65B0\u6807\u7B7E\u9875\u6253\u5F00\uFF09',\n 'balance.days': '{count} \u5929',\n 'balance.overYear': '> 365 \u5929',\n 'balance.noRunway': '\u8FD1 {days} \u5929\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u6CD5\u4F30\u7B97',\n 'balance.runwayTitle': '\u6309\u8FD1 {days} \u5929\u65E5\u5747 \u00A5{cost} \u4F30\u7B97\uFF08\u542B\u65E0\u7528\u91CF\u7684\u65E5\u5B50\uFF1B\u4ECA\u5929\u5C1A\u672A\u8FC7\u5B8C\uFF09',\n 'balance.empty': '\u8BFB\u4E0D\u5230\u4F59\u989D\uFF0C\u8BF7\u68C0\u67E5\u8D26\u53F7\u767B\u5F55\u6216 API Key \u540E\u5237\u65B0\u3002',\n 'sessionUsage.title': '\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017',\n 'common.estimated': '\u8D39\u7528\u4E3A\u4F30\u7B97',\n 'sessionUsage.cost': '\u8D39\u7528',\n 'sessionUsage.tokens': 'Tokens',\n 'sessionUsage.calls': '\u8C03\u7528\u6B21\u6570',\n 'sessionUsage.range': '\u6D3B\u8DC3\u65F6\u95F4 {range}',\n 'sessionUsage.single': '{model} \u00B7 \u8F93\u5165 {input} / \u8F93\u51FA {output} / \u7F13\u5B58 {cache}',\n 'sessionUsage.empty': '\u8FD9\u4E2A\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7528\u91CF\u3002',\n 'overview.title': '\u6D88\u8017\u6982\u89C8',\n 'overview.today': '\u4ECA\u65E5',\n 'overview.month': '\u672C\u6708',\n 'overview.total': '\u7D2F\u8BA1',\n 'overview.vsYesterday': '\u8F83\u6628\u65E5',\n 'overview.vsLastMonth': '\u8F83\u4E0A\u6708\u540C\u671F',\n 'overview.empty': '\u8FD8\u6CA1\u6709\u53EF\u7EDF\u8BA1\u7684\u6D88\u8017\u3002',\n 'usage.trendTitle': '\u7528\u91CF\u8D8B\u52BF',\n 'usage.windowInput': '{window}\u8F93\u5165',\n 'usage.modelCalls': '\u6A21\u578B\u8C03\u7528',\n 'heatmap.title': '\u7528\u91CF\u70ED\u529B\u56FE',\n 'peak.title': '\u9AD8\u5CF0 / \u95F2\u65F6\u5206\u5E03',\n 'cache.title': '\u7F13\u5B58\u547D\u4E2D\u4E0E\u8282\u7701',\n 'models.title': '\u6A21\u578B\u6210\u672C\u6392\u884C',\n 'sessions.title': '\u4F1A\u8BDD\u6210\u672C\u6392\u884C',\n 'links.title': '\u5FEB\u6377\u5165\u53E3',\n 'nav.label': '\u9875\u9762\u5927\u7EB2',\n 'nav.balance': '\u4F59\u989D',\n 'nav.session': '\u5F53\u524D\u4F1A\u8BDD',\n 'nav.overview': '\u6D88\u8017\u6982\u89C8',\n 'nav.trend': '\u7528\u91CF\u8D8B\u52BF',\n 'nav.heatmap': '\u7528\u91CF\u70ED\u529B\u56FE',\n 'nav.models': '\u6A21\u578B\u6210\u672C\u6392\u884C',\n 'nav.sessions': '\u4F1A\u8BDD\u6210\u672C\u6392\u884C',\n 'nav.peakcache': '\u9AD8\u5CF0 / \u7F13\u5B58',\n 'nav.settings': '\u8BBE\u7F6E',\n 'links.usage': '\u67E5\u770B\u989D\u5EA6 / \u7528\u91CF',\n 'links.apiKey': '\u751F\u6210 API Key',\n 'links.status': '\u670D\u52A1\u72B6\u6001',\n 'settings.title': '\u8BBE\u7F6E',\n 'settings.groupDisplay': '\u663E\u793A',\n 'settings.groupAlerts': '\u63D0\u9192',\n 'settings.groupLayout': '\u5E03\u5C40\u4E0E\u5165\u53E3',\n 'settings.widget': '\u5728\u5176\u4ED6\u9875\u9762\u663E\u793A\u53F3\u4E0B\u89D2\u60AC\u6D6E\u989D\u5EA6\u7A97\u53E3',\n 'settings.widgetHint': '\u989D\u5EA6\u9875\u81EA\u52A8\u9690\u85CF\uFF1B\u5176\u4ED6\u9875\u9762\u6309\u4E0B\u65B9\u9009\u62E9\u663E\u793A\u3002',\n 'settings.widgetTabs': '\u5C55\u793A\u6D6E\u7A97\u7684\u9875\u9762',\n 'settings.widgetTabsHint': '\u5217\u8868\u4F1A\u968F\u5DF2\u5B89\u88C5\u7684\u9875\u9762\u81EA\u52A8\u66F4\u65B0\u3002',\n 'settings.widgetTabsEmpty': '\u5F53\u524D\u6CA1\u6709\u53EF\u914D\u7F6E\u7684\u4F1A\u8BDD\u9875\u9762\u3002',\n 'settings.lowBalance': '\u4F59\u989D\u9884\u8B66\u7EBF',\n 'settings.lowBalanceOn': '\u4F59\u989D\u4F4E\u4E8E {amount} {currency} \u65F6\uFF0C\u8FD9\u91CC\u548C\u60AC\u6D6E\u7A97\u90FD\u4F1A\u8F6C\u4E3A\u8B66\u793A\u8272\u3002\u586B 0 \u5173\u95ED\u3002',\n 'settings.lowBalanceOff': '\u5DF2\u5173\u95ED\u4F59\u989D\u9884\u8B66\u3002\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u6570\u5F00\u542F\u3002',\n 'settings.monthlyBudget': '\u6708\u5EA6\u9884\u7B97',\n 'settings.monthlyBudgetOn': '\u6309\u5317\u4EAC\u65F6\u95F4\u81EA\u7136\u6708\u8DDF\u8E2A {amount} CNY \u9884\u7B97\uFF0C\u5E76\u5728\u6D88\u8017\u6982\u89C8\u9884\u6D4B\u6708\u5E95\u82B1\u8D39\u3002\u586B 0 \u5173\u95ED\u3002',\n 'settings.monthlyBudgetOff': '\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u91D1\u989D\uFF0C\u6D88\u8017\u6982\u89C8\u4F1A\u663E\u793A\u8FDB\u5EA6\u4E0E\u6708\u5E95\u9884\u6D4B\u3002',\n 'settings.sidebarEntry': '\u4FA7\u8FB9\u680F\u989D\u5EA6\u5165\u53E3',\n 'settings.sidebarEntryHint': '\u5728\u4FA7\u8FB9\u680F\u9876\u90E8\u6216\u5E95\u90E8\u653E\u4E00\u4E2A\u300C\u989D\u5EA6\u300D\u5165\u53E3\uFF0C\u6253\u5F00\u8D26\u6237\u7EA7\u989D\u5EA6\u9875\u3002',\n 'settings.sidebarEntryOff': '\u5173\u95ED',\n 'settings.sidebarEntryTop': '\u9876\u90E8',\n 'settings.sidebarEntryBottom': '\u5E95\u90E8',\n 'settings.tabPosition': '\u300C\u989D\u5EA6\u300D\u6807\u7B7E\u4F4D\u7F6E',\n 'settings.tabPositionHint': '\u62D6\u52A8\u300C\u989D\u5EA6\u300D\u8C03\u6574\u6807\u7B7E\u4F4D\u7F6E\u3002',\n 'settings.tabDragAria': '\u62D6\u52A8\u300C\u989D\u5EA6\u300D\u8C03\u6574\u6807\u7B7E\u4F4D\u7F6E',\n 'settings.tabMoveEarlier': '\u524D\u79FB',\n 'settings.tabMoveLater': '\u540E\u79FB',\n 'panel.caption': '\u8D26\u6237\u7EA7 \u00B7 \u8DE8\u5168\u90E8\u4F1A\u8BDD',\n 'panel.openAria': '\u6253\u5F00\u989D\u5EA6\u9875',\n 'widget.updatedNow': '\u521A\u521A\u66F4\u65B0',\n 'widget.stale': '{minutes} \u5206\u949F\u524D\u7684\u6570\u636E\uFF0C\u70B9 \u21BB \u66F4\u65B0',\n 'widget.loading': '\u67E5\u8BE2\u4E2D\u2026',\n 'widget.lowTitle': '\u4F59\u989D\u4F4E\u4E8E\u9884\u8B66\u7EBF {amount}',\n 'widget.todayCostTitle': '\u4ECA\u65E5\u6D88\u8017\uFF08\u4F30\u7B97\uFF09\u00B7 {age}',\n 'widget.todayCost': '\u4ECA\u65E5\u6D88\u8017',\n 'widget.sessionCostTitle': '\u5F53\u524D\u4F1A\u8BDD\u7D2F\u8BA1\u6D88\u8017\uFF08\u4F30\u7B97\uFF09',\n 'widget.sessionCost': '\u5F53\u524D\u4F1A\u8BDD',\n 'widget.noBalance': '\u6682\u65E0\u4F59\u989D\u6570\u636E',\n 'widget.dragCard': '\u62D6\u52A8\u5230\u56DB\u4E2A\u89D2\u843D',\n 'widget.dragGrip': '\u62D6\u52A8\u4EE5\u79FB\u52A8',\n 'widget.refresh': '\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF',\n 'widget.expand': '\u5C55\u5F00',\n 'widget.collapse': '\u6536\u8D77',\n 'widget.expandAria': '\u5C55\u5F00\u989D\u5EA6\u7A97\u53E3',\n 'widget.collapseAria': '\u6536\u8D77\u989D\u5EA6\u7A97\u53E3',\n 'messageCost.label': '\u672C\u8F6E\u8D39\u7528',\n 'sessionCost.title': '\u4F1A\u8BDD\u8D39\u7528',\n 'sessionCost.aria': '\u672C\u4F1A\u8BDD\u4F30\u7B97\u8D39\u7528 {amount}',\n 'sessionCost.active': '\u6D3B\u8DC3\u65F6\u95F4',\n 'messageCost.tooltip': '\u7531 dsh-usage-dashboard \u63D0\u4F9B \u00B7 \u672C\u8F6E\u5BF9\u8BDD\u8D39\u7528\u4E3A\u4F30\u7B97\u503C',\n 'messageCost.aria': '{amount}\uFF0C\u672C\u8F6E\u5BF9\u8BDD\u4F30\u7B97\u8D39\u7528\uFF0C\u7531 dsh-usage-dashboard \u63D0\u4F9B',\n 'boundary.title': '\u989D\u5EA6\u9762\u677F\u51FA\u9519\u4E86',\n 'boundary.body': '\u6E32\u67D3\u65F6\u629B\u4E86\u5F02\u5E38\uFF0C\u901A\u5E38\u662F\u6D4F\u89C8\u5668\u91CC\u5B58\u7740\u65E7\u7248\u672C\u7684\u7F13\u5B58\u6570\u636E\u3002\u6E05\u6389\u672C\u63D2\u4EF6\u7684\u672C\u5730\u6570\u636E\u518D\u91CD\u65B0\u52A0\u8F7D\u5C31\u80FD\u6062\u590D\u3002',\n 'boundary.reset': '\u6E05\u9664\u672C\u5730\u6570\u636E\u5E76\u91CD\u65B0\u52A0\u8F7D',\n} as const\n\nexport type LocaleKey = keyof typeof zh\n\nexport const en: Record<LocaleKey, string> = {\n 'meta.locale': 'en',\n 'nav.quota': 'Usage',\n 'widget.title': 'DeepSeek Usage',\n 'common.unknownModel': 'Unknown model',\n 'common.calls': '{count} calls',\n 'common.callsShort': '{count} calls',\n 'common.sessions': '{count} sessions',\n 'common.records': '{count} records',\n 'common.rows': '{count} rows',\n 'common.input': 'Input',\n 'common.output': 'Output',\n 'common.cacheHit': 'Cache hit',\n 'common.status': 'Status',\n 'common.available': 'Available',\n 'common.unavailable': 'Unavailable',\n 'common.justNow': 'Just now',\n 'common.minutesAgo': '{count}m ago',\n 'common.hoursAgo': '{count}h ago',\n 'common.daysAgo': '{count}d ago',\n 'common.listSeparator': ', ',\n 'common.period': '.',\n 'delta.noBaselineTitle': 'No usage in {label}, so there is no baseline',\n 'delta.noBaseline': 'No baseline',\n 'delta.flat': 'No change',\n 'period.volume': '{tokens} tokens \u00B7 {calls}',\n 'budget.unset': 'No monthly budget set.',\n 'budget.configure': 'Set budget',\n 'budget.over': 'Over budget by \u00A5{amount}',\n 'budget.forecastOver': 'At this pace, \u00A5{amount} over by month-end',\n 'budget.forecast': 'At this pace, \u00A5{amount} by month-end',\n 'budget.title': 'Monthly budget',\n 'budget.progressLabel': 'Monthly budget usage',\n 'budget.used': '{percent}% used. {forecast}',\n 'budget.remaining': '\u00A5{amount} remaining',\n 'budget.exceeded': '\u00A5{amount} over',\n 'pricing.title': 'Pricing details',\n 'pricing.currentPeak': 'Peak now',\n 'pricing.currentOffPeak': 'Off-peak now',\n 'pricing.model': 'Model',\n 'pricing.period': 'Period',\n 'pricing.inputCacheHit': 'Input \u00B7 cache hit',\n 'pricing.inputCacheMiss': 'Input \u00B7 cache miss',\n 'pricing.output': 'Output',\n 'pricing.peak': 'Peak',\n 'pricing.offPeak': 'Off-peak',\n 'pricing.unit': 'Unit: {currency} / million tokens. ',\n 'pricing.splitNote': 'Peak periods are {windows} Beijing time, Monday to Friday; off-peak rates are half price. Each record is estimated at the official rates in force when it was written. ',\n 'pricing.visionNote': 'Images are converted to tokens by size and charged together with text. ',\n 'pricing.unknown': 'Unknown models use deepseek-v4-pro rates.',\n 'coverage.noRange': 'No valid usage timestamps',\n 'coverage.title': 'Coverage',\n 'coverage.gaps': 'Gaps found',\n 'coverage.complete': 'Local logs complete',\n 'coverage.brief': 'Scanned {scanned} / {listed} sessions \u00B7 {records} usage records',\n 'coverage.scanned': 'Scanned',\n 'coverage.failed': 'Read failures',\n 'coverage.skipped': 'Skipped records',\n 'coverage.time': 'Record range: {range}',\n 'coverage.scope': 'Only DSH session logs on this device are included. Other devices, direct DeepSeek Platform calls, and deleted local logs are excluded.',\n 'coverage.warning': 'Some logs could not be read or contained invalid usage records, so totals may be lower than actual spend. Refresh to retry and use the DeepSeek Platform bill as the source of truth.',\n 'export.title': 'Export all local DSH session-log data (independent of the selected range)',\n 'export.done': 'Exported',\n 'export.action': 'Export',\n 'export.menuLabel': 'Choose export format',\n 'export.dailyCsv': 'Daily CSV',\n 'export.modelCsv': 'Model CSV',\n 'export.fullJson': 'Full JSON',\n 'export.jsonHint': 'Charts and rankings included',\n 'cache.empty': 'No cache data yet.',\n 'cache.rate': 'Cache hit rate',\n 'cache.saved': 'Saved vs. all-miss',\n 'cache.allMiss': 'Cost if all miss',\n 'cache.aria': '{hit}% cache hits, {miss}% misses',\n 'cache.hitLegend': 'Cache hits {tokens}',\n 'cache.missLegend': 'Misses {tokens} (charged at miss rate)',\n 'cache.basis': 'You paid \u00A5{cost}; with no cache hits it would be about \u00A5{miss}. The difference is what caching saved.',\n 'peak.empty': 'No usage yet.',\n 'peak.aria': '{peak}% peak, {offPeak}% off-peak',\n 'peak.peakLegend': 'Peak {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.offPeakLegend': 'Off-peak {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.shift': 'Saving if peak runs off-peak',\n 'peak.saving': '\u00A5{amount}',\n 'peak.basis': 'All off-peak would cost about \u00A5{total}, estimated at current prices \u2014 a different basis from \u201CSpend overview \u00B7 All time\u201D.',\n 'peak.clockTitle': \"Today's price windows\",\n 'peak.nowPeak': 'Peak now \u00B7 full price',\n 'peak.nowOff': 'Off-peak now \u00B7 half price',\n 'peak.clockAria': '24-hour price schedule, {state}',\n 'peak.clockHint': 'Peak 09\u201312 & 14\u201318 on weekdays; half price otherwise (Beijing time)',\n 'vision.empty': 'No image input in {window}.',\n 'vision.title': 'Image / multimodal usage',\n 'vision.images': 'Images',\n 'vision.tokens': 'Estimated image tokens',\n 'vision.cost': 'Estimated cost',\n 'vision.tokensShare': '{percent}% of input',\n 'vision.costShare': '{percent}% of cost',\n 'vision.note': 'Estimated with the official rule; provider usage numbers are the source of truth.',\n 'vision.sessionsTitle': 'Sessions with the most images',\n 'vision.sessionRow': '{images} images \u00B7 \u00A5{cost}',\n 'vision.dailyTitle': '{window} \u00B7 images per day',\n 'vision.barAria': '{date} \u00B7 {images} images \u00B7 est. {tokens} tokens',\n 'vision.barTitle': '{date} \u00B7 {images} images \u00B7 est. {tokens} tokens \u00B7 \u00A5{cost}',\n 'sessions.empty': 'No sessions have incurred cost yet.',\n 'sessions.detail': '{tokens} tokens \u00B7 {calls} \u00B7 {ago}',\n 'sessions.share': '{percent}% of total',\n 'sessions.more': '{count} sessions; showing the {shown} most expensive.',\n 'sessions.fallbackTitle': 'Session {id}',\n 'models.empty': 'No model usage can be classified yet.',\n 'models.shareAria': '{name} accounts for {percent}% of total cost',\n 'models.detail': '{tokens} tokens \u00B7 {calls} \u00B7 input {input} / output {output} / cache {cache}',\n 'models.all': 'All models',\n 'models.selected': '{count} models',\n 'models.filterTitle': 'Filter models shown in the chart',\n 'models.filterLabel': 'Filter chart models',\n 'window.year': 'Last year',\n 'window.days': 'Last {days} days',\n 'window.groupLabel': 'Date range',\n 'window.viewTitle': 'View usage and rankings for {window}',\n 'window.yearButton': '1 year',\n 'window.daysButton': '{days} days',\n 'metric.tokens': 'tokens',\n 'metric.usage': 'usage',\n 'metric.cost': 'cost',\n 'metric.calls': 'calls',\n 'metric.groupLabel': 'Chart metric',\n 'metric.compareTitle': 'Compare by {metric}',\n 'chart.dailyTitle': '{window} \u00B7 daily {metric}',\n 'chart.hourlyTitle': '{window} \u00B7 {metric} by hour (00\u201323)',\n 'chart.peak': 'Peak {value}',\n 'chart.dimensionLabel': 'Chart interval',\n 'chart.daily': 'Daily',\n 'chart.hourly': 'Hourly',\n 'chart.noWindowData': 'No usage in {window}.',\n 'chart.heatmapTitle': 'Last 12 months \u00B7 daily',\n 'chart.empty': 'No usage yet.',\n 'chart.hourPoint': '{hour}:00',\n 'chart.tooltip': '{head} \u00B7 {tokens} tokens \u00B7 \u00A5{cost} \u00B7 {calls}',\n 'chart.less': 'Less',\n 'chart.more': 'More',\n 'chart.month1': 'Jan',\n 'chart.month2': 'Feb',\n 'chart.month3': 'Mar',\n 'chart.month4': 'Apr',\n 'chart.month5': 'May',\n 'chart.month6': 'Jun',\n 'chart.month7': 'Jul',\n 'chart.month8': 'Aug',\n 'chart.month9': 'Sep',\n 'chart.month10': 'Oct',\n 'chart.month11': 'Nov',\n 'chart.month12': 'Dec',\n 'number.tenThousand': '{value}0K',\n 'number.hundredMillion': '{value}00M',\n 'fresh.none': 'No successful sync yet',\n 'fresh.justNow': 'Updated just now',\n 'fresh.minutes': 'Updated {count}m ago',\n 'fresh.hours': 'Updated {count}h ago',\n 'fresh.days': 'Updated {count}d ago',\n 'sync.first': 'Syncing for the first time',\n 'sync.syncing': 'Syncing \u00B7 current data {age}',\n 'sync.fresh': 'Synced \u00B7 {age}',\n 'sync.cached': 'Local cache \u00B7 {age}',\n 'sync.fallback': 'Using cache \u00B7 {age}',\n 'sync.error': 'Sync failed \u00B7 no usage to display',\n 'status.neverSynced': 'Usage has not synced successfully yet',\n 'status.usageTime': 'Usage data timestamp: {time}',\n 'status.forceRefresh': 'Force refresh (bypass cache)',\n 'status.refreshing': 'Refreshing',\n 'status.refresh': 'Refresh',\n 'error.balanceLoad': 'Balance failed to load',\n 'error.usageLoad': 'Usage failed to load',\n 'error.refreshCached': 'Refresh failed; showing cached data ({error})',\n 'error.balanceRefreshCached': 'Balance refresh failed; showing cached balance ({error})',\n 'error.usageRefreshCached': 'Usage refresh failed; showing cached usage ({error})',\n 'error.query': 'Request failed',\n 'error.credentialsUnavailable': 'Credential service is unavailable',\n 'error.credentialRead': 'Could not read the API key: {detail}',\n 'error.noApiKey': 'DEEPSEEK_API_KEY is not configured (add it under Settings \u2192 Models)',\n 'error.accountBalanceUnavailable': 'The account balance endpoint is unavailable and DEEPSEEK_API_KEY is not configured',\n 'error.balanceRequest': 'Balance request failed: {detail}',\n 'error.balanceHttp': 'Balance endpoint returned HTTP {status}',\n 'error.balanceParse': 'Could not parse the balance response',\n 'error.persistenceUnavailable': 'Session persistence is unavailable',\n 'error.sessionList': 'Could not read the session list: {detail}',\n 'error.sessionLogRead': 'Could not read the session log: {detail}',\n 'error.missingSessionId': 'Missing session id',\n 'alert.lowTitle': 'Balance {balance} {currency} is below the {threshold} warning threshold',\n 'alert.runway': '; about {days} left at recent usage',\n 'alert.topUp': 'Top up',\n 'balance.title': 'Account balance',\n 'balance.remaining': 'Remaining balance',\n 'balance.breakdownTitle': 'View topped-up and granted balance details',\n 'balance.toppedUp': 'Topped up {amount}',\n 'balance.granted': 'Granted {amount}',\n 'balance.runway': 'Estimated runway',\n 'balance.runwayBreakdownTitle': 'View estimated runway details',\n 'balance.topUpTitle': 'Low balance \u2014 top up on the DeepSeek platform (opens a new tab)',\n 'balance.days': '{count} days',\n 'balance.overYear': '> 365 days',\n 'balance.noRunway': 'No usage in the last {days} days, so runway cannot be estimated',\n 'balance.runwayTitle': 'Based on \u00A5{cost} average daily spend over the last {days} days (including idle days; today is incomplete)',\n 'balance.empty': 'Balance is unavailable. Check your sign-in or API key, then refresh.',\n 'sessionUsage.title': 'Current session spend',\n 'common.estimated': 'Estimated cost',\n 'sessionUsage.cost': 'Cost',\n 'sessionUsage.tokens': 'Tokens',\n 'sessionUsage.calls': 'Calls',\n 'sessionUsage.range': 'Active {range}',\n 'sessionUsage.single': '{model} \u00B7 input {input} / output {output} / cache {cache}',\n 'sessionUsage.empty': 'No usage in this session yet.',\n 'overview.title': 'Spend overview',\n 'overview.today': 'Today',\n 'overview.month': 'This month',\n 'overview.total': 'All time',\n 'overview.vsYesterday': 'vs yesterday',\n 'overview.vsLastMonth': 'vs same period last month',\n 'overview.empty': 'No spend to summarize yet.',\n 'usage.trendTitle': 'Usage trend',\n 'usage.windowInput': '{window} input',\n 'usage.modelCalls': 'Model calls',\n 'heatmap.title': 'Usage heatmap',\n 'peak.title': 'Peak / off-peak distribution',\n 'cache.title': 'Cache hits and savings',\n 'models.title': 'Model cost ranking',\n 'sessions.title': 'Session cost ranking',\n 'links.title': 'Quick Links',\n 'nav.label': 'On this page',\n 'nav.balance': 'Balance',\n 'nav.session': 'This session',\n 'nav.overview': 'Spend overview',\n 'nav.trend': 'Usage trend',\n 'nav.heatmap': 'Usage heatmap',\n 'nav.models': 'Model cost',\n 'nav.sessions': 'Session cost',\n 'nav.peakcache': 'Peak & cache',\n 'nav.settings': 'Settings',\n 'links.usage': 'View balance / usage',\n 'links.apiKey': 'Create API key',\n 'links.status': 'Service status',\n 'settings.title': 'Settings',\n 'settings.groupDisplay': 'Display',\n 'settings.groupAlerts': 'Alerts',\n 'settings.groupLayout': 'Layout & entry',\n 'settings.widget': 'Show the floating balance widget on other views',\n 'settings.widgetHint': 'Hidden on Usage; shown on the views selected below.',\n 'settings.widgetTabs': 'Show widget on',\n 'settings.widgetTabsHint': 'Updates automatically as views are installed.',\n 'settings.widgetTabsEmpty': 'There are no configurable conversation views right now.',\n 'settings.lowBalance': 'Balance warning',\n 'settings.lowBalanceOn': 'This page and the widget turn amber below {amount} {currency}. Enter 0 to disable.',\n 'settings.lowBalanceOff': 'Balance warnings are off. Enter an amount above 0 to enable them.',\n 'settings.monthlyBudget': 'Monthly budget',\n 'settings.monthlyBudgetOn': 'Track a {amount} CNY budget by Beijing calendar month and forecast month-end spend. Enter 0 to disable.',\n 'settings.monthlyBudgetOff': 'Enter an amount above 0 to show progress and a month-end forecast.',\n 'settings.sidebarEntry': 'Sidebar Usage entry',\n 'settings.sidebarEntryHint': 'Add a Usage entry at the top or bottom of the sidebar; it opens the account-wide Usage page.',\n 'settings.sidebarEntryOff': 'Off',\n 'settings.sidebarEntryTop': 'Top',\n 'settings.sidebarEntryBottom': 'Bottom',\n 'settings.tabPosition': 'Usage tab position',\n 'settings.tabPositionHint': 'Drag Usage to change its tab position.',\n 'settings.tabDragAria': 'Drag Usage to change its tab position',\n 'settings.tabMoveEarlier': 'Move earlier',\n 'settings.tabMoveLater': 'Move later',\n 'panel.caption': 'Account-wide \u00B7 across all sessions',\n 'panel.openAria': 'Open Usage',\n 'widget.updatedNow': 'Updated just now',\n 'widget.stale': 'Data from {minutes}m ago; press \u21BB to update',\n 'widget.loading': 'Loading\u2026',\n 'widget.lowTitle': 'Balance below warning threshold {amount}',\n 'widget.todayCostTitle': 'Today\u2019s spend (estimated) \u00B7 {age}',\n 'widget.todayCost': 'Today\u2019s spend',\n 'widget.sessionCostTitle': 'Estimated spend for the current session',\n 'widget.sessionCost': 'Current session',\n 'widget.noBalance': 'No balance data',\n 'widget.dragCard': 'Drag to any corner',\n 'widget.dragGrip': 'Drag to move',\n 'widget.refresh': 'Refresh balance and today\u2019s usage',\n 'widget.expand': 'Expand',\n 'widget.collapse': 'Collapse',\n 'widget.expandAria': 'Expand balance widget',\n 'widget.collapseAria': 'Collapse balance widget',\n 'messageCost.label': 'Turn cost',\n 'sessionCost.title': 'Session cost',\n 'sessionCost.aria': 'Estimated session cost {amount}',\n 'sessionCost.active': 'Active time',\n 'messageCost.tooltip': 'Provided by dsh-usage-dashboard \u00B7 estimated cost for this turn',\n 'messageCost.aria': '{amount}, estimated cost for this turn, provided by dsh-usage-dashboard',\n 'boundary.title': 'The usage dashboard crashed',\n 'boundary.body': 'Rendering failed, usually because this browser still has cached data from an older version. Clear this plugin\u2019s local data and reload to recover.',\n 'boundary.reset': 'Clear local data and reload',\n}\n", "/** Shared lookups into the DSH host shell DOM. Both the floating widget\n * (keeping its drag bounds clear of the header/composer) and the dashboard\n * (keeping its scroll content clear of the fixed composer on narrow\n * viewports) need to find the same host elements \u2014 sharing the lookup here\n * keeps the two readings of \"where is the composer\" from drifting apart.\n */\n\n/** The shell's main column: the region between the sidebar and the details\n * panel. Found through the stable `conversation` slot anchor rather than the\n * hashed layout class names. */\nexport function getMainColumn(frame: HTMLElement): HTMLElement | null {\n const anchor = frame.querySelector('[data-slot=\"conversation\"]')\n const column = anchor?.parentElement ?? null\n return column === frame ? null : column\n}\n\n/**\n * The laid-out element behind a slot. Slot wrappers are 0\u00D70, and which\n * neighbour carries the real box differs per slot: the session header\n * renders inside its wrapper (`'child'`), while the composer's wrapper sits\n * inside the seat that reserves the space (`'ancestor'`). Picking the wrong\n * side silently yields a box in the wrong place, so the caller says which one\n * it means.\n */\nfunction slotElement(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): HTMLElement | null {\n const anchor = frame.querySelector(`[data-slot=\"${slot}\"]`)\n if (anchor === null) return null\n if (side === 'child') {\n const el = anchor.firstElementChild as HTMLElement | null\n return el !== null && el.getBoundingClientRect().height > 0 ? el : null\n }\n let el: HTMLElement | null = anchor.parentElement\n for (let depth = 0; depth < 4 && el !== null && el !== frame; depth++) {\n if (el.getBoundingClientRect().height > 0) return el\n el = el.parentElement\n }\n return null\n}\n\n/** The laid-out box behind a slot (see `slotElement`), or null if the slot is\n * not currently present or not yet laid out. */\nexport function slotBox(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): DOMRect | null {\n return slotElement(frame, slot, side)?.getBoundingClientRect() ?? null\n}\n\n/** The DSH shell frame \u2014 the element that hosts the sidebar, conversation\n * column and fixed composer \u2014 found by walking up from any node inside our\n * own plugin root via the stable `[data-shell-overlay]` anchor. */\nexport function getShellFrame(node: HTMLElement | null): HTMLElement | null {\n const overlay = node !== null && typeof node.closest === 'function' ? node.closest('[data-shell-overlay]') : null\n return (overlay?.parentElement as HTMLElement | null) ?? null\n}\n\n/** The composer's laid-out element (the seat that reserves its space, not the\n * 0\u00D70 slot wrapper), or null if the slot is not present in the current DOM\n * (host markup changed, or mid-navigation). Callers that only need the box\n * can call `.getBoundingClientRect()`; callers that want to observe size\n * changes (e.g. `ResizeObserver`) need the element itself.\n *\n * `frame` may be null: the floating widget lives inside the shell overlay\n * subtree, but the dashboard's plugin root is mounted in the conversation\n * pane and cannot reach the shell frame that way. A frame-less call falls\n * back to a document-wide lookup \u2014 the composer is unique in the active\n * shell, so this cannot hit an ambiguous element. */\nexport function getComposerElement(frame: HTMLElement | null): HTMLElement | null {\n if (frame === null) {\n return slotElement(document.documentElement, 'conversation.composer.dock', 'ancestor')\n }\n return slotElement(frame, 'conversation.composer.dock', 'ancestor')\n}\n\n/**\n * The composer's *input card* \u2014 the rounded panel that visually IS the input\n * box (textarea + send row, ~780px max in DSH). The `.dock` seat found by\n * {@link getComposerElement} spans the whole pane, so its width is the wrong\n * answer for any width-parity goal: the visible input card is narrower, and\n * it is the column the dashboard cards must align with. The card is located\n * from the textarea's ancestor chain \u2014 the first ancestor with a visible\n * background and a non-zero border radius, the shape DSH gives the input\n * panel. Returns null when the host markup stops matching; callers then fall\n * back to {@link getComposerElement}. */\nexport function getComposerInputElement(frame: HTMLElement | null): HTMLElement | null {\n const root = frame ?? document.documentElement\n const textarea = root.querySelector(\n '[data-slot=\"conversation.composer\"] textarea, [data-slot=\"conversation.composer.bar\"] textarea, textarea',\n )\n if (textarea === null) return null\n let el = textarea.parentElement\n for (let depth = 0; depth < 6 && el !== null; depth++) {\n const cs = getComputedStyle(el)\n if (cs.borderRadius !== '0px' && cs.backgroundColor !== 'rgba(0, 0, 0, 0)') return el\n el = el.parentElement\n }\n return null\n}\n\n/** Resolve the active `conversation.view` id from the host's semantic tablist.\n * The DOM intentionally carries no view id, but it renders buttons in the\n * exact order of the slot ledger. Indexing into that same live ledger avoids\n * translated-label matching and remains compatible with third-party tabs. */\nexport function getActiveConversationViewId(\n frame: HTMLElement | null,\n viewIds: string[],\n): string | null {\n if (viewIds.length === 0) return null\n const header = frame === null ? null : slotElement(frame, 'conversation.session.header', 'child')\n const tablist = header?.querySelector('[role=\"tablist\"]') ?? null\n if (tablist === null) return viewIds[0] ?? null\n const tabs = [...tablist.querySelectorAll('[role=\"tab\"]')]\n const activeIndex = tabs.findIndex(tab => tab.getAttribute('aria-selected') === 'true')\n return activeIndex < 0 ? viewIds[0] ?? null : viewIds[activeIndex] ?? null\n}\n", "import type { UsageData } from '../contract.ts'\n\nconst BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000\n\n/** YYYYMMDD in DeepSeek's billing timezone. */\nexport function exportDateStamp(nowMs = Date.now()): string {\n const date = new Date(nowMs + BEIJING_OFFSET_MS)\n return [\n date.getUTCFullYear(),\n String(date.getUTCMonth() + 1).padStart(2, '0'),\n String(date.getUTCDate()).padStart(2, '0'),\n ].join('')\n}\n\n/** RFC 4180 cell escaping plus spreadsheet-formula neutralisation for labels. */\nexport function csvCell(value: string | number): string {\n let text = String(value)\n if (typeof value === 'string' && /^[=+\\-@]/.test(text)) text = `'${text}`\n return /[\",\\r\\n]/.test(text) ? `\"${text.replaceAll('\"', '\"\"')}\"` : text\n}\n\nconst csv = (rows: Array<Array<string | number>>): string =>\n `\\uFEFF${rows.map(row => row.map(csvCell).join(',')).join('\\r\\n')}\\r\\n`\n\nexport function dailyUsageCsv(usage: UsageData): string {\n return csv([\n ['date', 'input_tokens', 'output_tokens', 'cache_hit_tokens', 'total_tokens', 'calls', 'estimated_cost_cny'],\n ...usage.daily.map(day => [day.date, day.input, day.output, day.cache, day.total, day.calls, day.cost]),\n ])\n}\n\nexport function modelUsageCsv(usage: UsageData): string {\n return csv([\n ['provider', 'model', 'input_tokens', 'output_tokens', 'cache_hit_tokens', 'total_tokens', 'calls', 'estimated_cost_cny'],\n ...usage.models.map(model => [\n model.provider, model.model, model.input, model.output, model.cache, model.total, model.calls, model.cost,\n ]),\n ])\n}\n\nexport function fullUsageJson(usage: UsageData, nowMs = Date.now()): string {\n return `${JSON.stringify({\n schemaVersion: 1,\n exportedAt: new Date(nowMs).toISOString(),\n scope: 'local-dsh-session-logs',\n data: usage,\n }, null, 2)}\\n`\n}\n\nexport function downloadText(filename: string, text: string, mediaType: string): void {\n const url = URL.createObjectURL(new Blob([text], { type: mediaType }))\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.hidden = true\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n window.setTimeout(() => URL.revokeObjectURL(url), 0)\n}\n", "import { fallbackT, type Translate } from './i18n.tsx'\n\nexport type SyncState = 'syncing' | 'fresh' | 'cached' | 'fallback' | 'error'\n\n/** Short, stable freshness copy for the dashboard status row. */\nexport function updatedText(updatedAt: number | null, nowMs = Date.now(), t: Translate = fallbackT): string {\n if (updatedAt === null || !Number.isFinite(updatedAt)) return t('fresh.none')\n const elapsed = Math.max(0, nowMs - updatedAt)\n if (elapsed < 60_000) return t('fresh.justNow')\n const minutes = Math.floor(elapsed / 60_000)\n if (minutes < 60) return t('fresh.minutes', { count: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('fresh.hours', { count: hours })\n return t('fresh.days', { count: Math.floor(hours / 24) })\n}\n\nexport function syncStatusText(state: SyncState, updatedAt: number | null, nowMs = Date.now(), t: Translate = fallbackT): string {\n const age = updatedText(updatedAt, nowMs, t)\n if (state === 'syncing') return updatedAt === null ? t('sync.first') : t('sync.syncing', { age })\n if (state === 'fresh') return t('sync.fresh', { age })\n if (state === 'cached') return t('sync.cached', { age })\n if (state === 'fallback') return t('sync.fallback', { age })\n return t('sync.error')\n}\n", "import { fallbackT, type Translate } from './i18n.tsx'\n\n/** Value axis shared by daily, hourly, and per-model usage charts. */\nexport const CHART_METRICS = ['tokens', 'cost', 'calls'] as const\nexport type ChartMetric = (typeof CHART_METRICS)[number]\n\nexport interface ChartMetricPoint {\n total: number\n cost: number\n calls: number\n}\n\nexport const isChartMetric = (value: unknown): value is ChartMetric =>\n typeof value === 'string' && CHART_METRICS.some(metric => metric === value)\n\nexport function chartMetricValue(metric: ChartMetric, point: ChartMetricPoint): number {\n if (metric === 'cost') return point.cost\n if (metric === 'calls') return point.calls\n return point.total\n}\n\nexport function chartMetricName(metric: ChartMetric, t: Translate = fallbackT): string {\n if (metric === 'cost') return t('metric.cost')\n if (metric === 'calls') return t('metric.calls')\n return t('metric.usage')\n}\n", "/**\n * localStorage-backed user preferences for the plugin.\n *\n * Everything the user deliberately sets (widget visibility, the corner it was\n * dragged to, whether it is collapsed) belongs here so a page refresh does not\n * throw the choice away. Keys share one prefix and carry a version suffix so\n * the shape can evolve without reading back stale values.\n *\n * Every read is validated by the caller's guard: a corrupted or hand-edited\n * entry falls back instead of poisoning the UI.\n */\n\nconst PREFIX = 'dsh-usage-dashboard:pref:'\nconst VERSION = 1\n\nconst keyOf = (key: string): string => `${PREFIX}${key}:v${VERSION}`\n\nexport function loadPref<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): T {\n if (typeof localStorage === 'undefined') return fallback\n try {\n const raw = localStorage.getItem(keyOf(key))\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n return isValid(parsed) ? (parsed as T) : fallback\n } catch {\n return fallback\n }\n}\n\nexport function savePref(key: string, value: unknown): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(keyOf(key), JSON.stringify(value))\n } catch {\n // Quota / private-mode failures must never break the UI.\n }\n}\n\nexport const isBoolean = (value: unknown): boolean => typeof value === 'boolean'\n", "/**\n * Package-local stores for settings both surfaces read: the dashboard writes\n * them, the floating widget reacts. Every value is persisted (see ./prefs.ts),\n * so a choice survives a page refresh.\n */\nimport { USAGE_WINDOW_DAYS, type UsageWindowDays } from '../contract.ts'\nimport { isChartMetric, type ChartMetric } from './metric.ts'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\n\nexport interface Store<T> {\n get(): T\n set(value: T): void\n subscribe(fn: () => void): () => void\n}\n\nexport function createStore<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): Store<T> {\n let current = loadPref<T>(key, isValid, fallback)\n const listeners = new Set<() => void>()\n return {\n get: () => current,\n set: (value: T) => {\n current = value\n savePref(key, value)\n for (const listener of [...listeners]) listener()\n },\n subscribe: (fn: () => void) => {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n }\n}\n\nconst isThreshold = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/** Whether the floating balance widget is shown. */\nexport const widgetVisibleStore = createStore<boolean>('widget.visible', isBoolean, true)\n\nconst isWidgetTabIds = (value: unknown): boolean => value === null\n || (Array.isArray(value) && value.every(id => typeof id === 'string' && id !== '')\n && new Set(value).size === value.length)\n\n/** Conversation view ids on which the widget is allowed to appear. `null`\n * means \"all available views\" and preserves the pre-setting default; once a\n * user customizes the list, newly installed plugin tabs arrive unchecked. */\nexport const widgetTabIdsStore = createStore<string[] | null>('widget.tabIds', isWidgetTabIds, null)\n\n/** Balance (in the account's own currency) below which both surfaces warn.\n * 0 turns the warning off. */\nexport const lowBalanceStore = createStore<number>('alert.lowBalance', isThreshold, 10)\n\n/** Monthly estimated-cost budget in CNY. 0 leaves budget tracking disabled. */\nexport const monthlyBudgetStore = createStore<number>('budget.monthly', isThreshold, 0)\n\nconst isUsageWindowDays = (value: unknown): value is UsageWindowDays =>\n typeof value === 'number' && USAGE_WINDOW_DAYS.some(days => days === value)\n\n/** Shared time range for the usage chart and both cost rankings. */\nexport const usageWindowStore = createStore<UsageWindowDays>('usage.windowDays', isUsageWindowDays, 30)\n\n/** Whether charts compare token volume, estimated CNY cost, or call count. */\nexport const chartMetricStore = createStore<ChartMetric>('usage.chartMetric', isChartMetric, 'tokens')\n\n/** Ephemeral presence of the full dashboard. The widget uses it to step out of\n * the way without changing the user's persisted visibility preference. */\nlet quotaViewActive = false\nconst quotaViewListeners = new Set<() => void>()\nexport const quotaViewActiveStore: Store<boolean> = {\n get: () => quotaViewActive,\n set: (value) => {\n if (value === quotaViewActive) return\n quotaViewActive = value\n for (const listener of [...quotaViewListeners]) listener()\n },\n subscribe: (fn) => {\n quotaViewListeners.add(fn)\n return () => {\n quotaViewListeners.delete(fn)\n }\n },\n}\n", "/**\n * Layout preferences shared by the dashboard's Settings section and the\n * client registration half (`./index.tsx`).\n *\n * These two sides must agree on two placement choices, and neither may import\n * the other (the registration half mounts the dashboard, so the reverse import\n * would be a cycle). Keeping the stores in their own module lets both read and\n * write the same persisted values.\n */\nimport { createStore, type Store } from './store.ts'\n\n/** The global panel id shared by the `main` slot entry and the sidebar entry\n * that selects it. Stable: it is only ever compared within this package. */\nexport const QUOTA_PANEL_ID = 'quota'\n\n/** Where the optional\u300C\u989D\u5EA6\u300Dshortcut, if enabled, lives in the sidebar. */\nexport type SidebarEntryPlacement = 'off' | 'top' | 'bottom'\n\nconst isPlacement = (value: unknown): value is SidebarEntryPlacement =>\n value === 'off' || value === 'top' || value === 'bottom'\n\n/**\n * `off` keeps the host's sidebar untouched (the default, so updating the\n * plugin never silently adds chrome). `top` joins the global-panel icon row;\n * `bottom` sits beside Settings in the sidebar foot.\n */\nexport const sidebarEntryStore: Store<SidebarEntryPlacement> =\n createStore<SidebarEntryPlacement>('layout.sidebarEntry', isPlacement, 'off')\n\nconst isTabIndex = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 50\n\n/**\n * Position of the\u300C\u989D\u5EA6\u300Dtab among the registered conversation views, as an\n * index in the live tab roster (0 = first). The registration half maps it onto\n * a slot `order` relative to the neighbouring entries, so it survives host\n * plugins arriving with their own orders. Default 2 reproduces the historical\n * fixed position: \u5BF9\u8BDD, \u8F68\u8FF9, \u989D\u5EA6.\n */\nexport const quotaTabIndexStore: Store<number> =\n createStore<number>('layout.tabIndex', isTabIndex, 2)\n\n/** One `conversation.view` slot entry, as far as ordering needs to see it. */\nexport interface ViewOrderEntry {\n options: { id?: string; order?: number }\n}\n\n/**\n * Clamp a persisted roster index into `[0, count]`; `count` itself is the\n * legal \"end of the list\" insertion position when there are `count` tabs.\n */\nexport function clampTabIndex(index: number, count: number): number {\n return Math.max(0, Math.min(index, Math.max(count, 0)))\n}\n\n/**\n * Turn a 0-based roster position into the `order` for our own view entry.\n *\n * The host sorts list entries by `order` (ties keep registration order), so\n * the placement is expressed relative to the live neighbours rather than as an\n * absolute number: the first/last positions step outside the current range,\n * and an interior position lands between the two adjacent orders (including\n * the degenerate equal-order case). Other entries are never touched.\n * @param entries - live `conversation.view` entries.\n * @param index - desired 0-based position in the roster *including* our tab.\n * @param selfId - this plugin's entry id (excluded from the anchor list).\n * @param fallback - order used while the host has no other view registered.\n * @returns the slot `order` for our registration.\n */\nexport function viewOrderForIndex(\n entries: readonly ViewOrderEntry[],\n index: number,\n selfId = 'balance',\n fallback = 20,\n): number {\n const others = entries.filter(entry => entry.options.id !== selfId)\n if (others.length === 0) return fallback\n const clamped = clampTabIndex(index, others.length)\n // The host sorts an omitted `order` as 0, so mirror that effective value\n // instead of inventing a per-position default.\n const orderAt = (position: number): number => others[position]?.options.order ?? 0\n if (clamped === 0) return orderAt(0) - 10\n if (clamped === others.length) return orderAt(others.length - 1) + 10\n const previous = orderAt(clamped - 1)\n const next = orderAt(clamped)\n return previous >= next ? previous + 0.5 : (previous + next) / 2\n}\n", "/** Where the top-up shortcuts send the user, on both surfaces that offer one. */\nexport const TOP_UP_URL = 'https://platform.deepseek.com/top_up'\n\n/** Balance (in the account's own currency) below which the shortcut is\n * offered regardless of the configurable warning line: that line can be\n * lowered or switched off (0), but a balance this close to zero still deserves\n * a one-click way out. */\nconst TOP_UP_FLOOR = 10\n\n/**\n * Whether the balance is low enough to offer the top-up shortcut.\n *\n * Two independent conditions, OR-ed on purpose: the fixed floor keeps the\n * shortcut available when warnings are disabled or set lower than 10, while a\n * raised warning line lets an early warning also carry the shortcut.\n * @param balance - account balance in its own currency; NaN/Infinity never qualifies.\n * @param warningLine - configured balance warning line; 0 disables that half.\n * @returns true when the \u53BB\u5145\u503C shortcut should be shown.\n */\nexport function needsTopUp(balance: number, warningLine: number): boolean {\n if (!Number.isFinite(balance)) return false\n return balance < TOP_UP_FLOOR || (warningLine > 0 && balance < warningLine)\n}\n", "/** Estimated spend contributed beside each completed chat turn. */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport type { SessionUsageData, TurnUsage } from '../contract.ts'\nimport { fetchSessionUsage, getCachedSessionUsage, subscribeSessionUsage } from './api.ts'\nimport { useI18n } from './i18n.tsx'\n\nexport interface MessageCostProps {\n sessionId: string\n messageId: string\n}\n\n/** Small costs need more than the dashboard's two-decimal money formatter or\n * almost every individual turn would misleadingly read as \u00A50.00. */\nexport const fmtTurnCost = (cost: number): string => cost.toLocaleString(undefined, {\n minimumFractionDigits: cost > 0 && cost < 0.01 ? 4 : 2,\n maximumFractionDigits: cost > 0 && cost < 0.01 ? 6 : 4,\n})\n\nconst cachedData = (sessionId: string): SessionUsageData | null => {\n const response = getCachedSessionUsage(sessionId)\n return response?.ok === true ? response.data ?? null : null\n}\n\nexport function MessageCost({ sessionId, messageId }: MessageCostProps): ReactElement | null {\n const { t } = useI18n()\n const [data, setData] = useState<SessionUsageData | null>(() => cachedData(sessionId))\n\n useEffect(() => {\n setData(cachedData(sessionId))\n const unsubscribe = subscribeSessionUsage(sessionId, () => setData(cachedData(sessionId)))\n const hit = cachedData(sessionId)?.turns.some(turn => turn.messageId === messageId) ?? false\n if (!hit) void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [messageId, sessionId])\n\n const turn: TurnUsage | undefined = data?.turns.find(candidate => candidate.messageId === messageId)\n if (turn === undefined) return null\n const amount = `\u00A5${fmtTurnCost(turn.cost)}`\n const tooltip = t('messageCost.tooltip')\n return (\n <span\n className=\"dq-message-cost\"\n tabIndex={0}\n data-dq-tooltip={tooltip}\n aria-label={t('messageCost.aria', { amount })}\n >\n <span className=\"dq-message-cost-separator\" aria-hidden>\u00B7</span>\n <span className=\"dq-message-cost-amount\">{amount}</span>\n </span>\n )\n}\n", "/**\n * Session cost pill in the composer dock (next to the host's\u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300Dand\n * \u300CToken \u7528\u91CF\u300Dpills). It shows the estimated spend of the whole conversation\n * and opens a small detail dialog above the dock \u2014 the same pill/dialog skin\n * the host uses for its own composer statistics, so the three read as one row.\n *\n * The figure comes from the plugin's own session-usage API (the same endpoint\n * the \u300C\u989D\u5EA6\u300Dtab's current-session card and the per-turn chip use), not from\n * host projections: cost has to follow this plugin's pricing table.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactElement } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { SessionUsageData } from '../contract.ts'\nimport { fetchSessionUsage, getCachedSessionUsage, subscribeSessionUsage } from './api.ts'\nimport { fmtInt } from './charts.tsx'\nimport { useI18n } from './i18n.tsx'\nimport { fmtTurnCost } from './message-cost.tsx'\nimport { ratesAt } from '../pricing.ts'\n\n/** Viewport margin kept by the dialog clamp. */\nconst PANEL_MARGIN = 12\n/** Distance between the pill's top edge and the dialog's bottom edge. */\nconst PANEL_GAP = 8\n\nconst cachedData = (sessionId: string): SessionUsageData | null => {\n const response = getCachedSessionUsage(sessionId)\n return response?.ok === true ? response.data ?? null : null\n}\n\n/** \u00A5 roundel, drawn at the host's 16-unit stroke-icon grid (rendered at 14px\n * by the pill, matching the neighbouring pills' glyph size). */\nfunction CostIcon(): ReactElement {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6\" />\n <path d=\"M5.5 5.3 8 8.4l2.5-3.1\" />\n <path d=\"M8 8.4v2.9\" />\n <path d=\"M5.8 9.5h4.4\" />\n <path d=\"M5.8 10.9h4.4\" />\n </svg>\n )\n}\n\n/** One session cost reading plus its click-open breakdown. */\nexport function SessionCostPill({ sessionId }: { sessionId?: string }): ReactElement | null {\n const { t, locale } = useI18n()\n const [data, setData] = useState<SessionUsageData | null>(\n () => (sessionId === undefined || sessionId === '' ? null : cachedData(sessionId)),\n )\n const [open, setOpen] = useState(false)\n const anchorRef = useRef<HTMLSpanElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n const [pos, setPos] = useState<{ left: number; bottom: number } | null>(null)\n\n useEffect(() => {\n if (sessionId === undefined || sessionId === '') return\n setData(cachedData(sessionId))\n const unsubscribe = subscribeSessionUsage(sessionId, () => setData(cachedData(sessionId)))\n // The per-turn chips fetch this same resource; skip a duplicate request\n // when one of them already warmed the cache for this session.\n if (getCachedSessionUsage(sessionId) === null) void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [sessionId])\n\n // Portal placement: fixed above the pill and clamped to the viewport, the\n // same geometry the host's stat dialogs use. Measuring happens after the\n // hidden first paint so the clamp uses the panel's real width.\n useLayoutEffect(() => {\n if (!open) {\n setPos(null)\n return\n }\n const anchor = anchorRef.current\n const panel = panelRef.current\n if (anchor === null || panel === null) return\n const pill = anchor.getBoundingClientRect()\n const width = panel.getBoundingClientRect().width\n setPos({\n left: Math.min(Math.max(pill.left, PANEL_MARGIN), Math.max(PANEL_MARGIN, window.innerWidth - width - PANEL_MARGIN)),\n bottom: window.innerHeight - pill.top + PANEL_GAP,\n })\n }, [open, data])\n\n // Outside pointerdown, Escape, resize and any scroll dismiss the dialog;\n // it is anchored to a dock that scrolls away with the conversation.\n useEffect(() => {\n if (!open) return\n const close = (): void => setOpen(false)\n const onPointerDown = (event: PointerEvent): void => {\n const target = event.target\n if (!(target instanceof Node)) return\n if (anchorRef.current?.contains(target) === true || panelRef.current?.contains(target) === true) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n window.addEventListener('resize', close)\n document.addEventListener('scroll', close, true)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n window.removeEventListener('resize', close)\n document.removeEventListener('scroll', close, true)\n }\n }, [open])\n\n if (sessionId === undefined || sessionId === '' || data === null || data.calls === 0) return null\n\n const amount = `\u00A5${fmtTurnCost(data.cost)}`\n // Money per billing bucket, not token counts: every model's recorded cost is\n // split across its three buckets in proportion to that bucket's share of the\n // bill at the session's own price era. Peak/off-peak multiply all three\n // buckets equally, so the share is not affected by when within the era the\n // session ran; the split still sums to the same total the pill shows.\n const priceAt = data.lastActive ?? Date.now()\n const split = data.models.reduce(\n (sum, model) => {\n const rates = ratesAt(priceAt, model.model)\n const weighted = {\n input: model.input * rates.input,\n cache: model.cache * rates.cacheHit,\n output: model.output * rates.output,\n }\n const weight = weighted.input + weighted.cache + weighted.output\n if (weight <= 0) return sum\n sum.input += model.cost * (weighted.input / weight)\n sum.cache += model.cost * (weighted.cache / weight)\n sum.output += model.cost * (weighted.output / weight)\n return sum\n },\n { input: 0, cache: 0, output: 0 },\n )\n const rangeTime = new Intl.DateTimeFormat(locale === 'en' ? 'en-US' : 'zh-CN', {\n timeZone: 'Asia/Shanghai', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = data.firstActive !== null && data.lastActive !== null\n ? `${rangeTime.format(data.firstActive)} \u2013 ${rangeTime.format(data.lastActive)}`\n : null\n\n return (\n <>\n <span ref={anchorRef} className=\"dq-cost-anchor\">\n <button\n type=\"button\"\n className=\"dq-cost-pill\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label={t('sessionCost.aria', { amount })}\n onClick={() => setOpen(value => !value)}\n >\n <CostIcon />\n <span className=\"dq-cost-pill-label\">{amount}</span>\n </button>\n </span>\n {open && createPortal(\n <div\n ref={panelRef}\n className=\"dq-cost-panel\"\n role=\"dialog\"\n aria-label={t('sessionCost.title')}\n style={pos === null\n ? { visibility: 'hidden', left: 0, top: 0 }\n : { visibility: 'visible', left: pos.left, bottom: pos.bottom, top: 'auto' }}\n >\n <div className=\"dq-cost-panel-title\">\n <span className=\"dq-cost-panel-title-label\">\n <CostIcon />\n {t('sessionCost.title')}\n </span>\n <span className=\"dq-cost-panel-value\">{amount}</span>\n </div>\n <div className=\"dq-cost-panel-rule\" aria-hidden />\n <dl className=\"dq-cost-details\">\n <dt>{t('common.input')}</dt>\n <dd>\u00A5{fmtTurnCost(split.input)}</dd>\n <dt>{t('common.cacheHit')}</dt>\n <dd>\u00A5{fmtTurnCost(split.cache)}</dd>\n <dt>{t('common.output')}</dt>\n <dd>\u00A5{fmtTurnCost(split.output)}</dd>\n <dt>{t('sessionUsage.calls')}</dt>\n <dd>{fmtInt(data.calls)}</dd>\n {range !== null && (\n <>\n <dt>{t('sessionCost.active')}</dt>\n <dd>{range}</dd>\n </>\n )}\n </dl>\n </div>,\n document.body,\n )}\n </>\n )\n}\n", "/**\n * DeepSeek API price table and cost estimation.\n *\n * Every record is priced with the table that was in force at the moment it was\n * written \u2014 CNY per 1M tokens, from DeepSeek's official pricing page:\n *\n * - until 2026-08-17 00:00 Beijing: one flat price per model;\n * - 2026-08-17 00:00: peak/off-peak pricing \u2014 peak windows 09:00\u201312:00 and\n * 14:00\u201318:00 every day, off-peak exactly half of peak;\n * - 2026-09-10 12:00: the V4.1-Flash price cut (flash 0.04/2/8 peak), and the\n * peak windows narrow to Monday\u2013Friday;\n * - 2026-09-14 12:00: `deepseek-v4-pro` requests are served by V4.1-Flash and\n * billed at Flash rates until a V4.1 Pro ships.\n *\n * `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp` are legacy names for\n * the model now published as `deepseek-flash`; both keep billing at Flash\n * rates. Images cost tokens rather than a multiplier of their own: they are\n * converted by size and priced together with the text tokens. Historical days\n * therefore keep the price that was actually charged.\n *\n * Editing this table is the one place to touch when DeepSeek changes prices.\n */\nimport type { PricingInfo, PricingRates } from './contract.ts'\n\n/** 2026-08-17 00:00 Beijing time (UTC+8), when peak/off-peak pricing took effect. */\nexport const PEAK_PRICING_FROM_MS = Date.UTC(2026, 7, 16, 16, 0, 0)\n\n/** 2026-09-10 12:00 Beijing, when the V4.1-Flash prices and the weekday-only\n * peak windows took effect. */\nexport const V41_FLASH_PRICING_FROM_MS = Date.UTC(2026, 8, 10, 4, 0, 0)\n\n/** 2026-09-14 12:00 Beijing, from when `deepseek-v4-pro` requests are routed\n * to V4.1-Flash and billed at Flash rates. */\nexport const PRO_ROUTED_TO_FLASH_FROM_MS = Date.UTC(2026, 8, 14, 4, 0, 0)\n\n/** Peak hours in Beijing time, as [startHour, endHour) pairs. */\nconst PEAK_WINDOWS: Array<[number, number]> = [[9, 12], [14, 18]]\n\nconst BEIJING_OFFSET_MS = 8 * 3_600_000\n\ntype Tier = 'pro' | 'flash' | 'vision'\n\n/** Flat rates in effect until 2026-08-17. */\nconst FLAT_RATES: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.025, input: 3, output: 6 },\n flash: { cacheHit: 0.02, input: 1, output: 2 },\n // The vision model billed at flash rates from day one, so its pre-switch\n // history is costed at the same flat prices as flash.\n vision: { cacheHit: 0.02, input: 1, output: 2 },\n}\n\n/** Peak rates from 2026-08-17; off-peak is exactly half of each. */\nconst PEAK_RATES_08_17: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.3, input: 9, output: 27 },\n flash: { cacheHit: 0.1, input: 3, output: 9 },\n // Official policy: the vision model is priced identically to flash; images\n // cost tokens, not their own multiplier.\n vision: { cacheHit: 0.1, input: 3, output: 9 },\n}\n\n/** Peak rates from 2026-09-10, the V4.1-Flash table; off-peak is half. */\nconst PEAK_RATES_09_10: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.3, input: 9, output: 27 },\n flash: { cacheHit: 0.04, input: 2, output: 8 },\n vision: { cacheHit: 0.04, input: 2, output: 8 },\n}\n\n/** One dated price table; `fromMs` is inclusive. */\ninterface PriceEra {\n readonly fromMs: number\n readonly peak: Record<Tier, PricingRates>\n /** Whether the peak windows apply Monday\u2013Friday only. */\n readonly weekdaysOnly: boolean\n}\n\n/** Oldest first \u2014 the last entry whose `fromMs` has passed is the one in force. */\nconst PRICE_ERAS: readonly PriceEra[] = [\n { fromMs: PEAK_PRICING_FROM_MS, peak: PEAK_RATES_08_17, weekdaysOnly: false },\n { fromMs: V41_FLASH_PRICING_FROM_MS, peak: PEAK_RATES_09_10, weekdaysOnly: true },\n]\n\n/** The price table in force at a moment. */\nfunction eraAt(timeMs: number): PriceEra {\n let era = PRICE_ERAS[0]\n for (const candidate of PRICE_ERAS) if (timeMs >= candidate.fromMs) era = candidate\n return era\n}\n\nconst halved = (rates: PricingRates): PricingRates => ({\n cacheHit: rates.cacheHit / 2,\n input: rates.input / 2,\n output: rates.output / 2,\n})\n\n/** Which price tier a model name falls into; anything unrecognised is billed\n * as pro, the conservative (more expensive) guess. Vision is matched first:\n * `deepseek-v4-flash-vision-exp` also contains \"flash\". */\nexport function tierOf(model: string): Tier {\n const name = model.toLowerCase()\n if (name.includes('vision')) return 'vision'\n if (name.includes('flash')) return 'flash'\n return 'pro'\n}\n\n/** The tier a model actually bills at: from 2026-09-14 `deepseek-v4-pro`\n * requests are served by V4.1-Flash and charged the Flash price. */\nfunction billedTierOf(timeMs: number, model: string): Tier {\n const tier = tierOf(model)\n return tier === 'pro' && timeMs >= PRO_ROUTED_TO_FLASH_FROM_MS ? 'flash' : tier\n}\n\n/** Beijing-time Monday\u2013Friday, which the peak windows honour from 2026-09-10. */\nfunction isBeijingWeekday(timeMs: number): boolean {\n const day = new Date(timeMs + BEIJING_OFFSET_MS).getUTCDay()\n return day >= 1 && day <= 5\n}\n\n/**\n * Image token conversion (DeepSeek official rule, Vision guide):\n * - Images below roughly 384\u00D7384 pixels are scaled UP preserving aspect\n * ratio; larger images are scaled DOWN so their pixel count is roughly that\n * of an 800\u00D7800 image.\n * - Tokens are proportional to the (resized) pixel count, capped at 384\n * tokens per image, so 2000\u00D72000 and 5000\u00D75000 cost the same.\n * - Each image is counted independently; `detail: low` caps at 512\u00D7512.\n *\n * The estimate is for the \"how much came from images\" breakdown; the exact\n * provider count is already folded into the usage record's `inputTokens`.\n * Returns tokens (possibly fractional) \u2014 0 for missing/invalid dimensions.\n */\nexport function estimateImageTokens(width: number, height: number): number {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return 0\n const area = width * height\n const scaledArea = Math.min(800 * 800, Math.max(384 * 384, area))\n return 384 * (scaledArea / (800 * 800))\n}\n\n/** Whether a moment falls in a peak window, judged in Beijing time so the\n * estimate does not drift with the machine's timezone. */\nexport function isPeak(timeMs: number): boolean {\n if (eraAt(timeMs).weekdaysOnly && !isBeijingWeekday(timeMs)) return false\n const hour = Math.floor((((timeMs + BEIJING_OFFSET_MS) % 86_400_000) + 86_400_000) % 86_400_000 / 3_600_000)\n return PEAK_WINDOWS.some(([from, to]) => hour >= from && hour < to)\n}\n\n/** Rates applying to one model at one moment. */\nexport function ratesAt(timeMs: number, model: string): PricingRates {\n if (timeMs < PEAK_PRICING_FROM_MS) return FLAT_RATES[tierOf(model)]\n const peak = eraAt(timeMs).peak[billedTierOf(timeMs, model)]\n return isPeak(timeMs) ? peak : halved(peak)\n}\n\n/**\n * What prefix caching saved on one record: the cache-hit tokens re-priced at\n * the cache-miss rate, minus what they actually cost.\n */\nexport function cacheSavingOf(timeMs: number, model: string, cache: number): number {\n const rates = ratesAt(timeMs, model)\n return (cache * (rates.input - rates.cacheHit)) / 1_000_000\n}\n\nconst applyRates = (rates: PricingRates, input: number, cache: number, output: number): number =>\n (input * rates.input + cache * rates.cacheHit + output * rates.output) / 1_000_000\n\n/** Estimated CNY cost of one usage record. */\nexport function costOf(timeMs: number, model: string, input: number, cache: number, output: number): number {\n return applyRates(ratesAt(timeMs, model), input, cache, output)\n}\n\n/**\n * The same record priced as if it had landed in an idle window \u2014 used to\n * answer \"what would shifting work off-peak save me\". Prices come from the\n * newest table, the one in force now: the question is about scheduling the\n * next batch, not about re-pricing history.\n */\nexport function costUnderPeakEra(timeMs: number, model: string, input: number, cache: number, output: number, forceOffPeak = false): number {\n const peak = PRICE_ERAS[PRICE_ERAS.length - 1].peak[billedTierOf(timeMs, model)]\n const rates = !forceOffPeak && isPeak(timeMs) ? peak : halved(peak)\n return applyRates(rates, input, cache, output)\n}\n\n/** The price table to show the user: the two models the official docs list,\n * so the rows match the page they come from \u2014 legacy names, image tokens and\n * the pro routing live in the small print next to the table. */\nexport function pricingInfo(nowMs: number): PricingInfo {\n const era = eraAt(nowMs)\n const row = (model: string, tier: Tier) => ({ model, peak: era.peak[tier], offPeak: halved(era.peak[tier]) })\n return {\n currency: 'CNY',\n switchDate: '2026-08-17',\n inPeakNow: isPeak(nowMs),\n peakWindows: ['09:00\u201312:00', '14:00\u201318:00'],\n tiers: [row('deepseek-flash', 'flash'), row('deepseek-v4-pro', 'pro')],\n }\n}\n", "/** All plugin styles in one sheet, injected once at client load. */\n\nexport const css = `\n.dsh-quota-root{-webkit-text-size-adjust:100%;text-size-adjust:100%;position:absolute;right:16px;bottom:16px;z-index:2147483000;pointer-events:auto;opacity:1;visibility:visible;font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.45;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary,#1f2328);--dq-text-success:#1a7f37;--dq-text-success:color-mix(in oklab,var(--dsw-alias-state-success-primary,#2da44e) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);--dq-text-warn:#9a6700;--dq-text-warn:color-mix(in oklab,var(--dsw-alias-state-warn-primary,#bf8700) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1),opacity .16s ease-out,visibility 0s linear}\n.dsh-quota-root.dsh-quota-root--hidden{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .14s ease-out,visibility 0s linear .14s}\n.dsh-quota-root.dsh-quota-dragging{transition:none}\n.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}\n.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}\n.dsh-quota-root.dsh-quota-dragging .dsh-quota-card{cursor:grabbing;box-shadow:0 12px 32px rgba(0,0,0,.28)}\n.dsh-quota-header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;min-width:0}\n.dsh-quota-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden}\n.dsh-quota-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-quota-grip{color:var(--dsw-alias-label-secondary,#59636e);opacity:.7;font-size:12px;letter-spacing:0;cursor:grab;flex:none}\n.dsh-quota-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#2da44e);flex:none}\n.dsh-quota-dot--error{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dsh-quota-dot--warn{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dsh-quota-total--low{color:var(--dq-text-warn)!important}\n.dsh-quota-dot--idle{background:var(--dsw-alias-label-secondary,#59636e);opacity:.6}\n.dsh-quota-collapsed-total-row{margin-top:6px}\n.dsh-quota-collapsed-total{font-weight:700;font-size:13px;color:var(--dsw-alias-state-business-primary,#0969da);font-variant-numeric:tabular-nums}\n.dsh-quota-actions{display:flex;gap:2px;flex:none}\n.dsh-quota-btn{border:none;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);padding:3px 7px;border-radius:6px;font-size:13px;line-height:1}\n.dsh-quota-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));color:var(--dsw-alias-label-primary,#1f2328)}\n.dsh-quota-btn:active:not(:disabled){transform:scale(.92)}\n.dsh-quota-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dsh-quota-btn:disabled{opacity:.5;cursor:default}\n.dsh-quota-body{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-remaining-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-bottom:2px}\n.dsh-quota-total{font-size:18px;font-weight:700;color:var(--dsw-alias-label-primary,#1f2328);letter-spacing:-.02em;line-height:1.2;font-variant-numeric:tabular-nums}\n.dsh-quota-currency{font-size:13px;font-weight:500;margin-left:4px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:12px}\n.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-message-cost{-webkit-text-size-adjust:100%;text-size-adjust:100%;position:relative;display:inline-flex;align-items:center;order:10;gap:10px;height:28px;color:var(--dsw-alias-label-tertiary,#59636e);font-size:12px;line-height:20px;font-variant-numeric:tabular-nums;white-space:nowrap;cursor:help}\n.dq-message-cost-separator{cursor:default}\n.dq-message-cost-amount{text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;text-underline-offset:4px}\n.dq-message-cost:hover{color:var(--dsw-alias-label-secondary,#3f4852)}\n.dq-message-cost:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px;border-radius:4px}\n.dq-message-cost::after{content:attr(data-dq-tooltip);position:absolute;left:0;bottom:calc(100% + 6px);top:auto;z-index:2147483001;width:max-content;max-width:min(240px,calc(100vw - 24px));padding:6px 9px;border-radius:8px;background:var(--dsw-alias-tooltip-bg,#1f2328);color:var(--dsw-static-neutral-bluish-00,#fff);box-shadow:0 6px 18px rgba(0,0,0,.22);font-size:12px;font-weight:400;line-height:1.5;text-align:left;white-space:normal;pointer-events:none;opacity:0;visibility:hidden;transform:translateY(3px);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear .12s}\n.dq-message-cost:hover::after,.dq-message-cost:focus-visible::after{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear}\n@media (hover:hover){\n [data-time-hover-root] .dq-message-cost{opacity:0;transition:opacity 80ms ease}\n [data-time-hover-root]:hover .dq-message-cost,[data-time-hover-root]:focus-within .dq-message-cost{opacity:1}\n}\n/* Composer-dock session cost pill: one more reading beside the host's own\n \u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300D/\u300CToken \u7528\u91CF\u300Dpills (same slot, same compact skin). */\n.dq-cost-anchor{display:inline-flex;min-width:0;font-size:calc(var(--dsh-content-font-size-secondary,13px) - 1px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}\n.dq-cost-pill{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;max-width:100%;padding:1px 8px;border:0;border-radius:var(--dsw-radius-sm,8px);background:transparent;color:var(--dsw-alias-label-tertiary,#59636e);font:inherit;font-variant-numeric:tabular-nums;line-height:inherit;white-space:nowrap;cursor:pointer}\n.dq-cost-pill:hover,.dq-cost-pill[aria-expanded=\"true\"]{background:var(--dsw-alias-interactive-bg-hover,rgba(120,130,150,.12));color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cost-pill:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-cost-pill svg{flex:none}\n.dq-cost-pill-label{min-width:0;overflow:hidden;text-overflow:ellipsis}\n/* Click-open breakdown: the host stat-dialog skin (menu surface, prominent\n elevation, 12/18 rows), portaled to the body and placed above the pill. */\n.dq-cost-panel{position:fixed;z-index:1100;box-sizing:border-box;width:max-content;min-width:min(300px,calc(100vw - 24px));max-width:min(440px,calc(100vw - 24px));padding:16px;border:0;border-radius:var(--dsw-radius-lg,16px);background:var(--dsw-specific-menu,var(--dsw-alias-bg-overlay,#fff));-webkit-backdrop-filter:var(--dsw-menu-backdrop-filter,blur(40px) saturate(150%));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(40px) saturate(150%));box-shadow:var(--dsw-elevation-prominent,0 12px 32px rgba(0,0,0,.24));font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#59636e);cursor:default}\n.dq-cost-panel-title{display:flex;justify-content:space-between;gap:16px;margin-bottom:8px;color:var(--dsw-alias-label-primary,#1f2328);font-weight:500}\n.dq-cost-panel-title-label{display:inline-flex;align-items:center;gap:6px;min-width:0}\n.dq-cost-panel-title-label svg{flex:none}\n.dq-cost-panel-value{font-variant-numeric:tabular-nums}\n.dq-cost-panel-rule{margin-bottom:10px;border-top:.5px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}\n.dq-cost-details{display:grid;grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-cost-details dt,.dq-cost-details dd{min-width:0;margin:0}\n.dq-cost-details dd{color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;text-align:right}\n/* \u5361\u7247\u95F4\u8DDD\uFF08\u6B64\u5904 gap\uFF09\u523B\u610F\u5927\u4E8E\u5361\u5185\u5C0F\u8282\u95F4\u8DDD\uFF08margin-top:12/14/16px \u90A3\u4E00\u6863\uFF09\uFF0C\u5236\u9020\"\u5361\u7247\u5916\u758F\u3001\u5361\u7247\u5185\u5BC6\"\u7684\n \u758F\u5BC6\u5BF9\u6BD4\uFF1A24px \u76F8\u5BF9\u5361\u5185\u6700\u5927\u6863 16px \u4ECD\u6709 1.5 \u500D\u7EA7\u5DEE\uFF0C\u76F8\u5BF9\u5E38\u89C1\u6863 12px \u6709 2 \u500D\u7EA7\u5DEE\uFF0C\u4E0D\u4E0E .dq-card \u7684\n padding\uFF0816px/20px\uFF0C\u5361\u7247\u5185\u90E8\u547C\u5438\u611F\uFF0C\u8F6E\u6B21 36 \u5DF2\u5B9A\uFF09\u6DF7\u540C\u3002 */\n/* Width parity with the host composer: the dashboard column reserves the\n same max-width as the conversation reading column (860px, \u8F6E\u6B21 42 kept it\n deliberately), but on narrower viewports the fixed 860px would overhang\n the input box \u2014 measured in dashboard.tsx as --dq-composer-w, capped at\n the reading-column width so wide viewports are unchanged. */\n.dq-balance{-webkit-text-size-adjust:100%;text-size-adjust:100%;box-sizing:border-box;width:100%;min-width:0;display:flex;flex-direction:column;gap:32px;padding:20px 24px 48px;max-width:min(860px,var(--dq-composer-w,860px));margin:0 auto;font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.5;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary,#1f2328);--dq-text-success:#1a7f37;--dq-text-success:color-mix(in oklab,var(--dsw-alias-state-success-primary,#2da44e) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);--dq-text-warn:#9a6700;--dq-text-warn:color-mix(in oklab,var(--dsw-alias-state-warn-primary,#bf8700) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);}\n@media (max-width:620px){.dq-balance{max-width:100%;gap:24px;padding:16px 12px calc(var(--dq-composer-h,126px) + 16px)}.dq-card{padding:16px}.dq-card--hero{padding:0 16px}.dq-status-row{padding:0 16px}}\n/* \u8F6E\u6B21 55\uFF1A\u53EA\u6709\u4E3B\u5361\u7247\u5E26\u6846\u3002\u6B21\u7EA7\u5206\u6790\u4E0E\u8BBE\u7F6E\u662F\u65E0\u6846\u5C0F\u8282\uFF0C\u9760 32px \u6BB5\u8DDD\u548C 13px \u4E3B\u8272\u6807\u9898\u5206\u7EC4\uFF1B\n \u5DE6\u53F3 20px \u5185\u8FB9\u8DDD\u8BA9\u5B83\u4EEC\u7684\u6587\u5B57\u8FB9\u4E0E\u4E3B\u5361\u7247\u5185\u6587\u5BF9\u9F50\uFF0C\u6574\u9875\u53EA\u6709\u4E00\u6761\u6587\u5B57\u5DE6\u8FB9\u7EBF\u3002 */\n.dq-card{box-sizing:border-box;min-width:0;max-width:100%;padding:20px;background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.10));border-radius:12px}\n.dq-card-title{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 8px;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 16px;letter-spacing:0;text-wrap:balance}\n.dq-card-caption{font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}\n.dq-card-head .dq-card-title{margin:0}\n.dq-card-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;min-width:0}\n/* \u4E3B\u5361\u7247\uFF08\u4F59\u989D/\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017/\u6D88\u8017\u6982\u89C8/\u7528\u91CF\u8D8B\u52BF\uFF0C\u8F6E\u6B21 45 \u65B0\u589E\u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300D\uFF09\u89C6\u89C9\u6743\u91CD\u9AD8\u4E8E\u6B21\u7EA7\u5206\u6790\n \u5361\u7247\u4E0E\u5BFC\u822A\u7C7B\u5361\u7247\uFF1A\u53EA\u8C03\u6392\u7248\u5C5E\u6027\u2014\u2014\u5185\u8FB9\u8DDD\u3001\u6807\u9898\u5B57\u53F7\u5B57\u91CD\u4E0E\u53D6\u8272\u3001\u8FB9\u6846\u6DF1\u6D45\u2014\u2014\u4E0D\u5F15\u5165\u65B0\u914D\u8272\u4F53\u7CFB\u3002\u4E24\u6761\u89C4\u5219\n \u4E0E\u4E0A\u9762\u7684\u57FA\u7840\u89C4\u5219\u540C\u4E3A\u5355\u7C7B\u9009\u62E9\u5668\u4E14\u6E90\u7801\u987A\u5E8F\u66F4\u9760\u540E\uFF0C\u5929\u7136\u8986\u76D6\uFF0C\u4E0D\u9700\u8981 !important\u3002\u6B21\u7EA7\u5206\u6790\u5361\u7247\uFF08\u7528\u91CF\n \u70ED\u529B\u56FE/\u9AD8\u5CF0\u95F2\u65F6/\u7F13\u5B58\u547D\u4E2D/\u6A21\u578B\u6392\u884C/\u4F1A\u8BDD\u6392\u884C\uFF09\u4E0E\u5BFC\u822A\u7C7B\u5361\u7247\uFF08\u8BBE\u7F6E\uFF0C\u542B\u8F6E\u6B21 39 \u5E76\u5165\u7684\u5B98\u65B9\u5E73\u53F0\u94FE\u63A5\uFF09\u90FD\u4E0D\u52A0\n \u8FD9\u4E2A\u4FEE\u9970\u7C7B\uFF0C\u7EF4\u6301\u539F\u6709 .dq-card \u57FA\u7EBF\uFF0C\u5F62\u6210\u4E24\u6863\u6743\u91CD\u3002\u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300D\u5347\u7EA7\u4E3A\u4E3B\u5361\u7247\u7684\u7406\u7531\uFF1A\u5B83\u548C\u4F59\u989D\u4E00\u6837\u662F\n \u6253\u5F00\u8FD9\u4E2A\u300C\u989D\u5EA6\u300Dtab \u65F6\u4E0A\u4E0B\u6587\u6700\u76F4\u63A5\u76F8\u5173\u7684\u6570\u5B57\uFF08\u8FD9\u4E2A tab \u6302\u5728\u5177\u4F53\u4F1A\u8BDD\u5185\u90E8\uFF0C\u89C1 DESIGN_NOTES\u300C\u4FE1\u606F\u5C42\u7EA7\u300D\uFF09\uFF0C\n \u4E0D\u5C5E\u4E8E\u539F\u6709\u8D26\u6237\u5168\u5C40\u5C42\u7EA7 1-3 \u7684\u4EFB\u4F55\u4E00\u7EA7\uFF0C\u800C\u662F\u4E0E\u4E4B\u6B63\u4EA4\u7684\u53E6\u4E00\u4E2A\u7EF4\u5EA6\uFF0C\u4F46\u540C\u6837\u662F\u9996\u5C4F\u5FC5\u8BFB\uFF0C\u56E0\u6B64\u540C\u6837\u7ED9\n primary \u6743\u91CD\uFF0C\u4E0D\u65B0\u5F00\u7B2C\u4E09\u6863\u3002 */\n.dq-card--primary{padding:20px;border-color:var(--dsw-alias-border-l3,rgba(0,0,0,.12))}\n/* \u4F59\u989D\u662F\u6574\u9875\u552F\u4E00\u7684 hero\uFF1A\u4E0D\u5957\u6846\uFF0C32px \u6570\u5B57\u72EC\u5360\u4E00\u6863\uFF0C\u8BA9\u5B83\u5728\u906E\u4F4F\u6587\u5B57\u65F6\u4ECD\u662F\u7B2C\u4E00\u773C\u3002 */\n.dq-card--hero{padding:0 20px;background:transparent;border:0;border-radius:0}\n.dq-card-pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(340px,100%),1fr));gap:24px;min-width:0}\n.dq-card--hero .dq-stat-label{font-size:13px;margin-bottom:2px}\n.dq-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.dq-card--hero .dq-balance-grid{align-items:stretch;gap:12px 48px}\n.dq-card--hero .dq-stat{display:flex;flex-direction:column;justify-content:space-between}\n/* hero \u6570\u5B57\u4E0D\u753B\u70B9\u72B6\u4E0B\u5212\u7EBF\uFF0840px \u4E0B\u592A\u91CD\uFF09\uFF1B\u53EF\u70B9\u6027\u9760\u60AC\u505C\u5E95\u8272\u548C title \u63D0\u793A\u3002 */\n.dq-card--hero details>summary{text-decoration:none;margin:-2px -6px;padding:2px 6px;border-radius:8px;transition:background .15s ease}\n.dq-card--hero details>summary:hover,.dq-card--hero details[open]>summary{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.05))}\n@media (max-width:620px){.dq-card{padding:16px}.dq-card--hero{padding:0 16px}}\n.dq-window-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.08))}\n.dq-window-btn{border:0;border-radius:6px;padding:4px 8px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;white-space:nowrap;cursor:pointer;transition:background .15s ease,color .15s ease,box-shadow .15s ease}\n.dq-window-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-window-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.12)}\n.dq-window-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n@media (max-width:620px){.dq-card-head{align-items:flex-start;flex-wrap:wrap}.dq-card-actions{width:100%;justify-content:space-between}}\n.dq-export{position:relative;flex:none}\n.dq-export-btn{min-width:58px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease,background .15s ease}\n.dq-export-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-export-btn--done{border-color:rgba(45,164,78,.35);color:var(--dsw-alias-state-success-primary,#1a7f37);background:rgba(45,164,78,.08)}\n.dq-export-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:180px;padding:6px;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);display:flex;flex-direction:column;gap:2px}\n.dq-export-menu button{display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;border:0;border-radius:6px;padding:7px 8px;background:transparent;color:var(--dsw-alias-label-primary,#1f2328);font-size:12px;text-align:left;cursor:pointer}\n.dq-export-menu button:hover,.dq-export-menu button:focus-visible{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-export-menu button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-1px}\n.dq-export-menu small{font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e);white-space:nowrap}\n/* Small-text tier system (\u8F6E\u6B21 41 \u6536\u655B): two whole-pixel tiers replace what used to be four values\n (11/11.5/12/12.5px) spaced only 0.5px apart \u2014 a gap browsers subpixel-round away, so it read as one\n size with extra maintenance cost, not an actual visual hierarchy. 11px = \"micro\" chrome the user\n scans rather than reads (dt-style stat/period labels, delta/status/coverage pills, share %, tags,\n the widget grip) \u2014 kept as-is. 12px = \"secondary text\" (section titles, hint/footnote/legend/sub\n prose, table cells, tooltip copy, alert/empty-state sentences, and filter/segmented-control button\n labels like .dq-window-btn/.dq-chart-switch-btn, which are the same control family and should share\n one size) \u2014 absorbed the old 11.5px and 12.5px selectors, all by rounding toward the nearer tier\n (11.5\u219212 grows slightly for legibility, safe because none of the affected containers are width-\n capped; 12.5\u219212 shrinks by 0.5px on two full-sentence blocks, imperceptible). Weight/color still do\n the job of separating titles from body text within the 12px tier, same as before this merge. Do not\n reintroduce a fractional-px value in this range; if a selector needs to stand apart from these two,\n it belongs in an already-established different tier (10px icon glyphs, 13px+ hero-adjacent text). */\n.dq-balance-grid{display:flex;flex-wrap:wrap;gap:12px 24px}\n.dq-stat{min-width:110px}\n.dq-stat-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-bottom:4px}\n.dq-stat-value{font-size:18px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-stat-value--ok{color:var(--dq-text-success)}\n.dq-stat-value--bad{color:var(--dsw-alias-state-error-primary,#cf222e)}\n/* \u8F6E\u6B21 43: .dq-runway is a controlled <details> (see dashboard.tsx) \u2014 hover/toggle state\n drives the real open attribute now, so .dq-runway-detail only needs to react to [open];\n an unopened <details>'s non-summary children don't actually render in current Chromium no\n matter what display value author CSS gives them (:hover{display:block} alone is a dead end). */\n.dq-runway{position:relative}\n.dq-runway>summary{display:inline-block;list-style:none;border-radius:4px;cursor:pointer;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-runway>summary::-webkit-details-marker{display:none}\n.dq-runway>summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:3px}\n.dq-runway-detail{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;max-width:240px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:normal;font-size:12px;font-weight:500;line-height:1.6;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-runway[open] .dq-runway-detail{display:block}\n/* hero number for the balance, matching .dq-period-cost; relies on cascade order (declared after\n .dq-stat-value, same specificity) to win over the .dq-stat-value it's paired with in JSX \u2014 keep it below */\n/* \u8F6E\u6B21 47: .dq-remaining is a controlled <details> too now (see dashboard.tsx), same reason as\n .dq-runway above \u2014 an unopened <details>'s non-summary children don't actually render in current\n Chromium regardless of author display value, so the old :hover{display:flex} branch was dead code. */\n.dq-remaining{position:relative;font-size:32px;font-weight:700;letter-spacing:-.025em;line-height:1.1}\n.dq-hero-unit{font-size:13px;font-weight:500;letter-spacing:0;margin-left:4px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-remaining>summary{display:inline-block;list-style:none;border-radius:4px;cursor:pointer;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-remaining>summary::-webkit-details-marker{display:none}\n.dq-remaining>summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:3px}\n.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-remaining[open] .dq-remaining-breakdown{display:flex}\n.dq-remaining-granted{color:var(--dsw-alias-label-secondary,#59636e);font-weight:400;font-size:12px}\n/* Low-balance top-up shortcut beside the runway value. It is an <a>, not a\n <button>, because it leaves the app; the \u2197 glyph states that. Colours come\n from the host's primary-button tokens (the same pair DSH's own filled\n buttons use) so the page keeps exactly one filled call to action instead of\n reading as another filter chip. Height stays on the runway text line so the\n hero row does not grow. */\n.dq-runway-line{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px}\n.dq-topup{display:inline-flex;align-items:center;gap:2px;height:26px;padding:0 10px;border-radius:var(--dsw-radius-sm,8px);background:var(--dsw-alias-button-primary-fill,#0969da);color:var(--dsw-alias-label-primary-foreground,#fff);font-size:12px;font-weight:600;line-height:1;text-decoration:none;white-space:nowrap;transition:background .15s ease}\n.dq-topup:hover{background:var(--dsw-alias-button-primary-hover,#0757ba)}\n.dq-topup:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-topup-arrow{font-size:10px;line-height:1;transform:translateY(-1px)}\n/* narrow screens: .dq-balance-grid wraps its 3 stats onto separate lines, so the absolutely-positioned\n .dq-remaining-breakdown/.dq-runway-detail popovers can float down over whichever stat now sits in the\n next row (e.g. \"\u4F59\u989D\u660E\u7EC6\" open covering \"\u9884\u8BA1\u53EF\u7528\"'s clickable summary) \u2014 force each stat onto its own\n full-width row and switch both popovers to normal in-flow layout so an open one pushes its own row\n taller instead of overlaying a sibling; desktop keeps the original hover-overlay behavior unchanged */\n@media (max-width:620px){\n .dq-card--hero .dq-balance-grid{gap:12px 32px}\n .dq-card--primary .dq-balance-grid,.dq-session-expand .dq-balance-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 16px}\n .dq-card--primary .dq-balance-grid .dq-stat,.dq-session-expand .dq-balance-grid .dq-stat{min-width:0}\n .dq-remaining-breakdown,.dq-runway-detail{position:static;margin-top:6px;box-shadow:none;max-width:none;white-space:normal}\n}\n.dq-period-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 32px}\n.dq-period{min-width:0}\n/* \u7A84\u5C4F\uFF1A\u4E09\u4E2A\u5468\u671F\u6539\u6210\u5217\u8868\u884C\u2014\u2014\u6807\u7B7E\u4E0E\u6DA8\u8DCC\u5728\u5DE6\u3001\u91D1\u989D\u53F3\u5BF9\u9F50\u3001\u660E\u7EC6\u5360\u7B2C\u4E8C\u884C\uFF0C\u4E09\u6BB5\u53EA\u5360\u7EA6 150px\u3002 */\n@media (max-width:620px){.dq-period-grid{grid-template-columns:1fr;gap:16px}.dq-period{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;align-items:center}.dq-period-head{margin:0}.dq-period-cost{grid-column:2;grid-row:1}.dq-period-sub{grid-column:1/-1;margin-top:2px}}\n.dq-period-head{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-bottom:8px}\n.dq-period-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-period-cost{font-size:18px;font-weight:700;letter-spacing:-.01em;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;line-height:1.2}\n.dq-period-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-top:4px;font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-budget{margin-top:24px}\n.dq-budget--unset{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-budget-action{border:0;background:transparent;padding:3px 4px;border-radius:5px;color:var(--dsw-alias-state-business-primary,#0969da);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer}\n.dq-budget-action:hover{text-decoration:underline;text-underline-offset:3px}\n.dq-budget-action:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-budget-head,.dq-budget-meta{display:flex;align-items:center;justify-content:space-between;gap:12px}\n.dq-budget-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-budget-amount{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-budget-track{height:8px;margin-top:8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-budget-fill{width:100%;height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transform-origin:left center;transition:transform .35s cubic-bezier(.22,1,.36,1)}\n.dq-budget--risk .dq-budget-fill{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-budget--over .dq-budget-fill{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-budget-meta{margin-top:6px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-budget--risk .dq-budget-meta span:last-child{color:var(--dq-text-warn);font-weight:600}\n.dq-budget--over .dq-budget-meta{color:var(--dsw-alias-state-error-primary,#cf222e);font-weight:600}\n@media (max-width:620px){.dq-budget-head,.dq-budget-meta,.dq-budget--unset{align-items:flex-start;flex-direction:column;gap:4px}.dq-budget-action{margin-left:-4px}}\n.dq-delta{display:inline-flex;align-items:center;gap:3px;font-size:12px;font-weight:600;padding:1px 6px;border-radius:999px;white-space:nowrap;cursor:help;font-variant-numeric:tabular-nums}\n.dq-delta--up{color:var(--dq-text-warn);background:rgba(191,135,0,.14)}\n.dq-delta--down{color:var(--dq-text-success);background:rgba(45,164,78,.14)}\n.dq-delta--flat,.dq-delta--new{color:var(--dsw-alias-label-secondary,#59636e);background:rgba(120,130,150,.14);font-weight:500}\n.dq-delta-label{font-weight:400;opacity:.8}\n.dq-pricing{margin-top:16px}\n.dq-pricing-summary{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);cursor:pointer;list-style:none;width:fit-content;border-radius:6px;padding:2px 4px;margin-left:-4px}\n.dq-pricing-summary::-webkit-details-marker{display:none}\n.dq-pricing-summary::before{content:\"\";display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease}\n.dq-pricing[open] .dq-pricing-summary::before{transform:rotate(90deg)}\n.dq-pricing-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-pricing-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-pricing-now{font-size:12px;font-weight:600;padding:1px 7px;border-radius:999px;color:var(--dsw-alias-label-secondary,#59636e);background:rgba(120,130,150,.14)}\n.dq-pricing-now--peak{color:var(--dq-text-warn);background:rgba(191,135,0,.14)}\n.dq-pricing-body{margin-top:8px;overflow-x:auto}\n.dq-pricing-table{border-collapse:collapse;font-size:12px;font-variant-numeric:tabular-nums;min-width:100%}\n.dq-pricing-table th{text-align:left;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e);padding:4px 12px 4px 0;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-pricing-table td{padding:4px 12px 4px 0;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;vertical-align:top}\n/* Align by counting from the end: a peak row starts with the rowSpan'd model\n cell (5 cells) while its off-peak pair starts at \u65F6\u6BB5 (4 cells), so\n nth-child(n+3) left the off-peak cache-hit price stranded under \u65F6\u6BB5. The\n last three cells are the three price columns in both row shapes. */\n.dq-pricing-table th:nth-last-child(-n+3),.dq-pricing-table td:nth-last-child(-n+3){text-align:right}\n.dq-pricing-table th:last-child,.dq-pricing-table td:last-child{padding-right:0}\n.dq-pricing-table tbody td:first-child{font-weight:500}\n.dq-pricing-table tbody tr+tr td{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.05))}\n.dq-pricing-foot{margin:8px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-coverage{margin-top:24px}\n.dq-coverage-summary{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;cursor:pointer;list-style:none;width:fit-content;max-width:100%;margin-left:-4px;padding:3px 4px;border-radius:6px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-summary::-webkit-details-marker{display:none}\n.dq-coverage-summary::before{content:\"\";display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease}\n.dq-coverage[open] .dq-coverage-summary::before{transform:rotate(90deg)}\n.dq-coverage-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-coverage-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-coverage-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-status{padding:1px 7px;border-radius:999px;background:rgba(45,164,78,.14);color:var(--dq-text-success);font-size:12px;font-weight:600}\n.dq-coverage--warn .dq-coverage-status{background:rgba(191,135,0,.14);color:var(--dq-text-warn)}\n.dq-coverage-brief{font-size:12px;font-variant-numeric:tabular-nums}\n.dq-coverage-body{margin-top:8px;padding:12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-coverage-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 24px;margin:0}\n.dq-coverage-metrics div{min-width:0}\n.dq-coverage-metrics dt{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-metrics dd{margin:3px 0 0;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-coverage-range,.dq-coverage-note,.dq-coverage-warning{margin:8px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-coverage-range{font-variant-numeric:tabular-nums}\n.dq-coverage-warning{padding:8px 10px;border-radius:8px;background:rgba(191,135,0,.10);color:var(--dq-text-warn)}\n@media (max-width:620px){.dq-coverage-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.dq-coverage-brief{flex-basis:100%;margin-left:19px}}\n.dq-peak-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85;overflow:hidden}\n.dq-peak-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-peak-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-peak-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--peak{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-legend-swatch--offpeak{background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85}\n.dq-peak-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:16px}\n.dq-peak-foot{margin:12px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-clock{margin-bottom:16px}\n.dq-clock-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px}\n.dq-clock-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-clock-status{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;padding:2px 8px;border-radius:999px}\n.dq-clock-status::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor}\n.dq-clock-status--peak{color:var(--dq-text-warn);background:rgba(191,135,0,.12)}\n.dq-clock-status--off{color:var(--dq-text-success);background:rgba(45,164,78,.12)}\n.dq-clock-track{position:relative;display:flex;gap:1px;height:10px}\n.dq-clock-cell{flex:1 1 0;height:100%;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.55}\n.dq-clock-cell--peak{background:var(--dsw-alias-state-warning-primary,#bf8700);opacity:.92}\n.dq-clock-cell:first-child{border-radius:999px 0 0 999px}\n.dq-clock-cell:last-child{border-radius:0 999px 999px 0}\n.dq-clock-now{position:absolute;top:-3px;bottom:-3px;width:2px;background:var(--dsw-alias-label-primary,#1f2328);border-radius:2px;transform:translateX(-1px)}\n.dq-clock-now::before{content:'';position:absolute;top:-4px;left:50%;transform:translateX(-50%);width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-primary,#1f2328)}\n.dq-clock-scale{display:flex;justify-content:space-between;margin-top:4px;font-size:10px;color:var(--dsw-alias-label-tertiary,#59636e);font-variant-numeric:tabular-nums}\n.dq-clock-hint{margin:6px 0 0;font-size:11px;line-height:1.5;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cache-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-bottom:12px}\n@media (max-width:620px){.dq-cache-figures{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 16px}.dq-cache-figures .dq-stat{min-width:0}}\n.dq-muted-value{color:var(--dsw-alias-label-secondary,#59636e)!important;font-weight:500}\n.dq-stat-value--warn{color:var(--dq-text-warn)}\n.dq-cache-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);overflow:hidden}\n.dq-cache-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-cache-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-cache-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--hit{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-legend-swatch--miss{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-cache-foot{margin:12px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-sessions{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:16px}\n.dq-session{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dq-session-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-session-title{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-session-cost{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-session-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-session-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-business-primary,#4176e6);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-session-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n/* The \u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300Dcard uses this class on a bare <p> (no flex-gap parent\n to lean on, unlike the .dq-session usage above), so it needs its own\n explicit spacing rather than falling back to the browser's implicit <p>\n margin \u2014 this project always declares spacing explicitly. */\n.dq-session-meta{margin:12px 0 0;display:flex;flex-direction:column;gap:2px}\n.dq-session-meta p.dq-session-sub{margin:0}\n.dq-session-meta+.dq-rank{margin-top:16px}\n.dq-session-foot{margin:12px 0 0;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n/* \u8F6E\u6B21 46: each ranking row is now a <details> whose <summary> wraps the existing\n head/track/sub trio unchanged (in a flex-column body div) plus a leading chevron \u2014\n same disclosure grammar as .dq-pricing/.dq-coverage above (hidden native marker,\n rotating glyph, :focus-visible ring), just applied to a multi-line summary instead\n of a single line. .dq-session-details needs its own min-width:0 because it is now\n the flex item inside .dq-session that the ellipsis chain must shrink through. */\n.dq-session-details{min-width:0}\n.dq-session-details>summary{list-style:none;cursor:pointer}\n.dq-session-details>summary::-webkit-details-marker{display:none}\n.dq-session-summary{display:flex;align-items:flex-start;gap:8px;border-radius:8px;padding:4px;margin:-4px}\n.dq-session-summary:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.05))}\n.dq-session-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n/* \u5C55\u5F00\u7BAD\u5934\uFF1A14px \u7EBF\u6761\u56FE\u6807\uFF08mask \u53D6 currentColor\uFF09\uFF0C\u66FF\u4EE3\u539F\u6765 10px \u7684\u300C\u25B8\u300D\u5B57\u7B26\u2014\u2014\u90A3\u4E2A\u5B57\u5F62\u592A\u5C0F\u3001\u592A\u6D45\uFF0C\u70B9\u51FB\u76EE\u6807\u4E5F\u96BE\u627E\u3002 */\n.dq-session-chevron{display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease;margin-top:3px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-session-details[open] .dq-session-chevron{transform:rotate(90deg)}\n.dq-session-summary-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}\n/* Expanded body reuses the same shaded-inset language as .dq-coverage-body (10px\n gap from the summary, 11px/12px padding, 10px radius, bg-layer-2) rather than\n inventing a new \"nested panel\" look. SessionUsageCard renders inside unchanged. */\n.dq-session-expand{margin-top:8px;padding:12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-rank{display:flex;flex-direction:column;gap:16px}\n.dq-rank-row{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dq-rank-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-rank-name{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-rank-cost{display:inline-flex;align-items:baseline;gap:8px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-rank-share{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e);min-width:30px;text-align:right}\n.dq-rank-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-rank-fill{height:100%;border-radius:999px;transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-rank-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-alert{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:10px;font-size:12px;line-height:1.6;color:var(--dq-text-warn);background:rgba(191,135,0,.12);border:1px solid rgba(191,135,0,.35);text-wrap:pretty}\n.dq-alert-icon{flex:none;width:18px;height:18px;border-radius:50%;background:var(--dsw-alias-state-warning-primary,#bf8700);color:#fff;font-weight:700;font-size:12px;line-height:18px;text-align:center}\n.dq-alert strong{font-weight:600}\n.dq-alert-link{margin-left:8px;color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}\n.dq-setting{display:flex;align-items:flex-start;gap:16px;margin-top:24px}\n@media (max-width:620px){.dq-setting{flex-direction:column;gap:8px}.dq-setting-label{width:auto;padding-top:0}}\n.dq-setting-label{width:128px;font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);padding-top:6px;flex:none}\n.dq-setting-control{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}\n.dq-setting-hint{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);line-height:1.5}\n.dq-setting-group{margin-top:28px}\n.dq-setting-group:first-of-type{margin-top:0}\n.dq-setting-group-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:0 0 10px;letter-spacing:.02em}\n.dq-setting-group .dq-toggle{margin-top:0}\n.dq-setting-group .dq-setting{margin-top:16px}\n/* Page footer: the package name + version, injected at build time from\n package.json (see build.mjs) so it can never drift from the release. */\n.dq-footer{margin:16px 0 0;font-size:12px;text-align:center;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-sectionnav{position:fixed;top:50%;transform:translateY(-50%);z-index:20;width:max-content;pointer-events:none}\n.dq-sectionnav--hidden{display:none}\n.dq-sectionnav ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;pointer-events:auto}\n.dq-sectionnav li{display:flex;justify-content:flex-end}\n.dq-sectionnav-dot{display:inline-flex;align-items:center;justify-content:flex-end;gap:8px;padding:4px 2px;border:0;background:transparent;border-radius:6px;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.2;white-space:nowrap;transition:color .15s ease,background .15s ease}\n.dq-sectionnav-dot:hover,.dq-sectionnav-dot:focus-visible{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10))}\n.dq-sectionnav-dot:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-sectionnav-label{font-size:12px;color:inherit}\n.dq-sectionnav-pip{flex:none;width:9px;height:9px;border-radius:50%;background:var(--dsw-alias-border-l2,rgba(0,0,0,.22));transition:background .15s ease,transform .15s ease}\n.dq-sectionnav-dot:hover .dq-sectionnav-pip{background:var(--dsw-alias-label-secondary,#59636e)}\n.dq-sectionnav-dot--active{color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}\n.dq-sectionnav-dot--active .dq-sectionnav-pip{background:var(--dsw-alias-state-business-primary,#0969da);transform:scale(1.25)}\n@media (max-width:1199px){.dq-sectionnav{display:none}}\n.dq-number{width:82px;padding:5px 8px;font-size:13px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-number:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;border-color:transparent}\n.dq-links{display:flex;flex-wrap:wrap;gap:8px}\n.dq-link{display:inline-flex;align-items:center;gap:4px;padding:8px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);text-decoration:none;font-size:13px;font-weight:500;cursor:pointer}\n.dq-link::after{content:\"\u2197\";font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-link:hover{border-color:var(--dsw-alias-label-secondary,#59636e);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n/* .dq-toggle is the first settings control after the links row (\u8F6E\u6B21 39 merge) \u2014 its own\n border-top separates the \"\u5FEB\u6377\u5165\u53E3\" links (originally the standalone \u5B98\u65B9\u5E73\u53F0 card, renamed\n in \u8F6E\u6B21 39 fix-round-1 to read as part of \u8BBE\u7F6E's own navigation area) from \u8BBE\u7F6E controls\n inside the merged card, same 14px/14px/border-l1 recipe as .dq-setting so the two\n sub-sections read at equal weight. */\n.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px;font-weight:500;margin-top:24px}\n.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}\n.dq-toggle-hint{margin:4px 0 0 26px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-widget-tabs{align-items:flex-start;flex-direction:column;gap:8px}\n.dq-widget-tab-list{display:flex;align-items:center;flex-wrap:wrap;gap:4px 16px}\n.dq-widget-tab{display:inline-flex;align-items:center;gap:7px;min-height:28px;color:var(--dsw-alias-label-primary,#1f2328);font-size:12px;font-weight:500;cursor:pointer}\n.dq-widget-tab input{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-toggle input:focus-visible,.dq-model-item input:focus-visible,.dq-widget-tab input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible,.dq-export-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-usage-totals{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px 24px;margin-bottom:20px}\n/* value itself (number+unit, e.g. \"9999.9\u4E07\") must never break across lines inside its own column \u2014\n nowrap+ellipsis is a defensive floor for all widths; the actual fix for the realistic 320px 2-col\n case is the font-size drop below, which keeps every measured stress value comfortably under the\n 83px column width without ever hitting the ellipsis fallback (see round 38 PROGRESS entry) */\n.dq-usage-totals .dq-stat-value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.dq-vision-share{display:inline-block;margin-left:6px;font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-vision-sessions{margin-top:12px;display:flex;flex-direction:column;gap:8px;min-width:0}\n/* The vision card's session rows reuse .dq-session-head, but \u2014 unlike the\n ranking card's rows \u2014 they sit directly under .dq-session with no\n .dq-session-summary-body wrapper to carry min-width:0. Without the chain\n below, a long session title (nowrap) sets the row's min-content width and\n can stretch the card past its siblings / the container. */\n.dq-vision-sessions .dq-session{min-width:0}\n.dq-vision-sessions .dq-session-head{min-width:0}\n.dq-vision-sessions .dq-session-title{flex:1 1 auto;min-width:0}\n@media (max-width:620px){.dq-usage-totals{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 24px}.dq-usage-totals .dq-stat{min-width:0}.dq-usage-totals .dq-stat-value{font-size:13px}}\n.dq-chart-peak{margin-left:8px;font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-chart-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);margin:16px 0 8px}\n.dq-chart-title:first-of-type{margin-top:0}\n.dq-chart-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 12px}\n.dq-chart-block-head .dq-chart-title{margin:0}\n.dq-chart-controls{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex:none;flex-wrap:wrap}\n@media (max-width:620px){.dq-chart-block-head{align-items:flex-start;flex-direction:column}.dq-chart-controls{width:100%;justify-content:flex-start}}\n.dq-model-picker{position:relative}\n.dq-model-btn{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.dq-model-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-model-btn::after{content:\"\u25BE\";font-size:10px;opacity:.7}\n.dq-model-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:190px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:6px;display:flex;flex-direction:column;gap:2px}\n.dq-model-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:12px;cursor:pointer;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-model-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-model-item input{width:14px;height:14px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-model-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-model-item--all{border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-bottom:8px;margin-bottom:2px;border-radius:6px}\n.dq-model-tag{color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;flex:none}\n.dq-bar-group{display:flex;flex-direction:column-reverse;width:100%}\n.dq-bar-group .dq-bar{flex:0 0 auto;width:100%;border-radius:0}\n.dq-bar-group .dq-bar:first-child{border-radius:0 0 2px 2px}\n.dq-bar-group .dq-bar:last-child{border-radius:2px 2px 0 0}\n.dq-bar-group .dq-bar:not(:last-child){box-shadow:inset 0 1px 0 rgba(0,0,0,.18)}\n.dq-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-legend-item{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch{width:10px;height:10px;border-radius:3px;flex:none}\n.dq-chart-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));border-radius:999px;flex:none}\n.dq-chart-switch-btn{border:none;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;transition:background .15s ease,color .15s ease}\n.dq-chart-switch-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-chart-switch-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.14)}\n.dq-chart-wrap{position:relative}\n.dq-plot{display:flex;align-items:flex-end;gap:8px}\n.dq-yaxis{flex:none;width:46px;display:flex;flex-direction:column;justify-content:space-between;margin-bottom:18px;font-size:11px;line-height:1;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;text-align:right;pointer-events:none}\n.dq-yaxis span{white-space:nowrap}\n.dq-bars-scroll{flex:1 1 auto;min-width:0;overflow-x:auto;overflow-y:hidden;padding-bottom:2px}\n.dq-tip{position:absolute;transform:translate(-50%,14px);z-index:40;pointer-events:none;background:var(--dsw-alias-tooltip-bg,#1f2328);color:var(--dsw-static-neutral-bluish-00,#fff);border-radius:8px;padding:7px 10px;font-size:12px;line-height:1.5;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.28);font-variant-numeric:tabular-nums}\n.dq-tip--above{transform:translate(-50%,calc(-100% - 8px))}\n.dq-tip-head{font-weight:600;margin-bottom:2px}\n.dq-tip-row{opacity:.85}\n.dq-bars{display:flex;align-items:flex-end;gap:2px;width:100%}\n.dq-bar-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}\n.dq-bar{background:var(--dsw-alias-state-business-primary,#4176e6);border-radius:2px 2px 0 0;min-height:1px;transition:filter .12s ease}\n.dq-bar-col{cursor:default}\n.dq-bar-col,.dq-bar,.dq-heat-cell{scroll-margin-block-start:24px;scroll-margin-block-end:160px}\n.dq-bar-col:hover .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-bar-col:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-2px;border-radius:3px}\n.dq-bar:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;filter:brightness(1.18) saturate(1.1);position:relative;z-index:2}\n.dq-bar-col--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-2px;border-radius:3px}\n.dq-bar-col--pinned .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-bar--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;filter:brightness(1.18) saturate(1.1);position:relative;z-index:2}\n.dq-heat-cell:not(.dq-heat-cell--pad):hover{outline:1.5px solid var(--dsw-alias-label-primary,#1f2328);outline-offset:1px}\n.dq-heat-cell:not(.dq-heat-cell--pad):focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;position:relative;z-index:2}\n.dq-heat-cell--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;position:relative;z-index:2}\n.dq-bar-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);text-align:center;margin-top:4px;overflow:visible;white-space:nowrap}\n.dq-heat{display:flex;flex-direction:column;gap:8px;max-width:100%}\n.dq-heat-scroll{overflow:hidden;padding-bottom:2px}\n.dq-heatmap{display:flex;gap:2px}\n.dq-heat-week{display:flex;flex:1 1 0;min-width:0;flex-direction:column;gap:2px}\n.dq-heat-cell{width:100%;aspect-ratio:1/1;border-radius:2px;flex:none;min-width:0}\n.dq-heat-cell--pad{background:transparent}\n.dq-heat-months{display:flex;gap:2px;margin-top:4px}\n.dq-heat-month{flex:1 1 0;min-width:0;font-size:12px;line-height:15px;color:var(--dsw-alias-label-secondary,#59636e);white-space:nowrap;overflow:visible}\n.dq-heat-key{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-scale{display:flex;align-items:center;gap:3px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);align-self:flex-end}\n.dq-heat-scale>span:first-child{margin-right:2px}\n.dq-heat-scale>span:last-child{margin-left:2px}\n.dq-muted{color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-warn{color:var(--dq-text-warn)}\n.dq-crash{margin:10px 0 14px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10));border-radius:8px;font-size:12px;line-height:1.6;color:var(--dsw-alias-state-error-primary,#cf222e);white-space:pre-wrap;word-break:break-word;font-family:var(--ds-font-family-code,ui-monospace,SFMono-Regular,Menlo,monospace)}\n.dq-empty{color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.6;padding:6px 0;text-wrap:pretty}\n/* Error-state modifier for a card body that has nothing else to show (mirrors the .dq-stat-value--ok/\n --bad/--warn pattern: same layout as .dq-empty, declared after it so this color wins at equal\n specificity). Used by the current-session card when its own fetch failed and there is no prior\n data to fall back to \u2014 the status-row .dq-error/.dq-warn spans are for the account-wide balance/\n usage fetch, this is the per-card equivalent. */\n.dq-empty--error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-skel{background:linear-gradient(90deg,rgba(125,135,155,.10) 25%,rgba(125,135,155,.20) 37%,rgba(125,135,155,.10) 63%);background-size:400% 100%;border-radius:5px;animation:dq-shimmer 1.5s ease-in-out infinite}\n.dq-stat .dq-skel+.dq-skel{margin-top:6px}\n.dq-skel-bars{display:flex;align-items:flex-end;gap:2px;width:100%;height:160px;margin-top:12px}\n.dq-skel-bar{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0}\n@keyframes dq-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}\n.dq-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:20px;padding:0 20px;margin-bottom:-12px}\n.dq-status-messages{display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0}\n.dq-status-row .dq-warn,.dq-status-row .dq-error{font-size:12px;line-height:1.5}\n.dq-sync{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-sync-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--dsw-alias-label-tertiary,#8c959f)}\n.dq-sync--fresh .dq-sync-dot{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-sync--syncing .dq-sync-dot{background:var(--dsw-alias-state-business-primary,#4176e6);animation:dq-sync-pulse 1.2s ease-in-out infinite}\n.dq-sync--fallback{color:var(--dq-text-warn)}\n.dq-sync--fallback .dq-sync-dot{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-sync--error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-sync--error .dq-sync-dot{background:var(--dsw-alias-state-error-primary,#cf222e)}\n@keyframes dq-sync-pulse{50%{opacity:.35;transform:scale(.8)}}\n.dq-refresh-btn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-status-actions{display:flex;align-items:center;gap:8px;flex:none}\n.dq-settings-btn{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-settings-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-settings-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-settings-caret{font-size:10px;line-height:1;transition:transform .2s cubic-bezier(.16,1,.3,1)}\n.dq-settings-caret--open{transform:rotate(180deg)}\n.dq-settings-panel{box-sizing:border-box;min-width:0;max-width:100%;padding:20px;background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.10));border-radius:12px}\n/* Motion: eased (easeOutExpo) arrivals. Operate surface \u2014 fast, purposeful,\n and fully disabled under prefers-reduced-motion (see the global reduce block). */\n.dq-export-menu,.dq-model-menu{transform-origin:top right;animation:dq-pop .18s cubic-bezier(.16,1,.3,1)}\n@keyframes dq-pop{from{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:none}}\n.dq-alert{animation:dq-alert-in .28s cubic-bezier(.16,1,.3,1)}\n@keyframes dq-alert-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}\n@media (max-width:620px){.dq-settings-panel{padding:16px}}\n.dq-refresh-btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-refresh-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-refresh-btn:disabled{cursor:default;opacity:.6}\n.dq-refresh-icon{display:inline-block;line-height:1}\n.dq-refresh-icon--spin{animation:dq-spin .9s linear infinite}\n@keyframes dq-spin{to{transform:rotate(360deg)}}\n/* ============================================================================\n Host chrome: the \u300C\u989D\u5EA6\u300Dconversation view does not use the chat composer.\n The attribute is set by index.tsx only when the dashboard is mounted inside\n the conversation scrollport, so the account-wide panel never hides it.\n '!important' because the composer's slot anchor is a \"display:contents\"\n wrapper whose display we must beat regardless of host rule order.\n ============================================================================ */\nhtml[data-dq-quota-view] [data-slot=\"conversation.composer\"]{display:none!important}\n/* The narrow-viewport rule pads for the fixed composer; with it hidden there\n is nothing to clear, so fall back to the page's own bottom breathing room. */\nhtml[data-dq-quota-view] .dq-balance{padding-bottom:48px}\n/* ============================================================================\n Account-wide \u300C\u989D\u5EA6\u300Dpanel (the optional sidebar entry opens this main\n keyed panel). The dashboard keeps its own width/padding; the panel only\n supplies the page title row and the scrolling box the main column lacks.\n ============================================================================ */\n/* Account-wide page frame: mirrors DSH's first-level pages (Plugins /\n Scheduled tasks) \u2014 full-height scroll box, 28px top inset on the heading,\n a 960px centred column, clamp(24px,4vw,48px) inline + 48px bottom insets and\n a 20px/28px/500 page title, so the three sibling entries line up. */\n.dq-panel{box-sizing:border-box;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;padding:0 clamp(24px,4vw,48px) 48px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.5}\n.dq-panel-head{box-sizing:border-box;display:flex;flex-direction:column;align-items:flex-start;gap:4px;width:100%;max-width:960px;margin:0 auto 32px;padding-top:28px}\n.dq-panel-title{margin:0;font-size:20px;font-weight:500;line-height:28px;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-panel-caption{font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-panel .dq-balance{box-sizing:border-box;width:100%;max-width:960px;padding:0}\n/* macOS hiddenInset titlebar: the frame's top clearance keeps the heading\n below the window's top strip, matching the host's sibling pages. */\n[data-platform=\"darwin\"] .dq-panel-head{padding-top:calc(28px + var(--dsh-frame-top-clearance,0px))}\n@media (max-width:620px){\n .dq-panel-head{padding-top:24px;margin-bottom:24px}\n .dq-panel .dq-balance{max-width:100%;padding:0}\n}\n/* Optional sidebar entry. Top placement joins the host's global-panel icon\n row (only the glyph is ours); bottom placement renders a row beside\n Settings, collapsing to a square rail button with the sidebar. */\n/* The glyph is an SVG matching the host's 16px stroke icons; color inherits\n from the sidebar row so selected/hover states stay the host's business. */\n.dq-side-icon{flex:none;display:block}\n.dq-side-entry{display:flex;align-items:center;gap:8px;box-sizing:border-box;width:100%;border:0;border-radius:8px;padding:7px 8px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font:inherit;font-size:13px;line-height:1.3;text-align:left;cursor:pointer}\n.dq-side-entry:hover{background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10));color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-side-entry:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-side-entry[aria-pressed=\"true\"]{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-side-entry--rail{justify-content:center;width:32px;height:32px;margin:0 auto;padding:0}\n.dq-side-entry-icon{flex:none;display:inline-flex;align-items:center;justify-content:center}\n.dq-side-entry-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* ============================================================================\n Settings controls for the two layout preferences: a compact select and the\n draggable tab-order strip.\n ============================================================================ */\n.dq-select{font:inherit;font-size:13px;line-height:1.3;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));border-radius:8px;padding:5px 8px;min-width:96px;cursor:pointer}\n.dq-select:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-tab-order{display:flex;flex-wrap:wrap;align-items:center;gap:6px;box-sizing:border-box;max-width:100%;min-height:32px;padding:4px;border:1px dashed var(--dsw-alias-border-l2,rgba(0,0,0,.16));border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-tab-chip{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));border-radius:999px;background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.4;white-space:nowrap}\n.dq-tab-chip--current{cursor:grab;color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-state-business-primary,#0969da);font-weight:600;user-select:none;-webkit-user-select:none;touch-action:none}\n.dq-tab-chip--current:active{cursor:grabbing}\n.dq-tab-chip--current:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-tab-chip--dragging{opacity:.55}\n.dq-tab-chip--drop-target{border-style:dashed;border-color:var(--dsw-alias-state-business-primary,#0969da)}\n/* ============================================================================\n \u300C\u56FE\u7247 / \u591A\u6A21\u6001\u7528\u91CF\u300Dlives inside the usage-trend card. The grid-rows 0fr\u21921fr\n trick animates the section's real height as a window range makes it appear\n or disappear; opacity/translate make the change read as a reveal rather\n than a reflow. The body keeps 14px of top room in both states (clipped by\n the 0fr row when closed) so opening never jumps.\n ============================================================================ */\n.dq-vision-inline{display:grid;grid-template-rows:0fr;margin-top:0;opacity:0;transform:translateY(-3px);overflow:hidden;transition:grid-template-rows .32s cubic-bezier(.22,1,.36,1),margin-top .32s cubic-bezier(.22,1,.36,1),opacity .2s ease,transform .32s cubic-bezier(.22,1,.36,1)}\n.dq-vision-inline[data-open=\"true\"]{grid-template-rows:1fr;margin-top:24px;opacity:1;transform:none}\n.dq-vision-inline-body{min-height:0;overflow:hidden}\n.dq-vision-inline-body>.dq-chart-title{margin-top:0}\n.dq-vision-inline-body>.dq-chart-title{margin-top:0}\n\n@media (prefers-reduced-motion:reduce){\n .dsh-quota-root,.dsh-quota-root *,\n .dsh-quota-root *::before,.dsh-quota-root *::after,\n .dq-message-cost,.dq-message-cost::after,\n .dq-balance,.dq-balance *,\n .dq-balance *::before,.dq-balance *::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}\n}\n`\n", "/** The draggable bottom-right floating balance widget.\n *\n * Where it sits (corner) and whether it is collapsed are user choices, so both\n * are persisted (see ./prefs.ts) and restored before the first paint; the\n * widget also re-snaps to its corner when the frame resizes (window resize,\n * sidebar collapse) instead of stranding itself at stale pixel coordinates.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport {\n fetchBalance,\n fetchSessionUsage,\n fetchUsage,\n getCachedBalance,\n getCachedSessionUsage,\n getCachedUsage,\n getCachedUsageAt,\n subscribeSessionUsage,\n subscribeUsage,\n} from './api.ts'\nimport { fmt } from './charts.tsx'\nimport type { BalanceData, SessionUsageData, UsageData } from '../contract.ts'\nimport { getActiveConversationViewId, getMainColumn, getShellFrame, slotBox } from './dom.ts'\nimport { localizeApiError, useI18n } from './i18n.tsx'\nimport { fmtTurnCost } from './message-cost.tsx'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\nimport { currentSessionIdOf, type SessionListStateFace } from './sessions.ts'\nimport { lowBalanceStore, quotaViewActiveStore, widgetTabIdsStore, widgetVisibleStore } from './store.ts'\nimport type { ConversationViewTab, ConversationViewsSource } from './views.ts'\n\nconst MARGIN = 16\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br'\n\nconst CORNER_KEY = 'widget.corner'\nconst COLLAPSED_KEY = 'widget.collapsed'\n\nconst isCorner = (value: unknown): boolean =>\n value === 'tl' || value === 'tr' || value === 'bl' || value === 'br'\n\ninterface Bounds {\n left: number\n top: number\n right: number\n bottom: number\n}\n\ninterface DragSession {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n width: number\n height: number\n bounds: Bounds\n}\n\n/** Below this the region is too short to park a widget in, so an exclusion is\n * skipped rather than squeezing the widget out of the frame. */\nconst MIN_REGION_HEIGHT = 140\n\n/**\n * Draggable area = the main column minus the session header and the composer.\n *\n * Using the main column (rather than the whole frame minus the sidebar) also\n * keeps the widget clear of the right-hand details panel when it is open.\n * The header is excluded so the widget can never park on the Chat / Trajectory\n * / \u989D\u5EA6 tab row and swallow its clicks, and the composer is excluded because a\n * bottom-right widget otherwise covers the model picker and the send button \u2014\n * the two controls the user reaches for most.\n */\nfunction getBounds(node: HTMLElement | null): Bounds {\n const fallback: Bounds = { left: 0, top: 0, right: 100000, bottom: 100000 }\n if (node === null) return fallback\n const frame = getShellFrame(node)\n if (frame === null) return fallback\n const frameRect = frame.getBoundingClientRect()\n let left = frameRect.left\n let right = frameRect.right\n let top = frameRect.top\n const mainRect = getMainColumn(frame)?.getBoundingClientRect() ?? null\n if (mainRect !== null && mainRect.width > 0) {\n left = mainRect.left\n right = mainRect.right\n top = mainRect.top\n } else {\n const sidebarRect = (frame.children[0] as HTMLElement | undefined)?.getBoundingClientRect() ?? null\n if (sidebarRect !== null) left = sidebarRect.right\n }\n let bottom = frameRect.bottom\n const headerRect = slotBox(frame, 'conversation.session.header', 'child')\n if (headerRect !== null && headerRect.bottom > top && headerRect.bottom < bottom - MIN_REGION_HEIGHT) {\n top = headerRect.bottom\n }\n const composerRect = slotBox(frame, 'conversation.composer.dock', 'ancestor')\n if (composerRect !== null && composerRect.top < bottom && composerRect.top > top + MIN_REGION_HEIGHT) {\n bottom = composerRect.top\n }\n return { left, top, right, bottom }\n}\n\nfunction cornerPos(corner: Corner, node: HTMLElement | null, bounds: Bounds): { x: number; y: number } {\n const rect = node?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const xLeft = bounds.left + MARGIN\n const yTop = bounds.top + MARGIN\n const xRight = bounds.right - w - MARGIN\n const yBottom = bounds.bottom - h - MARGIN\n if (corner === 'tl') return { x: xLeft, y: yTop }\n if (corner === 'tr') return { x: xRight, y: yTop }\n if (corner === 'bl') return { x: xLeft, y: yBottom }\n return { x: xRight, y: yBottom }\n}\n\nexport type UseSessionsHook = <T>(selector: (state: SessionListStateFace) => T) => T\n\nexport function QuotaWidget(props: {\n useSessions: UseSessionsHook\n views: ConversationViewsSource\n}): ReactElement | null {\n const { t } = useI18n()\n const sessionId = props.useSessions(currentSessionIdOf)\n const [visible, setVisible] = useState(widgetVisibleStore.get())\n useEffect(() => widgetVisibleStore.subscribe(() => setVisible(widgetVisibleStore.get())), [])\n const [quotaViewActive, setQuotaViewActive] = useState(quotaViewActiveStore.get())\n useEffect(() => quotaViewActiveStore.subscribe(() => setQuotaViewActive(quotaViewActiveStore.get())), [])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n useEffect(() => lowBalanceStore.subscribe(() => setLowBalance(lowBalanceStore.get())), [])\n const [selectedTabIds, setSelectedTabIds] = useState(widgetTabIdsStore.get())\n useEffect(() => widgetTabIdsStore.subscribe(() => setSelectedTabIds(widgetTabIdsStore.get())), [])\n const [viewTabs, setViewTabs] = useState<ConversationViewTab[]>(() => props.views.list())\n useEffect(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views])\n const [activeViewId, setActiveViewId] = useState<string | null>(null)\n\n const cachedBalance = getCachedBalance()\n const [data, setData] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(cachedBalance === null)\n const [collapsed, setCollapsed] = useState(() => loadPref<boolean>(COLLAPSED_KEY, isBoolean, false))\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null)\n const [corner, setCorner] = useState<Corner>(() => loadPref<Corner>(CORNER_KEY, isCorner, 'br'))\n const [dragging, setDragging] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const dragRef = useRef<DragSession | null>(null)\n\n // Today's spend comes from the shared usage cache \u2014 never fetched on the\n // widget's own poll, since aggregating the session logs takes seconds. A\n // manual refresh (below) is the one place the widget pays for it.\n const readUsage = (): { data: UsageData | null; at: number | null } => {\n const cached = getCachedUsage()\n return { data: cached?.ok === true ? cached.data ?? null : null, at: getCachedUsageAt() }\n }\n const [usage, setUsage] = useState(readUsage)\n useEffect(() => subscribeUsage(() => setUsage(readUsage())), [])\n\n const readSessionUsage = (id: string | undefined): SessionUsageData | null => {\n if (id === undefined) return null\n const response = getCachedSessionUsage(id)\n return response?.ok === true ? response.data ?? null : null\n }\n const [sessionUsage, setSessionUsage] = useState<SessionUsageData | null>(() => readSessionUsage(sessionId))\n useEffect(() => {\n setSessionUsage(readSessionUsage(sessionId))\n if (sessionId === undefined) return\n const unsubscribe = subscribeSessionUsage(sessionId, () => setSessionUsage(readSessionUsage(sessionId)))\n void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [sessionId])\n\n // The root-scoped overlay does not receive the session's active view store.\n // Read the host's semantic tablist instead and map its selected button by\n // index to the same live slot ledger used to build that tablist.\n useLayoutEffect(() => {\n const viewIds = viewTabs.map(tab => tab.id)\n const read = (): void => {\n const next = getActiveConversationViewId(getShellFrame(rootRef.current), viewIds)\n setActiveViewId(previous => previous === next ? previous : next)\n }\n read()\n const frame = getShellFrame(rootRef.current)\n let observer: MutationObserver | null = null\n if (frame !== null && typeof MutationObserver === 'function') {\n observer = new MutationObserver(read)\n observer.observe(frame, { subtree: true, childList: true, attributes: true, attributeFilter: ['aria-selected'] })\n }\n const poll = setInterval(read, 1000)\n return () => {\n observer?.disconnect()\n clearInterval(poll)\n }\n }, [sessionId, viewTabs])\n\n const load = async (showLoading: boolean, force = false): Promise<void> => {\n if (showLoading) setLoading(true)\n try {\n const res = await fetchBalance(force)\n if (res.ok && res.data !== undefined) {\n setData(res.data)\n setError(null)\n } else {\n setData(null)\n setError(res.error ?? '')\n }\n } catch (err) {\n setData(null)\n setError((err as { message?: string } | null)?.message ?? String(err))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void load(true)\n const id = setInterval(() => { void load(false) }, 60_000)\n return () => clearInterval(id)\n }, [])\n\n /**\n * Keep the widget parked in its corner: on mount (restoring the persisted\n * corner before the first paint), when collapse/expand changes its size, and\n * whenever the layout moves under it \u2014 window resize, sidebar collapse or\n * the details panel opening (observed), plus a slow poll that catches the\n * one change no observer reports: the session header mounting *after* the\n * overlay, which would otherwise leave the widget parked over the tab row.\n *\n * `place` keeps the previous object when the corner has not actually moved,\n * so repeated triggers cost one rect read and no re-render.\n */\n useLayoutEffect(() => {\n if (!visible || quotaViewActive) return\n const node = rootRef.current\n if (node === null) return\n const place = (): void => {\n if (dragRef.current !== null) return\n const next = cornerPos(corner, node, getBounds(node))\n setPos(prev => (prev !== null && prev.x === next.x && prev.y === next.y ? prev : next))\n }\n place()\n const frame = getShellFrame(node)\n let observer: ResizeObserver | null = null\n if (frame !== null && typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(place)\n observer.observe(frame)\n const main = getMainColumn(frame)\n if (main !== null) observer.observe(main)\n }\n window.addEventListener('resize', place)\n const poll = setInterval(place, 1000)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', place)\n clearInterval(poll)\n }\n }, [visible, quotaViewActive, corner, collapsed])\n\n const snapToNearest = (session: DragSession): void => {\n const node = rootRef.current\n if (node === null) return\n const { width: w, height: h, bounds: b } = session\n const corners: Array<{ c: Corner; x: number; y: number }> = [\n { c: 'tl', x: b.left + MARGIN, y: b.top + MARGIN },\n { c: 'tr', x: b.right - w - MARGIN, y: b.top + MARGIN },\n { c: 'bl', x: b.left + MARGIN, y: b.bottom - h - MARGIN },\n { c: 'br', x: b.right - w - MARGIN, y: b.bottom - h - MARGIN },\n ]\n const rect = node.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n let best = corners[0]\n let bestDistance = Number.POSITIVE_INFINITY\n for (const candidate of corners) {\n const ccx = candidate.x + w / 2\n const ccy = candidate.y + h / 2\n const distance = (ccx - cx) ** 2 + (ccy - cy) ** 2\n if (distance < bestDistance) {\n bestDistance = distance\n best = candidate\n }\n }\n setCorner(best.c)\n savePref(CORNER_KEY, best.c)\n setPos({ x: best.x, y: best.y })\n }\n\n /** Idempotent end-of-drag; also the missed-pointerup backstop. */\n const endDrag = (snap: boolean): void => {\n const session = dragRef.current\n if (session === null) return\n dragRef.current = null\n setDragging(false)\n const node = rootRef.current\n if (node !== null && typeof node.releasePointerCapture === 'function') {\n try {\n node.releasePointerCapture(session.pointerId)\n } catch {\n // capture already released\n }\n }\n if (snap) {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => snapToNearest(session))\n } else {\n snapToNearest(session)\n }\n }\n }\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return\n const target = e.target as Element | null\n if (target !== null && typeof target.closest === 'function' && target.closest('button') !== null) return\n const node = rootRef.current\n if (node === null) return\n const bounds = getBounds(node)\n const rect = node.getBoundingClientRect()\n dragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: rect.left,\n originY: rect.top,\n width: rect.width,\n height: rect.height,\n bounds,\n }\n node.setPointerCapture(e.pointerId)\n setDragging(true)\n e.preventDefault()\n }\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n if ((e.buttons & 1) === 0) {\n endDrag(true)\n return\n }\n const dx = e.clientX - session.startX\n const dy = e.clientY - session.startY\n const maxX = session.bounds.right - session.width - MARGIN\n const maxY = session.bounds.bottom - session.height - MARGIN\n const minX = session.bounds.left + MARGIN\n const minY = session.bounds.top + MARGIN\n setPos({\n x: Math.max(minX, Math.min(session.originX + dx, maxX)),\n y: Math.max(minY, Math.min(session.originY + dy, maxY)),\n })\n }\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n endDrag(true)\n }\n\n if (!visible) return null\n\n const allowedOnActiveView = activeViewId === null\n ? sessionId === undefined\n : activeViewId !== 'balance' && (selectedTabIds === null || selectedTabIds.includes(activeViewId))\n const hidden = quotaViewActive || !allowedOnActiveView\n\n const primary = data !== null && data.balances.length > 0 ? data.balances[0] : null\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n const low = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const dotClass = primary === null\n ? 'dsh-quota-dot dsh-quota-dot--idle'\n : data?.isAvailable === false\n ? 'dsh-quota-dot dsh-quota-dot--error'\n : low ? 'dsh-quota-dot dsh-quota-dot--warn' : 'dsh-quota-dot'\n\n // The usage figure can be minutes old (it is only refreshed on demand), so\n // say how old rather than presenting it as live.\n const ageMinutes = usage.at === null ? null : Math.floor((Date.now() - usage.at) / 60_000)\n const usageAgeText = ageMinutes === null || ageMinutes < 1\n ? t('widget.updatedNow')\n : t('widget.stale', { minutes: ageMinutes })\n const sessionCostRow = sessionUsage === null ? null : (\n <div className=\"dsh-quota-row\" title={t('widget.sessionCostTitle')}>\n <span className=\"dsh-quota-label\">{t('widget.sessionCost')}</span>\n <span className=\"dsh-quota-value\">\u00A5{fmtTurnCost(sessionUsage.cost)}</span>\n </div>\n )\n\n let body: ReactElement | null = null\n if (!collapsed) {\n if (loading && data === null && error === null) {\n body = <div className=\"dsh-quota-body\"><div>{t('widget.loading')}</div>{sessionCostRow}</div>\n } else if (error !== null && data === null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-error\">{localizeApiError(error, t, 'error.query')}</div>\n {sessionCostRow}\n </div>\n )\n } else if (primary !== null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-remaining-label\">{t('balance.remaining')}</div>\n <div title={low ? t('widget.lowTitle', { amount: fmt(lowBalance) }) : undefined}>\n <span className={`dsh-quota-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)}</span>\n <span className=\"dsh-quota-currency\">{primary.currency}</span>\n </div>\n {usage.data !== null && (\n <div className=\"dsh-quota-row\" title={t('widget.todayCostTitle', { age: usageAgeText })}>\n <span className=\"dsh-quota-label\">{t('widget.todayCost')}</span>\n <span className=\"dsh-quota-value\">\u00A5{fmt(usage.data.summary.today.cost)}</span>\n </div>\n )}\n {sessionCostRow}\n {data?.isAvailable === false && (\n <div className=\"dsh-quota-row\">\n <span className=\"dsh-quota-label\">{t('common.status')}</span>\n <span className=\"dsh-quota-value dsh-quota-error\">{t('common.unavailable')}</span>\n </div>\n )}\n </div>\n )\n } else {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-error\">{t('widget.noBalance')}</div>\n {sessionCostRow}\n </div>\n )\n }\n }\n\n const style: CSSProperties | undefined = pos !== null\n ? { left: `${pos.x}px`, top: `${pos.y}px`, right: 'auto', bottom: 'auto' }\n : undefined\n\n return (\n <div\n className={`dsh-quota-root${dragging ? ' dsh-quota-dragging' : ''}${hidden ? ' dsh-quota-root--hidden' : ''}`}\n style={style}\n aria-hidden={hidden}\n >\n <div\n ref={rootRef}\n className=\"dsh-quota-card\"\n title={t('widget.dragCard')}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={() => endDrag(false)}\n onLostPointerCapture={() => endDrag(false)}\n >\n <div className=\"dsh-quota-header\">\n <div className=\"dsh-quota-title\">\n <span className=\"dsh-quota-grip\" title={t('widget.dragGrip')}>\u2807</span>\n <span className={dotClass} />\n <span className=\"dsh-quota-name\">{t('widget.title')}</span>\n </div>\n <div className=\"dsh-quota-actions\">\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={t('widget.refresh')}\n aria-label={t('widget.refresh')}\n disabled={loading}\n onClick={() => {\n void load(true, true)\n void fetchUsage(true)\n if (sessionId !== undefined) void fetchSessionUsage(sessionId, true)\n }}\n >\n \u21BB\n </button>\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={collapsed ? t('widget.expand') : t('widget.collapse')}\n aria-label={collapsed ? t('widget.expandAria') : t('widget.collapseAria')}\n aria-expanded={!collapsed}\n onClick={() => {\n const next = !collapsed\n setCollapsed(next)\n savePref(COLLAPSED_KEY, next)\n }}\n >\n {collapsed ? '+' : '\u2212'}\n </button>\n </div>\n </div>\n {collapsed && primary !== null && (\n <div className=\"dsh-quota-collapsed-total-row\">\n <span className={`dsh-quota-collapsed-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)} {primary.currency}</span>\n </div>\n )}\n {body}\n </div>\n </div>\n )\n}\n", "/**\n * Structural face of the host's session-list state, and the one selector this\n * plugin needs from it.\n *\n * The hosts this plugin runs on speak two dialects. 0.1.5-era hosts kept a\n * flat `current` field; 0.1.6+ removed it and mark the open session through\n * `byId[*].retainedBy.mainView` \u2014 the same signal the host's own document\n * title and sidebar selection read. Both fields stay optional so neither\n * generation fails, and consumers keep working across a host upgrade without\n * a plugin re-release.\n */\n\n/** One session row; only the fields the selector reads. */\nexport interface SessionSummaryFace {\n id?: string\n retainedBy?: { mainView?: number }\n}\n\nexport interface SessionListStateFace {\n byId?: Readonly<Record<string, SessionSummaryFace | undefined>>\n /** 0.1.5-era hosts: the flat current-session field. */\n current?: string\n}\n\n/** The session currently shown in the main panel, if any. */\nexport function currentSessionIdOf(state: SessionListStateFace): string | undefined {\n const retained = Object.values(state.byId ?? {})\n .find(row => (row?.retainedBy?.mainView ?? 0) > 0)\n return retained?.id ?? state.current\n}\n", "/** Live projection of the host's `conversation.view` slot ledger. */\n\nexport interface ConversationViewTab {\n id: string\n label: string\n}\n\nexport interface ConversationViewsSource {\n list(): ConversationViewTab[]\n subscribe(fn: () => void): () => void\n}\n\nexport interface ConversationViewSlotEntry {\n options: {\n id?: string\n order?: number\n label?: string | (() => string)\n }\n}\n\nexport interface ConversationViewSlots {\n entries(name: string): ConversationViewSlotEntry[]\n subscribe(name: string, fn: () => void): () => void\n}\n\nconst labelOf = (entry: ConversationViewSlotEntry): string => {\n const { id = '', label } = entry.options\n try {\n const resolved = typeof label === 'function' ? label() : label\n return typeof resolved === 'string' && resolved !== '' ? resolved : id\n } catch {\n return id\n }\n}\n\n/** Build a source once at plugin apply-time. The ledger owns ordering, so the\n * same index also maps to the host's rendered tab buttons without relying on\n * hashed class names or translated labels. */\nexport function conversationViewsSource(slots: ConversationViewSlots): ConversationViewsSource {\n return {\n list: () => slots.entries('conversation.view')\n .flatMap(entry => entry.options.id === undefined\n ? []\n : [{ id: entry.options.id, label: labelOf(entry) }]),\n subscribe: fn => slots.subscribe('conversation.view', fn),\n }\n}\n"],
5
- "mappings": "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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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",
4
+ "sourcesContent": ["/**\n * dsh-usage-dashboard client half: mounts the floating balance widget\n * (`shell.overlay`), the \u300C\u989D\u5EA6\u300D view tab (`conversation.view`), an optional\n * sidebar entry / account-wide panel, and the per-turn cost chip.\n * Data arrives through the package's own host API via same-origin fetch.\n */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport { ErrorBoundary } from './boundary.tsx'\nimport type { ClientContext } from './context.ts'\nimport { fetchBalance, fetchUsage } from './api.ts'\nimport { BalanceDashboard } from './dashboard.tsx'\nimport { LocaleProvider, type Translate } from './i18n.tsx'\nimport { QUOTA_PANEL_ID, quotaTabIndexStore, sidebarEntryStore, viewOrderForIndex } from './layout-prefs.ts'\nimport { en, NS, zh } from './locales.ts'\nimport { MessageCost } from './message-cost.tsx'\nimport { SessionCostPill } from './session-cost-pill.tsx'\nimport { css } from './styles.ts'\nimport { quotaViewActiveStore } from './store.ts'\nimport { QuotaWidget, type UseSessionsHook } from './widget.tsx'\nimport { conversationViewsSource } from './views.ts'\n\n/** Plugin identity for the client bundle. */\nexport const name = 'dsh-usage-dashboard'\n\n/** Services required before load. */\nexport const inject = ['slots', 'locale', 'layout']\n\n/** The host's `conversation.view` props include a session-addressable view\n * switcher; the tab-position setting uses it to come back to \u989D\u5EA6 after the\n * registration is replaced with a new `order`. */\ntype OpenView = (view: string, focus: string) => void\n\n/** Kept outside React so the registration half can restore the tab after a\n * dispose/re-register cycle, even when that cycle unmounts the dashboard. */\nlet openQuotaTab: OpenView | null = null\n\n/**\n * Mount the plugin surfaces.\n * @param ctx - client Cordis context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-usage-dashboard: browser dictionaries')\n const t = ctx.locale.bind(NS)\n const views = conversationViewsSource(ctx.slots)\n // One stylesheet for the whole plugin; the module loader claims and removes\n // plugin-owned style tags on unload.\n if (typeof document !== 'undefined') {\n // A hot reload can leave the previous version's tag behind; two sheets would\n // then mix old and new rules, so drop any stale copy before adding ours.\n document.querySelectorAll('style[data-plugin=\"dsh-usage-dashboard\"]').forEach(node => node.remove())\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-usage-dashboard'\n tag.textContent = css\n document.head.appendChild(tag)\n }\n\n // Warm both caches the moment the client bundle loads, rather than waiting\n // for the \u300C\u989D\u5EA6\u300D tab to mount. Usage aggregation alone takes seconds (it\n // replays every session log), so without this the tab's first open always\n // paid that latency; with it, by the time someone actually clicks the tab\n // the fetch has usually already landed and the tab renders from cache. Not\n // awaited and not surfaced: a failure here just leaves the widget/tab to\n // fetch (and report) it themselves on mount, same as before this existed.\n void fetchBalance().catch(() => {})\n void fetchUsage().catch(() => {})\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register(\n { name: 'shell.overlay', id: 'deepseek-quota', order: 1000, locale: NS, label: () => t('widget.title') },\n ({ t: slotT, useSessions }: { t: Translate; useSessions: UseSessionsHook }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent><QuotaWidget useSessions={useSessions} views={views} /></ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n // Composer-dock session reading: one more pill beside the host's own\n // \u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300D/\u300CToken \u7528\u91CF\u300Dentries (same slot, same skin), showing the\n // whole conversation's estimated spend and opening a detail dialog.\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n { name: 'conversation.composer.dock', id: 'quota-cost', order: 2, locale: NS },\n ({ t: slotT, sessionId }: { t: Translate; sessionId?: string }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent><SessionCostPill sessionId={sessionId} /></ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n ctx.slots.inject('conversation.chat.assistant-actions', () => ctx.slots.register(\n {\n name: 'conversation.chat.assistant-actions',\n id: 'dsh-usage-turn-cost',\n order: 5,\n locale: NS,\n label: () => t('messageCost.label'),\n },\n ({ t: slotT, sessionId, messageId }: { t: Translate; sessionId: string; messageId: string }) => (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT} silent>\n <MessageCost sessionId={sessionId} messageId={messageId} />\n </ErrorBoundary>\n </LocaleProvider>\n ),\n ))\n\n // --- \u300C\u989D\u5EA6\u300Dconversation tab, with a user-configurable position -----------\n //\n // The host orders view tabs by the slot entry's `order` (then registration\n // sequence), and the registration options are immutable once registered. A\n // position change therefore replaces the registration: the persisted index\n // is turned into an order between the neighbouring live entries, so it still\n // means the same thing when another plugin adds/removes a tab. Disposing the\n // entry makes the host fall back to Chat for a moment; the captured\n // `openView` switches back to \u989D\u5EA6 right after the new entry exists.\n const QuotaView = ({ t: slotT, sessionId, openView }: {\n t: Translate\n sessionId?: string\n openView?: OpenView\n }): ReactElement => {\n useEffect(() => { if (openView !== undefined) openQuotaTab = openView }, [openView])\n return (\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT}><BalanceDashboard sessionId={sessionId} views={views} /></ErrorBoundary>\n </LocaleProvider>\n )\n }\n\n ctx.effect(() => {\n let disposeView: (() => void) | null = null\n const mount = (): void => {\n disposeView?.()\n disposeView = ctx.slots.inject('conversation.view', () => ctx.slots.register(\n {\n name: 'conversation.view',\n id: 'balance',\n order: viewOrderForIndex(ctx.slots.entries('conversation.view'), quotaTabIndexStore.get()),\n locale: NS,\n label: () => t('nav.quota'),\n },\n // `conversation.view` is a session-scoped slot, so the host injects its\n // standard session props (including `sessionId`) alongside `t`; only the\n // fields this plugin needs are destructured, per the existing\n // \"hand-write the minimal structural type\" convention (see context.ts).\n // `sessionId` stays optional: BalanceDashboard renders the current-\n // session card only when it actually has one, never throws either way.\n QuotaView,\n ))\n }\n mount()\n const unsubscribe = quotaTabIndexStore.subscribe(() => {\n // Only a conversation-mounted dashboard needs the view restored; in the\n // global panel the attribute is absent and the panel stays selected.\n const restore = document !== undefined\n && document.documentElement.hasAttribute('data-dq-quota-view')\n disposeView?.()\n disposeView = null\n mount()\n if (restore) queueMicrotask(() => openQuotaTab?.('balance', 'dsh-usage-dashboard:tab-order'))\n })\n return () => {\n unsubscribe()\n disposeView?.()\n }\n }, 'dsh-usage-dashboard: quota tab registration')\n\n // --- account-wide \u989D\u5EA6 panel + optional sidebar entry ---------------------\n const QuotaPanel = ({ t: slotT }: { t: Translate }): ReactElement => (\n <div className=\"dq-panel\">\n <div className=\"dq-panel-head\" data-window-drag>\n <h1 className=\"dq-panel-title\">{slotT('nav.quota')}</h1>\n <span className=\"dq-panel-caption\">{slotT('panel.caption')}</span>\n </div>\n <LocaleProvider t={slotT}>\n <ErrorBoundary t={slotT}><BalanceDashboard views={views} /></ErrorBoundary>\n </LocaleProvider>\n </div>\n )\n\n /** The \u00A5 glyph drawn as a 16-unit stroke icon so it occupies the same box as\n * the host's own sidebar icons (a text glyph is only ~8px wide, which pushed\n * this row's label ~8px left of every other row). */\n const QuotaGlyph = ({ size, active }: { size: number; active?: boolean }): ReactElement => (\n <svg\n className=\"dq-side-icon\"\n data-active={active === true ? 'true' : 'false'}\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.1}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M3.5 3.3 8 8.7l4.5-5.4\" />\n <path d=\"M8 8.7V13.2\" />\n <path d=\"M3.5 10.2h9\" />\n <path d=\"M3.5 12.1h9\" />\n </svg>\n )\n\n const QuotaFooterButton = ({ wide, t: slotT }: { wide: boolean; t: Translate }): ReactElement => {\n const [active, setActive] = useState(() => ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID)\n useEffect(() => {\n const sync = (): void => {\n setActive(ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID)\n }\n sync()\n return ctx.layout.panelInfo.subscribe(sync)\n }, [])\n return (\n <button\n type=\"button\"\n className={`dq-side-entry${wide ? '' : ' dq-side-entry--rail'}`}\n title={slotT('panel.openAria')}\n aria-label={slotT('nav.quota')}\n aria-pressed={active}\n onClick={() => { ctx.layout.selectPanel(active ? null : QUOTA_PANEL_ID) }}\n >\n <span className=\"dq-side-entry-icon\"><QuotaGlyph size={16} /></span>\n {wide && <span className=\"dq-side-entry-label\">{slotT('nav.quota')}</span>}\n </button>\n )\n }\n\n // The panel itself always exists (its sidebar entry may be off); the entry\n // that reaches it is what the setting turns on and off.\n ctx.effect(() => ctx.slots.inject('main', () => ctx.slots.register(\n { name: 'main', key: QUOTA_PANEL_ID, locale: NS },\n QuotaPanel,\n )), 'dsh-usage-dashboard: quota panel')\n\n ctx.effect(() => {\n let disposeEntry: (() => void) | null = null\n const sync = (): void => {\n disposeEntry?.()\n disposeEntry = null\n const placement = sidebarEntryStore.get()\n if (placement === 'top') {\n // Append after the host's global panels (Plugins / Scheduled tasks /\n // Context insights) instead of taking the first row: the entry is an\n // addition to the existing navigation, not a replacement for its\n // order. A high order keeps that true even for plugins that register\n // after this one (the host sorts the list by order).\n disposeEntry = ctx.slots.inject('sidebar.panellist', () => ctx.slots.register(\n { name: 'sidebar.panellist', id: QUOTA_PANEL_ID, order: 1000, label: () => t('nav.quota'), locale: NS },\n QuotaGlyph,\n ))\n return\n }\n if (placement === 'bottom') {\n disposeEntry = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register(\n { name: 'sidebar.footer.action', id: 'quota', order: 10, locale: NS },\n QuotaFooterButton,\n ))\n return\n }\n // Turning the entry off while its panel is open must not strand the\n // user on a panel with no visible entry: return to the conversation.\n if (ctx.layout.panelInfo.getSnapshot().activePanelId === QUOTA_PANEL_ID) ctx.layout.selectPanel(null)\n }\n sync()\n const unsubscribe = sidebarEntryStore.subscribe(sync)\n return () => {\n unsubscribe()\n disposeEntry?.()\n }\n }, 'dsh-usage-dashboard: sidebar entry')\n\n // --- hide the composer while the \u300C\u989D\u5EA6\u300Dconversation view is active -------\n //\n // The dashboard does not need the chat input, and hiding it gives the long\n // page the full column height. The attribute is only set when the mount is\n // inside the conversation scrollport, so the account-wide panel (which has\n // no composer) never touches host chrome. `quotaViewActiveStore` is the\n // already-existing \"the dashboard is mounted\" signal the widget reacts to.\n ctx.effect(() => {\n let applied = false\n const sync = (): void => {\n const root = document.querySelector('.dq-balance')\n const should = quotaViewActiveStore.get()\n && root !== null\n && root.closest('[data-conversation-scroll]') !== null\n if (should === applied) return\n applied = should\n if (should) document.documentElement.setAttribute('data-dq-quota-view', '')\n else document.documentElement.removeAttribute('data-dq-quota-view')\n }\n sync()\n const unsubscribe = quotaViewActiveStore.subscribe(sync)\n return () => {\n unsubscribe()\n if (applied) document.documentElement.removeAttribute('data-dq-quota-view')\n }\n }, 'dsh-usage-dashboard: composer visibility')\n}\n", "/**\n * Error boundary for the plugin's two slot entries.\n *\n * A slot component that throws while rendering takes its whole subtree down \u2014\n * for the \u300C\u989D\u5EA6\u300D view that meant a blank tab, and the only thing that fixed it\n * was a browser profile with no localStorage. A crash should degrade to\n * something the user can act on, and it should never be the tab's silent\n * default state.\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react'\nimport type { Translate } from './i18n.tsx'\n\nconst PREFIX = 'dsh-usage-dashboard:'\n\n/** Drop every key this plugin owns \u2014 caches and preferences alike. */\nfunction clearPluginStorage(): void {\n if (typeof localStorage === 'undefined') return\n try {\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(PREFIX)) localStorage.removeItem(key)\n }\n } catch {\n // Nothing better to do; the reload below is still worth attempting.\n }\n}\n\ninterface Props {\n /** Shown instead of the fallback UI when the surface has no room for it. */\n silent?: boolean\n t: Translate\n children: ReactNode\n}\n\ninterface State {\n message: string | null\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n state: State = { message: null }\n\n static getDerivedStateFromError(error: unknown): State {\n return { message: (error as { message?: string } | null)?.message ?? String(error) }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo): void {\n console.error('[dsh-usage-dashboard] render failed', error, info.componentStack)\n }\n\n private readonly reset = (): void => {\n clearPluginStorage()\n location.reload()\n }\n\n render(): ReactNode {\n const { message } = this.state\n if (message === null) return this.props.children\n if (this.props.silent === true) return null\n const { t } = this.props\n return (\n <div className=\"dq-balance\">\n <div className=\"dq-card\">\n <div className=\"dq-card-title\">{t('boundary.title')}</div>\n <p className=\"dq-empty\">{t('boundary.body')}</p>\n <pre className=\"dq-crash\">{message}</pre>\n <button type=\"button\" className=\"dq-refresh-btn\" onClick={this.reset}>\n {t('boundary.reset')}\n </button>\n </div>\n </div>\n )\n }\n}\n", "/**\n * Package-local TTL caches shared by the widget, the dashboard, and every\n * tab switch. Cached values outlive the TTL: `get()` still returns them\n * (marked by `at`) so a reopening tab can render instantly and refresh in\n * the background, while `getFresh()` is the cache-aware fetch path.\n *\n * When a `storageKey` is given, every `put()` also mirrors the entry to\n * localStorage so a page refresh keeps the instant first paint (the data\n * shown is the last known good value; a background refresh updates it).\n */\n\n/** Bump whenever the persisted shape changes in a way `isUsable` cannot catch. */\nconst LS_VERSION = 2\n\nexport interface CacheHit<T> {\n data: T\n at: number\n}\n\nexport interface ResourceCache<T> {\n /** Last cached value even when stale; null when never cached. */\n get(): CacheHit<T> | null\n /** Value only when it is still within the TTL. */\n getFresh(): T | null\n put(data: T): void\n}\n\n/**\n * Read a persisted entry, but only trust it if it still matches the shape the\n * current code reads. A payload written by an older build can be missing fields\n * this one dereferences, and because the first render is seeded straight from\n * here, an unchecked stale entry crashes the view \u2014 for the user it looks like\n * a blank tab that only a fresh browser profile fixes.\n */\nfunction loadPersisted<T>(storageKey: string, isUsable?: (data: T) => boolean): CacheHit<T> | null {\n if (typeof localStorage === 'undefined') return null\n const key = `${storageKey}:v${LS_VERSION}`\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return null\n const parsed = JSON.parse(raw) as { data?: T; at?: number }\n if (parsed.data === undefined || typeof parsed.at !== 'number') return null\n if (isUsable !== undefined && !isUsable(parsed.data)) {\n localStorage.removeItem(key)\n return null\n }\n return { data: parsed.data, at: parsed.at }\n } catch {\n return null\n }\n}\n\n/** Drop entries this key wrote under earlier versions; nothing reads them again. */\nfunction pruneOldVersions(storageKey: string): void {\n if (typeof localStorage === 'undefined') return\n try {\n const current = `${storageKey}:v${LS_VERSION}`\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(`${storageKey}:v`) && key !== current) localStorage.removeItem(key)\n }\n } catch {\n // Leaving stale keys behind is harmless; they are never read.\n }\n}\n\nfunction persist<T>(storageKey: string, hit: CacheHit<T>): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(`${storageKey}:v${LS_VERSION}`, JSON.stringify(hit))\n } catch {\n // Quota / private-mode failures must never break the in-memory path.\n }\n}\n\nexport function createCache<T>(ttlMs: number, storageKey?: string, isUsable?: (data: T) => boolean): ResourceCache<T> {\n if (storageKey !== undefined) pruneOldVersions(storageKey)\n let hit: CacheHit<T> | null = storageKey === undefined ? null : loadPersisted<T>(storageKey, isUsable)\n return {\n get: () => hit,\n getFresh: () => (hit !== null && Date.now() - hit.at < ttlMs ? hit.data : null),\n put: (data) => {\n hit = { data, at: Date.now() }\n if (storageKey !== undefined) persist(storageKey, hit)\n },\n }\n}\n", "/** Wire contracts shared by the host API and the client fetchers. */\n\nexport interface BalanceInfo {\n currency: string\n total: string\n granted: string\n toppedUp: string\n}\n\nexport interface BalanceData {\n isAvailable: boolean\n balances: BalanceInfo[]\n}\n\nexport interface BalanceResponse {\n ok: boolean\n error?: string\n data?: BalanceData\n}\n\nexport interface DailyUsage {\n date: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n}\n\nexport interface HourlyUsage {\n hour: number\n total: number\n cost: number\n calls: number\n}\n\nexport interface HeatmapUsage {\n date: string\n total: number\n cost: number\n calls: number\n}\n\nexport interface UsageTotals {\n input: number\n output: number\n cache: number\n reasoning: number\n total: number\n cost: number\n calls: number\n /**\n * What the cache-hit tokens would have cost at cache-miss rates, minus what\n * they actually cost \u2014 i.e. the money prefix caching saved. Folded per\n * record so it respects each record's model and time-of-day rates.\n */\n cacheSavings: number\n}\n\n/** One per-day / per-hour point of a single model's series. */\nexport interface ModelSeriesPoint {\n total: number\n cost: number\n calls: number\n}\n\n/** Per-model usage aggregation: overall totals plus 30-day and 24-hour series. */\nexport interface ModelUsage {\n provider: string\n model: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n daily: ModelSeriesPoint[]\n hourly: ModelSeriesPoint[]\n}\n\n/** Usage rolled up over one time window. */\nexport interface PeriodUsage {\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Time-anchored rollups. \"Accumulated since forever\" answers no question a\n * user actually has; these do: what did today cost, what has this month cost,\n * and is that more or less than the comparable window before it.\n */\nexport interface UsageSummary {\n today: PeriodUsage\n yesterday: PeriodUsage\n /** Current calendar month, to date. */\n month: PeriodUsage\n /** Previous calendar month up to the same day-of-month, so a mid-month\n * comparison is against a same-length window rather than a full month. */\n lastMonthToDate: PeriodUsage\n}\n\n/** CNY per 1M tokens for one model tier. */\nexport interface PricingRates {\n cacheHit: number\n input: number\n output: number\n}\n\nexport interface PricingTier {\n model: string\n peak: PricingRates\n offPeak: PricingRates\n}\n\n/** What the cost column was computed with, so the estimate can be audited. */\nexport interface PricingInfo {\n currency: string\n /** Date peak/off-peak pricing took effect; earlier usage is costed at the\n * flat rates that were actually charged then. */\n switchDate: string\n inPeakNow: boolean\n peakWindows: string[]\n tiers: PricingTier[]\n}\n\n/**\n * How usage divides between DeepSeek's peak and off-peak windows, plus the\n * same usage re-priced as if everything had landed off-peak \u2014 answering\n * \"what would shifting batch work off-peak save me\" under the peak/off-peak\n * table in effect since 2026-08-17.\n */\nexport interface PeakSplit {\n peak: PeriodUsage\n offPeak: PeriodUsage\n /** Every record priced under the peak/off-peak table, as actually classified. */\n peakEraCost: number\n /** Every record priced under that table as if it had landed off-peak. */\n offPeakEraCost: number\n}\n\n/** One session's share of the bill. */\nexport interface SessionCost {\n id: string\n /** The session's title from its log; falls back to a short id. */\n title: string\n total: number\n cost: number\n calls: number\n /** Epoch ms of the last usage record in this session. */\n lastActive: number\n}\n\n/**\n * Multimodal (image) usage, folded from the same log replay: image blocks in\n * user messages and tool results are counted and sized, then estimated with\n * the official resizing rule (see `estimateImageTokens`). Each image is\n * attributed to the next usage record \u2014 the model call whose prompt carried\n * it \u2014 and priced at that call's input (cache-miss) rate, so the share answer\n * \"how much of the bill came from pictures\" has a real number.\n */\nexport interface VisionStats {\n /** Image blocks counted in the scope. */\n images: number\n /** Estimated image tokens under the official conversion rule. */\n imageTokens: number\n /** Estimated CNY cost of those image tokens at the consuming calls' rates. */\n cost: number\n /** Total image payload bytes when the attachment refs carried a size. */\n bytes: number\n}\n\n/** One day's image usage for the per-window / per-day series. */\nexport interface VisionDayPoint {\n date: string\n images: number\n imageTokens: number\n cost: number\n}\n\n/** One session's image usage, ranked for \"which run kept sending pictures\". */\nexport interface VisionSession {\n id: string\n title: string\n images: number\n imageTokens: number\n cost: number\n}\n\n/**\n * What the local log replay could actually inspect. Totals can otherwise look\n * authoritative even when one corrupt session was skipped, so this metadata\n * travels with every usage response and lets the UI disclose partial results.\n */\nexport interface UsageCoverage {\n scope: 'local-dsh-session-logs'\n /** Session headers with a usable id returned by the local persistence. */\n listedSessions: number\n /** Session logs read successfully, including logs with no usage. */\n scannedSessions: number\n /** Valid assistant usage records folded into the totals. */\n usageRecords: number\n /** Usage records rejected because their time or token data was invalid. */\n skippedRecords: number\n /** Session logs that could not be read at all. */\n failedSessions: number\n /** Epoch ms of the first/last valid usage record across all local logs. */\n earliestAt: number | null\n latestAt: number | null\n}\n\nexport const USAGE_WINDOW_DAYS = [7, 30, 90, 365] as const\nexport type UsageWindowDays = (typeof USAGE_WINDOW_DAYS)[number]\n\n/**\n * Session ids observed in this codebase (host-issued, e.g.\n * `session-484a1c14-c6fe-4d6a-abfd-a2d8d2f664d5`) are always plain\n * ASCII-safe tokens \u2014 no documented format contract exists for them outside\n * this repo (`SessionPersistenceFace` is implemented by the DSH host, not\n * here), so this is a defensive charset whitelist rather than an\n * exact-format check: letters, digits, `-`, `_` only, with a generous length\n * cap. It exists specifically to stop path-separator / `..` / null-byte\n * payloads from ever reaching the session-log read \u2014 `id` on the\n * `/session` route arrives verbatim from the browser-controlled `?id=` query\n * parameter, unlike `fetchUsage()`'s session ids, which the host itself\n * enumerates via `persistence.list()`.\n */\nexport const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/\n\nexport const isValidSessionId = (id: string): boolean => SESSION_ID_PATTERN.test(id)\n\n/** One internally consistent view of the same local logs over a calendar window. */\nexport interface UsageWindow {\n days: UsageWindowDays\n daily: DailyUsage[]\n hourly: HourlyUsage[]\n totals: UsageTotals\n models: ModelUsage[]\n /** Most expensive sessions inside this window, capped at SESSION_TOP_N. */\n sessions: SessionCost[]\n /** All sessions that contributed usage inside this window. */\n sessionCount: number\n vision: VisionStats\n visionDaily: VisionDayPoint[]\n /** Sessions that sent the most images inside this window, capped. */\n visionSessions: VisionSession[]\n}\n\nexport interface UsageData {\n daily: DailyUsage[]\n hourly: HourlyUsage[]\n heatmap: HeatmapUsage[]\n totals: UsageTotals\n models: ModelUsage[]\n summary: UsageSummary\n pricing: PricingInfo\n peakSplit: PeakSplit\n /** Most expensive sessions first, capped \u2014 see SESSION_TOP_N. */\n sessions: SessionCost[]\n /** How many sessions contributed usage in total. */\n sessionCount: number\n coverage: UsageCoverage\n windows: UsageWindow[]\n vision: VisionStats\n visionDaily: VisionDayPoint[]\n /** Sessions that sent the most images, capped \u2014 see SESSION_TOP_N. */\n visionSessions: VisionSession[]\n}\n\nexport interface UsageResponse {\n ok: boolean\n error?: string\n data?: UsageData\n}\n\n/**\n * One model's contribution to a single session's bill \u2014 the same field\n * shape as `ModelUsage` minus the `daily`/`hourly` series, which only make\n * sense aggregated across many sessions.\n */\nexport interface SessionModelUsage {\n provider: string\n model: string\n input: number\n output: number\n cache: number\n total: number\n cost: number\n calls: number\n}\n\n/** One completed conversation turn's usage. `messageId` is the durable id of\n * the turn's final assistant message \u2014 the same identity the chat action-strip\n * slot exposes to client plugins. Tool-call steps inside the turn are folded\n * into this one figure rather than shown as misleading separate charges. */\nexport interface TurnUsage {\n messageId: string\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Usage for exactly one session \u2014 what the \u300C\u989D\u5EA6\u300Dtab's own conversation\n * is costing, as opposed to `UsageData`'s account-wide totals. Fetched on\n * demand (see `fetchSessionUsage`), not part of the 5-minute `usage` memo:\n * a single session read is cheap and must reflect the session's live state.\n */\nexport interface SessionUsageData {\n sessionId: string\n /** The session's own title from its log; falls back to a short id. */\n title: string\n total: number\n cost: number\n calls: number\n /** Epoch ms of the first/last valid usage record in this session, or null\n * when the session has produced no usage yet. */\n firstActive: number | null\n lastActive: number | null\n /** Most expensive model first. */\n models: SessionModelUsage[]\n /** Completed turns, in log order, addressed by their final message id. */\n turns: TurnUsage[]\n}\n\nexport interface SessionUsageResponse {\n ok: boolean\n error?: string\n data?: SessionUsageData\n}\n", "/**\n * Same-origin fetchers for the host half's JSON API, backed by package-local\n * TTL caches (see ./cache.ts). A fresh cache hit resolves without any network\n * work, so tab switches render instantly; `force` bypasses both the memory\n * cache and the HTTP cache (fetch cache: 'no-store') and asks the host to\n * bypass its own memo via `?refresh=1`.\n */\nimport { createCache } from './cache.ts'\nimport { USAGE_WINDOW_DAYS } from '../contract.ts'\nimport type { BalanceResponse, SessionUsageResponse, UsageResponse } from '../contract.ts'\n\n/** Mirror the host memos: balance 60s, usage 5min. */\nconst BALANCE_TTL_MS = 60_000\nconst USAGE_TTL_MS = 5 * 60_000\n\nasync function getJson<T>(path: string, cache: RequestCache): Promise<T> {\n const res = await fetch(path, { headers: { accept: 'application/json' }, cache })\n if (!res.ok) {\n return { ok: false, error: `HTTP ${res.status}` } as unknown as T\n }\n return res.json() as Promise<T>\n}\n\n/**\n * Every field the UI dereferences off a cached payload. A persisted entry that\n * predates one of them would otherwise be rendered as if it were current and\n * take the whole view down; listing them here keeps that failure impossible\n * instead of merely unlikely. Add a line whenever the UI starts reading a new\n * top-level field.\n */\nconst usageIsUsable = (res: UsageResponse): boolean => {\n if (res.ok !== true) return false\n const data = res.data\n return data !== undefined\n && Array.isArray(data.daily) && Array.isArray(data.hourly) && Array.isArray(data.heatmap)\n && Array.isArray(data.models) && Array.isArray(data.sessions)\n && typeof data.sessionCount === 'number'\n && data.coverage?.scope === 'local-dsh-session-logs'\n && typeof data.coverage.scannedSessions === 'number'\n && typeof data.coverage.skippedRecords === 'number'\n && Array.isArray(data.windows) && data.windows.length === USAGE_WINDOW_DAYS.length\n && USAGE_WINDOW_DAYS.every(days => data.windows.some(window => window.days === days))\n && data.windows.every(window => Array.isArray(window.daily)\n && Array.isArray(window.hourly) && Array.isArray(window.models) && Array.isArray(window.sessions))\n && data.vision !== undefined && typeof data.vision.images === 'number'\n && typeof data.vision.imageTokens === 'number' && typeof data.vision.cost === 'number'\n && Array.isArray(data.visionDaily) && Array.isArray(data.visionSessions)\n && data.windows.every(window => window.vision !== undefined\n && Array.isArray(window.visionDaily) && Array.isArray(window.visionSessions))\n && data.totals !== undefined && typeof data.totals.cacheSavings === 'number'\n && data.summary?.today !== undefined\n && Array.isArray(data.pricing?.tiers)\n && data.peakSplit?.peak !== undefined\n}\n\nconst balanceIsUsable = (res: BalanceResponse): boolean =>\n res.ok === true && Array.isArray(res.data?.balances)\n\nconst balanceCache = createCache<BalanceResponse>(BALANCE_TTL_MS, 'dsh-usage-dashboard:balance', balanceIsUsable)\nconst usageCache = createCache<UsageResponse>(USAGE_TTL_MS, 'dsh-usage-dashboard:usage', usageIsUsable)\n\n/** Last cached value (possibly stale), for an instant first render. */\nexport const getCachedBalance = (): BalanceResponse | null => balanceCache.get()?.data ?? null\nexport const getCachedUsage = (): UsageResponse | null => usageCache.get()?.data ?? null\n/** When the cached usage was fetched, so a consumer can say how old it is. */\nexport const getCachedUsageAt = (): number | null => usageCache.get()?.at ?? null\n\n/**\n * Notified whenever usage is (re)fetched. The floating widget reads usage\n * straight from this cache rather than fetching on its own: aggregating every\n * session log takes seconds, and a background widget must not pay that\n * repeatedly. It subscribes here so it still updates when the dashboard \u2014 or\n * its own refresh button \u2014 brings fresh data in.\n */\nconst usageListeners = new Set<() => void>()\n\nexport const subscribeUsage = (fn: () => void): (() => void) => {\n usageListeners.add(fn)\n return () => {\n usageListeners.delete(fn)\n }\n}\n\n// Non-force calls made while an identical one is already in flight join it\n// instead of firing a second request \u2014 the case that matters is the\n// preload kicked off at plugin load (see index.tsx) landing moments before\n// the widget's or the dashboard's own mount-time fetch. `force` (the\n// refresh button) always fires its own request, since the user asked for a\n// bypass specifically.\nlet balanceInflight: Promise<BalanceResponse> | null = null\nlet usageInflight: Promise<UsageResponse> | null = null\n\nexport async function fetchBalance(force = false): Promise<BalanceResponse> {\n if (!force) {\n const hit = balanceCache.getFresh()\n if (hit !== null) return hit\n if (balanceInflight !== null) return balanceInflight\n }\n const suffix = force ? '?refresh=1' : ''\n const task = getJson<BalanceResponse>(`/api/dsh-usage-dashboard/balance${suffix}`, force ? 'no-store' : 'default')\n .then(res => {\n if (res.ok) balanceCache.put(res)\n return res\n })\n if (!force) {\n balanceInflight = task.finally(() => { balanceInflight = null })\n return balanceInflight\n }\n return task\n}\n\nexport async function fetchUsage(force = false): Promise<UsageResponse> {\n if (!force) {\n const hit = usageCache.getFresh()\n if (hit !== null) return hit\n if (usageInflight !== null) return usageInflight\n }\n const suffix = force ? '?refresh=1' : ''\n // `cache: 'no-store'` on every path, not just force: the host memoizes the\n // expensive replay anyway, and our own TTL cache prevents repeat fetches \u2014\n // but the browser's HTTP cache would happily serve a payload captured before\n // a host upgrade (the old body lacks fields the current UI reads, e.g. the\n // vision block) for up to the max-age it was tagged with.\n const task = getJson<UsageResponse>(`/api/dsh-usage-dashboard/usage${suffix}`, 'no-store')\n .then(res => {\n // Only shapes the current UI dereferences may enter the cache. A host\n // still serving a pre-vision payload (not yet restarted) is therefore\n // never persisted \u2014 the dashboard renders it defensively instead of\n // crashing on the next mount.\n if (res.ok && usageIsUsable(res)) {\n usageCache.put(res)\n for (const listener of [...usageListeners]) listener()\n }\n return res\n })\n if (!force) {\n usageInflight = task.finally(() => { usageInflight = null })\n return usageInflight\n }\n return task\n}\n\n/**\n * Session usage stays memory-only: the widget, dashboard, and every visible\n * turn-cost cell share the latest read without persisting one entry per\n * session. A newly completed turn whose message id is absent from this cache\n * triggers one fresh read; the in-flight map coalesces all cells mounting in\n * the same transcript render.\n */\nconst sessionUsageInflight = new Map<string, Promise<SessionUsageResponse>>()\nconst sessionUsageCache = new Map<string, SessionUsageResponse>()\nconst sessionUsageListeners = new Map<string, Set<() => void>>()\n\nexport const getCachedSessionUsage = (sessionId: string): SessionUsageResponse | null =>\n sessionUsageCache.get(sessionId) ?? null\n\nexport const subscribeSessionUsage = (sessionId: string, fn: () => void): (() => void) => {\n let listeners = sessionUsageListeners.get(sessionId)\n if (listeners === undefined) {\n listeners = new Set()\n sessionUsageListeners.set(sessionId, listeners)\n }\n listeners.add(fn)\n return () => {\n listeners?.delete(fn)\n if (listeners?.size === 0) sessionUsageListeners.delete(sessionId)\n }\n}\n\nconst publishSessionUsage = (sessionId: string, response: SessionUsageResponse): void => {\n if (!response.ok) return\n sessionUsageCache.set(sessionId, response)\n for (const listener of [...(sessionUsageListeners.get(sessionId) ?? [])]) listener()\n}\n\nexport async function fetchSessionUsage(sessionId: string, force = false): Promise<SessionUsageResponse> {\n if (typeof sessionId !== 'string' || sessionId === '') {\n return { ok: false, error: '\u7F3A\u5C11\u4F1A\u8BDD id' }\n }\n if (!force) {\n const inflight = sessionUsageInflight.get(sessionId)\n if (inflight !== undefined) return inflight\n }\n const task = getJson<SessionUsageResponse>(`/api/dsh-usage-dashboard/session?id=${encodeURIComponent(sessionId)}`, 'no-store')\n .then(response => {\n publishSessionUsage(sessionId, response)\n return response\n })\n if (force) return task\n const tracked = task.finally(() => {\n if (sessionUsageInflight.get(sessionId) === tracked) sessionUsageInflight.delete(sessionId)\n })\n sessionUsageInflight.set(sessionId, tracked)\n return tracked\n}\n", "/** The \u300C\u989D\u5EA6\u300D conversation view tab: full balance & usage dashboard.\n *\n * Caching: the first render comes straight from the package-local cache\n * (see ./api.ts), so reopening the tab shows data instantly. A background\n * refresh then updates it without blocking; a full-screen \u52A0\u8F7D\u4E2D only\n * appears when nothing has ever been cached.\n */\nimport { Fragment, useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type DragEvent as ReactDragEvent, type KeyboardEvent as ReactKeyboardEvent, type ReactElement, type ReactNode } from 'react'\nimport { USAGE_WINDOW_DAYS } from '../contract.ts'\nimport { fetchBalance, fetchSessionUsage, fetchUsage, getCachedBalance, getCachedUsage, getCachedUsageAt } from './api.ts'\nimport { budgetSnapshot } from './budget.ts'\nimport { Bars, GroupedBars, Heatmap, MODEL_COLORS, fmt, fmtCompact, fmtInt } from './charts.tsx'\nimport { getComposerElement, getComposerInputElement, getShellFrame } from './dom.ts'\nimport { dailyUsageCsv, downloadText, exportDateStamp, fullUsageJson, modelUsageCsv } from './export.ts'\nimport { syncStatusText, type SyncState } from './freshness.ts'\nimport { fallbackT, intlLocale, localizeApiError, useI18n, type Translate } from './i18n.tsx'\nimport { quotaTabIndexStore, sidebarEntryStore, type SidebarEntryPlacement } from './layout-prefs.ts'\nimport { CHART_METRICS, chartMetricName, chartMetricValue, type ChartMetric } from './metric.ts'\nimport type { BalanceData, ModelUsage, PeakSplit, PeriodUsage, PricingInfo, SessionCost, SessionUsageData, UsageCoverage, UsageData, UsageWindowDays, VisionDayPoint, VisionSession, VisionStats } from '../contract.ts'\nimport { chartMetricStore, lowBalanceStore, monthlyBudgetStore, quotaViewActiveStore, usageWindowStore, widgetTabIdsStore, widgetVisibleStore } from './store.ts'\nimport { TOP_UP_URL, needsTopUp } from './top-up.ts'\nimport type { ConversationViewTab, ConversationViewsSource } from './views.ts'\n\n/** `<package name> v<version>`, injected by build.mjs from package.json so the\n * footer on the \u989D\u5EA6 page reports exactly the version that was built. */\ndeclare const __PLUGIN_LABEL__: string\n\n/** Fallback composer height for the narrow-screen bottom safe area, used only\n * until the real measurement below lands (or if the host markup ever stops\n * exposing the `conversation.composer` slot). DSH has no `--dsw-*` variable\n * for composer height \u2014 this number is not a guess: it is the measured\n * composer seat height on a live DSH instance at 620 / 480 / 390px viewports\n * (126px, stable across all three; see LEARNINGS.md). Kept in sync with the\n * small margin added in styles.ts's `.dq-balance` narrow media query. */\nconst COMPOSER_FALLBACK_PX = 126\n\n/** One shimmering placeholder block, sized by the caller. */\nfunction Skel(props: { w: number; h: number }): ReactElement {\n return <div className=\"dq-skel\" style={{ width: `${props.w}px`, height: `${props.h}px` }} />\n}\n\n/** Placeholder for the balance card while the first fetch is in flight. */\nfunction BalanceSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={56} h={11} /><Skel w={150} h={22} /></div>\n <div className=\"dq-stat\"><Skel w={28} h={11} /><Skel w={48} h={22} /></div>\n </div>\n )\n}\n\n/** Placeholder for the current-session card: same three-`Stat` grammar as\n * the balance card's skeleton above, just one more column. */\nfunction SessionUsageSkeleton(): ReactElement {\n return (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\"><Skel w={64} h={11} /><Skel w={96} h={18} /></div>\n <div className=\"dq-stat\"><Skel w={70} h={11} /><Skel w={80} h={18} /></div>\n <div className=\"dq-stat\"><Skel w={64} h={11} /><Skel w={40} h={18} /></div>\n </div>\n )\n}\n\n/** Placeholder for the usage trend card: replaying every session log takes\n * seconds, and an empty-state string there would read as \"you have no usage\". */\nfunction UsageSkeleton(): ReactElement {\n return (\n <>\n <div className=\"dq-usage-totals\">\n {[44, 44, 62, 62].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={w > 70 ? 84 : 56} h={20} /></div>\n ))}\n </div>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\">\n {Array.from({ length: 30 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${18 + ((i * 37) % 82)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Placeholder for the heatmap card, same loading grammar as the trend card's\n * bar skeleton above \u2014 the heatmap has no separate fetch, it just renders\n * once `usage` lands, so the two cards share one loading vocabulary. */\nfunction HeatmapSkeleton(): ReactElement {\n return (\n <>\n <Skel w={140} h={12} />\n <div className=\"dq-skel-bars\" style={{ height: '88px' }}>\n {Array.from({ length: 52 }, (_, i) => (\n <div key={i} className=\"dq-skel dq-skel-bar\" style={{ height: `${14 + ((i * 29) % 60)}px` }} />\n ))}\n </div>\n </>\n )\n}\n\n/** Percentage chip comparing a window against the one before it. */\nfunction Delta(props: { current: number; previous: number; label: string }): ReactElement | null {\n const { t } = useI18n()\n const { current, previous, label } = props\n if (previous <= 0) {\n if (current <= 0) return null\n return <span className=\"dq-delta dq-delta--new\" title={t('delta.noBaselineTitle', { label })}>{t('delta.noBaseline')}</span>\n }\n const percent = Math.round(((current - previous) / previous) * 100)\n const title = `${label} \u00A5${fmt(previous)}`\n if (percent === 0) return <span className=\"dq-delta dq-delta--flat\" title={title}>{t('delta.flat')}</span>\n const up = percent > 0\n // A tiny previous baseline makes the ratio explode (e.g. \u21919176%), which reads\n // like a bug rather than a fact. Cap the displayed magnitude; the title keeps\n // the exact baseline the number was computed from.\n const magnitude = Math.abs(percent) >= 1000 ? '999+' : String(Math.abs(percent))\n return (\n <span className={`dq-delta ${up ? 'dq-delta--up' : 'dq-delta--down'}`} title={title}>\n {up ? '\u2191' : '\u2193'}{magnitude}% <span className=\"dq-delta-label\">{label}</span>\n </span>\n )\n}\n\n/** One window of the \u6D88\u8017\u6982\u89C8 card: cost headline, volume underneath. */\nfunction Period(props: {\n label: string\n period: PeriodUsage\n previous?: PeriodUsage\n compare?: string\n}): ReactElement {\n const { t, locale } = useI18n()\n const { period, previous, compare } = props\n return (\n <div className=\"dq-period\">\n <div className=\"dq-period-head\">\n <span className=\"dq-period-label\">{props.label}</span>\n {previous !== undefined && compare !== undefined && (\n <Delta current={period.cost} previous={previous.cost} label={compare} />\n )}\n </div>\n <div className=\"dq-period-cost\">\u00A5{fmt(period.cost)}</div>\n <div className=\"dq-period-sub\">{t('period.volume', {\n tokens: fmtCompact(period.total, locale),\n calls: t('common.calls', { count: fmtInt(period.calls) }),\n })}</div>\n </div>\n )\n}\n\n/** Monthly guardrail, kept inside the overview rather than adding another card. */\nfunction BudgetMeter(props: { spent: number; budget: number; onConfigure: () => void }): ReactElement {\n const { t } = useI18n()\n if (props.budget <= 0) {\n return (\n <div className=\"dq-budget dq-budget--unset\">\n <span>{t('budget.unset')}</span>\n <button type=\"button\" className=\"dq-budget-action\" onClick={props.onConfigure}>{t('budget.configure')}</button>\n </div>\n )\n }\n\n const snapshot = budgetSnapshot(props.spent, props.budget)\n const usedPercent = snapshot.ratio * 100\n const barPercent = Math.min(100, usedPercent)\n const forecastText = snapshot.status === 'over'\n ? t('budget.over', { amount: fmt(Math.abs(snapshot.remaining)) })\n : snapshot.forecastOver > 0\n ? t('budget.forecastOver', { amount: fmt(snapshot.forecastOver) })\n : t('budget.forecast', { amount: fmt(snapshot.forecast) })\n\n return (\n <div className={`dq-budget dq-budget--${snapshot.status}`}>\n <div className=\"dq-budget-head\">\n <span className=\"dq-budget-title\">{t('budget.title')}</span>\n <span className=\"dq-budget-amount\">\u00A5{fmt(snapshot.spent)} / \u00A5{fmt(snapshot.budget)}</span>\n </div>\n <div\n className=\"dq-budget-track\"\n role=\"progressbar\"\n aria-label={t('budget.progressLabel')}\n aria-valuemin={0}\n aria-valuemax={snapshot.budget}\n aria-valuenow={Math.min(snapshot.spent, snapshot.budget)}\n aria-valuetext={t('budget.used', { percent: usedPercent.toFixed(1), forecast: forecastText })}\n >\n <div className=\"dq-budget-fill\" style={{ transform: `scaleX(${barPercent / 100})` }} />\n </div>\n <div className=\"dq-budget-meta\">\n <span>{snapshot.remaining >= 0\n ? t('budget.remaining', { amount: fmt(snapshot.remaining) })\n : t('budget.exceeded', { amount: fmt(Math.abs(snapshot.remaining)) })}</span>\n <span>{forecastText}</span>\n </div>\n </div>\n )\n}\n\nconst rate = (value: number): string => `\u00A5${value.toLocaleString(undefined, { maximumFractionDigits: 3 })}`\n\n/** Auditable breakdown of the rates the cost estimate was computed with \u2014\n * a `<details>` so it is keyboard-reachable without any extra state. */\nfunction PricingNote(props: { pricing: PricingInfo }): ReactElement {\n const { t } = useI18n()\n const { pricing } = props\n return (\n <details className=\"dq-pricing\">\n <summary className=\"dq-pricing-summary\">\n {t('pricing.title')}\n <span className={`dq-pricing-now${pricing.inPeakNow ? ' dq-pricing-now--peak' : ''}`}>\n {pricing.inPeakNow ? t('pricing.currentPeak') : t('pricing.currentOffPeak')}\n </span>\n </summary>\n <div className=\"dq-pricing-body\">\n <table className=\"dq-pricing-table\">\n <thead>\n <tr>\n <th>{t('pricing.model')}</th>\n <th>{t('pricing.period')}</th>\n <th>{t('pricing.inputCacheHit')}</th>\n <th>{t('pricing.inputCacheMiss')}</th>\n <th>{t('pricing.output')}</th>\n </tr>\n </thead>\n <tbody>\n {pricing.tiers.map(tier => (\n <Fragment key={tier.model}>\n <tr>\n <td rowSpan={2}>{tier.model}</td>\n <td>{t('pricing.peak')}</td>\n <td>{rate(tier.peak.cacheHit)}</td>\n <td>{rate(tier.peak.input)}</td>\n <td>{rate(tier.peak.output)}</td>\n </tr>\n <tr>\n <td>{t('pricing.offPeak')}</td>\n <td>{rate(tier.offPeak.cacheHit)}</td>\n <td>{rate(tier.offPeak.input)}</td>\n <td>{rate(tier.offPeak.output)}</td>\n </tr>\n </Fragment>\n ))}\n </tbody>\n </table>\n <p className=\"dq-pricing-foot\">\n {t('pricing.unit', { currency: pricing.currency })}\n {t('pricing.splitNote', { windows: pricing.peakWindows.join(t('common.listSeparator')) })}\n {t('pricing.visionNote')}\n {t('pricing.unknown')}\n </p>\n </div>\n </details>\n )\n}\n\n/** Make a locally-computed bill honest about which logs it could inspect. */\nfunction CoverageDiagnostics(props: { coverage: UsageCoverage }): ReactElement {\n const { t, locale } = useI18n()\n const { coverage } = props\n const hasGaps = coverage.failedSessions > 0\n || coverage.skippedRecords > 0\n || coverage.scannedSessions < coverage.listedSessions\n const coverageTime = new Intl.DateTimeFormat(intlLocale(locale), {\n timeZone: 'Asia/Shanghai', year: 'numeric', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = coverage.earliestAt === null || coverage.latestAt === null\n ? t('coverage.noRange')\n : `${coverageTime.format(coverage.earliestAt)} \u2013 ${coverageTime.format(coverage.latestAt)}`\n\n return (\n <details className={`dq-coverage${hasGaps ? ' dq-coverage--warn' : ''}`}>\n <summary className=\"dq-coverage-summary\">\n <span className=\"dq-coverage-title\">{t('coverage.title')}</span>\n <span className=\"dq-coverage-status\">{hasGaps ? t('coverage.gaps') : t('coverage.complete')}</span>\n <span className=\"dq-coverage-brief\">{t('coverage.brief', {\n scanned: fmtInt(coverage.scannedSessions), listed: fmtInt(coverage.listedSessions), records: fmtInt(coverage.usageRecords),\n })}</span>\n </summary>\n <div className=\"dq-coverage-body\">\n <dl className=\"dq-coverage-metrics\">\n <div><dt>{t('coverage.scanned')}</dt><dd>{t('common.sessions', { count: fmtInt(coverage.scannedSessions) })}</dd></div>\n <div><dt>{t('coverage.failed')}</dt><dd>{t('common.sessions', { count: fmtInt(coverage.failedSessions) })}</dd></div>\n <div><dt>{t('coverage.skipped')}</dt><dd>{t('common.records', { count: fmtInt(coverage.skippedRecords) })}</dd></div>\n </dl>\n <p className=\"dq-coverage-range\">{t('coverage.time', { range })}</p>\n <p className=\"dq-coverage-note\">{t('coverage.scope')}</p>\n {hasGaps && (\n <p className=\"dq-coverage-warning\">{t('coverage.warning')}</p>\n )}\n </div>\n </details>\n )\n}\n\n/** Section heading: a short title, plus an optional quiet caption on the same line\n * (scope / caveat such as \u300C\u8FD1 30 \u5929\u300D\u300C\u8D39\u7528\u4E3A\u4F30\u7B97\u300D) so the title itself stays short. */\nfunction CardTitle(props: { children: ReactNode; caption?: ReactNode; srOnly?: boolean }): ReactElement {\n return (\n <h2 className={`dq-card-title${props.srOnly === true ? ' dq-sr-only' : ''}`}>\n {props.children}\n {props.caption !== undefined && <span className=\"dq-card-caption\">{props.caption}</span>}\n </h2>\n )\n}\n\n/** In-column section rail: one dot per top-level card, scroll-spy synced, sitting\n * in the centred column's left gutter. Purely additive navigation \u2014 it never\n * reorders or restyles the cards \u2014 and hides when there is no gutter to sit in,\n * so it cannot compete with the host's own sidebar. */\nfunction SectionNav(props: {\n rootRef: { readonly current: HTMLDivElement | null }\n label: string\n sections: Array<{ key: string; label: string }>\n}): ReactElement | null {\n const { rootRef, label, sections } = props\n const [targets, setTargets] = useState<Array<{ el: HTMLElement; label: string }>>([])\n const [active, setActive] = useState(0)\n const [pos, setPos] = useState({ right: 0, visible: false })\n const signature = sections.map(section => `${section.key}:${section.label}`).join('|')\n\n // Pair the label list with the rendered top-level cards in DOM order. The only\n // conditional card is the current-session one, reflected in both lists above.\n useEffect(() => {\n const root = rootRef.current\n if (root === null) return\n const nodes = Array.from(root.querySelectorAll<HTMLElement>(':scope > .dq-card, :scope > .dq-card-pair'))\n setTargets(nodes.map((el, i) => ({ el, label: sections[i]?.label ?? '' })).filter(item => item.label !== ''))\n // `signature` captures the label list; `sections` itself changes identity each render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rootRef, signature])\n\n // Keep the rail in the gutter; hide it when the column is too close to an edge.\n useEffect(() => {\n const root = rootRef.current\n if (root === null) return\n const scrollport = root.closest('[data-conversation-scroll]') as HTMLElement | null\n const measure = (): void => {\n const rect = root.getBoundingClientRect()\n setPos({ right: window.innerWidth - rect.left + 12, visible: window.innerWidth >= 1200 && rect.left >= 170 })\n }\n measure()\n const scroller: HTMLElement | Window = scrollport ?? window\n scroller.addEventListener('scroll', measure, { passive: true })\n window.addEventListener('resize', measure)\n return () => {\n scroller.removeEventListener('scroll', measure)\n window.removeEventListener('resize', measure)\n }\n }, [rootRef])\n\n // Scroll-spy: the last card whose top crossed the top band is \"current\".\n useEffect(() => {\n if (targets.length === 0) return\n const root = rootRef.current\n if (root === null) return\n const scrollport = root.closest('[data-conversation-scroll]') as HTMLElement | null\n const onScroll = (): void => {\n const base = scrollport === null ? 0 : scrollport.getBoundingClientRect().top\n let current = 0\n targets.forEach((target, i) => {\n if (target.el.getBoundingClientRect().top - base <= 120) current = i\n })\n setActive(current)\n }\n onScroll()\n const scroller: HTMLElement | Window = scrollport ?? window\n scroller.addEventListener('scroll', onScroll, { passive: true })\n return () => scroller.removeEventListener('scroll', onScroll)\n }, [targets, rootRef])\n\n if (targets.length < 3) return null\n\n const go = (el: HTMLElement): void => {\n const root = rootRef.current\n const scrollport = root?.closest('[data-conversation-scroll]') as HTMLElement | null\n const reduce = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const behavior: ScrollBehavior = reduce ? 'auto' : 'smooth'\n if (scrollport !== null) {\n const base = scrollport.getBoundingClientRect().top\n scrollport.scrollTo({ top: scrollport.scrollTop + el.getBoundingClientRect().top - base - 12, behavior })\n } else {\n window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 12, behavior })\n }\n }\n\n return (\n <nav className={`dq-sectionnav${pos.visible ? '' : ' dq-sectionnav--hidden'}`} style={{ right: `${pos.right}px` }} aria-label={label}>\n <ol>\n {targets.map((target, i) => (\n <li key={`${target.label}-${String(i)}`}>\n <button\n type=\"button\"\n className={`dq-sectionnav-dot${i === active ? ' dq-sectionnav-dot--active' : ''}`}\n aria-current={i === active ? 'true' : undefined}\n onClick={() => go(target.el)}\n >\n <span className=\"dq-sectionnav-label\">{target.label}</span>\n <span className=\"dq-sectionnav-pip\" aria-hidden=\"true\" />\n </button>\n </li>\n ))}\n </ol>\n </nav>\n )\n}\n\n/** Height reveal + retract for content that stays mounted but toggles visibility\n * (the settings panel). Styles are applied in a layout effect so the panel is\n * already collapsed to height 0 BEFORE the first paint \u2014 no full-height flash,\n * then it eases 0\u2192measured (easeOutExpo). Closing animates back to 0 (ease-in)\n * before display:none. Reduced motion snaps straight to the final state. */\nfunction Collapsible(props: { open: boolean; children: ReactNode }): ReactElement {\n const ref = useRef<HTMLDivElement | null>(null)\n const animationRef = useRef<Animation | null>(null)\n const open = props.open\n useLayoutEffect(() => {\n const el = ref.current\n if (el === null) return\n animationRef.current?.cancel()\n animationRef.current = null\n const reduce = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const canAnimate = typeof el.animate === 'function' && !reduce\n const reset = (): void => { el.style.height = ''; el.style.overflow = ''; el.style.opacity = '' }\n if (open) {\n if (!canAnimate) {\n el.style.display = ''\n reset()\n return\n }\n // Collapse synchronously before paint so measuring the natural height never\n // shows the full panel for a frame.\n el.style.display = 'block'\n el.style.overflow = 'hidden'\n el.style.height = '0px'\n el.style.opacity = '0'\n const height = el.scrollHeight\n const animation = el.animate(\n [{ height: '0px', opacity: 0 }, { height: `${height}px`, opacity: 1 }],\n { duration: 300, easing: 'cubic-bezier(0.16, 1, 0.3, 1)' },\n )\n animationRef.current = animation\n animation.addEventListener('finish', reset)\n return () => animation.cancel()\n }\n if (el.style.display === 'none') return\n if (!canAnimate) {\n reset()\n el.style.display = 'none'\n return\n }\n const height = el.getBoundingClientRect().height || el.scrollHeight\n el.style.overflow = 'hidden'\n el.style.height = `${height}px`\n const animation = el.animate(\n [{ height: `${height}px`, opacity: 1 }, { height: '0px', opacity: 0 }],\n { duration: 220, easing: 'cubic-bezier(0.4, 0, 1, 1)' },\n )\n animationRef.current = animation\n animation.addEventListener('finish', () => { reset(); el.style.display = 'none' })\n return () => animation.cancel()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n return <div ref={ref}>{props.children}</div>\n}\n\nfunction Stat(props: { label: string; children: ReactNode }): ReactElement {\n return (\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{props.label}</div>\n {props.children}\n </div>\n )\n}\n\nfunction Link(props: { href: string; children: ReactNode }): ReactElement {\n return (\n <a className=\"dq-link\" href={props.href} target=\"_blank\" rel=\"noreferrer\">{props.children}</a>\n )\n}\n\n/** Download menu kept compact in the usage card header. */\nfunction ExportMenu(props: { usage: UsageData }): ReactElement {\n const { t } = useI18n()\n const [open, setOpen] = useState(false)\n const [done, setDone] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const doneTimerRef = useRef<number | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(event.target as Node)) setOpen(false)\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n setOpen(false)\n triggerRef.current?.focus()\n }\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n window.requestAnimationFrame(() => menuRef.current?.querySelector<HTMLButtonElement>('button')?.focus())\n return () => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n useEffect(() => () => {\n if (doneTimerRef.current !== null) window.clearTimeout(doneTimerRef.current)\n }, [])\n\n const finish = (): void => {\n setOpen(false)\n setDone(true)\n if (doneTimerRef.current !== null) window.clearTimeout(doneTimerRef.current)\n doneTimerRef.current = window.setTimeout(() => setDone(false), 1400)\n }\n\n const exportDaily = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-${stamp}.csv`, dailyUsageCsv(props.usage), 'text/csv;charset=utf-8')\n finish()\n }\n const exportModels = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-models-${stamp}.csv`, modelUsageCsv(props.usage), 'text/csv;charset=utf-8')\n finish()\n }\n const exportJson = (): void => {\n const stamp = exportDateStamp()\n downloadText(`dsh-usage-${stamp}.json`, fullUsageJson(props.usage), 'application/json;charset=utf-8')\n finish()\n }\n\n return (\n <div className=\"dq-export\" ref={rootRef}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={`dq-export-btn${done ? ' dq-export-btn--done' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={open}\n title={t('export.title')}\n onClick={() => setOpen(value => !value)}\n >\n {done ? t('export.done') : t('export.action')}\n </button>\n {open && (\n <div ref={menuRef} className=\"dq-export-menu\" aria-label={t('export.menuLabel')}>\n <button type=\"button\" onClick={exportDaily}>\n <span>{t('export.dailyCsv')}</span><small>{t('common.rows', { count: props.usage.daily.length })}</small>\n </button>\n <button type=\"button\" onClick={exportModels}>\n <span>{t('export.modelCsv')}</span><small>{t('common.rows', { count: props.usage.models.length })}</small>\n </button>\n <button type=\"button\" onClick={exportJson}>\n <span>{t('export.fullJson')}</span><small>{t('export.jsonHint')}</small>\n </button>\n </div>\n )}\n </div>\n )\n}\n\nexport const modelKeyOf = (m: ModelUsage): string => (m.provider !== '' ? `${m.provider}/${m.model}` : m.model)\n\nexport const modelNameOf = (m: ModelUsage, t: Translate = fallbackT): string => (m.model !== '' ? m.model : t('common.unknownModel'))\n\n/**\n * Usage for exactly the session the \u300C\u989D\u5EA6\u300D tab is opened inside \u2014 the one\n * dimension every other card on this page does not answer (they are all\n * account-wide, replayed across every local session log). Deliberately\n * reuses the same `.dq-balance-grid`/`Stat` headline layout as the balance\n * card above it and the same `.dq-rank`/`MODEL_COLORS` breakdown as the\n * model cost ranking card further down, rather than inventing a third\n * visual language for numbers that are structurally the same kind of thing.\n */\nfunction SessionUsageCard(props: { data: SessionUsageData }): ReactElement {\n const { t, locale } = useI18n()\n const { data } = props\n if (data.calls === 0) return <div className=\"dq-empty\">{t('sessionUsage.empty')}</div>\n\n const rangeTime = new Intl.DateTimeFormat(intlLocale(locale), {\n timeZone: 'Asia/Shanghai', year: 'numeric', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = data.firstActive !== null && data.lastActive !== null\n ? (data.firstActive === data.lastActive\n ? rangeTime.format(data.firstActive)\n : `${rangeTime.format(data.firstActive)} \u2013 ${rangeTime.format(data.lastActive)}`)\n : null\n\n return (\n <>\n <div className=\"dq-balance-grid\">\n <Stat label={t('sessionUsage.cost')}><div className=\"dq-stat-value\">\u00A5{fmt(data.cost)}</div></Stat>\n <Stat label={t('sessionUsage.tokens')}><div className=\"dq-stat-value\">{fmtCompact(data.total, locale)}</div></Stat>\n <Stat label={t('sessionUsage.calls')}><div className=\"dq-stat-value\">{fmtInt(data.calls)}</div></Stat>\n </div>\n {/* One model = the breakdown would repeat the totals above; fold it into one meta line. */}\n <div className=\"dq-session-meta\">\n {range !== null && <p className=\"dq-session-sub\">{t('sessionUsage.range', { range })}</p>}\n {data.models.length === 1 && (\n <p className=\"dq-session-sub\">{t('sessionUsage.single', {\n model: data.models[0].model !== '' ? data.models[0].model : t('common.unknownModel'),\n input: fmtCompact(data.models[0].input, locale),\n output: fmtCompact(data.models[0].output, locale),\n cache: fmtCompact(data.models[0].cache, locale),\n })}</p>\n )}\n </div>\n {data.models.length > 1 && (\n <div className=\"dq-rank\">\n {data.models.map((m, index) => {\n const key = m.provider !== '' ? `${m.provider}/${m.model}` : (m.model !== '' ? m.model : `model-${index}`)\n const name = m.model !== '' ? m.model : t('common.unknownModel')\n const color = MODEL_COLORS[index % MODEL_COLORS.length]\n const share = data.cost > 0 ? m.cost / data.cost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: color }} />\n {name}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5{fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={t('models.shareAria', { name, percent: (share * 100).toFixed(1) })}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: color }} />\n </div>\n <div className=\"dq-rank-sub\">\n {t('models.detail', {\n tokens: fmtCompact(m.total, locale),\n calls: t('common.calls', { count: fmtInt(m.calls) }),\n input: fmtCompact(m.input, locale), output: fmtCompact(m.output, locale), cache: fmtCompact(m.cache, locale),\n })}\n </div>\n </div>\n )\n })}\n </div>\n )}\n </>\n )\n}\n\n/**\n * What prefix caching is doing for the bill. Cache-hit tokens are priced at a\n * small fraction of cache-miss tokens, so on a DSH workload this is usually the\n * single biggest lever on cost \u2014 and it was invisible before.\n */\nfunction CacheCard(props: { totals: UsageData['totals'] }): ReactElement {\n const { t, locale } = useI18n()\n const { totals } = props\n const prompt = totals.input + totals.cache\n if (prompt === 0) return <div className=\"dq-empty\">{t('cache.empty')}</div>\n const rate = totals.cache / prompt\n const wouldHaveCost = totals.cost + totals.cacheSavings\n const low = rate < 0.6\n return (\n <div className=\"dq-cache\">\n <div className=\"dq-cache-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.rate')}</div>\n <div className={`dq-stat-value${low ? ' dq-stat-value--warn' : ' dq-stat-value--ok'}`}>\n {(rate * 100).toFixed(1)}%\n </div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.saved')}</div>\n <div className=\"dq-stat-value\">\u00A5{fmt(totals.cacheSavings)}</div>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('cache.allMiss')}</div>\n <div className=\"dq-stat-value dq-muted-value\">\u00A5{fmt(wouldHaveCost)}</div>\n </div>\n </div>\n <div className=\"dq-cache-track\" role=\"img\" aria-label={t('cache.aria', { hit: (rate * 100).toFixed(1), miss: ((1 - rate) * 100).toFixed(1) })}>\n <div className=\"dq-cache-fill\" style={{ width: `${rate * 100}%` }} />\n </div>\n <div className=\"dq-cache-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--hit\" />{t('cache.hitLegend', { tokens: fmtCompact(totals.cache, locale) })}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--miss\" />{t('cache.missLegend', { tokens: fmtCompact(totals.input, locale) })}</span>\n </div>\n <p className=\"dq-cache-foot\">{t('cache.basis', { cost: fmt(totals.cost), miss: fmt(wouldHaveCost) })}</p>\n </div>\n )\n}\n\n/** Everything `VisionCard` needs to paint one window's image usage. Captured\n * as a snapshot by the trend card so the closing animation can keep showing\n * the last payload after the live window stops reporting images. */\ninterface VisionSectionProps {\n vision: VisionStats\n daily: VisionDayPoint[]\n sessions: VisionSession[]\n windowLabel: string\n inputTokens: number\n costTotal: number\n}\n\n/**\n * Image / multimodal usage: how much of the bill came from pictures. Image\n * blocks are collected from user messages and tool results during the same\n * log replay that feeds the rest of the dashboard (no attachment bytes are\n * read \u2014 the refs already carry width/height), so this dimension costs the\n * replay nothing extra. Tokens are estimated with the official resizing rule\n * and priced at the consuming call's rates; shares are against the window's\n * reported input tokens and cost.\n */\nfunction VisionCard(props: VisionSectionProps): ReactElement {\n const { t, locale } = useI18n()\n const { vision, daily, sessions, windowLabel, inputTokens, costTotal } = props\n if (vision.images === 0) return <div className=\"dq-empty\">{t('vision.empty', { window: windowLabel })}</div>\n const tokensShare = inputTokens > 0 ? (vision.imageTokens / inputTokens) * 100 : 0\n const costShare = costTotal > 0 ? (vision.cost / costTotal) * 100 : 0\n const labelEvery = daily.length <= 7 ? 1 : daily.length <= 30 ? 5 : daily.length <= 90 ? 15 : 30\n const bars = daily.map(d => ({\n label: d.date.slice(8, 10),\n value: d.images,\n title: t('vision.barTitle', { date: d.date, images: fmtInt(d.images), tokens: fmtCompact(d.imageTokens, locale), cost: fmt(d.cost) }),\n }))\n return (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label={t('vision.images')}><div className=\"dq-stat-value\">{fmtInt(vision.images)}</div></Stat>\n <Stat label={t('vision.tokens')}>\n <div className=\"dq-stat-value\">\n {fmtCompact(vision.imageTokens, locale)}\n {tokensShare > 0 && <span className=\"dq-vision-share\">{t('vision.tokensShare', { percent: tokensShare.toFixed(1) })}</span>}\n </div>\n </Stat>\n <Stat label={t('vision.cost')}>\n <div className=\"dq-stat-value\">\n \u00A5{fmt(vision.cost)}\n {costShare > 0 && <span className=\"dq-vision-share\">{t('vision.costShare', { percent: costShare.toFixed(1) })}</span>}\n </div>\n </Stat>\n </div>\n <div className=\"dq-chart-title\">{t('vision.dailyTitle', { window: windowLabel })}</div>\n <Bars data={bars} height={80} labelEvery={labelEvery} />\n {sessions.length > 0 && (\n <div className=\"dq-vision-sessions\">\n <div className=\"dq-chart-title\">{t('vision.sessionsTitle')}</div>\n {sessions.map(session => (\n <div key={session.id} className=\"dq-session\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={session.id}>{session.title}</span>\n <span className=\"dq-session-cost\">\n {t('vision.sessionRow', { images: fmtInt(session.images), cost: fmt(session.cost) })}\n </span>\n </div>\n </div>\n ))}\n </div>\n )}\n <p className=\"dq-cache-foot\">{t('vision.note')}</p>\n </>\n )\n}\n\n/**\n * Peak vs off-peak: which side of DeepSeek's price windows the usage falls on,\n * and what shifting the peak share off-peak would have saved.\n */\nfunction PeakCard(props: { split: PeakSplit; pricing: PricingInfo }): ReactElement {\n const { t, locale } = useI18n()\n const { split, pricing } = props\n // Live Beijing clock so \"now\" stays honest while the tab is open; one tick a\n // minute is plenty for an hour-resolution strip.\n const [nowMs, setNowMs] = useState(() => Date.now())\n useEffect(() => {\n const id = setInterval(() => setNowMs(Date.now()), 60_000)\n return () => clearInterval(id)\n }, [])\n const total = split.peak.total + split.offPeak.total\n if (total === 0) return <div className=\"dq-empty\">{t('peak.empty')}</div>\n const peakShare = split.peak.total / total\n const shiftSaving = split.peakEraCost - split.offPeakEraCost\n\n // DeepSeek peak windows are Beijing time and weekday-only in the current price\n // era. Derive the schedule from the same strings the pricing note shows, so the\n // clock cannot drift from the table.\n const beijing = new Date(nowMs + 8 * 3_600_000)\n const hour = beijing.getUTCHours()\n const minute = beijing.getUTCMinutes()\n const weekday = beijing.getUTCDay()\n const weekend = weekday === 0 || weekday === 6\n const windows = pricing.peakWindows\n .map(w => w.match(/(\\d{1,2}):\\d{2}\\D+(\\d{1,2}):\\d{2}/))\n .filter((m): m is RegExpMatchArray => m !== null)\n .map(m => [Number(m[1]), Number(m[2])] as const)\n const isPeakNow = !weekend && windows.some(([from, to]) => hour >= from && hour < to)\n const nowPercent = ((hour + minute / 60) / 24) * 100\n const clockCells = Array.from({ length: 24 }, (_, h) => !weekend && windows.some(([from, to]) => h >= from && h < to))\n const nowState = isPeakNow ? t('peak.nowPeak') : t('peak.nowOff')\n return (\n <div className=\"dq-peak\">\n <div className=\"dq-clock\">\n <div className=\"dq-clock-head\">\n <span className=\"dq-clock-title\">{t('peak.clockTitle')}</span>\n <span className={`dq-clock-status ${isPeakNow ? 'dq-clock-status--peak' : 'dq-clock-status--off'}`}>{nowState}</span>\n </div>\n <div className=\"dq-clock-track\" role=\"img\" aria-label={t('peak.clockAria', { state: nowState })}>\n {clockCells.map((peak, h) => (\n <span key={h} className={`dq-clock-cell${peak ? ' dq-clock-cell--peak' : ''}`} />\n ))}\n <span className=\"dq-clock-now\" style={{ left: `${nowPercent}%` }} aria-hidden=\"true\" />\n </div>\n <div className=\"dq-clock-scale\" aria-hidden=\"true\"><span>0</span><span>6</span><span>12</span><span>18</span><span>24</span></div>\n <p className=\"dq-clock-hint\">{t('peak.clockHint')}</p>\n </div>\n <div\n className=\"dq-peak-track\"\n role=\"img\"\n aria-label={t('peak.aria', { peak: (peakShare * 100).toFixed(1), offPeak: ((1 - peakShare) * 100).toFixed(1) })}\n >\n <div className=\"dq-peak-fill\" style={{ width: `${peakShare * 100}%` }} />\n </div>\n <div className=\"dq-peak-legend\">\n <span><span className=\"dq-legend-swatch dq-legend-swatch--peak\" />{t('peak.peakLegend', {\n share: (peakShare * 100).toFixed(1), tokens: fmtCompact(split.peak.total, locale), calls: t('common.callsShort', { count: fmtInt(split.peak.calls) }),\n })}</span>\n <span><span className=\"dq-legend-swatch dq-legend-swatch--offpeak\" />{t('peak.offPeakLegend', {\n share: ((1 - peakShare) * 100).toFixed(1), tokens: fmtCompact(split.offPeak.total, locale), calls: t('common.callsShort', { count: fmtInt(split.offPeak.calls) }),\n })}</span>\n </div>\n <div className=\"dq-peak-figures\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('peak.shift')}</div>\n <div className=\"dq-stat-value dq-stat-value--ok\">{t('peak.saving', { amount: fmt(shiftSaving) })}</div>\n </div>\n </div>\n <p className=\"dq-peak-foot\">{t('peak.basis', { total: fmt(split.offPeakEraCost) })}</p>\n </div>\n )\n}\n\n/** Coarse \"how long ago\", enough to tell a live session from last week's. */\nfunction agoText(ms: number, t: Translate): string {\n const minutes = Math.floor((Date.now() - ms) / 60_000)\n if (minutes < 1) return t('common.justNow')\n if (minutes < 60) return t('common.minutesAgo', { count: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('common.hoursAgo', { count: hours })\n return t('common.daysAgo', { count: Math.floor(hours / 24) })\n}\n\n/** Per-row fetch state for the ranking's on-demand expand \u2014 mirrors the\n * three-way {loading, error, data} shape `loadSessionUsage` already uses\n * for the current-session card, just keyed per row instead of per tab. */\ninterface SessionDetailState {\n error: string | null\n data: SessionUsageData | null\n}\n\n/** Body of one expanded ranking row: same loading/error/data three-way as the\n * current-session card, and the same `SessionUsageCard` rendering the data \u2014\n * this is deliberately not a second implementation of that layout. */\nfunction SessionDetail(props: { state: SessionDetailState | undefined }): ReactElement {\n const { t } = useI18n()\n const { state } = props\n if (state === undefined) return <SessionUsageSkeleton />\n if (state.data !== null) return <SessionUsageCard data={state.data} />\n if (state.error !== null) return <div className=\"dq-empty dq-empty--error\">{localizeApiError(state.error, t, 'error.query')}</div>\n return <SessionUsageSkeleton />\n}\n\n/**\n * Which sessions burned the money. Per-model and per-day views say what and\n * when; this says *which run*, which is the one an agent user can act on \u2014\n * a single expensive session is a prompt or a loop worth looking at.\n *\n * Each row is a native `<details>` (same disclosure grammar as `.dq-pricing`/\n * `.dq-coverage` above \u2014 no custom open/close state machine, keyboard and\n * touch come for free). Opening a row for the first time fires an on-demand\n * `fetchSessionUsage(s.id)` and renders the result with the exact same\n * `SessionUsageCard` the \u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300Dcard uses \u2014 the row only has the\n * summary fields (`SessionCost`), the full per-model breakdown only exists\n * once that fetch lands. `startedRef` guards against re-fetching on a\n * collapse/re-expand: once a row's fetch has been kicked off, later toggles\n * just show whatever is already cached in `details`.\n */\nfunction SessionRanking(props: { sessions: SessionCost[]; count: number; totalCost: number }): ReactElement {\n const { t, locale } = useI18n()\n const { sessions, count, totalCost } = props\n const [details, setDetails] = useState<Record<string, SessionDetailState>>({})\n const startedRef = useRef<Set<string>>(new Set())\n\n const loadDetail = (id: string): void => {\n if (startedRef.current.has(id)) return\n startedRef.current.add(id)\n fetchSessionUsage(id).then(res => {\n setDetails(prev => ({\n ...prev,\n [id]: res.ok && res.data !== undefined\n ? { error: null, data: res.data }\n : { error: res.error ?? null, data: null },\n }))\n }, err => {\n const message = (err as { message?: string } | null)?.message ?? String(err)\n setDetails(prev => ({ ...prev, [id]: { error: message, data: null } }))\n })\n }\n\n if (sessions.length === 0) return <div className=\"dq-empty\">{t('sessions.empty')}</div>\n const top = sessions[0].cost\n return (\n <>\n <ol className=\"dq-sessions\">\n {sessions.map(s => (\n <li key={s.id} className=\"dq-session\">\n <details\n className=\"dq-session-details\"\n onToggle={e => { if (e.currentTarget.open) loadDetail(s.id) }}\n >\n <summary className=\"dq-session-summary\">\n <span className=\"dq-session-chevron\" aria-hidden=\"true\" />\n <div className=\"dq-session-summary-body\">\n <div className=\"dq-session-head\">\n <span className=\"dq-session-title\" title={`${s.title}\\n${s.id}`}>{s.title || t('sessions.fallbackTitle', { id: s.id })}</span>\n <span className=\"dq-session-cost\">\u00A5{fmt(s.cost)}</span>\n </div>\n <div className=\"dq-session-track\">\n <div className=\"dq-session-fill\" style={{ width: `${Math.max((s.cost / (top || 1)) * 100, 1.5)}%` }} />\n </div>\n <div className=\"dq-session-sub\">\n {t('sessions.detail', {\n tokens: fmtCompact(s.total, locale),\n calls: t('common.calls', { count: fmtInt(s.calls) }),\n ago: agoText(s.lastActive, t),\n })}\n {totalCost > 0 && <> \u00B7 {t('sessions.share', { percent: ((s.cost / totalCost) * 100).toFixed(1) })}</>}\n </div>\n </div>\n </summary>\n <div className=\"dq-session-expand\">\n <SessionDetail state={details[s.id]} />\n </div>\n </details>\n </li>\n ))}\n </ol>\n {count > sessions.length && (\n <p className=\"dq-session-foot\">{t('sessions.more', { count: fmtInt(count), shown: sessions.length })}</p>\n )}\n </>\n )\n}\n\n/** Which model the money actually goes to, most expensive first. */\nfunction ModelRanking(props: {\n models: ModelUsage[]\n totalCost: number\n colorOf: (key: string) => string\n}): ReactElement {\n const { t, locale } = useI18n()\n const { models, totalCost } = props\n if (models.length === 0) return <div className=\"dq-empty\">{t('models.empty')}</div>\n return (\n <div className=\"dq-rank\">\n {models.map(m => {\n const key = modelKeyOf(m)\n const share = totalCost > 0 ? m.cost / totalCost : 0\n return (\n <div key={key} className=\"dq-rank-row\">\n <div className=\"dq-rank-head\">\n <span className=\"dq-rank-name\" title={key}>\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n {modelNameOf(m, t)}\n </span>\n <span className=\"dq-rank-cost\">\n \u00A5{fmt(m.cost)}\n <span className=\"dq-rank-share\">{(share * 100).toFixed(1)}%</span>\n </span>\n </div>\n <div\n className=\"dq-rank-track\"\n role=\"img\"\n aria-label={t('models.shareAria', { name: modelNameOf(m, t), percent: (share * 100).toFixed(1) })}\n >\n <div className=\"dq-rank-fill\" style={{ width: `${Math.max(share * 100, 1.5)}%`, background: props.colorOf(key) }} />\n </div>\n <div className=\"dq-rank-sub\">\n {t('models.detail', {\n tokens: fmtCompact(m.total, locale),\n calls: t('common.calls', { count: fmtInt(m.calls) }),\n input: fmtCompact(m.input, locale), output: fmtCompact(m.output, locale), cache: fmtCompact(m.cache, locale),\n })}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Multi-select model dropdown feeding the grouped bar chart. */\nfunction ModelPicker(props: {\n models: ModelUsage[]\n selected: string[]\n colorOf: (key: string) => string\n onChange: (keys: string[]) => void\n}): ReactElement | null {\n const { t, locale } = useI18n()\n const { models } = props\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: MouseEvent): void => {\n if (rootRef.current !== null && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape') return\n e.preventDefault()\n setOpen(false)\n triggerRef.current?.focus()\n }\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n window.requestAnimationFrame(() => menuRef.current?.querySelector<HTMLInputElement>('input')?.focus())\n return () => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n if (models.length === 0) return null\n\n const toggle = (key: string): void => {\n props.onChange(\n props.selected.includes(key)\n ? props.selected.filter(k => k !== key)\n : [...props.selected, key],\n )\n }\n\n const label = props.selected.length === 0 ? t('models.all') : t('models.selected', { count: props.selected.length })\n\n return (\n <div className=\"dq-model-picker\" ref={rootRef}>\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"dq-model-btn\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n aria-controls=\"dq-model-menu\"\n title={t('models.filterTitle')}\n onClick={() => setOpen(value => !value)}\n >\n {label}\n </button>\n {open && (\n <div id=\"dq-model-menu\" ref={menuRef} className=\"dq-model-menu\" role=\"group\" aria-label={t('models.filterLabel')}>\n <label className=\"dq-model-item dq-model-item--all\">\n <input\n type=\"checkbox\"\n checked={props.selected.length === 0}\n onChange={() => props.onChange([])}\n />\n <span>{t('models.all')}</span>\n </label>\n {models.map(m => {\n const key = modelKeyOf(m)\n return (\n <label key={key} className=\"dq-model-item\">\n <input type=\"checkbox\" checked={props.selected.includes(key)} onChange={() => toggle(key)} />\n <span className=\"dq-legend-swatch\" style={{ background: props.colorOf(key) }} />\n <span>{modelNameOf(m, t)}</span>\n <span className=\"dq-model-tag\">{fmtCompact(m.total, locale)}</span>\n </label>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nconst windowName = (days: UsageWindowDays, t: Translate = fallbackT): string => days === 365\n ? t('window.year')\n : t('window.days', { days })\n\n/** One range choice controls every metric whose title carries that range. */\nfunction UsageWindowPicker(props: { value: UsageWindowDays; onChange: (days: UsageWindowDays) => void }): ReactElement {\n const { t } = useI18n()\n return (\n <div className=\"dq-window-switch\" role=\"group\" aria-label={t('window.groupLabel')}>\n {USAGE_WINDOW_DAYS.map(days => (\n <button\n key={days}\n type=\"button\"\n className={`dq-window-btn${props.value === days ? ' dq-window-btn--on' : ''}`}\n aria-pressed={props.value === days}\n title={t('window.viewTitle', { window: windowName(days, t) })}\n onClick={() => props.onChange(days)}\n >\n {days === 365 ? t('window.yearButton') : t('window.daysButton', { days })}\n </button>\n ))}\n </div>\n )\n}\n\nconst chartMetricLabel = (metric: ChartMetric, t: Translate = fallbackT): string => metric === 'tokens'\n ? t('metric.tokens')\n : chartMetricName(metric, t)\n\nfunction ChartMetricPicker(props: { value: ChartMetric; onChange: (metric: ChartMetric) => void }): ReactElement {\n const { t } = useI18n()\n return (\n <div className=\"dq-chart-switch\" role=\"group\" aria-label={t('metric.groupLabel')}>\n {CHART_METRICS.map(metric => (\n <button\n key={metric}\n type=\"button\"\n className={`dq-chart-switch-btn${props.value === metric ? ' dq-chart-switch-btn--on' : ''}`}\n aria-pressed={props.value === metric}\n title={t('metric.compareTitle', { metric: chartMetricLabel(metric, t) })}\n onClick={() => props.onChange(metric)}\n >\n {chartMetricLabel(metric, t)}\n </button>\n ))}\n </div>\n )\n}\n\nexport function BalanceDashboard(props: { sessionId?: string; views: ConversationViewsSource }): ReactElement {\n const { t, locale } = useI18n()\n // Seed state from the cache so the tab never waits on the network when\n // data has been fetched before (stale-while-revalidate).\n const cachedBalance = getCachedBalance()\n const cachedUsage = getCachedUsage()\n const cachedUsageAt = getCachedUsageAt()\n const [balance, setBalance] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [usage, setUsage] = useState<UsageData | null>(cachedUsage?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<{ kind: 'all' | 'balance' | 'usage'; error: string } | null>(null)\n // Balance answers in well under a second, usage replays every session log and\n // takes seconds \u2014 so they get their own loading flags and paint independently\n // instead of the fast one waiting on the slow one.\n const [loadingBalance, setLoadingBalance] = useState(cachedBalance === null)\n const [loadingUsage, setLoadingUsage] = useState(cachedUsage === null)\n const [refreshing, setRefreshing] = useState(false)\n const [usageUpdatedAt, setUsageUpdatedAt] = useState<number | null>(cachedUsageAt)\n const [syncState, setSyncState] = useState<SyncState>(cachedUsageAt === null ? 'syncing' : 'cached')\n const [freshnessNow, setFreshnessNow] = useState(Date.now())\n const [settingsOpen, setSettingsOpen] = useState(false)\n const hadDataRef = useRef(cachedBalance !== null || cachedUsage !== null)\n const [widgetOn, setWidgetOn] = useState(widgetVisibleStore.get())\n const [widgetTabIds, setWidgetTabIds] = useState<string[] | null>(widgetTabIdsStore.get())\n const [viewTabs, setViewTabs] = useState<ConversationViewTab[]>(() => props.views.list())\n useEffect(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n const [monthlyBudget, setMonthlyBudget] = useState(monthlyBudgetStore.get())\n const [barMode, setBarMode] = useState<'daily' | 'hourly'>('daily')\n const [selectedModels, setSelectedModels] = useState<string[]>([])\n const [windowDays, setWindowDays] = useState<UsageWindowDays>(usageWindowStore.get())\n const [chartMetric, setChartMetric] = useState<ChartMetric>(chartMetricStore.get())\n // Layout preferences shared with the client registration half (see\n // ./layout-prefs.ts): the sidebar entry is applied there, and the \u300C\u989D\u5EA6\u300Dtab\n // position is mapped onto the host's slot order there. Seed locally and stay\n // subscribed so the row shows whatever actually got applied.\n const [sidebarEntry, setSidebarEntry] = useState<SidebarEntryPlacement>(sidebarEntryStore.get())\n useEffect(() => sidebarEntryStore.subscribe(() => setSidebarEntry(sidebarEntryStore.get())), [])\n // Chip drag state for the tab-position setting. `tabDropTarget` is the chip\n // currently under the pointer while dragging, only to paint the drop target.\n const [tabDragging, setTabDragging] = useState(false)\n const [tabDropTarget, setTabDropTarget] = useState<number | null>(null)\n // The inline image-usage section animates closed when the selected window\n // loses its images; the last payload that had images stays rendered for the\n // ~320ms collapse, so the section always has something to show while shrinking.\n const [retainedVision, setRetainedVision] = useState<VisionSectionProps | null>(null)\n // \"\u9884\u8BA1\u53EF\u7528\" hover preview: an unopened <details> skips rendering its\n // non-summary children in Chromium (a content-visibility-like platform\n // behavior), so CSS-only `:hover{display:block}` never paints anything\n // when the element isn't actually open. Drive `open` from state instead \u2014\n // hovering opens it for a live preview; a manual click/keyboard/touch open\n // keeps it open independent of hover.\n const [runwayHovering, setRunwayHovering] = useState(false)\n const [runwayManuallyOpened, setRunwayManuallyOpened] = useState(false)\n // \u8F6E\u6B21 47: same platform limitation applies to \"\u4F59\u989D\u660E\u7EC6\" \u2014 it used the same\n // CSS-only `:hover{display:flex}` on an uncontrolled <details> since round 29,\n // which never actually painted in current Chromium either. Same fix, same shape.\n const [remainingHovering, setRemainingHovering] = useState(false)\n const [remainingManuallyOpened, setRemainingManuallyOpened] = useState(false)\n const budgetInputRef = useRef<HTMLInputElement | null>(null)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const [composerHeight, setComposerHeight] = useState<number | null>(null)\n // The composer's measured width caps the dashboard column: on narrower\n // viewports the fixed 860px max-width would otherwise overhang the input\n // box the cards visually belong to (user-facing parity requirement).\n const [composerWidth, setComposerWidth] = useState<number | null>(null)\n // The current-session card: fetched per session id, not through the\n // account-wide balance/usage caches (see DESIGN_NOTES \u2014 session-scoped\n // data does not go through the localStorage-persisted cache). No cached\n // seed on first render since there is nothing to seed from.\n const [sessionUsage, setSessionUsage] = useState<SessionUsageData | null>(null)\n const [loadingSessionUsage, setLoadingSessionUsage] = useState(props.sessionId !== undefined && props.sessionId !== '')\n const [sessionUsageError, setSessionUsageError] = useState<string | null>(null)\n const sessionUsageIdRef = useRef<string | null>(null)\n\n // Narrow viewports only: keep the last card scrollable clear of the host's\n // fixed composer, which otherwise overlaps the bottom of a long dashboard\n // (see LEARNINGS.md). Reuses the same `conversation.composer` seat lookup\n // widget.tsx already excludes from its own drag bounds, so both readings of\n // \"where is the composer\" stay in sync. Desktop layout never reads the\n // height \u2014 the CSS variable is only consumed inside the 620px media query;\n // the width is consumed by .dq-balance at every viewport.\n useLayoutEffect(() => {\n const node = rootRef.current\n if (node === null) return\n const measure = (): void => {\n const frame = getShellFrame(node)\n const composer = getComposerElement(frame)\n const rect = composer?.getBoundingClientRect() ?? null\n const nextHeight = rect !== null && rect.height > 0 ? Math.round(rect.height) : null\n setComposerHeight(prev => (prev === nextHeight ? prev : nextHeight))\n // Width parity uses the composer's input card (the rounded panel with\n // the textarea), not the dock seat \u2014 the seat spans the whole pane, so\n // it can never narrow the dashboard column below 860px.\n const input = getComposerInputElement(frame)\n const inputRect = input?.getBoundingClientRect() ?? null\n const nextWidth = inputRect !== null && inputRect.width > 0 ? Math.round(inputRect.width) : null\n setComposerWidth(prev => (prev === nextWidth ? prev : nextWidth))\n }\n measure()\n const frame = getShellFrame(node)\n const composer = getComposerElement(frame)\n const input = getComposerInputElement(frame)\n let observer: ResizeObserver | null = null\n if (typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(measure)\n if (composer !== null) observer.observe(composer)\n if (input !== null) observer.observe(input)\n if (frame !== null) observer.observe(frame)\n }\n window.addEventListener('resize', measure)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', measure)\n }\n }, [])\n\n // All conversation view tabs (Chat / Trajectory / \u989D\u5EA6 \u2026) share one host\n // scrollport (`[data-conversation-scroll]`), and the host keeps scroll\n // memory only for Chat itself \u2014 switching to \u989D\u5EA6 from a scrolled-down Chat\n // otherwise opens the tab near the settings card instead of at the account\n // balance. Reset before paint on every mount; the view is remounted per tab\n // switch, and `sessionId` re-runs it if the host reuses the view for\n // another session.\n useLayoutEffect(() => {\n const node = rootRef.current\n if (node === null) return\n const scrollport = node.closest('[data-conversation-scroll]')\n if (scrollport instanceof HTMLElement) scrollport.scrollTop = 0\n }, [props.sessionId])\n\n // The full dashboard and the floating summary should never compete for the\n // same pixels. This does not touch the persisted widget preference: leaving\n // the tab restores it exactly as the user left it.\n useLayoutEffect(() => {\n quotaViewActiveStore.set(true)\n return () => quotaViewActiveStore.set(false)\n }, [])\n\n const errText = (err: unknown): string => (err as { message?: string } | null)?.message ?? String(err)\n\n /** Load both resources; each resolves to null on success or to its error\n * string on failure, so a partial failure can name the half that broke. */\n const load = async (force: boolean): Promise<void> => {\n const usageAtBefore = getCachedUsageAt()\n setError(null)\n setNotice(null)\n setRefreshing(true)\n setSyncState('syncing')\n const balanceTask = fetchBalance(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setBalance(res.data)\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingBalance(false)\n return result\n })\n const usageTask = fetchUsage(force).then(res => {\n if (res.ok && res.data !== undefined) {\n setUsage(res.data)\n const updatedAt = getCachedUsageAt()\n setUsageUpdatedAt(updatedAt)\n setFreshnessNow(Date.now())\n setSyncState(updatedAt !== null && updatedAt !== usageAtBefore ? 'fresh' : 'cached')\n hadDataRef.current = true\n return null\n }\n return res.error ?? '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25'\n }, err => errText(err)).then(result => {\n setLoadingUsage(false)\n return result\n })\n const [balanceError, usageError] = await Promise.all([balanceTask, usageTask])\n setRefreshing(false)\n if (usageError !== null) {\n const fallbackAt = getCachedUsageAt()\n setUsageUpdatedAt(fallbackAt)\n setFreshnessNow(Date.now())\n setSyncState(fallbackAt === null ? 'error' : 'fallback')\n }\n if (balanceError !== null && usageError !== null) {\n // Nothing came back at all: an error only when there is nothing to show.\n if (hadDataRef.current) setNotice({ kind: 'all', error: balanceError })\n else setError(balanceError)\n } else if (balanceError !== null) {\n setNotice({ kind: 'balance', error: balanceError })\n } else if (usageError !== null) {\n setNotice({ kind: 'usage', error: usageError })\n }\n // The current-session card rides along with an explicit force refresh so\n // the one refresh button covers all three data sources; the initial\n // mount-time fetch is handled separately below, keyed on the session id\n // itself, so it is not duplicated here (force=false would otherwise fire\n // twice on first render \u2014 once from this effect, once from that one).\n if (force && props.sessionId !== undefined && props.sessionId !== '') {\n void loadSessionUsage(props.sessionId, true)\n }\n }\n\n /** Stale-while-revalidate for the current-session card: on success, swap\n * in the new data; on failure, keep whatever is already on screen (a\n * refresh going bad should not blank out a card that was working). Guards\n * every state write against the session id having changed mid-flight, so\n * a slow request for a session the user has since navigated away from\n * cannot clobber the next one's numbers. */\n const loadSessionUsage = async (id: string, force: boolean): Promise<void> => {\n if (!force) setLoadingSessionUsage(true)\n try {\n const res = await fetchSessionUsage(id, force)\n if (sessionUsageIdRef.current !== id) return\n if (res.ok && res.data !== undefined) {\n setSessionUsage(res.data)\n setSessionUsageError(null)\n } else {\n setSessionUsageError(res.error ?? null)\n }\n } catch (err) {\n if (sessionUsageIdRef.current === id) setSessionUsageError(errText(err))\n } finally {\n if (sessionUsageIdRef.current === id) setLoadingSessionUsage(false)\n }\n }\n\n useEffect(() => {\n void load(false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Mount-time (and session-switch-time) fetch for the current-session card.\n // Independent of the balance/usage effect above: this data is scoped to\n // whichever session the tab happens to be open inside, not to the account.\n useEffect(() => {\n const id = props.sessionId\n sessionUsageIdRef.current = id ?? null\n if (id === undefined || id === '') {\n setSessionUsage(null)\n setSessionUsageError(null)\n setLoadingSessionUsage(false)\n return\n }\n setSessionUsage(null)\n setSessionUsageError(null)\n setLoadingSessionUsage(true)\n void loadSessionUsage(id, false)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.sessionId])\n\n useEffect(() => {\n const timer = window.setInterval(() => setFreshnessNow(Date.now()), 30_000)\n return () => window.clearInterval(timer)\n }, [])\n\n const toggle = (): void => {\n const next = !widgetOn\n setWidgetOn(next)\n widgetVisibleStore.set(next)\n }\n\n const widgetTabs = viewTabs.filter(tab => tab.id !== 'balance')\n const toggleWidgetTab = (id: string): void => {\n const selected = widgetTabIds ?? widgetTabs.map(tab => tab.id)\n const next = selected.includes(id) ? selected.filter(tabId => tabId !== id) : [...selected, id]\n setWidgetTabIds(next)\n widgetTabIdsStore.set(next)\n }\n\n const changeLowBalance = (value: number): void => {\n setLowBalance(value)\n lowBalanceStore.set(value)\n }\n\n const changeMonthlyBudget = (value: number): void => {\n setMonthlyBudget(value)\n monthlyBudgetStore.set(value)\n }\n\n const changeWindowDays = (value: UsageWindowDays): void => {\n setWindowDays(value)\n usageWindowStore.set(value)\n }\n\n const changeChartMetric = (value: ChartMetric): void => {\n setChartMetric(value)\n chartMetricStore.set(value)\n }\n\n const changeSidebarEntry = (value: SidebarEntryPlacement): void => {\n setSidebarEntry(value)\n sidebarEntryStore.set(value)\n }\n\n // \u300C\u989D\u5EA6\u300Dtab position: read from the live roster (never from local state) so\n // the chips show the order the host actually applied, including orders other\n // plugins picked.\n const balanceTabIndex = viewTabs.findIndex(tab => tab.id === 'balance')\n\n /** Final roster position for dropping the quota chip on `target`, before or\n * after that chip's midpoint. The dragged chip leaves the roster before it\n * is reinserted, so a rightward drop lands one slot earlier than the raw\n * target \u2014 `quotaTabIndexStore` stores the final position, not an insertion\n * gap, so the shift has to be undone here. */\n const finalTabIndex = (target: number, after: boolean): number => {\n const gap = after ? target + 1 : target\n const dropped = balanceTabIndex >= 0 && gap > balanceTabIndex ? gap - 1 : gap\n return Math.max(0, Math.min(dropped, Math.max(viewTabs.length - 1, 0)))\n }\n\n const endTabDrag = (): void => {\n setTabDragging(false)\n setTabDropTarget(null)\n }\n\n const previewTabDropTarget = (index: number): void => {\n setTabDropTarget(prev => (prev === index ? prev : index))\n }\n\n const applyQuotaTabIndex = (index: number): void => {\n const next = Math.max(0, Math.min(index, Math.max(viewTabs.length - 1, 0)))\n if (next === balanceTabIndex) return\n quotaTabIndexStore.set(next)\n // Applying the new slot order replaces our registration, which remounts\n // this dashboard: the chip loses DOM focus. Put it back after the remount\n // so holding ArrowLeft/ArrowRight can nudge the tab more than once.\n window.setTimeout(() => {\n const chip = document.querySelector<HTMLElement>('.dq-tab-chip--current')\n chip?.focus()\n }, 80)\n }\n\n const dropQuotaTab = (target: number, after: boolean): void => {\n applyQuotaTabIndex(finalTabIndex(target, after))\n endTabDrag()\n }\n\n const onQuotaTabDragStart = (event: ReactDragEvent<HTMLElement>): void => {\n setTabDragging(true)\n // Firefox refuses to start a drag unless some payload is attached.\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', 'balance')\n }\n\n const onChipDragOver = (event: ReactDragEvent<HTMLElement>, index: number): void => {\n // Only the quota chip's own drag reorders tabs; dragging a file, link or\n // selected text over the strip must not be accepted as a drop target.\n if (!tabDragging) return\n event.preventDefault()\n event.stopPropagation()\n previewTabDropTarget(index)\n }\n\n const onChipDrop = (event: ReactDragEvent<HTMLElement>, index: number): void => {\n if (!tabDragging) return\n event.preventDefault()\n event.stopPropagation()\n const rect = event.currentTarget.getBoundingClientRect()\n dropQuotaTab(index, event.clientX > rect.left + rect.width / 2)\n }\n\n const onOrderDragOver = (event: ReactDragEvent<HTMLDivElement>): void => {\n // The container itself (the chip-free tail) means \"move to the end\"; chips\n // stop propagation and compute a precise before/after slot.\n if (!tabDragging) return\n event.preventDefault()\n if (event.target === event.currentTarget) previewTabDropTarget(viewTabs.length - 1)\n }\n\n const onOrderDrop = (event: ReactDragEvent<HTMLDivElement>): void => {\n if (!tabDragging) return\n event.preventDefault()\n if (event.target !== event.currentTarget) return\n applyQuotaTabIndex(viewTabs.length - 1)\n endTabDrag()\n }\n\n const onQuotaTabKeyDown = (event: ReactKeyboardEvent<HTMLElement>): void => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n event.preventDefault()\n applyQuotaTabIndex(balanceTabIndex + (event.key === 'ArrowLeft' ? -1 : 1))\n }\n\n const primary = balance !== null && balance.balances.length > 0 ? balance.balances[0] : null\n\n // Runway: balance divided by the last 7 calendar days' average spend. Idle\n // days are included on purpose \u2014 that is the burn rate, not the busy-day rate.\n const recentDays = (usage?.daily ?? []).slice(-7)\n const avgDailyCost = recentDays.length > 0\n ? recentDays.reduce((sum, d) => sum + d.cost, 0) / recentDays.length\n : 0\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n // 0 disables the warning; an unreadable balance never triggers it.\n const balanceLow = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n // The top-up shortcut sits outside the configurable warning: either a balance\n // under the fixed floor or one under the user's line is \"time to top up\".\n const topUpPrompt = needsTopUp(balanceValue, lowBalance)\n const daysLeft = avgDailyCost > 0 && Number.isFinite(balanceValue) ? balanceValue / avgDailyCost : null\n const daysLeftText = daysLeft === null\n ? '\u2014'\n : daysLeft >= 365 ? t('balance.overYear') : t('balance.days', { count: daysLeft < 10 ? daysLeft.toFixed(1) : Math.round(daysLeft) })\n const runwayTitle = daysLeft === null\n ? t('balance.noRunway', { days: recentDays.length || 7 })\n : t('balance.runwayTitle', { days: recentDays.length, cost: fmt(avgDailyCost) })\n\n const activeWindow = usage?.windows.find(window => window.days === windowDays) ?? null\n const activeWindowName = windowName(windowDays, t)\n\n // Image / multimodal usage lives inside the \u7528\u91CF\u8D8B\u52BF card now, as a section\n // that opens and closes with the selected window: 0 images means no section\n // at all (a line saying \"no images\" is not worth the space). A host half\n // that has not been restarted yet sends a pre-vision payload, so the shape is\n // re-checked here rather than trusted from the types.\n const visionStats = activeWindow?.vision\n const visionOpen = usage !== null && activeWindow !== null && visionStats !== undefined\n && visionStats.images > 0\n && Array.isArray(activeWindow.visionDaily) && Array.isArray(activeWindow.visionSessions)\n const visionPayload = (window: NonNullable<typeof activeWindow>, stats: VisionStats, label: string): VisionSectionProps => ({\n vision: stats,\n daily: window.visionDaily,\n sessions: window.visionSessions,\n windowLabel: label,\n inputTokens: window.totals.input,\n costTotal: window.totals.cost,\n })\n const liveVision: VisionSectionProps | null = visionOpen && activeWindow !== null && visionStats !== undefined\n ? visionPayload(activeWindow, visionStats, activeWindowName)\n : null\n // Open: paint the live payload immediately. Closed: keep the last payload for\n // 320ms (matching the CSS grid-row collapse) and drop it afterwards. The\n // timer is cleared on every dependency change and on unmount.\n useEffect(() => {\n if (visionOpen && activeWindow !== null && visionStats !== undefined) {\n setRetainedVision(visionPayload(activeWindow, visionStats, activeWindowName))\n return\n }\n const timer = window.setTimeout(() => setRetainedVision(null), 320)\n return () => window.clearTimeout(timer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [visionOpen, activeWindow, activeWindowName])\n const shownVision = visionOpen ? liveVision : retainedVision\n\n const dailyBars = (activeWindow?.daily ?? []).map(d => ({\n label: windowDays === 365 ? d.date.slice(5).replace('-', '/') : d.date.slice(8, 10),\n value: chartMetricValue(chartMetric, d),\n title: t('chart.tooltip', {\n head: d.date, tokens: fmtInt(d.total), cost: fmt(d.cost), calls: t('common.calls', { count: d.calls }),\n }),\n }))\n const hourlyBars = (activeWindow?.hourly ?? []).map(h => ({\n label: String(h.hour),\n value: chartMetricValue(chartMetric, h),\n title: t('chart.tooltip', {\n head: t('chart.hourPoint', { hour: h.hour }), tokens: fmtInt(h.total), cost: fmt(h.cost), calls: t('common.calls', { count: h.calls }),\n }),\n }))\n\n // One canonical model order \u2014 most expensive first \u2014 shared by the ranking\n // card, the picker and the chart, so a model keeps its colour everywhere\n // instead of being coloured by the order it happened to be ticked in.\n // Tallest bar currently on screen \u2014 the chart has no y axis, so this is the\n // only thing giving the bars a magnitude.\n const chartPeak = (barMode === 'daily' ? dailyBars : hourlyBars)\n .reduce((peak, bar) => (bar.value > peak ? bar.value : peak), 0)\n const chartPeakText = chartMetric === 'cost'\n ? `\u00A5${fmt(chartPeak)}`\n : chartMetric === 'calls'\n ? t('common.callsShort', { count: fmtInt(chartPeak) })\n : `${fmtCompact(chartPeak, locale)} tokens`\n\n const modelList = [...(activeWindow?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const canonicalModels = [...(usage?.models ?? [])].sort((a, b) => b.cost - a.cost)\n const availableModelKeys = new Set(modelList.map(modelKeyOf))\n const effectiveSelection = selectedModels.filter(k => availableModelKeys.has(k))\n const colorOf = (key: string): string => {\n const index = canonicalModels.findIndex(m => modelKeyOf(m) === key)\n return MODEL_COLORS[(index < 0 ? 0 : index) % MODEL_COLORS.length]\n }\n const modelCostTotal = modelList.reduce((sum, m) => sum + m.cost, 0)\n\n // Per-model series for the grouped bar chart (only when models are selected).\n const grouped = effectiveSelection.map(key => {\n const m = modelList.find(x => modelKeyOf(x) === key)\n const name = m === undefined ? key : modelNameOf(m, t)\n const color = colorOf(key)\n if (barMode === 'daily') {\n return {\n key,\n name,\n color,\n bars: (m?.daily ?? []).map((p, i) => ({\n label: windowDays === 365\n ? ((activeWindow?.daily ?? [])[i]?.date.slice(5).replace('-', '/') ?? '')\n : ((activeWindow?.daily ?? [])[i]?.date.slice(8, 10) ?? ''),\n value: chartMetricValue(chartMetric, p),\n title: t('chart.tooltip', {\n head: `${name} \u00B7 ${(activeWindow?.daily ?? [])[i]?.date ?? ''}`,\n tokens: fmtInt(p.total), cost: fmt(p.cost), calls: t('common.calls', { count: p.calls }),\n }),\n })),\n }\n }\n return {\n key,\n name,\n color,\n bars: (m?.hourly ?? []).map((p, i) => ({\n label: String(i),\n value: chartMetricValue(chartMetric, p),\n title: t('chart.tooltip', {\n head: `${name} \u00B7 ${t('chart.hourPoint', { hour: i })}`,\n tokens: fmtInt(p.total), cost: fmt(p.cost), calls: t('common.calls', { count: p.calls }),\n }),\n })),\n }\n })\n const dailyLabelEvery = windowDays === 7 ? 1 : windowDays === 30 ? 5 : windowDays === 90 ? 15 : 30\n const dailyMinWidth = windowDays === 365 ? 1825 : undefined\n const noticeText = notice === null ? null : t(\n notice.kind === 'all'\n ? 'error.refreshCached'\n : notice.kind === 'balance' ? 'error.balanceRefreshCached' : 'error.usageRefreshCached',\n { error: localizeApiError(notice.error, t, 'error.query') },\n )\n const errorText = error === null ? null : localizeApiError(error, t, 'error.query')\n\n const composerSafeAreaStyle = {\n '--dq-composer-h': `${composerHeight ?? COMPOSER_FALLBACK_PX}px`,\n // Only set once measured; .dq-balance's max-width falls back to 860px\n // without it (pre-measurement render keeps the settled wide-viewport\n // column, then narrows in place \u2014 no flash of the old width).\n ...(composerWidth !== null ? { '--dq-composer-w': `${composerWidth}px` } : {}),\n } as CSSProperties\n\n const navSections = [\n { key: 'balance', label: t('nav.balance') },\n ...(props.sessionId !== undefined && props.sessionId !== '' ? [{ key: 'session', label: t('nav.session') }] : []),\n { key: 'overview', label: t('nav.overview') },\n { key: 'trend', label: t('nav.trend') },\n { key: 'heatmap', label: t('nav.heatmap') },\n { key: 'models', label: t('nav.models') },\n { key: 'sessions', label: t('nav.sessions') },\n { key: 'peakcache', label: t('nav.peakcache') },\n ]\n\n return (\n <div className=\"dq-balance\" ref={rootRef} style={composerSafeAreaStyle}>\n <SectionNav rootRef={rootRef} label={t('nav.label')} sections={navSections} />\n <div className=\"dq-status-row\">\n <div className=\"dq-status-messages\">\n <span\n className={`dq-sync dq-sync--${syncState}`}\n role=\"status\"\n aria-live=\"polite\"\n title={usageUpdatedAt === null\n ? t('status.neverSynced')\n : t('status.usageTime', { time: new Date(usageUpdatedAt).toLocaleString(intlLocale(locale), { timeZone: 'Asia/Shanghai' }) })}\n >\n <span className=\"dq-sync-dot\" aria-hidden=\"true\" />\n {syncStatusText(syncState, usageUpdatedAt, freshnessNow, t)}\n </span>\n {noticeText !== null && <span className=\"dq-warn\">{noticeText}</span>}\n {errorText !== null && <span className=\"dq-error\">{errorText}</span>}\n </div>\n <div className=\"dq-status-actions\">\n <button\n type=\"button\"\n className=\"dq-settings-btn\"\n aria-expanded={settingsOpen}\n aria-controls=\"dq-settings-panel\"\n onClick={() => setSettingsOpen(open => !open)}\n >\n {t('settings.title')}\n <span className={`dq-settings-caret${settingsOpen ? ' dq-settings-caret--open' : ''}`} aria-hidden=\"true\">\u25BE</span>\n </button>\n <button\n type=\"button\"\n className=\"dq-refresh-btn\"\n title={t('status.forceRefresh')}\n disabled={refreshing}\n aria-busy={refreshing}\n onClick={() => { void load(true) }}\n >\n <span className={`dq-refresh-icon${refreshing ? ' dq-refresh-icon--spin' : ''}`}>\u21BB</span>\n {refreshing ? t('status.refreshing') : t('status.refresh')}\n </button>\n </div>\n </div>\n\n {balanceLow && (\n <div className=\"dq-alert\" role=\"status\">\n <span className=\"dq-alert-icon\" aria-hidden=\"true\">!</span>\n <div>\n <strong>{t('alert.lowTitle', { balance: fmt(balanceValue), currency: primary?.currency, threshold: fmt(lowBalance) })}</strong>\n {daysLeft !== null && t('alert.runway', { days: daysLeftText })}{t('common.period')}\n <a className=\"dq-alert-link\" href={TOP_UP_URL} target=\"_blank\" rel=\"noreferrer\">{t('alert.topUp')}</a>\n </div>\n </div>\n )}\n\n <div className=\"dq-card dq-card--hero\">\n <CardTitle srOnly>{t('balance.title')}</CardTitle>\n {primary !== null ? (\n <div className=\"dq-balance-grid\">\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('balance.remaining')}</div>\n <details\n className=\"dq-stat-value dq-remaining\"\n open={remainingHovering || remainingManuallyOpened}\n onPointerEnter={() => setRemainingHovering(true)}\n onPointerLeave={() => setRemainingHovering(false)}\n >\n <summary\n title={t('balance.breakdownTitle')}\n aria-label={`${fmt(primary.total)} ${primary.currency}`}\n onClick={e => {\n // Own the toggle fully instead of the native default action: a controlled\n // <details> can be forced open by hover, and a plain native toggle here\n // would fight that (e.g. it flips to \"closed\" while the mouse is still\n // hovering). Preventing default and flipping our own \"manually opened\"\n // state keeps hover-preview and click/keyboard/tap-to-pin independent.\n e.preventDefault()\n setRemainingManuallyOpened(v => !v)\n }}\n >\n {fmt(primary.total)}<span className=\"dq-hero-unit\">{primary.currency}</span>\n </summary>\n <div className=\"dq-remaining-breakdown\">\n <span>{t('balance.toppedUp', { amount: fmt(primary.toppedUp) })}</span>\n <span className=\"dq-remaining-granted\">{t('balance.granted', { amount: fmt(primary.granted) })}</span>\n </div>\n </details>\n </div>\n <div className=\"dq-stat\">\n <div className=\"dq-stat-label\">{t('balance.runway')}</div>\n <div className=\"dq-runway-line\">\n <details\n className={`dq-stat-value dq-runway${daysLeft !== null && daysLeft < 3 ? ' dq-stat-value--bad' : ''}`}\n open={runwayHovering || runwayManuallyOpened}\n onPointerEnter={() => setRunwayHovering(true)}\n onPointerLeave={() => setRunwayHovering(false)}\n >\n <summary\n title={t('balance.runwayBreakdownTitle')}\n onClick={e => {\n // Own the toggle fully instead of the native default action: a controlled\n // <details> can be forced open by hover, and a plain native toggle here\n // would fight that (e.g. it flips to \"closed\" while the mouse is still\n // hovering). Preventing default and flipping our own \"manually opened\"\n // state keeps hover-preview and click/keyboard/tap-to-pin independent.\n e.preventDefault()\n setRunwayManuallyOpened(v => !v)\n }}\n >\n {daysLeftText}\n </summary>\n <div className=\"dq-runway-detail\">{runwayTitle}</div>\n </details>\n {topUpPrompt && (\n <a className=\"dq-topup\" href={TOP_UP_URL} target=\"_blank\" rel=\"noreferrer\" title={t('balance.topUpTitle')}>\n {t('alert.topUp')}\n <span className=\"dq-topup-arrow\" aria-hidden=\"true\">\u2197</span>\n </a>\n )}\n </div>\n </div>\n {/* \u300C\u53EF\u7528\u300D\u662F\u5E38\u6001\uFF0C\u4E0D\u5360 hero \u4F4D\uFF1B\u53EA\u6709\u8D26\u6237\u4E0D\u53EF\u7528\u65F6\u624D\u51FA\u73B0\uFF0C\u4E14\u7528\u9519\u8BEF\u8272\u3002 */}\n {balance?.isAvailable === false && (\n <Stat label={t('common.status')}>\n <div className=\"dq-stat-value dq-stat-value--bad\">{t('common.unavailable')}</div>\n </Stat>\n )}\n </div>\n ) : loadingBalance ? (\n <BalanceSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('balance.empty')}</div>\n )}\n </div>\n\n <Collapsible open={settingsOpen}>\n <div className=\"dq-settings-panel\" id=\"dq-settings-panel\" role=\"region\" aria-label={t('settings.title')}>\n <CardTitle>{t('settings.title')}</CardTitle>\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupDisplay')}</div>\n <label className=\"dq-toggle\">\n <input type=\"checkbox\" checked={widgetOn} onChange={toggle} />\n <span>{t('settings.widget')}</span>\n </label>\n <div className=\"dq-toggle-hint\">{t('settings.widgetHint')}</div>\n <div className=\"dq-setting dq-setting--tabs\">\n <div className=\"dq-setting-label\" id=\"dq-widget-tabs-label\">{t('settings.widgetTabs')}</div>\n <div className=\"dq-setting-control dq-widget-tabs\" role=\"group\" aria-labelledby=\"dq-widget-tabs-label\">\n <div className=\"dq-widget-tab-list\">\n {widgetTabs.map(tab => (\n <label className=\"dq-widget-tab\" key={tab.id}>\n <input\n type=\"checkbox\"\n checked={widgetTabIds === null || widgetTabIds.includes(tab.id)}\n onChange={() => toggleWidgetTab(tab.id)}\n />\n <span>{tab.label}</span>\n </label>\n ))}\n </div>\n <span className=\"dq-setting-hint\">\n {widgetTabs.length === 0 ? t('settings.widgetTabsEmpty') : t('settings.widgetTabsHint')}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupAlerts')}</div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-low-balance\">{t('settings.lowBalance')}</label>\n <div className=\"dq-setting-control\">\n <input\n id=\"dq-low-balance\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={1}\n value={lowBalance}\n onChange={e => changeLowBalance(Math.max(0, Number(e.target.value) || 0))}\n />\n <span className=\"dq-setting-hint\">\n {lowBalance > 0\n ? t('settings.lowBalanceOn', { amount: fmt(lowBalance), currency: primary?.currency ?? 'CNY' })\n : t('settings.lowBalanceOff')}\n </span>\n </div>\n </div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-monthly-budget\">{t('settings.monthlyBudget')}</label>\n <div className=\"dq-setting-control\">\n <input\n ref={budgetInputRef}\n id=\"dq-monthly-budget\"\n className=\"dq-number\"\n type=\"number\"\n min={0}\n step={10}\n value={monthlyBudget}\n aria-describedby=\"dq-monthly-budget-hint\"\n onChange={e => changeMonthlyBudget(Math.max(0, Number(e.target.value) || 0))}\n />\n <span id=\"dq-monthly-budget-hint\" className=\"dq-setting-hint\">\n {monthlyBudget > 0\n ? t('settings.monthlyBudgetOn', { amount: fmt(monthlyBudget) })\n : t('settings.monthlyBudgetOff')}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('settings.groupLayout')}</div>\n <div className=\"dq-setting\">\n <label className=\"dq-setting-label\" htmlFor=\"dq-sidebar-entry\">{t('settings.sidebarEntry')}</label>\n <div className=\"dq-setting-control\">\n <select\n id=\"dq-sidebar-entry\"\n className=\"dq-select\"\n value={sidebarEntry}\n onChange={e => changeSidebarEntry(e.target.value as SidebarEntryPlacement)}\n >\n <option value=\"off\">{t('settings.sidebarEntryOff')}</option>\n <option value=\"top\">{t('settings.sidebarEntryTop')}</option>\n <option value=\"bottom\">{t('settings.sidebarEntryBottom')}</option>\n </select>\n <span className=\"dq-setting-hint\">{t('settings.sidebarEntryHint')}</span>\n </div>\n </div>\n <div className=\"dq-setting\">\n <div className=\"dq-setting-label\" id=\"dq-tab-order-label\">{t('settings.tabPosition')}</div>\n <div className=\"dq-setting-control\">\n <div\n className=\"dq-tab-order\"\n role=\"group\"\n aria-labelledby=\"dq-tab-order-label\"\n aria-describedby=\"dq-tab-order-hint\"\n onDragOver={onOrderDragOver}\n onDrop={onOrderDrop}\n >\n {viewTabs.map((tab, index) => {\n const current = tab.id === 'balance'\n const dropTarget = tabDragging && !current && tabDropTarget === index\n return (\n <span\n key={tab.id}\n className={`dq-tab-chip${current ? ' dq-tab-chip--current' : ''}${current && tabDragging ? ' dq-tab-chip--dragging' : ''}${dropTarget ? ' dq-tab-chip--drop-target' : ''}`}\n draggable={current}\n tabIndex={current ? 0 : undefined}\n role={current ? 'button' : undefined}\n aria-label={current ? t('settings.tabDragAria') : undefined}\n onDragStart={current ? onQuotaTabDragStart : undefined}\n onDragEnd={current ? endTabDrag : undefined}\n onDragOver={event => onChipDragOver(event, index)}\n onDrop={event => onChipDrop(event, index)}\n onKeyDown={current ? onQuotaTabKeyDown : undefined}\n >\n {tab.label}\n </span>\n )\n })}\n </div>\n <span id=\"dq-tab-order-hint\" className=\"dq-setting-hint\">{t('settings.tabPositionHint')}</span>\n </div>\n </div>\n </div>\n\n <div className=\"dq-setting-group\">\n <div className=\"dq-setting-group-title\">{t('links.title')}</div>\n <div className=\"dq-links\">\n <Link href=\"https://platform.deepseek.com/usage\">{t('links.usage')}</Link>\n <Link href=\"https://platform.deepseek.com/api_keys\">{t('links.apiKey')}</Link>\n <Link href=\"https://status.deepseek.com\">{t('links.status')}</Link>\n </div>\n </div>\n </div>\n </Collapsible>\n\n {props.sessionId !== undefined && props.sessionId !== '' && (\n <div className=\"dq-card dq-card--primary\">\n <CardTitle caption={t('common.estimated')}>{t('sessionUsage.title')}</CardTitle>\n {sessionUsage !== null ? (\n <SessionUsageCard data={sessionUsage} />\n ) : loadingSessionUsage ? (\n <SessionUsageSkeleton />\n ) : sessionUsageError !== null ? (\n <div className=\"dq-empty dq-empty--error\">{localizeApiError(sessionUsageError, t, 'error.query')}</div>\n ) : (\n <div className=\"dq-empty\">{t('sessionUsage.empty')}</div>\n )}\n </div>\n )}\n\n <div className=\"dq-card dq-card--primary\">\n <CardTitle caption={t('common.estimated')}>{t('overview.title')}</CardTitle>\n {usage !== null ? (\n <div className=\"dq-period-grid\">\n <Period label={t('overview.today')} period={usage.summary.today} previous={usage.summary.yesterday} compare={t('overview.vsYesterday')} />\n <Period label={t('overview.month')} period={usage.summary.month} previous={usage.summary.lastMonthToDate} compare={t('overview.vsLastMonth')} />\n <Period\n label={t('overview.total')}\n period={{ total: usage.totals.total, cost: usage.totals.cost, calls: usage.totals.calls }}\n />\n </div>\n ) : loadingUsage ? (\n\n <div className=\"dq-period-grid\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-period\">\n <Skel w={40} h={11} /><Skel w={104} h={24} /><Skel w={132} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('overview.empty')}</div>\n )}\n {usage !== null && (\n <BudgetMeter\n spent={usage.summary.month.cost}\n budget={monthlyBudget}\n onConfigure={() => { setSettingsOpen(true); window.setTimeout(() => budgetInputRef.current?.focus(), 80) }}\n />\n )}\n {usage !== null && <PricingNote pricing={usage.pricing} />}\n </div>\n\n <div className=\"dq-card dq-card--primary\">\n <div className=\"dq-card-head\">\n <CardTitle>{t('usage.trendTitle')}</CardTitle>\n {usage !== null && (\n <div className=\"dq-card-actions\">\n <UsageWindowPicker value={windowDays} onChange={changeWindowDays} />\n <ExportMenu usage={usage} />\n </div>\n )}\n </div>\n {usage !== null && activeWindow !== null ? (\n <>\n <div className=\"dq-usage-totals\">\n <Stat label={t('usage.windowInput', { window: activeWindowName })}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.input, locale)}</div></Stat>\n <Stat label={t('common.output')}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.output, locale)}</div></Stat>\n <Stat label={t('common.cacheHit')}><div className=\"dq-stat-value\">{fmtCompact(activeWindow.totals.cache, locale)}</div></Stat>\n <Stat label={t('usage.modelCalls')}><div className=\"dq-stat-value\">{fmtInt(activeWindow.totals.calls)}</div></Stat>\n </div>\n <div className=\"dq-chart-block-head\">\n <div className=\"dq-chart-title\">\n {barMode === 'daily'\n ? t('chart.dailyTitle', { window: activeWindowName, metric: chartMetricName(chartMetric, t) })\n : t('chart.hourlyTitle', { window: activeWindowName, metric: chartMetricName(chartMetric, t) })}\n {chartPeak > 0 && <span className=\"dq-chart-peak\">{t('chart.peak', { value: chartPeakText })}</span>}\n </div>\n <div className=\"dq-chart-controls\">\n <ModelPicker models={modelList} selected={effectiveSelection} colorOf={colorOf} onChange={setSelectedModels} />\n <ChartMetricPicker value={chartMetric} onChange={changeChartMetric} />\n <div className=\"dq-chart-switch\" role=\"tablist\" aria-label={t('chart.dimensionLabel')}>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'daily'}\n className={`dq-chart-switch-btn${barMode === 'daily' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('daily')}\n >\n {t('chart.daily')}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={barMode === 'hourly'}\n className={`dq-chart-switch-btn${barMode === 'hourly' ? ' dq-chart-switch-btn--on' : ''}`}\n onClick={() => setBarMode('hourly')}\n >\n {t('chart.hourly')}\n </button>\n </div>\n </div>\n </div>\n {activeWindow.totals.calls === 0 ? (\n <div className=\"dq-empty\">{t('chart.noWindowData', { window: activeWindowName })}</div>\n ) : grouped.length > 0 ? (\n <>\n <GroupedBars\n series={grouped}\n height={barMode === 'daily' ? 160 : 140}\n labelEvery={barMode === 'daily' ? dailyLabelEvery : 3}\n minWidth={barMode === 'daily' ? dailyMinWidth : undefined}\n />\n <div className=\"dq-legend\">\n {grouped.map(s => (\n <span key={s.key} className=\"dq-legend-item\">\n <span className=\"dq-legend-swatch\" style={{ background: s.color }} />\n {s.name}\n </span>\n ))}\n </div>\n </>\n ) : barMode === 'daily' ? (\n <Bars data={dailyBars} height={160} labelEvery={dailyLabelEvery} minWidth={dailyMinWidth} />\n ) : (\n <Bars data={hourlyBars} height={140} labelEvery={3} />\n )}\n </>\n ) : loadingUsage ? (\n <UsageSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('chart.empty')}</div>\n )}\n {/* \u56FE\u7247\u7528\u91CF\u5E76\u5165\u672C\u5361\uFF1A\u7A97\u53E3\u5207\u5230\u6CA1\u6709\u56FE\u7247\u7684\u8303\u56F4\u65F6\u6574\u6BB5\u6536\u8D77\u3002\u5173\u95ED\u671F\u95F4\u4ECD\u6E32\u67D3\n \u6700\u540E\u4E00\u4EFD\u6709\u56FE\u6570\u636E\uFF0C\u8BA9 0fr\u21921fr \u7684\u6536\u8D77\u52A8\u753B\u6709\u5185\u5BB9\u53EF\u52A8\uFF1B\u52A0\u8F7D\u4E2D\u4E5F\u4FDD\u7559\u5173\u95ED\u6001\n \u7684\u7A7A\u58F3\uFF0C\u6570\u636E\u5230\u8FBE\u65F6\u624D\u662F\u771F\u7684\u300C\u5C55\u5F00\u300D\u800C\u4E0D\u662F\u76F4\u63A5\u51FA\u73B0\u3002 */}\n <div className=\"dq-vision-inline\" data-open={visionOpen ? 'true' : 'false'} aria-hidden={!visionOpen}>\n <div className=\"dq-vision-inline-body\">\n {shownVision !== null && (\n <>\n <div className=\"dq-chart-title\">{t('vision.title')}<span className=\"dq-chart-peak\">{shownVision.windowLabel}</span></div>\n <VisionCard\n vision={shownVision.vision}\n daily={shownVision.daily}\n sessions={shownVision.sessions}\n windowLabel={shownVision.windowLabel}\n inputTokens={shownVision.inputTokens}\n costTotal={shownVision.costTotal}\n />\n </>\n )}\n </div>\n </div>\n {usage !== null && <CoverageDiagnostics coverage={usage.coverage} />}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={t('chart.heatmapTitle')}>{t('heatmap.title')}</CardTitle>\n {usage !== null ? (\n <Heatmap data={usage.heatmap} />\n ) : loadingUsage ? (\n <HeatmapSkeleton />\n ) : (\n <div className=\"dq-empty\">{t('chart.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={activeWindowName}>{t('models.title')}</CardTitle>\n {activeWindow !== null ? (\n <ModelRanking models={modelList} totalCost={modelCostTotal} colorOf={colorOf} />\n ) : loadingUsage ? (\n <div className=\"dq-rank\">\n {[0, 1].map(i => (\n <div key={i} className=\"dq-rank-row\">\n <Skel w={148} h={13} />\n <div className=\"dq-rank-track\" />\n <Skel w={230} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('models.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle caption={activeWindowName}>{t('sessions.title')}</CardTitle>\n {activeWindow !== null ? (\n <SessionRanking sessions={activeWindow.sessions} count={activeWindow.sessionCount} totalCost={activeWindow.totals.cost} />\n ) : loadingUsage ? (\n <div className=\"dq-sessions\">\n {[0, 1, 2].map(i => (\n <div key={i} className=\"dq-session\">\n <Skel w={200} h={13} />\n <div className=\"dq-session-track\" />\n <Skel w={250} h={11} />\n </div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('sessions.empty')}</div>\n )}\n </div>\n\n {/* The two half-width analysis cards sit side by side while there is\n room; below the pair's own 340px column floor they stack. */}\n <div className=\"dq-card-pair\">\n <div className=\"dq-card\">\n <CardTitle>{t('peak.title')}</CardTitle>\n {usage !== null ? (\n <PeakCard split={usage.peakSplit} pricing={usage.pricing} />\n ) : loadingUsage ? (\n <>\n <div className=\"dq-peak-track\" />\n <div className=\"dq-peak-figures\"><Skel w={120} h={11} /><Skel w={96} h={20} /></div>\n </>\n ) : (\n <div className=\"dq-empty\">{t('peak.empty')}</div>\n )}\n </div>\n\n <div className=\"dq-card\">\n <CardTitle>{t('cache.title')}</CardTitle>\n {usage !== null ? (\n <CacheCard totals={usage.totals} />\n ) : loadingUsage ? (\n <div className=\"dq-cache-figures\">\n {[60, 96, 72].map((w, i) => (\n <div key={i} className=\"dq-stat\"><Skel w={w} h={11} /><Skel w={72} h={20} /></div>\n ))}\n </div>\n ) : (\n <div className=\"dq-empty\">{t('cache.empty')}</div>\n )}\n </div>\n </div>\n\n <p className=\"dq-footer\">{__PLUGIN_LABEL__}</p>\n </div>\n )\n}\n", "export type BudgetStatus = 'healthy' | 'risk' | 'over'\n\nexport interface BudgetSnapshot {\n spent: number\n budget: number\n ratio: number\n remaining: number\n forecast: number\n forecastOver: number\n status: BudgetStatus\n}\n\nconst BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000\n\n/**\n * Project the current month's cost to month end. DeepSeek's billing boundary\n * is Beijing time, so this stays deterministic even when the browser runs in\n * another timezone.\n */\nexport function budgetSnapshot(spentValue: number, budgetValue: number, nowMs = Date.now()): BudgetSnapshot {\n const spent = Number.isFinite(spentValue) ? Math.max(0, spentValue) : 0\n const budget = Number.isFinite(budgetValue) ? Math.max(0, budgetValue) : 0\n const beijingNow = new Date(nowMs + BEIJING_OFFSET_MS)\n const year = beijingNow.getUTCFullYear()\n const month = beijingNow.getUTCMonth()\n const start = Date.UTC(year, month, 1) - BEIJING_OFFSET_MS\n const end = Date.UTC(year, month + 1, 1) - BEIJING_OFFSET_MS\n const elapsedRatio = Math.min(1, Math.max(1 / (end - start), (nowMs - start) / (end - start)))\n const forecast = spent / elapsedRatio\n const ratio = budget > 0 ? spent / budget : 0\n const remaining = budget - spent\n const forecastOver = budget > 0 ? Math.max(0, forecast - budget) : 0\n const status: BudgetStatus = ratio >= 1\n ? 'over'\n : (ratio >= 0.8 || forecastOver > 0 ? 'risk' : 'healthy')\n\n return { spent, budget, ratio, remaining, forecast, forecastOver, status }\n}\n", "/** Dependency-free bar chart and heatmap primitives. */\nimport { useEffect, useRef, useState, type FocusEvent as ReactFocusEvent, type KeyboardEvent as ReactKeyboardEvent, type MutableRefObject, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport { isTapGesture, lastPopulatedIndex, maxOrOne, nextChartFocus, nextPinnedIndex, stackedTotals, type ChartFocusKey } from './chart-focus.ts'\nimport { intlLocale, useI18n, type LocaleId } from './i18n.tsx'\nimport type { LocaleKey } from './locales.ts'\n\nexport interface BarDatum {\n label: string\n value: number\n /** Tooltip text, composed as `heading \u00B7 row \u00B7 row`; each ` \u00B7 ` segment is\n * rendered on its own line, the first as the heading. */\n title?: string\n}\n\ninterface TipState {\n x: number\n y: number\n lines: string[]\n above: boolean\n}\n\n/**\n * Cursor-following tooltip shared by every chart. The native `title` attribute\n * this replaces waited about a second, could not be styled to match the shell,\n * and never appeared on touch.\n *\n * Touch has no hover, so a tap pins the tooltip open instead of showing it only\n * while the finger is down (which produced the original one-flicker-then-gone\n * complaint). `pinned` and `hide()` share one `pinnedRef` so a `touchend`\n * followed synchronously by `pointerleave` \u2014 both native events fired in the\n * same tick, before React re-renders \u2014 never reads a stale \"nothing pinned\"\n * state and hides the tooltip it was just asked to pin.\n */\nfunction useChartTip(): {\n wrapRef: MutableRefObject<HTMLDivElement | null>\n tip: TipState | null\n pinned: number | null\n show: (e: ReactPointerEvent<HTMLElement>, text: string | undefined) => void\n showFocused: (e: ReactFocusEvent<HTMLElement>, text: string | undefined) => void\n hide: () => void\n onPointStart: (e: ReactPointerEvent<HTMLElement>) => void\n onPointEnd: (e: ReactPointerEvent<HTMLElement>, index: number, text: string | undefined) => void\n} {\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const [tip, setTip] = useState<TipState | null>(null)\n const [pinned, setPinned] = useState<number | null>(null)\n const pinnedRef = useRef<number | null>(null)\n const touchStart = useRef<{ x: number; y: number; t: number } | null>(null)\n const setPin = (next: number | null): void => {\n pinnedRef.current = next\n setPinned(next)\n }\n const showAt = (target: HTMLElement, text: string | undefined, clientX?: number, clientY?: number): void => {\n const wrap = wrapRef.current\n if (text === undefined || text === '' || wrap === null) return\n const rect = wrap.getBoundingClientRect()\n const targetRect = target.getBoundingClientRect()\n // Keep the (centred) bubble inside the chart's own box.\n const x = Math.min(Math.max((clientX ?? targetRect.left + targetRect.width / 2) - rect.left, 70), Math.max(rect.width - 70, 70))\n const viewportY = clientY ?? targetRect.top\n const y = viewportY - rect.top\n setTip({ x, y, lines: text.split(' \u00B7 '), above: viewportY > window.innerHeight - 160 })\n }\n const show = (e: ReactPointerEvent<HTMLElement>, text: string | undefined): void => {\n // Touch has no hover; a bare `pointermove` while a finger drags across the\n // chart (e.g. scrolling the page) would otherwise flash tooltips at every\n // point it crosses. Touch only opens a tooltip via the deliberate tap\n // handled in `onPointEnd`.\n if (e.pointerType === 'touch') return\n showAt(e.currentTarget, text, e.clientX, e.clientY)\n }\n const showFocused = (e: ReactFocusEvent<HTMLElement>, text: string | undefined): void => {\n showAt(e.currentTarget, text)\n }\n const hide = (): void => {\n if (pinnedRef.current !== null) return\n setTip(null)\n }\n const onPointStart = (e: ReactPointerEvent<HTMLElement>): void => {\n if (e.pointerType === 'touch') touchStart.current = { x: e.clientX, y: e.clientY, t: Date.now() }\n }\n const onPointEnd = (e: ReactPointerEvent<HTMLElement>, index: number, text: string | undefined): void => {\n if (e.pointerType !== 'touch') return\n const start = touchStart.current\n touchStart.current = null\n if (start === null || !isTapGesture(e.clientX - start.x, e.clientY - start.y, Date.now() - start.t)) return\n const next = nextPinnedIndex(pinnedRef.current, index)\n setPin(next)\n if (next === null) setTip(null)\n else showAt(e.currentTarget, text, e.clientX, e.clientY)\n }\n useEffect(() => {\n if (pinned === null) return undefined\n const onDocPointerDown = (e: PointerEvent): void => {\n const wrap = wrapRef.current\n if (wrap !== null && e.target instanceof Node && wrap.contains(e.target)) return\n setPin(null)\n setTip(null)\n }\n document.addEventListener('pointerdown', onDocPointerDown)\n return () => document.removeEventListener('pointerdown', onDocPointerDown)\n }, [pinned])\n return { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd }\n}\n\nfunction useRovingChartPoints(count: number, initial: number, horizontalStep = 1): {\n active: number\n refs: MutableRefObject<Array<HTMLElement | null>>\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>, index: number) => void\n} {\n const refs = useRef<Array<HTMLElement | null>>([])\n const [active, setActive] = useState(initial)\n useEffect(() => setActive(Math.min(Math.max(0, initial), Math.max(0, count - 1))), [count, initial])\n const onKeyDown = (event: ReactKeyboardEvent<HTMLElement>, index: number): void => {\n if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) return\n event.preventDefault()\n const next = nextChartFocus(index, count, event.key as ChartFocusKey, horizontalStep)\n setActive(next)\n const target = refs.current[next]\n target?.focus({ preventScroll: true })\n target?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n }\n return { active, refs, onKeyDown }\n}\n\nfunction ChartTip(props: { tip: TipState | null }): ReactElement | null {\n const { tip } = props\n if (tip === null) return null\n const [head, ...rows] = tip.lines\n return (\n <div className={`dq-tip${tip.above ? ' dq-tip--above' : ''}`} style={{ left: `${tip.x}px`, top: `${tip.y}px` }} role=\"tooltip\">\n <div className=\"dq-tip-head\">{head}</div>\n {rows.map((row, i) => <div key={i} className=\"dq-tip-row\">{row}</div>)}\n </div>\n )\n}\n\n/** Color palette for per-model grouped bars, cycled by model order. */\nexport const MODEL_COLORS = ['#4176e6', '#2da44e', '#e16f24', '#8250df', '#bf8700', '#cf222e', '#1f883d', '#0969da']\n\nexport function Bars(props: { data: BarDatum[]; height?: number; labelEvery?: number; minWidth?: number }): ReactElement {\n const { data, height = 120, labelEvery = 1, minWidth } = props\n const { locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const initialFocus = lastPopulatedIndex(data.map(datum => datum.value))\n const roving = useRovingChartPoints(data.length, initialFocus)\n useEffect(() => {\n const scroll = scrollRef.current\n if (scroll !== null && minWidth !== undefined) scroll.scrollLeft = scroll.scrollWidth\n }, [data.length, minWidth])\n let max = 0\n for (const datum of data) if (datum.value > max) max = datum.value\n const scale = max > 0 ? max : 1\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-plot\">\n <div className=\"dq-yaxis\" style={{ height: `${height}px` }} aria-hidden=\"true\">\n <span>{max > 0 ? fmtCompact(max, locale) : ''}</span>\n <span>0</span>\n </div>\n <div className=\"dq-bars-scroll\" ref={scrollRef}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px`, minWidth: minWidth === undefined ? undefined : `${minWidth}px` }}>\n {data.map((datum, i) => {\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${datum.label}: ${datum.value.toLocaleString()}`\n return (\n <div\n key={i}\n className={`dq-bar-col${pinned === i ? ' dq-bar-col--pinned' : ''}`}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={i === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[i] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, i, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, i)}\n >\n <div className=\"dq-bar\" style={{ height: `${h}px` }} />\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>{datum.label}</div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nexport interface HeatDatum {\n date: string\n total: number\n cost: number\n calls: number\n}\n\n/**\n * Multi-series bar chart: one bar per time slot, each series' value stacked\n * inside it (series[0] at the bottom, later series stacked above, same order\n * in every column). Segment height is scaled against the largest *per-slot\n * total* across all slots (not the largest single value) so the stacked\n * height reflects that slot's combined usage and columns stay comparable to\n * each other. Each segment stays its own focusable/hoverable/tappable point \u2014\n * `pointIndex = i * series.length + seriesIndex` is unchanged from the old\n * side-by-side layout, so `chart-focus.ts`'s roving tabindex (plain \u00B11 /\n * Home / End, no 2-D semantics) needs no changes: arrow keys still move one\n * point at a time, they just now walk bottom-to-top through one column's\n * models before advancing to the next column, instead of left-to-right\n * through side-by-side bars.\n */\nexport function GroupedBars(props: {\n series: Array<{ key: string; color: string; bars: BarDatum[] }>\n height?: number\n labelEvery?: number\n minWidth?: number\n}): ReactElement {\n const { series, height = 120, labelEvery = 1, minWidth } = props\n const { locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const count = series.length > 0 ? series[0].bars.length : 0\n const pointValues = Array.from({ length: count }, (_, i) => series.map(s => s.bars[i]?.value ?? 0)).flat()\n const roving = useRovingChartPoints(pointValues.length, lastPopulatedIndex(pointValues))\n useEffect(() => {\n const scroll = scrollRef.current\n if (scroll !== null && minWidth !== undefined) scroll.scrollLeft = scroll.scrollWidth\n }, [count, minWidth])\n const totals = stackedTotals(series, count)\n const scale = maxOrOne(totals)\n const axisMax = totals.reduce((m, v) => Math.max(m, v), 0)\n return (\n <div className=\"dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-plot\">\n <div className=\"dq-yaxis\" style={{ height: `${height}px` }} aria-hidden=\"true\">\n <span>{axisMax > 0 ? fmtCompact(axisMax, locale) : ''}</span>\n <span>0</span>\n </div>\n <div className=\"dq-bars-scroll\" ref={scrollRef}>\n <div className=\"dq-bars\" style={{ height: `${height + 18}px`, minWidth: minWidth === undefined ? undefined : `${minWidth}px` }}>\n {Array.from({ length: count }, (_, i) => (\n <div\n key={i}\n className=\"dq-bar-col\"\n >\n <div className=\"dq-bar-group\">\n {series.map((s, seriesIndex) => {\n const datum = s.bars[i]\n const h = Math.max(1, Math.round((datum.value / scale) * height))\n const text = datum.title ?? `${s.key}: ${datum.value.toLocaleString()}`\n const pointIndex = i * series.length + seriesIndex\n return (\n <div\n key={s.key}\n className={`dq-bar${pinned === pointIndex ? ' dq-bar--pinned' : ''}`}\n style={{ height: `${h}px`, background: s.color }}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={pointIndex === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[pointIndex] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, pointIndex, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, pointIndex)}\n />\n )\n })}\n </div>\n <div className=\"dq-bar-label\" style={{ visibility: i % labelEvery === 0 ? 'visible' : 'hidden' }}>\n {series[0].bars[i].label}\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ChartTip tip={tip} />\n </div>\n )\n}\n\nfunction heatColor(level: number): string {\n if (level <= 0) return 'rgba(120,130,150,0.12)'\n if (level === 1) return 'rgba(65,118,230,0.25)'\n if (level === 2) return 'rgba(65,118,230,0.5)'\n if (level === 3) return 'rgba(65,118,230,0.75)'\n return 'rgba(65,118,230,1)'\n}\n\n/**\n * Calendar heatmap: one flex column per week, cells filling the card's full\n * width (rather than a fixed pixel size hugging the left edge), month labels\n * below the grid and a \u5C11\u2192\u591A scale legend \u2014 modelled on Codex's activity\n * graph. No weekday row: at this cell count a day is identified by hovering\n * it, not by which row it sits in.\n */\nexport function Heatmap(props: { data: HeatDatum[] }): ReactElement {\n const { data } = props\n const { t, locale } = useI18n()\n const { wrapRef, tip, pinned, show, showFocused, hide, onPointStart, onPointEnd } = useChartTip()\n const roving = useRovingChartPoints(data.length, lastPopulatedIndex(data.map(datum => datum.total)), 7)\n let max = 0\n for (const datum of data) if (datum.total > max) max = datum.total\n let firstDow = 0\n if (data.length > 0) {\n const dt = new Date(`${data[0].date}T00:00:00`)\n firstDow = Number.isNaN(dt.getTime()) ? 0 : dt.getDay()\n }\n const cells: Array<HeatDatum | null> = []\n for (let i = 0; i < firstDow; i++) cells.push(null)\n for (const datum of data) cells.push(datum)\n while (cells.length % 7 !== 0) cells.push(null)\n\n const weeks: Array<Array<HeatDatum | null>> = []\n for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7))\n\n // Label a column with its month when it is the first column of that month.\n let lastMonth = ''\n const monthLabels = weeks.map(week => {\n const first = week.find(cell => cell !== null)\n if (first === undefined || first === null) return ''\n const month = first.date.slice(0, 7)\n if (month === lastMonth) return ''\n lastMonth = month\n return t(`chart.month${Number(first.date.slice(5, 7))}` as LocaleKey)\n })\n\n const levelOf = (total: number): number => {\n if (total <= 0) return 0\n const r = max > 0 ? total / max : 0\n return r < 0.25 ? 1 : r < 0.5 ? 2 : r < 0.75 ? 3 : 4\n }\n\n return (\n <div className=\"dq-heat dq-chart-wrap\" ref={wrapRef} onPointerLeave={hide}>\n <div className=\"dq-heat-scroll\">\n <div className=\"dq-heatmap\">\n {weeks.map((week, w) => (\n <div key={w} className=\"dq-heat-week\">\n {week.map((datum, d) => {\n if (datum === null) return <div key={d} className=\"dq-heat-cell dq-heat-cell--pad\" />\n const text = t('chart.tooltip', {\n head: datum.date,\n tokens: datum.total.toLocaleString(intlLocale(locale)),\n cost: datum.cost.toFixed(2),\n calls: t('common.calls', { count: datum.calls }),\n })\n const index = w * 7 + d - firstDow\n return (\n <div\n key={d}\n className={`dq-heat-cell${pinned === index ? ' dq-heat-cell--pinned' : ''}`}\n style={{ background: heatColor(levelOf(datum.total)) }}\n role=\"img\"\n aria-label={text}\n aria-keyshortcuts=\"ArrowLeft ArrowRight ArrowUp ArrowDown Home End\"\n tabIndex={index === roving.active ? 0 : -1}\n ref={element => { roving.refs.current[index] = element }}\n onPointerMove={e => show(e, text)}\n onPointerDown={onPointStart}\n onPointerUp={e => onPointEnd(e, index, text)}\n onFocus={e => showFocused(e, text)}\n onBlur={hide}\n onKeyDown={e => roving.onKeyDown(e, index)}\n />\n )\n })}\n </div>\n ))}\n </div>\n <div className=\"dq-heat-months\" aria-hidden=\"true\">\n {monthLabels.map((label, i) => <div key={i} className=\"dq-heat-month\">{label}</div>)}\n </div>\n </div>\n <ChartTip tip={tip} />\n <div className=\"dq-heat-scale\">\n <span>{t('chart.less')}</span>\n {[0, 1, 2, 3, 4].map(level => (\n <span key={level} className=\"dq-heat-key\" style={{ background: heatColor(level) }} />\n ))}\n <span>{t('chart.more')}</span>\n </div>\n </div>\n )\n}\n\nexport const fmt = (v: string | number): string => {\n const n = Number(v)\n if (!Number.isFinite(n)) return String(v)\n return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n}\n\nexport const fmtInt = (v: number | undefined): string => Math.round(Number(v) || 0).toLocaleString()\n\n/**\n * Compact token/count formatting. English delegates to `Intl` compact notation;\n * Simplified Chinese keeps the \u4E07/\u4EBF scale words because \"1.6\u4E07 tokens\" reads\n * faster than \"16K tokens\" to Chinese readers.\n * @param v - raw number of tokens or calls.\n * @param locale - active plugin locale; defaults to Simplified Chinese.\n * @returns the compact string.\n */\nexport const fmtCompact = (v: number | undefined, locale: LocaleId = 'zh'): string => {\n const n = Number(v) || 0\n if (locale === 'en') {\n return new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(n)\n }\n if (n >= 100_000_000) return `${(n / 100_000_000).toFixed(1)}\u4EBF`\n if (n >= 10_000) return `${(n / 10_000).toFixed(1)}\u4E07`\n return Math.round(n).toLocaleString()\n}\n", "export type ChartFocusKey = 'ArrowLeft' | 'ArrowRight' | 'ArrowUp' | 'ArrowDown' | 'Home' | 'End'\n\n/** Resolve roving focus without adding every chart point to the page Tab order. */\nexport function nextChartFocus(\n current: number,\n count: number,\n key: ChartFocusKey,\n horizontalStep = 1,\n): number {\n if (count <= 0) return 0\n const index = Math.min(Math.max(0, current), count - 1)\n if (key === 'Home') return 0\n if (key === 'End') return count - 1\n const step = key === 'ArrowLeft' || key === 'ArrowRight' ? Math.max(1, horizontalStep) : 1\n const direction = key === 'ArrowLeft' || key === 'ArrowUp' ? -1 : 1\n return Math.min(Math.max(0, index + direction * step), count - 1)\n}\n\nexport function lastPopulatedIndex(values: number[]): number {\n for (let index = values.length - 1; index >= 0; index -= 1) {\n if (values[index] > 0) return index\n }\n return Math.max(0, values.length - 1)\n}\n\n/**\n * Touch tap toggles a chart point's tooltip pin: tapping the already-pinned\n * point releases it, tapping any other point (or none pinned yet) pins that\n * one instead. Shared by bar, grouped-bar and heatmap touch handling so pin\n * state never forks into a parallel machine per chart type.\n */\nexport function nextPinnedIndex(current: number | null, tapped: number): number | null {\n return current === tapped ? null : tapped\n}\n\n/**\n * Distinguishes a tap from a scroll/drag using the touch/pointer start-to-end\n * displacement and elapsed time. A page scroll that merely passes over a data\n * point moves well past `moveThreshold` before release; a long press held past\n * `timeThreshold` without lifting is not a quick tap either.\n */\nexport function isTapGesture(dx: number, dy: number, dt: number, moveThreshold = 10, timeThreshold = 500): boolean {\n return Math.hypot(dx, dy) <= moveThreshold && dt <= timeThreshold\n}\n\n/**\n * Per-slot totals across every series of a stacked bar chart: each column's\n * height must reflect the *summed* usage of every selected model at that\n * time slot, not any single model's value \u2014 otherwise a column with many\n * small models would look shorter than a column with one large one even\n * though it represents more total usage.\n */\nexport function stackedTotals(series: Array<{ bars: Array<{ value: number }> }>, count: number): number[] {\n return Array.from({ length: count }, (_, i) => series.reduce((sum, s) => sum + (s.bars[i]?.value ?? 0), 0))\n}\n\n/**\n * Highest value in the list, or 1 when every value is zero \u2014 the shared\n * fallback scale so an all-zero chart still divides safely instead of by 0.\n */\nexport function maxOrOne(values: number[]): number {\n let max = 0\n for (const v of values) if (v > max) max = v\n return max > 0 ? max : 1\n}\n", "import { createContext, useContext, type ReactElement, type ReactNode } from 'react'\nimport { zh, type LocaleKey } from './locales.ts'\n\n/**\n * Locales this plugin ships copy for: DSH's two built-in locales \u2014 Simplified\n * Chinese (`zh`, the host's own id) and English (`en`). The plugin keeps the\n * host's language catalog untouched on purpose: language selection stays a DSH\n * setting, and contributing a plugin-private third language would leave the\n * host UI and this dashboard speaking different languages, because no other\n * package ships a dictionary for it.\n */\nexport type LocaleId = 'zh' | 'en'\n\n/**\n * BCP 47 tags handed to `Intl` for date and number formatting. These are a\n * different vocabulary from {@link LocaleId}: the DSH id also addresses\n * dictionaries and the persisted language preference, while `Intl` wants a tag\n * with settled regional conventions. `zh` maps to `zh-CN`, matching the host's\n * internal document tag for its Simplified dictionary.\n */\nconst INTL_LOCALES: Record<LocaleId, string> = {\n zh: 'zh-CN',\n en: 'en-US',\n}\n\n/**\n * Resolve the `Intl` tag for a plugin locale.\n * @param locale - active plugin locale.\n * @returns the BCP 47 tag to pass to `Intl.*` / `toLocaleString`.\n */\nexport function intlLocale(locale: LocaleId): string {\n return INTL_LOCALES[locale]\n}\n\nexport type Translate = (key: LocaleKey, params?: Record<string, unknown>) => string\n\nexport const fallbackT: Translate = (key, params) => {\n const template = zh[key]\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n}\n\nconst TranslationContext = createContext<Translate>(fallbackT)\n\nexport function LocaleProvider(props: { t: Translate; children: ReactNode }): ReactElement {\n return <TranslationContext.Provider value={props.t}>{props.children}</TranslationContext.Provider>\n}\n\n/**\n * Read the translate function plus the concrete locale it is bound to. The\n * identity rides the dictionary itself (`meta.locale`), because slot components\n * receive only the `t` seat, not the host's locale snapshot; every dictionary\n * stores its own id there, so a language switch moves both together.\n * @returns the active `t` and the plugin locale it resolves to.\n */\nexport function useI18n(): { t: Translate; locale: LocaleId } {\n const t = useContext(TranslationContext)\n return { t, locale: t('meta.locale') === 'en' ? 'en' : 'zh' }\n}\n\n/** Translate host error copy that predates stable machine-readable error codes. */\nexport function localizeApiError(message: string | undefined, t: Translate, fallback: LocaleKey): string {\n if (message === undefined || message === '') return t(fallback)\n if (message === '\u51ED\u8BC1\u670D\u52A1\u4E0D\u53EF\u7528') return t('error.credentialsUnavailable')\n if (message === '\u67E5\u8BE2\u5931\u8D25') return t('error.query')\n if (message === '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25') return t('error.balanceLoad')\n if (message === '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25') return t('error.usageLoad')\n if (message === '\u672A\u914D\u7F6E DEEPSEEK_API_KEY\uFF08\u53EF\u5728\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u4E2D\u586B\u5199\uFF09') return t('error.noApiKey')\n if (message === '\u8D26\u53F7\u4F59\u989D\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u4E14\u672A\u914D\u7F6E DEEPSEEK_API_KEY') return t('error.accountBalanceUnavailable')\n if (message === '\u89E3\u6790\u4F59\u989D\u54CD\u5E94\u5931\u8D25') return t('error.balanceParse')\n if (message === '\u4F1A\u8BDD\u6301\u4E45\u5316\u670D\u52A1\u4E0D\u53EF\u7528') return t('error.persistenceUnavailable')\n if (message === '\u7F3A\u5C11\u4F1A\u8BDD id') return t('error.missingSessionId')\n const mappings: Array<[RegExp, LocaleKey, string]> = [\n [/^\u8BFB\u53D6 API Key \u5931\u8D25\uFF1A(.*)$/, 'error.credentialRead', 'detail'],\n [/^\u8BF7\u6C42\u4F59\u989D\u63A5\u53E3\u5931\u8D25\uFF1A(.*)$/, 'error.balanceRequest', 'detail'],\n [/^\u4F59\u989D\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP (\\d+)\uFF09$/, 'error.balanceHttp', 'status'],\n [/^\u8BFB\u53D6\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF1A(.*)$/, 'error.sessionList', 'detail'],\n [/^\u8BFB\u53D6\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A(.*)$/, 'error.sessionLogRead', 'detail'],\n ]\n for (const [pattern, key, field] of mappings) {\n const match = message.match(pattern)\n if (match !== null) return t(key, { [field]: match[1] })\n }\n return message\n}\n", "/** Locale namespace and complete bilingual copy for the dashboard surfaces. */\nexport const NS = 'dsh-usage-dashboard'\n\nexport const zh = {\n 'meta.locale': 'zh',\n 'nav.quota': '\u989D\u5EA6',\n 'widget.title': 'DeepSeek \u989D\u5EA6',\n 'common.unknownModel': '\u672A\u77E5\u6A21\u578B',\n 'common.calls': '{count} \u6B21\u8C03\u7528',\n 'common.callsShort': '{count} \u6B21',\n 'common.sessions': '{count} \u4E2A\u4F1A\u8BDD',\n 'common.records': '{count} \u6761',\n 'common.rows': '{count} \u884C',\n 'common.input': '\u8F93\u5165',\n 'common.output': '\u8F93\u51FA',\n 'common.cacheHit': '\u7F13\u5B58\u547D\u4E2D',\n 'common.status': '\u72B6\u6001',\n 'common.available': '\u53EF\u7528',\n 'common.unavailable': '\u4E0D\u53EF\u7528',\n 'common.justNow': '\u521A\u521A',\n 'common.minutesAgo': '{count} \u5206\u949F\u524D',\n 'common.hoursAgo': '{count} \u5C0F\u65F6\u524D',\n 'common.daysAgo': '{count} \u5929\u524D',\n 'common.listSeparator': '\u3001',\n 'common.period': '\u3002',\n 'delta.noBaselineTitle': '{label}\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u4ECE\u5BF9\u6BD4',\n 'delta.noBaseline': '\u65E0\u5BF9\u6BD4',\n 'delta.flat': '\u6301\u5E73',\n 'period.volume': '{tokens} tokens \u00B7 {calls}',\n 'budget.unset': '\u672A\u8BBE\u7F6E\u6708\u5EA6\u9884\u7B97\u3002',\n 'budget.configure': '\u8BBE\u7F6E\u9884\u7B97',\n 'budget.over': '\u5DF2\u8D85\u9884\u7B97 \u00A5{amount}',\n 'budget.forecastOver': '\u7167\u5F53\u524D\u901F\u5EA6\uFF0C\u9884\u8BA1\u8D85\u51FA \u00A5{amount}',\n 'budget.forecast': '\u7167\u5F53\u524D\u901F\u5EA6\uFF0C\u9884\u8BA1\u6708\u5E95 \u00A5{amount}',\n 'budget.title': '\u672C\u6708\u9884\u7B97',\n 'budget.progressLabel': '\u672C\u6708\u9884\u7B97\u4F7F\u7528\u8FDB\u5EA6',\n 'budget.used': '\u5DF2\u4F7F\u7528 {percent}%\uFF0C{forecast}',\n 'budget.remaining': '\u5269\u4F59 \u00A5{amount}',\n 'budget.exceeded': '\u8D85\u51FA \u00A5{amount}',\n 'pricing.title': '\u8BA1\u4EF7\u8BF4\u660E',\n 'pricing.currentPeak': '\u5F53\u524D \u9AD8\u5CF0\u65F6\u6BB5',\n 'pricing.currentOffPeak': '\u5F53\u524D \u95F2\u65F6',\n 'pricing.model': '\u6A21\u578B',\n 'pricing.period': '\u65F6\u6BB5',\n 'pricing.inputCacheHit': '\u8F93\u5165\u00B7\u7F13\u5B58\u547D\u4E2D',\n 'pricing.inputCacheMiss': '\u8F93\u5165\u00B7\u672A\u547D\u4E2D',\n 'pricing.output': '\u8F93\u51FA',\n 'pricing.peak': '\u9AD8\u5CF0',\n 'pricing.offPeak': '\u95F2\u65F6',\n 'pricing.unit': '\u5355\u4F4D\uFF1A{currency} / \u767E\u4E07 tokens\u3002',\n 'pricing.splitNote': '\u9AD8\u5CF0\u65F6\u6BB5\u4E3A\u5317\u4EAC\u65F6\u95F4 {windows}\uFF08\u5468\u4E00\u81F3\u5468\u4E94\uFF09\uFF0C\u5176\u4F59\u4E3A\u95F2\u65F6\uFF08\u4EF7\u683C\u51CF\u534A\uFF09\uFF1B\u6BCF\u6761\u7528\u91CF\u6309\u53D1\u751F\u65F6\u523B\u751F\u6548\u7684\u5B98\u65B9\u4EF7\u683C\u4F30\u7B97\u3002',\n 'pricing.visionNote': '\u56FE\u7247\u6309\u5C3A\u5BF8\u6298\u7B97 token\uFF0C\u4E0E\u6587\u672C\u4E00\u5E76\u8BA1\u8D39\u3002',\n 'pricing.unknown': '\u672A\u77E5\u6A21\u578B\u6309 deepseek-v4-pro \u8BA1\u4EF7\u3002',\n 'coverage.noRange': '\u6682\u65E0\u6709\u6548\u7528\u91CF\u65F6\u95F4',\n 'coverage.title': '\u7EDF\u8BA1\u8303\u56F4',\n 'coverage.gaps': '\u5B58\u5728\u7F3A\u53E3',\n 'coverage.complete': '\u672C\u673A\u8BFB\u53D6\u5B8C\u6574',\n 'coverage.brief': '\u626B\u63CF {scanned} / {listed} \u4E2A\u4F1A\u8BDD \u00B7 {records} \u6761\u7528\u91CF\u8BB0\u5F55',\n 'coverage.scanned': '\u6210\u529F\u626B\u63CF',\n 'coverage.failed': '\u8BFB\u53D6\u5931\u8D25',\n 'coverage.skipped': '\u8DF3\u8FC7\u8BB0\u5F55',\n 'coverage.time': '\u8BB0\u5F55\u65F6\u95F4\uFF1A{range}',\n 'coverage.scope': '\u8FD9\u91CC\u53EA\u7EDF\u8BA1\u5F53\u524D\u8BBE\u5907\u4E0A\u7684 DSH \u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u4E0D\u5305\u542B\u5176\u4ED6\u8BBE\u5907\u3001DeepSeek \u5E73\u53F0\u76F4\u63A5\u8C03\u7528\u6216\u5DF2\u5220\u9664\u7684\u672C\u5730\u65E5\u5FD7\u3002',\n 'coverage.warning': '\u672C\u6B21\u56DE\u653E\u6709\u65E5\u5FD7\u65E0\u6CD5\u8BFB\u53D6\u6216\u7528\u91CF\u8BB0\u5F55\u683C\u5F0F\u5F02\u5E38\uFF0C\u9875\u9762\u6C47\u603B\u53EF\u80FD\u4F4E\u4E8E\u5B9E\u9645\u6D88\u8017\uFF1B\u53EF\u5237\u65B0\u91CD\u8BD5\uFF0C\u5E76\u4EE5 DeepSeek \u5B98\u65B9\u5E73\u53F0\u8D26\u5355\u4E3A\u51C6\u3002',\n 'export.title': '\u5BFC\u51FA\u5168\u90E8\u672C\u673A DSH \u4F1A\u8BDD\u65E5\u5FD7\u6570\u636E\uFF08\u4E0D\u53D7\u7EDF\u8BA1\u5468\u671F\u5F71\u54CD\uFF09',\n 'export.done': '\u5DF2\u5BFC\u51FA',\n 'export.action': '\u5BFC\u51FA',\n 'export.menuLabel': '\u9009\u62E9\u5BFC\u51FA\u683C\u5F0F',\n 'export.dailyCsv': '\u9010\u5929 CSV',\n 'export.modelCsv': '\u9010\u6A21\u578B CSV',\n 'export.fullJson': '\u5B8C\u6574 JSON',\n 'export.jsonHint': '\u542B\u56FE\u8868\u4E0E\u6392\u884C',\n 'cache.empty': '\u6682\u65E0\u7F13\u5B58\u547D\u4E2D\u6570\u636E\u3002',\n 'cache.rate': '\u7F13\u5B58\u547D\u4E2D\u7387',\n 'cache.saved': '\u8F83\u5168\u672A\u547D\u4E2D\u7701\u4E0B',\n 'cache.allMiss': '\u82E5\u5168\u672A\u547D\u4E2D',\n 'cache.aria': '\u7F13\u5B58\u547D\u4E2D {hit}%\uFF0C\u672A\u547D\u4E2D {miss}%',\n 'cache.hitLegend': '\u7F13\u5B58\u547D\u4E2D {tokens}',\n 'cache.missLegend': '\u672A\u547D\u4E2D {tokens}\uFF08\u6309\u672A\u547D\u4E2D\u4EF7\u8BA1\u8D39\uFF09',\n 'cache.basis': '\u5B9E\u4ED8 \u00A5{cost}\uFF1B\u82E5\u5168\u90E8\u672A\u547D\u4E2D\u7EA6 \u00A5{miss}\uFF0C\u4E24\u8005\u5DEE\u989D\u5373\u547D\u4E2D\u7F13\u5B58\u7701\u4E0B\u7684\u8D39\u7528\u3002',\n 'peak.empty': '\u6682\u65E0\u7528\u91CF\u3002',\n 'peak.aria': '\u9AD8\u5CF0\u65F6\u6BB5 {peak}%\uFF0C\u95F2\u65F6 {offPeak}%',\n 'peak.peakLegend': '\u9AD8\u5CF0 {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.offPeakLegend': '\u95F2\u65F6 {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.shift': '\u9AD8\u5CF0\u6539\u8D70\u95F2\u65F6\u53EF\u7701',\n 'peak.saving': '\u00A5{amount}',\n 'peak.basis': '\u5168\u90E8\u6539\u8D70\u95F2\u65F6\u7EA6 \u00A5{total}\uFF1B\u6B64\u5904\u6309\u5F53\u524D\u4EF7\u76EE\u4F30\u7B97\uFF0C\u4E0E\u300C\u6D88\u8017\u6982\u89C8 \u00B7 \u7D2F\u8BA1\u300D\u7684\u5B9E\u9645\u82B1\u8D39\u53E3\u5F84\u4E0D\u540C\u3002',\n 'peak.clockTitle': '\u4ECA\u65E5\u4EF7\u683C\u65F6\u6BB5',\n 'peak.nowPeak': '\u73B0\u5728\u9AD8\u5CF0 \u00B7 \u5168\u4EF7',\n 'peak.nowOff': '\u73B0\u5728\u95F2\u65F6 \u00B7 \u534A\u4EF7',\n 'peak.clockAria': '24 \u5C0F\u65F6\u4EF7\u683C\u65F6\u6BB5\uFF0C{state}',\n 'peak.clockHint': '\u5DE5\u4F5C\u65E5 09\u201312\u300114\u201318 \u4E3A\u9AD8\u5CF0\uFF0C\u5176\u4F59\u65F6\u6BB5\u534A\u4EF7\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09',\n 'vision.empty': '{window}\u6CA1\u6709\u56FE\u7247\u8F93\u5165\u3002',\n 'vision.title': '\u56FE\u7247 / \u591A\u6A21\u6001\u7528\u91CF',\n 'vision.images': '\u56FE\u7247\u5F20\u6570',\n 'vision.tokens': '\u4F30\u7B97\u56FE\u7247 tokens',\n 'vision.cost': '\u4F30\u7B97\u8D39\u7528',\n 'vision.tokensShare': '\u5360\u8F93\u5165 {percent}%',\n 'vision.costShare': '\u5360\u8D39\u7528 {percent}%',\n 'vision.note': '\u6309\u5B98\u65B9\u89C4\u5219\u4F30\u7B97\uFF0C\u5B9E\u9645\u4EE5\u63A5\u53E3\u8FD4\u56DE\u7684\u7528\u91CF\u4E3A\u51C6\u3002',\n 'vision.sessionsTitle': '\u56FE\u7247\u6700\u591A\u7684\u4F1A\u8BDD',\n 'vision.sessionRow': '{images} \u5F20 \u00B7 \u00A5{cost}',\n 'vision.dailyTitle': '{window} \u00B7 \u6BCF\u5929\u56FE\u7247\u6570',\n 'vision.barAria': '{date} \u00B7 {images} \u5F20\u56FE\u7247 \u00B7 \u4F30\u7B97 {tokens} tokens',\n 'vision.barTitle': '{date} \u00B7 {images} \u5F20\u56FE\u7247 \u00B7 \u4F30\u7B97 {tokens} tokens \u00B7 \u00A5{cost}',\n 'sessions.empty': '\u8FD8\u6CA1\u6709\u4EA7\u751F\u8D39\u7528\u7684\u4F1A\u8BDD\u3002',\n 'sessions.detail': '{tokens} tokens \u00B7 {calls} \u00B7 {ago}',\n 'sessions.share': '\u5360 {percent}%',\n 'sessions.more': '\u5171 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u663E\u793A\u6700\u8D35\u7684 {shown} \u4E2A\u3002',\n 'sessions.fallbackTitle': '\u4F1A\u8BDD {id}',\n 'models.empty': '\u8FD8\u6CA1\u6709\u53EF\u5F52\u7C7B\u7684\u6A21\u578B\u7528\u91CF\u3002',\n 'models.shareAria': '{name} \u5360\u603B\u8D39\u7528 {percent}%',\n 'models.detail': '{tokens} tokens \u00B7 {calls} \u00B7 \u8F93\u5165 {input} / \u8F93\u51FA {output} / \u7F13\u5B58 {cache}',\n 'models.all': '\u5168\u90E8\u6A21\u578B',\n 'models.selected': '\u6A21\u578B \u00D7{count}',\n 'models.filterTitle': '\u7B5B\u9009\u56FE\u8868\u4E2D\u663E\u793A\u7684\u6A21\u578B',\n 'models.filterLabel': '\u7B5B\u9009\u56FE\u8868\u6A21\u578B',\n 'window.year': '\u8FD1 1 \u5E74',\n 'window.days': '\u8FD1 {days} \u5929',\n 'window.groupLabel': '\u7EDF\u8BA1\u5468\u671F',\n 'window.viewTitle': '\u67E5\u770B{window}\u7684\u7528\u91CF\u4E0E\u6392\u884C',\n 'window.yearButton': '1 \u5E74',\n 'window.daysButton': '{days} \u5929',\n 'metric.tokens': 'tokens',\n 'metric.usage': '\u7528\u91CF',\n 'metric.cost': '\u8D39\u7528',\n 'metric.calls': '\u8C03\u7528',\n 'metric.groupLabel': '\u56FE\u8868\u6307\u6807',\n 'metric.compareTitle': '\u6309{metric}\u6BD4\u8F83',\n 'chart.dailyTitle': '{window} \u00B7 \u9010\u5929{metric}',\n 'chart.hourlyTitle': '{window} \u00B7 {metric}\u6309\u5C0F\u65F6\u5206\u5E03\uFF080\u201323 \u70B9\uFF09',\n 'chart.peak': '\u5CF0\u503C {value}',\n 'chart.dimensionLabel': '\u5207\u6362\u56FE\u8868\u7EF4\u5EA6',\n 'chart.daily': '\u9010\u5929',\n 'chart.hourly': '\u9010\u5C0F\u65F6',\n 'chart.noWindowData': '{window}\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002',\n 'chart.heatmapTitle': '\u8FD1\u4E00\u5E74 \u00B7 \u6BCF\u65E5',\n 'chart.empty': '\u8FD8\u6CA1\u6709\u7528\u91CF\u8BB0\u5F55\u3002',\n 'chart.hourPoint': '{hour} \u70B9',\n 'chart.tooltip': '{head} \u00B7 {tokens} tokens \u00B7 \u00A5{cost} \u00B7 {calls}',\n 'chart.less': '\u5C11',\n 'chart.more': '\u591A',\n 'chart.month1': '1\u6708',\n 'chart.month2': '2\u6708',\n 'chart.month3': '3\u6708',\n 'chart.month4': '4\u6708',\n 'chart.month5': '5\u6708',\n 'chart.month6': '6\u6708',\n 'chart.month7': '7\u6708',\n 'chart.month8': '8\u6708',\n 'chart.month9': '9\u6708',\n 'chart.month10': '10\u6708',\n 'chart.month11': '11\u6708',\n 'chart.month12': '12\u6708',\n 'number.tenThousand': '{value}\u4E07',\n 'number.hundredMillion': '{value}\u4EBF',\n 'fresh.none': '\u5C1A\u65E0\u6210\u529F\u8BB0\u5F55',\n 'fresh.justNow': '\u521A\u521A\u66F4\u65B0',\n 'fresh.minutes': '\u66F4\u65B0\u4E8E {count} \u5206\u949F\u524D',\n 'fresh.hours': '\u66F4\u65B0\u4E8E {count} \u5C0F\u65F6\u524D',\n 'fresh.days': '\u66F4\u65B0\u4E8E {count} \u5929\u524D',\n 'sync.first': '\u9996\u6B21\u540C\u6B65\u4E2D',\n 'sync.syncing': '\u540C\u6B65\u4E2D \u00B7 \u5F53\u524D\u6570\u636E{age}',\n 'sync.fresh': '\u5DF2\u540C\u6B65 \u00B7 {age}',\n 'sync.cached': '\u672C\u5730\u7F13\u5B58 \u00B7 {age}',\n 'sync.fallback': '\u7F13\u5B58\u56DE\u9000 \u00B7 {age}',\n 'sync.error': '\u540C\u6B65\u5931\u8D25 \u00B7 \u6682\u65E0\u53EF\u663E\u793A\u7684\u7528\u91CF',\n 'status.neverSynced': '\u8FD8\u6CA1\u6709\u6210\u529F\u540C\u6B65\u8FC7\u7528\u91CF\u6570\u636E',\n 'status.usageTime': '\u7528\u91CF\u6570\u636E\u65F6\u95F4\uFF1A{time}',\n 'status.forceRefresh': '\u5F3A\u5236\u5237\u65B0\uFF08\u7ED5\u8FC7\u7F13\u5B58\uFF09',\n 'status.refreshing': '\u5237\u65B0\u4E2D',\n 'status.refresh': '\u5237\u65B0',\n 'error.balanceLoad': '\u4F59\u989D\u52A0\u8F7D\u5931\u8D25',\n 'error.usageLoad': '\u7528\u91CF\u52A0\u8F7D\u5931\u8D25',\n 'error.refreshCached': '\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u6570\u636E\uFF08{error}\uFF09',\n 'error.balanceRefreshCached': '\u4F59\u989D\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u4F59\u989D\uFF08{error}\uFF09',\n 'error.usageRefreshCached': '\u7528\u91CF\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u5C55\u793A\u7F13\u5B58\u7528\u91CF\uFF08{error}\uFF09',\n 'error.query': '\u67E5\u8BE2\u5931\u8D25',\n 'error.credentialsUnavailable': '\u51ED\u8BC1\u670D\u52A1\u4E0D\u53EF\u7528',\n 'error.credentialRead': '\u8BFB\u53D6 API Key \u5931\u8D25\uFF1A{detail}',\n 'error.noApiKey': '\u672A\u914D\u7F6E DEEPSEEK_API_KEY\uFF08\u53EF\u5728\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u4E2D\u586B\u5199\uFF09',\n 'error.accountBalanceUnavailable': '\u8D26\u53F7\u4F59\u989D\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u4E14\u672A\u914D\u7F6E DEEPSEEK_API_KEY',\n 'error.balanceRequest': '\u8BF7\u6C42\u4F59\u989D\u63A5\u53E3\u5931\u8D25\uFF1A{detail}',\n 'error.balanceHttp': '\u4F59\u989D\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP {status}\uFF09',\n 'error.balanceParse': '\u89E3\u6790\u4F59\u989D\u54CD\u5E94\u5931\u8D25',\n 'error.persistenceUnavailable': '\u4F1A\u8BDD\u6301\u4E45\u5316\u670D\u52A1\u4E0D\u53EF\u7528',\n 'error.sessionList': '\u8BFB\u53D6\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF1A{detail}',\n 'error.sessionLogRead': '\u8BFB\u53D6\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A{detail}',\n 'error.missingSessionId': '\u7F3A\u5C11\u4F1A\u8BDD id',\n 'alert.lowTitle': '\u4F59\u989D {balance} {currency} \u5DF2\u4F4E\u4E8E\u9884\u8B66\u7EBF {threshold}',\n 'alert.runway': '\uFF0C\u6309\u8FD1\u671F\u7528\u91CF\u4F30\u8BA1\u8FD8\u80FD\u6491 {days}',\n 'alert.topUp': '\u53BB\u5145\u503C',\n 'balance.title': '\u8D26\u6237\u4F59\u989D',\n 'balance.remaining': '\u5269\u4F59\u4F59\u989D',\n 'balance.breakdownTitle': '\u67E5\u770B\u5145\u503C\u4E0E\u8D60\u9001\u989D\u5EA6\u660E\u7EC6',\n 'balance.toppedUp': '\u5145\u503C\u989D\u5EA6 {amount}',\n 'balance.granted': '\u8D60\u9001\u989D\u5EA6 {amount}',\n 'balance.runway': '\u9884\u8BA1\u53EF\u7528',\n 'balance.runwayBreakdownTitle': '\u67E5\u770B\u9884\u8BA1\u53EF\u7528\u5929\u6570\u8BF4\u660E',\n 'balance.topUpTitle': '\u4F59\u989D\u504F\u4F4E\uFF0C\u524D\u5F80 DeepSeek \u5F00\u653E\u5E73\u53F0\u5145\u503C\uFF08\u65B0\u6807\u7B7E\u9875\u6253\u5F00\uFF09',\n 'balance.days': '{count} \u5929',\n 'balance.overYear': '> 365 \u5929',\n 'balance.noRunway': '\u8FD1 {days} \u5929\u6CA1\u6709\u7528\u91CF\uFF0C\u65E0\u6CD5\u4F30\u7B97',\n 'balance.runwayTitle': '\u6309\u8FD1 {days} \u5929\u65E5\u5747 \u00A5{cost} \u4F30\u7B97\uFF08\u542B\u65E0\u7528\u91CF\u7684\u65E5\u5B50\uFF1B\u4ECA\u5929\u5C1A\u672A\u8FC7\u5B8C\uFF09',\n 'balance.empty': '\u8BFB\u4E0D\u5230\u4F59\u989D\uFF0C\u8BF7\u68C0\u67E5\u8D26\u53F7\u767B\u5F55\u6216 API Key \u540E\u5237\u65B0\u3002',\n 'sessionUsage.title': '\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017',\n 'common.estimated': '\u8D39\u7528\u4E3A\u4F30\u7B97',\n 'sessionUsage.cost': '\u8D39\u7528',\n 'sessionUsage.tokens': 'Tokens',\n 'sessionUsage.calls': '\u8C03\u7528\u6B21\u6570',\n 'sessionUsage.range': '\u6D3B\u8DC3\u65F6\u95F4 {range}',\n 'sessionUsage.single': '{model} \u00B7 \u8F93\u5165 {input} / \u8F93\u51FA {output} / \u7F13\u5B58 {cache}',\n 'sessionUsage.empty': '\u8FD9\u4E2A\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7528\u91CF\u3002',\n 'overview.title': '\u6D88\u8017\u6982\u89C8',\n 'overview.today': '\u4ECA\u65E5',\n 'overview.month': '\u672C\u6708',\n 'overview.total': '\u7D2F\u8BA1',\n 'overview.vsYesterday': '\u8F83\u6628\u65E5',\n 'overview.vsLastMonth': '\u8F83\u4E0A\u6708\u540C\u671F',\n 'overview.empty': '\u8FD8\u6CA1\u6709\u53EF\u7EDF\u8BA1\u7684\u6D88\u8017\u3002',\n 'usage.trendTitle': '\u7528\u91CF\u8D8B\u52BF',\n 'usage.windowInput': '{window}\u8F93\u5165',\n 'usage.modelCalls': '\u6A21\u578B\u8C03\u7528',\n 'heatmap.title': '\u7528\u91CF\u70ED\u529B\u56FE',\n 'peak.title': '\u9AD8\u5CF0 / \u95F2\u65F6\u5206\u5E03',\n 'cache.title': '\u7F13\u5B58\u547D\u4E2D\u4E0E\u8282\u7701',\n 'models.title': '\u6A21\u578B\u6210\u672C\u6392\u884C',\n 'sessions.title': '\u4F1A\u8BDD\u6210\u672C\u6392\u884C',\n 'links.title': '\u5FEB\u6377\u5165\u53E3',\n 'nav.label': '\u9875\u9762\u5927\u7EB2',\n 'nav.balance': '\u4F59\u989D',\n 'nav.session': '\u5F53\u524D\u4F1A\u8BDD',\n 'nav.overview': '\u6D88\u8017\u6982\u89C8',\n 'nav.trend': '\u7528\u91CF\u8D8B\u52BF',\n 'nav.heatmap': '\u7528\u91CF\u70ED\u529B\u56FE',\n 'nav.models': '\u6A21\u578B\u6210\u672C\u6392\u884C',\n 'nav.sessions': '\u4F1A\u8BDD\u6210\u672C\u6392\u884C',\n 'nav.peakcache': '\u9AD8\u5CF0 / \u7F13\u5B58',\n 'nav.settings': '\u8BBE\u7F6E',\n 'links.usage': '\u67E5\u770B\u989D\u5EA6 / \u7528\u91CF',\n 'links.apiKey': '\u751F\u6210 API Key',\n 'links.status': '\u670D\u52A1\u72B6\u6001',\n 'settings.title': '\u8BBE\u7F6E',\n 'settings.groupDisplay': '\u663E\u793A',\n 'settings.groupAlerts': '\u63D0\u9192',\n 'settings.groupLayout': '\u5E03\u5C40\u4E0E\u5165\u53E3',\n 'settings.widget': '\u5728\u5176\u4ED6\u9875\u9762\u663E\u793A\u53F3\u4E0B\u89D2\u60AC\u6D6E\u989D\u5EA6\u7A97\u53E3',\n 'settings.widgetHint': '\u989D\u5EA6\u9875\u81EA\u52A8\u9690\u85CF\uFF1B\u5176\u4ED6\u9875\u9762\u6309\u4E0B\u65B9\u9009\u62E9\u663E\u793A\u3002',\n 'settings.widgetTabs': '\u5C55\u793A\u6D6E\u7A97\u7684\u9875\u9762',\n 'settings.widgetTabsHint': '\u5217\u8868\u4F1A\u968F\u5DF2\u5B89\u88C5\u7684\u9875\u9762\u81EA\u52A8\u66F4\u65B0\u3002',\n 'settings.widgetTabsEmpty': '\u5F53\u524D\u6CA1\u6709\u53EF\u914D\u7F6E\u7684\u4F1A\u8BDD\u9875\u9762\u3002',\n 'settings.lowBalance': '\u4F59\u989D\u9884\u8B66\u7EBF',\n 'settings.lowBalanceOn': '\u4F59\u989D\u4F4E\u4E8E {amount} {currency} \u65F6\uFF0C\u8FD9\u91CC\u548C\u60AC\u6D6E\u7A97\u90FD\u4F1A\u8F6C\u4E3A\u8B66\u793A\u8272\u3002\u586B 0 \u5173\u95ED\u3002',\n 'settings.lowBalanceOff': '\u5DF2\u5173\u95ED\u4F59\u989D\u9884\u8B66\u3002\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u6570\u5F00\u542F\u3002',\n 'settings.monthlyBudget': '\u6708\u5EA6\u9884\u7B97',\n 'settings.monthlyBudgetOn': '\u6309\u5317\u4EAC\u65F6\u95F4\u81EA\u7136\u6708\u8DDF\u8E2A {amount} CNY \u9884\u7B97\uFF0C\u5E76\u5728\u6D88\u8017\u6982\u89C8\u9884\u6D4B\u6708\u5E95\u82B1\u8D39\u3002\u586B 0 \u5173\u95ED\u3002',\n 'settings.monthlyBudgetOff': '\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u91D1\u989D\uFF0C\u6D88\u8017\u6982\u89C8\u4F1A\u663E\u793A\u8FDB\u5EA6\u4E0E\u6708\u5E95\u9884\u6D4B\u3002',\n 'settings.sidebarEntry': '\u4FA7\u8FB9\u680F\u989D\u5EA6\u5165\u53E3',\n 'settings.sidebarEntryHint': '\u5728\u4FA7\u8FB9\u680F\u9876\u90E8\u6216\u5E95\u90E8\u653E\u4E00\u4E2A\u300C\u989D\u5EA6\u300D\u5165\u53E3\uFF0C\u6253\u5F00\u8D26\u6237\u7EA7\u989D\u5EA6\u9875\u3002',\n 'settings.sidebarEntryOff': '\u5173\u95ED',\n 'settings.sidebarEntryTop': '\u9876\u90E8',\n 'settings.sidebarEntryBottom': '\u5E95\u90E8',\n 'settings.tabPosition': '\u300C\u989D\u5EA6\u300D\u6807\u7B7E\u4F4D\u7F6E',\n 'settings.tabPositionHint': '\u62D6\u52A8\u300C\u989D\u5EA6\u300D\u8C03\u6574\u6807\u7B7E\u4F4D\u7F6E\u3002',\n 'settings.tabDragAria': '\u62D6\u52A8\u300C\u989D\u5EA6\u300D\u8C03\u6574\u6807\u7B7E\u4F4D\u7F6E',\n 'settings.tabMoveEarlier': '\u524D\u79FB',\n 'settings.tabMoveLater': '\u540E\u79FB',\n 'panel.caption': '\u8D26\u6237\u7EA7 \u00B7 \u8DE8\u5168\u90E8\u4F1A\u8BDD',\n 'panel.openAria': '\u6253\u5F00\u989D\u5EA6\u9875',\n 'widget.updatedNow': '\u521A\u521A\u66F4\u65B0',\n 'widget.stale': '{minutes} \u5206\u949F\u524D\u7684\u6570\u636E\uFF0C\u70B9 \u21BB \u66F4\u65B0',\n 'widget.loading': '\u67E5\u8BE2\u4E2D\u2026',\n 'widget.lowTitle': '\u4F59\u989D\u4F4E\u4E8E\u9884\u8B66\u7EBF {amount}',\n 'widget.todayCostTitle': '\u4ECA\u65E5\u6D88\u8017\uFF08\u4F30\u7B97\uFF09\u00B7 {age}',\n 'widget.todayCost': '\u4ECA\u65E5\u6D88\u8017',\n 'widget.sessionCostTitle': '\u5F53\u524D\u4F1A\u8BDD\u7D2F\u8BA1\u6D88\u8017\uFF08\u4F30\u7B97\uFF09',\n 'widget.sessionCost': '\u5F53\u524D\u4F1A\u8BDD',\n 'widget.noBalance': '\u6682\u65E0\u4F59\u989D\u6570\u636E',\n 'widget.dragCard': '\u62D6\u52A8\u5230\u56DB\u4E2A\u89D2\u843D',\n 'widget.dragGrip': '\u62D6\u52A8\u4EE5\u79FB\u52A8',\n 'widget.refresh': '\u5237\u65B0\u4F59\u989D\u4E0E\u4ECA\u65E5\u7528\u91CF',\n 'widget.expand': '\u5C55\u5F00',\n 'widget.collapse': '\u6536\u8D77',\n 'widget.expandAria': '\u5C55\u5F00\u989D\u5EA6\u7A97\u53E3',\n 'widget.collapseAria': '\u6536\u8D77\u989D\u5EA6\u7A97\u53E3',\n 'messageCost.label': '\u672C\u8F6E\u8D39\u7528',\n 'sessionCost.title': '\u4F1A\u8BDD\u8D39\u7528',\n 'sessionCost.aria': '\u672C\u4F1A\u8BDD\u4F30\u7B97\u8D39\u7528 {amount}',\n 'sessionCost.active': '\u6D3B\u8DC3\u65F6\u95F4',\n 'messageCost.tooltip': '\u7531 dsh-usage-dashboard \u63D0\u4F9B \u00B7 \u672C\u8F6E\u5BF9\u8BDD\u8D39\u7528\u4E3A\u4F30\u7B97\u503C',\n 'messageCost.aria': '{amount}\uFF0C\u672C\u8F6E\u5BF9\u8BDD\u4F30\u7B97\u8D39\u7528\uFF0C\u7531 dsh-usage-dashboard \u63D0\u4F9B',\n 'boundary.title': '\u989D\u5EA6\u9762\u677F\u51FA\u9519\u4E86',\n 'boundary.body': '\u6E32\u67D3\u65F6\u629B\u4E86\u5F02\u5E38\uFF0C\u901A\u5E38\u662F\u6D4F\u89C8\u5668\u91CC\u5B58\u7740\u65E7\u7248\u672C\u7684\u7F13\u5B58\u6570\u636E\u3002\u6E05\u6389\u672C\u63D2\u4EF6\u7684\u672C\u5730\u6570\u636E\u518D\u91CD\u65B0\u52A0\u8F7D\u5C31\u80FD\u6062\u590D\u3002',\n 'boundary.reset': '\u6E05\u9664\u672C\u5730\u6570\u636E\u5E76\u91CD\u65B0\u52A0\u8F7D',\n} as const\n\nexport type LocaleKey = keyof typeof zh\n\nexport const en: Record<LocaleKey, string> = {\n 'meta.locale': 'en',\n 'nav.quota': 'Usage',\n 'widget.title': 'DeepSeek Usage',\n 'common.unknownModel': 'Unknown model',\n 'common.calls': '{count} calls',\n 'common.callsShort': '{count} calls',\n 'common.sessions': '{count} sessions',\n 'common.records': '{count} records',\n 'common.rows': '{count} rows',\n 'common.input': 'Input',\n 'common.output': 'Output',\n 'common.cacheHit': 'Cache hit',\n 'common.status': 'Status',\n 'common.available': 'Available',\n 'common.unavailable': 'Unavailable',\n 'common.justNow': 'Just now',\n 'common.minutesAgo': '{count}m ago',\n 'common.hoursAgo': '{count}h ago',\n 'common.daysAgo': '{count}d ago',\n 'common.listSeparator': ', ',\n 'common.period': '.',\n 'delta.noBaselineTitle': 'No usage in {label}, so there is no baseline',\n 'delta.noBaseline': 'No baseline',\n 'delta.flat': 'No change',\n 'period.volume': '{tokens} tokens \u00B7 {calls}',\n 'budget.unset': 'No monthly budget set.',\n 'budget.configure': 'Set budget',\n 'budget.over': 'Over budget by \u00A5{amount}',\n 'budget.forecastOver': 'At this pace, \u00A5{amount} over by month-end',\n 'budget.forecast': 'At this pace, \u00A5{amount} by month-end',\n 'budget.title': 'Monthly budget',\n 'budget.progressLabel': 'Monthly budget usage',\n 'budget.used': '{percent}% used. {forecast}',\n 'budget.remaining': '\u00A5{amount} remaining',\n 'budget.exceeded': '\u00A5{amount} over',\n 'pricing.title': 'Pricing details',\n 'pricing.currentPeak': 'Peak now',\n 'pricing.currentOffPeak': 'Off-peak now',\n 'pricing.model': 'Model',\n 'pricing.period': 'Period',\n 'pricing.inputCacheHit': 'Input \u00B7 cache hit',\n 'pricing.inputCacheMiss': 'Input \u00B7 cache miss',\n 'pricing.output': 'Output',\n 'pricing.peak': 'Peak',\n 'pricing.offPeak': 'Off-peak',\n 'pricing.unit': 'Unit: {currency} / million tokens. ',\n 'pricing.splitNote': 'Peak periods are {windows} Beijing time, Monday to Friday; off-peak rates are half price. Each record is estimated at the official rates in force when it was written. ',\n 'pricing.visionNote': 'Images are converted to tokens by size and charged together with text. ',\n 'pricing.unknown': 'Unknown models use deepseek-v4-pro rates.',\n 'coverage.noRange': 'No valid usage timestamps',\n 'coverage.title': 'Coverage',\n 'coverage.gaps': 'Gaps found',\n 'coverage.complete': 'Local logs complete',\n 'coverage.brief': 'Scanned {scanned} / {listed} sessions \u00B7 {records} usage records',\n 'coverage.scanned': 'Scanned',\n 'coverage.failed': 'Read failures',\n 'coverage.skipped': 'Skipped records',\n 'coverage.time': 'Record range: {range}',\n 'coverage.scope': 'Only DSH session logs on this device are included. Other devices, direct DeepSeek Platform calls, and deleted local logs are excluded.',\n 'coverage.warning': 'Some logs could not be read or contained invalid usage records, so totals may be lower than actual spend. Refresh to retry and use the DeepSeek Platform bill as the source of truth.',\n 'export.title': 'Export all local DSH session-log data (independent of the selected range)',\n 'export.done': 'Exported',\n 'export.action': 'Export',\n 'export.menuLabel': 'Choose export format',\n 'export.dailyCsv': 'Daily CSV',\n 'export.modelCsv': 'Model CSV',\n 'export.fullJson': 'Full JSON',\n 'export.jsonHint': 'Charts and rankings included',\n 'cache.empty': 'No cache data yet.',\n 'cache.rate': 'Cache hit rate',\n 'cache.saved': 'Saved vs. all-miss',\n 'cache.allMiss': 'Cost if all miss',\n 'cache.aria': '{hit}% cache hits, {miss}% misses',\n 'cache.hitLegend': 'Cache hits {tokens}',\n 'cache.missLegend': 'Misses {tokens} (charged at miss rate)',\n 'cache.basis': 'You paid \u00A5{cost}; with no cache hits it would be about \u00A5{miss}. The difference is what caching saved.',\n 'peak.empty': 'No usage yet.',\n 'peak.aria': '{peak}% peak, {offPeak}% off-peak',\n 'peak.peakLegend': 'Peak {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.offPeakLegend': 'Off-peak {share}% \u00B7 {tokens} tokens \u00B7 {calls}',\n 'peak.shift': 'Saving if peak runs off-peak',\n 'peak.saving': '\u00A5{amount}',\n 'peak.basis': 'All off-peak would cost about \u00A5{total}, estimated at current prices \u2014 a different basis from \u201CSpend overview \u00B7 All time\u201D.',\n 'peak.clockTitle': \"Today's price windows\",\n 'peak.nowPeak': 'Peak now \u00B7 full price',\n 'peak.nowOff': 'Off-peak now \u00B7 half price',\n 'peak.clockAria': '24-hour price schedule, {state}',\n 'peak.clockHint': 'Peak 09\u201312 & 14\u201318 on weekdays; half price otherwise (Beijing time)',\n 'vision.empty': 'No image input in {window}.',\n 'vision.title': 'Image / multimodal usage',\n 'vision.images': 'Images',\n 'vision.tokens': 'Estimated image tokens',\n 'vision.cost': 'Estimated cost',\n 'vision.tokensShare': '{percent}% of input',\n 'vision.costShare': '{percent}% of cost',\n 'vision.note': 'Estimated with the official rule; provider usage numbers are the source of truth.',\n 'vision.sessionsTitle': 'Sessions with the most images',\n 'vision.sessionRow': '{images} images \u00B7 \u00A5{cost}',\n 'vision.dailyTitle': '{window} \u00B7 images per day',\n 'vision.barAria': '{date} \u00B7 {images} images \u00B7 est. {tokens} tokens',\n 'vision.barTitle': '{date} \u00B7 {images} images \u00B7 est. {tokens} tokens \u00B7 \u00A5{cost}',\n 'sessions.empty': 'No sessions have incurred cost yet.',\n 'sessions.detail': '{tokens} tokens \u00B7 {calls} \u00B7 {ago}',\n 'sessions.share': '{percent}% of total',\n 'sessions.more': '{count} sessions; showing the {shown} most expensive.',\n 'sessions.fallbackTitle': 'Session {id}',\n 'models.empty': 'No model usage can be classified yet.',\n 'models.shareAria': '{name} accounts for {percent}% of total cost',\n 'models.detail': '{tokens} tokens \u00B7 {calls} \u00B7 input {input} / output {output} / cache {cache}',\n 'models.all': 'All models',\n 'models.selected': '{count} models',\n 'models.filterTitle': 'Filter models shown in the chart',\n 'models.filterLabel': 'Filter chart models',\n 'window.year': 'Last year',\n 'window.days': 'Last {days} days',\n 'window.groupLabel': 'Date range',\n 'window.viewTitle': 'View usage and rankings for {window}',\n 'window.yearButton': '1 year',\n 'window.daysButton': '{days} days',\n 'metric.tokens': 'tokens',\n 'metric.usage': 'usage',\n 'metric.cost': 'cost',\n 'metric.calls': 'calls',\n 'metric.groupLabel': 'Chart metric',\n 'metric.compareTitle': 'Compare by {metric}',\n 'chart.dailyTitle': '{window} \u00B7 daily {metric}',\n 'chart.hourlyTitle': '{window} \u00B7 {metric} by hour (00\u201323)',\n 'chart.peak': 'Peak {value}',\n 'chart.dimensionLabel': 'Chart interval',\n 'chart.daily': 'Daily',\n 'chart.hourly': 'Hourly',\n 'chart.noWindowData': 'No usage in {window}.',\n 'chart.heatmapTitle': 'Last 12 months \u00B7 daily',\n 'chart.empty': 'No usage yet.',\n 'chart.hourPoint': '{hour}:00',\n 'chart.tooltip': '{head} \u00B7 {tokens} tokens \u00B7 \u00A5{cost} \u00B7 {calls}',\n 'chart.less': 'Less',\n 'chart.more': 'More',\n 'chart.month1': 'Jan',\n 'chart.month2': 'Feb',\n 'chart.month3': 'Mar',\n 'chart.month4': 'Apr',\n 'chart.month5': 'May',\n 'chart.month6': 'Jun',\n 'chart.month7': 'Jul',\n 'chart.month8': 'Aug',\n 'chart.month9': 'Sep',\n 'chart.month10': 'Oct',\n 'chart.month11': 'Nov',\n 'chart.month12': 'Dec',\n 'number.tenThousand': '{value}0K',\n 'number.hundredMillion': '{value}00M',\n 'fresh.none': 'No successful sync yet',\n 'fresh.justNow': 'Updated just now',\n 'fresh.minutes': 'Updated {count}m ago',\n 'fresh.hours': 'Updated {count}h ago',\n 'fresh.days': 'Updated {count}d ago',\n 'sync.first': 'Syncing for the first time',\n 'sync.syncing': 'Syncing \u00B7 current data {age}',\n 'sync.fresh': 'Synced \u00B7 {age}',\n 'sync.cached': 'Local cache \u00B7 {age}',\n 'sync.fallback': 'Using cache \u00B7 {age}',\n 'sync.error': 'Sync failed \u00B7 no usage to display',\n 'status.neverSynced': 'Usage has not synced successfully yet',\n 'status.usageTime': 'Usage data timestamp: {time}',\n 'status.forceRefresh': 'Force refresh (bypass cache)',\n 'status.refreshing': 'Refreshing',\n 'status.refresh': 'Refresh',\n 'error.balanceLoad': 'Balance failed to load',\n 'error.usageLoad': 'Usage failed to load',\n 'error.refreshCached': 'Refresh failed; showing cached data ({error})',\n 'error.balanceRefreshCached': 'Balance refresh failed; showing cached balance ({error})',\n 'error.usageRefreshCached': 'Usage refresh failed; showing cached usage ({error})',\n 'error.query': 'Request failed',\n 'error.credentialsUnavailable': 'Credential service is unavailable',\n 'error.credentialRead': 'Could not read the API key: {detail}',\n 'error.noApiKey': 'DEEPSEEK_API_KEY is not configured (add it under Settings \u2192 Models)',\n 'error.accountBalanceUnavailable': 'The account balance endpoint is unavailable and DEEPSEEK_API_KEY is not configured',\n 'error.balanceRequest': 'Balance request failed: {detail}',\n 'error.balanceHttp': 'Balance endpoint returned HTTP {status}',\n 'error.balanceParse': 'Could not parse the balance response',\n 'error.persistenceUnavailable': 'Session persistence is unavailable',\n 'error.sessionList': 'Could not read the session list: {detail}',\n 'error.sessionLogRead': 'Could not read the session log: {detail}',\n 'error.missingSessionId': 'Missing session id',\n 'alert.lowTitle': 'Balance {balance} {currency} is below the {threshold} warning threshold',\n 'alert.runway': '; about {days} left at recent usage',\n 'alert.topUp': 'Top up',\n 'balance.title': 'Account balance',\n 'balance.remaining': 'Remaining balance',\n 'balance.breakdownTitle': 'View topped-up and granted balance details',\n 'balance.toppedUp': 'Topped up {amount}',\n 'balance.granted': 'Granted {amount}',\n 'balance.runway': 'Estimated runway',\n 'balance.runwayBreakdownTitle': 'View estimated runway details',\n 'balance.topUpTitle': 'Low balance \u2014 top up on the DeepSeek platform (opens a new tab)',\n 'balance.days': '{count} days',\n 'balance.overYear': '> 365 days',\n 'balance.noRunway': 'No usage in the last {days} days, so runway cannot be estimated',\n 'balance.runwayTitle': 'Based on \u00A5{cost} average daily spend over the last {days} days (including idle days; today is incomplete)',\n 'balance.empty': 'Balance is unavailable. Check your sign-in or API key, then refresh.',\n 'sessionUsage.title': 'Current session spend',\n 'common.estimated': 'Estimated cost',\n 'sessionUsage.cost': 'Cost',\n 'sessionUsage.tokens': 'Tokens',\n 'sessionUsage.calls': 'Calls',\n 'sessionUsage.range': 'Active {range}',\n 'sessionUsage.single': '{model} \u00B7 input {input} / output {output} / cache {cache}',\n 'sessionUsage.empty': 'No usage in this session yet.',\n 'overview.title': 'Spend overview',\n 'overview.today': 'Today',\n 'overview.month': 'This month',\n 'overview.total': 'All time',\n 'overview.vsYesterday': 'vs yesterday',\n 'overview.vsLastMonth': 'vs same period last month',\n 'overview.empty': 'No spend to summarize yet.',\n 'usage.trendTitle': 'Usage trend',\n 'usage.windowInput': '{window} input',\n 'usage.modelCalls': 'Model calls',\n 'heatmap.title': 'Usage heatmap',\n 'peak.title': 'Peak / off-peak distribution',\n 'cache.title': 'Cache hits and savings',\n 'models.title': 'Model cost ranking',\n 'sessions.title': 'Session cost ranking',\n 'links.title': 'Quick Links',\n 'nav.label': 'On this page',\n 'nav.balance': 'Balance',\n 'nav.session': 'This session',\n 'nav.overview': 'Spend overview',\n 'nav.trend': 'Usage trend',\n 'nav.heatmap': 'Usage heatmap',\n 'nav.models': 'Model cost',\n 'nav.sessions': 'Session cost',\n 'nav.peakcache': 'Peak & cache',\n 'nav.settings': 'Settings',\n 'links.usage': 'View balance / usage',\n 'links.apiKey': 'Create API key',\n 'links.status': 'Service status',\n 'settings.title': 'Settings',\n 'settings.groupDisplay': 'Display',\n 'settings.groupAlerts': 'Alerts',\n 'settings.groupLayout': 'Layout & entry',\n 'settings.widget': 'Show the floating balance widget on other views',\n 'settings.widgetHint': 'Hidden on Usage; shown on the views selected below.',\n 'settings.widgetTabs': 'Show widget on',\n 'settings.widgetTabsHint': 'Updates automatically as views are installed.',\n 'settings.widgetTabsEmpty': 'There are no configurable conversation views right now.',\n 'settings.lowBalance': 'Balance warning',\n 'settings.lowBalanceOn': 'This page and the widget turn amber below {amount} {currency}. Enter 0 to disable.',\n 'settings.lowBalanceOff': 'Balance warnings are off. Enter an amount above 0 to enable them.',\n 'settings.monthlyBudget': 'Monthly budget',\n 'settings.monthlyBudgetOn': 'Track a {amount} CNY budget by Beijing calendar month and forecast month-end spend. Enter 0 to disable.',\n 'settings.monthlyBudgetOff': 'Enter an amount above 0 to show progress and a month-end forecast.',\n 'settings.sidebarEntry': 'Sidebar Usage entry',\n 'settings.sidebarEntryHint': 'Add a Usage entry at the top or bottom of the sidebar; it opens the account-wide Usage page.',\n 'settings.sidebarEntryOff': 'Off',\n 'settings.sidebarEntryTop': 'Top',\n 'settings.sidebarEntryBottom': 'Bottom',\n 'settings.tabPosition': 'Usage tab position',\n 'settings.tabPositionHint': 'Drag Usage to change its tab position.',\n 'settings.tabDragAria': 'Drag Usage to change its tab position',\n 'settings.tabMoveEarlier': 'Move earlier',\n 'settings.tabMoveLater': 'Move later',\n 'panel.caption': 'Account-wide \u00B7 across all sessions',\n 'panel.openAria': 'Open Usage',\n 'widget.updatedNow': 'Updated just now',\n 'widget.stale': 'Data from {minutes}m ago; press \u21BB to update',\n 'widget.loading': 'Loading\u2026',\n 'widget.lowTitle': 'Balance below warning threshold {amount}',\n 'widget.todayCostTitle': 'Today\u2019s spend (estimated) \u00B7 {age}',\n 'widget.todayCost': 'Today\u2019s spend',\n 'widget.sessionCostTitle': 'Estimated spend for the current session',\n 'widget.sessionCost': 'Current session',\n 'widget.noBalance': 'No balance data',\n 'widget.dragCard': 'Drag to any corner',\n 'widget.dragGrip': 'Drag to move',\n 'widget.refresh': 'Refresh balance and today\u2019s usage',\n 'widget.expand': 'Expand',\n 'widget.collapse': 'Collapse',\n 'widget.expandAria': 'Expand balance widget',\n 'widget.collapseAria': 'Collapse balance widget',\n 'messageCost.label': 'Turn cost',\n 'sessionCost.title': 'Session cost',\n 'sessionCost.aria': 'Estimated session cost {amount}',\n 'sessionCost.active': 'Active time',\n 'messageCost.tooltip': 'Provided by dsh-usage-dashboard \u00B7 estimated cost for this turn',\n 'messageCost.aria': '{amount}, estimated cost for this turn, provided by dsh-usage-dashboard',\n 'boundary.title': 'The usage dashboard crashed',\n 'boundary.body': 'Rendering failed, usually because this browser still has cached data from an older version. Clear this plugin\u2019s local data and reload to recover.',\n 'boundary.reset': 'Clear local data and reload',\n}\n", "/** Shared lookups into the DSH host shell DOM. Both the floating widget\n * (keeping its drag bounds clear of the header/composer) and the dashboard\n * (keeping its scroll content clear of the fixed composer on narrow\n * viewports) need to find the same host elements \u2014 sharing the lookup here\n * keeps the two readings of \"where is the composer\" from drifting apart.\n */\n\n/** The shell's main column: the region between the sidebar and the details\n * panel. Found through the stable `conversation` slot anchor rather than the\n * hashed layout class names. */\nexport function getMainColumn(frame: HTMLElement): HTMLElement | null {\n const anchor = frame.querySelector('[data-slot=\"conversation\"]')\n const column = anchor?.parentElement ?? null\n return column === frame ? null : column\n}\n\n/**\n * The laid-out element behind a slot. Slot wrappers are 0\u00D70, and which\n * neighbour carries the real box differs per slot: the session header\n * renders inside its wrapper (`'child'`), while the composer's wrapper sits\n * inside the seat that reserves the space (`'ancestor'`). Picking the wrong\n * side silently yields a box in the wrong place, so the caller says which one\n * it means.\n */\nfunction slotElement(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): HTMLElement | null {\n const anchor = frame.querySelector(`[data-slot=\"${slot}\"]`)\n if (anchor === null) return null\n if (side === 'child') {\n const el = anchor.firstElementChild as HTMLElement | null\n return el !== null && el.getBoundingClientRect().height > 0 ? el : null\n }\n let el: HTMLElement | null = anchor.parentElement\n for (let depth = 0; depth < 4 && el !== null && el !== frame; depth++) {\n if (el.getBoundingClientRect().height > 0) return el\n el = el.parentElement\n }\n return null\n}\n\n/** The laid-out box behind a slot (see `slotElement`), or null if the slot is\n * not currently present or not yet laid out. */\nexport function slotBox(frame: HTMLElement, slot: string, side: 'child' | 'ancestor'): DOMRect | null {\n return slotElement(frame, slot, side)?.getBoundingClientRect() ?? null\n}\n\n/** The DSH shell frame \u2014 the element that hosts the sidebar, conversation\n * column and fixed composer \u2014 found by walking up from any node inside our\n * own plugin root via the stable `[data-shell-overlay]` anchor. */\nexport function getShellFrame(node: HTMLElement | null): HTMLElement | null {\n const overlay = node !== null && typeof node.closest === 'function' ? node.closest('[data-shell-overlay]') : null\n return (overlay?.parentElement as HTMLElement | null) ?? null\n}\n\n/** The composer's laid-out box \u2014 the seat that reserves the composer's space,\n * or null if the slot is not present in the current DOM (host markup changed,\n * no session open, or mid-navigation). Callers that only need the box can\n * call `.getBoundingClientRect()`; callers that want to observe size changes\n * (e.g. `ResizeObserver`) need the element itself.\n *\n * Read `conversation.composer`, not the `.dock` sub-slot: the dock anchor\n * renders *inside* the composer card, and its nearest laid-out ancestor is a\n * 26px toolbar row (DSH 0.2.1), so measuring it reports a box that is both\n * far too short and ~100px below the composer's real top \u2014 the floating\n * widget then parks itself over the Send button instead of above it.\n *\n * `frame` may be null: the floating widget lives inside the shell overlay\n * subtree, but the dashboard's plugin root is mounted in the conversation\n * pane and cannot reach the shell frame that way. A frame-less call falls\n * back to a document-wide lookup \u2014 the composer is unique in the active\n * shell, so this cannot hit an ambiguous element. */\nexport function getComposerElement(frame: HTMLElement | null): HTMLElement | null {\n const root = frame ?? document.documentElement\n return slotElement(root, 'conversation.composer', 'ancestor')\n ?? slotElement(root, 'conversation.composer.dock', 'ancestor')\n}\n\n/**\n * The composer's *input card* \u2014 the rounded panel that visually IS the input\n * box (textarea + send row, ~780px max in DSH). The `.dock` seat found by\n * {@link getComposerElement} spans the whole pane, so its width is the wrong\n * answer for any width-parity goal: the visible input card is narrower, and\n * it is the column the dashboard cards must align with. The card is located\n * from the textarea's ancestor chain \u2014 the first ancestor with a visible\n * background and a non-zero border radius, the shape DSH gives the input\n * panel. Returns null when the host markup stops matching; callers then fall\n * back to {@link getComposerElement}. */\nexport function getComposerInputElement(frame: HTMLElement | null): HTMLElement | null {\n const root = frame ?? document.documentElement\n const textarea = root.querySelector(\n '[data-slot=\"conversation.composer\"] textarea, [data-slot=\"conversation.composer.bar\"] textarea, textarea',\n )\n if (textarea === null) return null\n let el = textarea.parentElement\n for (let depth = 0; depth < 6 && el !== null; depth++) {\n const cs = getComputedStyle(el)\n if (cs.borderRadius !== '0px' && cs.backgroundColor !== 'rgba(0, 0, 0, 0)') return el\n el = el.parentElement\n }\n return null\n}\n\n/** Resolve the active `conversation.view` id from the host's semantic tablist.\n * The DOM intentionally carries no view id, but it renders buttons in the\n * exact order of the slot ledger. Indexing into that same live ledger avoids\n * translated-label matching and remains compatible with third-party tabs. */\nexport function getActiveConversationViewId(\n frame: HTMLElement | null,\n viewIds: string[],\n): string | null {\n if (viewIds.length === 0) return null\n const header = frame === null ? null : slotElement(frame, 'conversation.session.header', 'child')\n const tablist = header?.querySelector('[role=\"tablist\"]') ?? null\n if (tablist === null) return viewIds[0] ?? null\n const tabs = [...tablist.querySelectorAll('[role=\"tab\"]')]\n const activeIndex = tabs.findIndex(tab => tab.getAttribute('aria-selected') === 'true')\n return activeIndex < 0 ? viewIds[0] ?? null : viewIds[activeIndex] ?? null\n}\n", "import type { UsageData } from '../contract.ts'\n\nconst BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000\n\n/** YYYYMMDD in DeepSeek's billing timezone. */\nexport function exportDateStamp(nowMs = Date.now()): string {\n const date = new Date(nowMs + BEIJING_OFFSET_MS)\n return [\n date.getUTCFullYear(),\n String(date.getUTCMonth() + 1).padStart(2, '0'),\n String(date.getUTCDate()).padStart(2, '0'),\n ].join('')\n}\n\n/** RFC 4180 cell escaping plus spreadsheet-formula neutralisation for labels. */\nexport function csvCell(value: string | number): string {\n let text = String(value)\n if (typeof value === 'string' && /^[=+\\-@]/.test(text)) text = `'${text}`\n return /[\",\\r\\n]/.test(text) ? `\"${text.replaceAll('\"', '\"\"')}\"` : text\n}\n\nconst csv = (rows: Array<Array<string | number>>): string =>\n `\\uFEFF${rows.map(row => row.map(csvCell).join(',')).join('\\r\\n')}\\r\\n`\n\nexport function dailyUsageCsv(usage: UsageData): string {\n return csv([\n ['date', 'input_tokens', 'output_tokens', 'cache_hit_tokens', 'total_tokens', 'calls', 'estimated_cost_cny'],\n ...usage.daily.map(day => [day.date, day.input, day.output, day.cache, day.total, day.calls, day.cost]),\n ])\n}\n\nexport function modelUsageCsv(usage: UsageData): string {\n return csv([\n ['provider', 'model', 'input_tokens', 'output_tokens', 'cache_hit_tokens', 'total_tokens', 'calls', 'estimated_cost_cny'],\n ...usage.models.map(model => [\n model.provider, model.model, model.input, model.output, model.cache, model.total, model.calls, model.cost,\n ]),\n ])\n}\n\nexport function fullUsageJson(usage: UsageData, nowMs = Date.now()): string {\n return `${JSON.stringify({\n schemaVersion: 1,\n exportedAt: new Date(nowMs).toISOString(),\n scope: 'local-dsh-session-logs',\n data: usage,\n }, null, 2)}\\n`\n}\n\nexport function downloadText(filename: string, text: string, mediaType: string): void {\n const url = URL.createObjectURL(new Blob([text], { type: mediaType }))\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.hidden = true\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n window.setTimeout(() => URL.revokeObjectURL(url), 0)\n}\n", "import { fallbackT, type Translate } from './i18n.tsx'\n\nexport type SyncState = 'syncing' | 'fresh' | 'cached' | 'fallback' | 'error'\n\n/** Short, stable freshness copy for the dashboard status row. */\nexport function updatedText(updatedAt: number | null, nowMs = Date.now(), t: Translate = fallbackT): string {\n if (updatedAt === null || !Number.isFinite(updatedAt)) return t('fresh.none')\n const elapsed = Math.max(0, nowMs - updatedAt)\n if (elapsed < 60_000) return t('fresh.justNow')\n const minutes = Math.floor(elapsed / 60_000)\n if (minutes < 60) return t('fresh.minutes', { count: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('fresh.hours', { count: hours })\n return t('fresh.days', { count: Math.floor(hours / 24) })\n}\n\nexport function syncStatusText(state: SyncState, updatedAt: number | null, nowMs = Date.now(), t: Translate = fallbackT): string {\n const age = updatedText(updatedAt, nowMs, t)\n if (state === 'syncing') return updatedAt === null ? t('sync.first') : t('sync.syncing', { age })\n if (state === 'fresh') return t('sync.fresh', { age })\n if (state === 'cached') return t('sync.cached', { age })\n if (state === 'fallback') return t('sync.fallback', { age })\n return t('sync.error')\n}\n", "import { fallbackT, type Translate } from './i18n.tsx'\n\n/** Value axis shared by daily, hourly, and per-model usage charts. */\nexport const CHART_METRICS = ['tokens', 'cost', 'calls'] as const\nexport type ChartMetric = (typeof CHART_METRICS)[number]\n\nexport interface ChartMetricPoint {\n total: number\n cost: number\n calls: number\n}\n\nexport const isChartMetric = (value: unknown): value is ChartMetric =>\n typeof value === 'string' && CHART_METRICS.some(metric => metric === value)\n\nexport function chartMetricValue(metric: ChartMetric, point: ChartMetricPoint): number {\n if (metric === 'cost') return point.cost\n if (metric === 'calls') return point.calls\n return point.total\n}\n\nexport function chartMetricName(metric: ChartMetric, t: Translate = fallbackT): string {\n if (metric === 'cost') return t('metric.cost')\n if (metric === 'calls') return t('metric.calls')\n return t('metric.usage')\n}\n", "/**\n * localStorage-backed user preferences for the plugin.\n *\n * Everything the user deliberately sets (widget visibility, the corner it was\n * dragged to, whether it is collapsed) belongs here so a page refresh does not\n * throw the choice away. Keys share one prefix and carry a version suffix so\n * the shape can evolve without reading back stale values.\n *\n * Every read is validated by the caller's guard: a corrupted or hand-edited\n * entry falls back instead of poisoning the UI.\n */\n\nconst PREFIX = 'dsh-usage-dashboard:pref:'\nconst VERSION = 1\n\nconst keyOf = (key: string): string => `${PREFIX}${key}:v${VERSION}`\n\nexport function loadPref<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): T {\n if (typeof localStorage === 'undefined') return fallback\n try {\n const raw = localStorage.getItem(keyOf(key))\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n return isValid(parsed) ? (parsed as T) : fallback\n } catch {\n return fallback\n }\n}\n\nexport function savePref(key: string, value: unknown): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(keyOf(key), JSON.stringify(value))\n } catch {\n // Quota / private-mode failures must never break the UI.\n }\n}\n\nexport const isBoolean = (value: unknown): boolean => typeof value === 'boolean'\n", "/**\n * Package-local stores for settings both surfaces read: the dashboard writes\n * them, the floating widget reacts. Every value is persisted (see ./prefs.ts),\n * so a choice survives a page refresh.\n */\nimport { USAGE_WINDOW_DAYS, type UsageWindowDays } from '../contract.ts'\nimport { isChartMetric, type ChartMetric } from './metric.ts'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\n\nexport interface Store<T> {\n get(): T\n set(value: T): void\n subscribe(fn: () => void): () => void\n}\n\nexport function createStore<T>(key: string, isValid: (value: unknown) => boolean, fallback: T): Store<T> {\n let current = loadPref<T>(key, isValid, fallback)\n const listeners = new Set<() => void>()\n return {\n get: () => current,\n set: (value: T) => {\n current = value\n savePref(key, value)\n for (const listener of [...listeners]) listener()\n },\n subscribe: (fn: () => void) => {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n }\n}\n\nconst isThreshold = (value: unknown): boolean =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0\n\n/** Whether the floating balance widget is shown. */\nexport const widgetVisibleStore = createStore<boolean>('widget.visible', isBoolean, true)\n\nconst isWidgetTabIds = (value: unknown): boolean => value === null\n || (Array.isArray(value) && value.every(id => typeof id === 'string' && id !== '')\n && new Set(value).size === value.length)\n\n/** Conversation view ids on which the widget is allowed to appear. `null`\n * means \"all available views\" and preserves the pre-setting default; once a\n * user customizes the list, newly installed plugin tabs arrive unchecked. */\nexport const widgetTabIdsStore = createStore<string[] | null>('widget.tabIds', isWidgetTabIds, null)\n\n/** Balance (in the account's own currency) below which both surfaces warn.\n * 0 turns the warning off. */\nexport const lowBalanceStore = createStore<number>('alert.lowBalance', isThreshold, 10)\n\n/** Monthly estimated-cost budget in CNY. 0 leaves budget tracking disabled. */\nexport const monthlyBudgetStore = createStore<number>('budget.monthly', isThreshold, 0)\n\nconst isUsageWindowDays = (value: unknown): value is UsageWindowDays =>\n typeof value === 'number' && USAGE_WINDOW_DAYS.some(days => days === value)\n\n/** Shared time range for the usage chart and both cost rankings. */\nexport const usageWindowStore = createStore<UsageWindowDays>('usage.windowDays', isUsageWindowDays, 30)\n\n/** Whether charts compare token volume, estimated CNY cost, or call count. */\nexport const chartMetricStore = createStore<ChartMetric>('usage.chartMetric', isChartMetric, 'tokens')\n\n/** Ephemeral presence of the full dashboard. The widget uses it to step out of\n * the way without changing the user's persisted visibility preference. */\nlet quotaViewActive = false\nconst quotaViewListeners = new Set<() => void>()\nexport const quotaViewActiveStore: Store<boolean> = {\n get: () => quotaViewActive,\n set: (value) => {\n if (value === quotaViewActive) return\n quotaViewActive = value\n for (const listener of [...quotaViewListeners]) listener()\n },\n subscribe: (fn) => {\n quotaViewListeners.add(fn)\n return () => {\n quotaViewListeners.delete(fn)\n }\n },\n}\n", "/**\n * Layout preferences shared by the dashboard's Settings section and the\n * client registration half (`./index.tsx`).\n *\n * These two sides must agree on two placement choices, and neither may import\n * the other (the registration half mounts the dashboard, so the reverse import\n * would be a cycle). Keeping the stores in their own module lets both read and\n * write the same persisted values.\n */\nimport { createStore, type Store } from './store.ts'\n\n/** The global panel id shared by the `main` slot entry and the sidebar entry\n * that selects it. Stable: it is only ever compared within this package. */\nexport const QUOTA_PANEL_ID = 'quota'\n\n/** Where the optional\u300C\u989D\u5EA6\u300Dshortcut, if enabled, lives in the sidebar. */\nexport type SidebarEntryPlacement = 'off' | 'top' | 'bottom'\n\nconst isPlacement = (value: unknown): value is SidebarEntryPlacement =>\n value === 'off' || value === 'top' || value === 'bottom'\n\n/**\n * `off` keeps the host's sidebar untouched (the default, so updating the\n * plugin never silently adds chrome). `top` joins the global-panel icon row;\n * `bottom` sits beside Settings in the sidebar foot.\n */\nexport const sidebarEntryStore: Store<SidebarEntryPlacement> =\n createStore<SidebarEntryPlacement>('layout.sidebarEntry', isPlacement, 'off')\n\nconst isTabIndex = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 50\n\n/**\n * Position of the\u300C\u989D\u5EA6\u300Dtab among the registered conversation views, as an\n * index in the live tab roster (0 = first). The registration half maps it onto\n * a slot `order` relative to the neighbouring entries, so it survives host\n * plugins arriving with their own orders. Default 2 reproduces the historical\n * fixed position: \u5BF9\u8BDD, \u8F68\u8FF9, \u989D\u5EA6.\n */\nexport const quotaTabIndexStore: Store<number> =\n createStore<number>('layout.tabIndex', isTabIndex, 2)\n\n/** One `conversation.view` slot entry, as far as ordering needs to see it. */\nexport interface ViewOrderEntry {\n options: { id?: string; order?: number }\n}\n\n/**\n * Clamp a persisted roster index into `[0, count]`; `count` itself is the\n * legal \"end of the list\" insertion position when there are `count` tabs.\n */\nexport function clampTabIndex(index: number, count: number): number {\n return Math.max(0, Math.min(index, Math.max(count, 0)))\n}\n\n/**\n * Turn a 0-based roster position into the `order` for our own view entry.\n *\n * The host sorts list entries by `order` (ties keep registration order), so\n * the placement is expressed relative to the live neighbours rather than as an\n * absolute number: the first/last positions step outside the current range,\n * and an interior position lands between the two adjacent orders (including\n * the degenerate equal-order case). Other entries are never touched.\n * @param entries - live `conversation.view` entries.\n * @param index - desired 0-based position in the roster *including* our tab.\n * @param selfId - this plugin's entry id (excluded from the anchor list).\n * @param fallback - order used while the host has no other view registered.\n * @returns the slot `order` for our registration.\n */\nexport function viewOrderForIndex(\n entries: readonly ViewOrderEntry[],\n index: number,\n selfId = 'balance',\n fallback = 20,\n): number {\n const others = entries.filter(entry => entry.options.id !== selfId)\n if (others.length === 0) return fallback\n const clamped = clampTabIndex(index, others.length)\n // The host sorts an omitted `order` as 0, so mirror that effective value\n // instead of inventing a per-position default.\n const orderAt = (position: number): number => others[position]?.options.order ?? 0\n if (clamped === 0) return orderAt(0) - 10\n if (clamped === others.length) return orderAt(others.length - 1) + 10\n const previous = orderAt(clamped - 1)\n const next = orderAt(clamped)\n return previous >= next ? previous + 0.5 : (previous + next) / 2\n}\n", "/** Where the top-up shortcuts send the user, on both surfaces that offer one. */\nexport const TOP_UP_URL = 'https://platform.deepseek.com/top_up'\n\n/** Balance (in the account's own currency) below which the shortcut is\n * offered regardless of the configurable warning line: that line can be\n * lowered or switched off (0), but a balance this close to zero still deserves\n * a one-click way out. */\nconst TOP_UP_FLOOR = 10\n\n/**\n * Whether the balance is low enough to offer the top-up shortcut.\n *\n * Two independent conditions, OR-ed on purpose: the fixed floor keeps the\n * shortcut available when warnings are disabled or set lower than 10, while a\n * raised warning line lets an early warning also carry the shortcut.\n * @param balance - account balance in its own currency; NaN/Infinity never qualifies.\n * @param warningLine - configured balance warning line; 0 disables that half.\n * @returns true when the \u53BB\u5145\u503C shortcut should be shown.\n */\nexport function needsTopUp(balance: number, warningLine: number): boolean {\n if (!Number.isFinite(balance)) return false\n return balance < TOP_UP_FLOOR || (warningLine > 0 && balance < warningLine)\n}\n", "/** Estimated spend contributed beside each completed chat turn. */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport type { SessionUsageData, TurnUsage } from '../contract.ts'\nimport { fetchSessionUsage, getCachedSessionUsage, subscribeSessionUsage } from './api.ts'\nimport { useI18n } from './i18n.tsx'\n\nexport interface MessageCostProps {\n sessionId: string\n messageId: string\n}\n\n/** Small costs need more than the dashboard's two-decimal money formatter or\n * almost every individual turn would misleadingly read as \u00A50.00. */\nexport const fmtTurnCost = (cost: number): string => cost.toLocaleString(undefined, {\n minimumFractionDigits: cost > 0 && cost < 0.01 ? 4 : 2,\n maximumFractionDigits: cost > 0 && cost < 0.01 ? 6 : 4,\n})\n\nconst cachedData = (sessionId: string): SessionUsageData | null => {\n const response = getCachedSessionUsage(sessionId)\n return response?.ok === true ? response.data ?? null : null\n}\n\nexport function MessageCost({ sessionId, messageId }: MessageCostProps): ReactElement | null {\n const { t } = useI18n()\n const [data, setData] = useState<SessionUsageData | null>(() => cachedData(sessionId))\n\n useEffect(() => {\n setData(cachedData(sessionId))\n const unsubscribe = subscribeSessionUsage(sessionId, () => setData(cachedData(sessionId)))\n const hit = cachedData(sessionId)?.turns.some(turn => turn.messageId === messageId) ?? false\n if (!hit) void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [messageId, sessionId])\n\n const turn: TurnUsage | undefined = data?.turns.find(candidate => candidate.messageId === messageId)\n if (turn === undefined) return null\n const amount = `\u00A5${fmtTurnCost(turn.cost)}`\n const tooltip = t('messageCost.tooltip')\n return (\n <span\n className=\"dq-message-cost\"\n tabIndex={0}\n data-dq-tooltip={tooltip}\n aria-label={t('messageCost.aria', { amount })}\n >\n <span className=\"dq-message-cost-separator\" aria-hidden>\u00B7</span>\n <span className=\"dq-message-cost-amount\">{amount}</span>\n </span>\n )\n}\n", "/**\n * Session cost pill in the composer dock (next to the host's\u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300Dand\n * \u300CToken \u7528\u91CF\u300Dpills). It shows the estimated spend of the whole conversation\n * and opens a small detail dialog above the dock \u2014 the same pill/dialog skin\n * the host uses for its own composer statistics, so the three read as one row.\n *\n * The figure comes from the plugin's own session-usage API (the same endpoint\n * the \u300C\u989D\u5EA6\u300Dtab's current-session card and the per-turn chip use), not from\n * host projections: cost has to follow this plugin's pricing table.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactElement } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { SessionUsageData } from '../contract.ts'\nimport { fetchSessionUsage, getCachedSessionUsage, subscribeSessionUsage } from './api.ts'\nimport { fmtInt } from './charts.tsx'\nimport { useI18n } from './i18n.tsx'\nimport { fmtTurnCost } from './message-cost.tsx'\nimport { ratesAt } from '../pricing.ts'\n\n/** Viewport margin kept by the dialog clamp. */\nconst PANEL_MARGIN = 12\n/** Distance between the pill's top edge and the dialog's bottom edge. */\nconst PANEL_GAP = 8\n\nconst cachedData = (sessionId: string): SessionUsageData | null => {\n const response = getCachedSessionUsage(sessionId)\n return response?.ok === true ? response.data ?? null : null\n}\n\n/** \u00A5 roundel, drawn at the host's 16-unit stroke-icon grid (rendered at 14px\n * by the pill, matching the neighbouring pills' glyph size). */\nfunction CostIcon(): ReactElement {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6\" />\n <path d=\"M5.5 5.3 8 8.4l2.5-3.1\" />\n <path d=\"M8 8.4v2.9\" />\n <path d=\"M5.8 9.5h4.4\" />\n <path d=\"M5.8 10.9h4.4\" />\n </svg>\n )\n}\n\n/** One session cost reading plus its click-open breakdown. */\nexport function SessionCostPill({ sessionId }: { sessionId?: string }): ReactElement | null {\n const { t, locale } = useI18n()\n const [data, setData] = useState<SessionUsageData | null>(\n () => (sessionId === undefined || sessionId === '' ? null : cachedData(sessionId)),\n )\n const [open, setOpen] = useState(false)\n const anchorRef = useRef<HTMLSpanElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n const [pos, setPos] = useState<{ left: number; bottom: number } | null>(null)\n\n useEffect(() => {\n if (sessionId === undefined || sessionId === '') return\n setData(cachedData(sessionId))\n const unsubscribe = subscribeSessionUsage(sessionId, () => setData(cachedData(sessionId)))\n // The per-turn chips fetch this same resource; skip a duplicate request\n // when one of them already warmed the cache for this session.\n if (getCachedSessionUsage(sessionId) === null) void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [sessionId])\n\n // Portal placement: fixed above the pill and clamped to the viewport, the\n // same geometry the host's stat dialogs use. Measuring happens after the\n // hidden first paint so the clamp uses the panel's real width.\n useLayoutEffect(() => {\n if (!open) {\n setPos(null)\n return\n }\n const anchor = anchorRef.current\n const panel = panelRef.current\n if (anchor === null || panel === null) return\n const pill = anchor.getBoundingClientRect()\n const width = panel.getBoundingClientRect().width\n setPos({\n left: Math.min(Math.max(pill.left, PANEL_MARGIN), Math.max(PANEL_MARGIN, window.innerWidth - width - PANEL_MARGIN)),\n bottom: window.innerHeight - pill.top + PANEL_GAP,\n })\n }, [open, data])\n\n // Outside pointerdown, Escape, resize and any scroll dismiss the dialog;\n // it is anchored to a dock that scrolls away with the conversation.\n useEffect(() => {\n if (!open) return\n const close = (): void => setOpen(false)\n const onPointerDown = (event: PointerEvent): void => {\n const target = event.target\n if (!(target instanceof Node)) return\n if (anchorRef.current?.contains(target) === true || panelRef.current?.contains(target) === true) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n window.addEventListener('resize', close)\n document.addEventListener('scroll', close, true)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n window.removeEventListener('resize', close)\n document.removeEventListener('scroll', close, true)\n }\n }, [open])\n\n if (sessionId === undefined || sessionId === '' || data === null || data.calls === 0) return null\n\n const amount = `\u00A5${fmtTurnCost(data.cost)}`\n // Money per billing bucket, not token counts: every model's recorded cost is\n // split across its three buckets in proportion to that bucket's share of the\n // bill at the session's own price era. Peak/off-peak multiply all three\n // buckets equally, so the share is not affected by when within the era the\n // session ran; the split still sums to the same total the pill shows.\n const priceAt = data.lastActive ?? Date.now()\n const split = data.models.reduce(\n (sum, model) => {\n const rates = ratesAt(priceAt, model.model)\n const weighted = {\n input: model.input * rates.input,\n cache: model.cache * rates.cacheHit,\n output: model.output * rates.output,\n }\n const weight = weighted.input + weighted.cache + weighted.output\n if (weight <= 0) return sum\n sum.input += model.cost * (weighted.input / weight)\n sum.cache += model.cost * (weighted.cache / weight)\n sum.output += model.cost * (weighted.output / weight)\n return sum\n },\n { input: 0, cache: 0, output: 0 },\n )\n const rangeTime = new Intl.DateTimeFormat(locale === 'en' ? 'en-US' : 'zh-CN', {\n timeZone: 'Asia/Shanghai', month: 'numeric', day: 'numeric',\n hour: '2-digit', minute: '2-digit', hour12: false,\n })\n const range = data.firstActive !== null && data.lastActive !== null\n ? `${rangeTime.format(data.firstActive)} \u2013 ${rangeTime.format(data.lastActive)}`\n : null\n\n return (\n <>\n <span ref={anchorRef} className=\"dq-cost-anchor\">\n <button\n type=\"button\"\n className=\"dq-cost-pill\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label={t('sessionCost.aria', { amount })}\n onClick={() => setOpen(value => !value)}\n >\n <CostIcon />\n <span className=\"dq-cost-pill-label\">{amount}</span>\n </button>\n </span>\n {open && createPortal(\n <div\n ref={panelRef}\n className=\"dq-cost-panel\"\n role=\"dialog\"\n aria-label={t('sessionCost.title')}\n style={pos === null\n ? { visibility: 'hidden', left: 0, top: 0 }\n : { visibility: 'visible', left: pos.left, bottom: pos.bottom, top: 'auto' }}\n >\n <div className=\"dq-cost-panel-title\">\n <span className=\"dq-cost-panel-title-label\">\n <CostIcon />\n {t('sessionCost.title')}\n </span>\n <span className=\"dq-cost-panel-value\">{amount}</span>\n </div>\n <div className=\"dq-cost-panel-rule\" aria-hidden />\n <dl className=\"dq-cost-details\">\n <dt>{t('common.input')}</dt>\n <dd>\u00A5{fmtTurnCost(split.input)}</dd>\n <dt>{t('common.cacheHit')}</dt>\n <dd>\u00A5{fmtTurnCost(split.cache)}</dd>\n <dt>{t('common.output')}</dt>\n <dd>\u00A5{fmtTurnCost(split.output)}</dd>\n <dt>{t('sessionUsage.calls')}</dt>\n <dd>{fmtInt(data.calls)}</dd>\n {range !== null && (\n <>\n <dt>{t('sessionCost.active')}</dt>\n <dd>{range}</dd>\n </>\n )}\n </dl>\n </div>,\n document.body,\n )}\n </>\n )\n}\n", "/**\n * DeepSeek API price table and cost estimation.\n *\n * Every record is priced with the table that was in force at the moment it was\n * written \u2014 CNY per 1M tokens, from DeepSeek's official pricing page:\n *\n * - until 2026-08-17 00:00 Beijing: one flat price per model;\n * - 2026-08-17 00:00: peak/off-peak pricing \u2014 peak windows 09:00\u201312:00 and\n * 14:00\u201318:00 every day, off-peak exactly half of peak;\n * - 2026-09-10 12:00: the V4.1-Flash price cut (flash 0.04/2/8 peak), and the\n * peak windows narrow to Monday\u2013Friday;\n * - 2026-09-14 12:00: `deepseek-v4-pro` requests are served by V4.1-Flash and\n * billed at Flash rates until a V4.1 Pro ships.\n *\n * `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp` are legacy names for\n * the model now published as `deepseek-flash`; both keep billing at Flash\n * rates. Images cost tokens rather than a multiplier of their own: they are\n * converted by size and priced together with the text tokens. Historical days\n * therefore keep the price that was actually charged.\n *\n * Editing this table is the one place to touch when DeepSeek changes prices.\n */\nimport type { PricingInfo, PricingRates } from './contract.ts'\n\n/** 2026-08-17 00:00 Beijing time (UTC+8), when peak/off-peak pricing took effect. */\nexport const PEAK_PRICING_FROM_MS = Date.UTC(2026, 7, 16, 16, 0, 0)\n\n/** 2026-09-10 12:00 Beijing, when the V4.1-Flash prices and the weekday-only\n * peak windows took effect. */\nexport const V41_FLASH_PRICING_FROM_MS = Date.UTC(2026, 8, 10, 4, 0, 0)\n\n/** 2026-09-14 12:00 Beijing, from when `deepseek-v4-pro` requests are routed\n * to V4.1-Flash and billed at Flash rates. */\nexport const PRO_ROUTED_TO_FLASH_FROM_MS = Date.UTC(2026, 8, 14, 4, 0, 0)\n\n/** Peak hours in Beijing time, as [startHour, endHour) pairs. */\nconst PEAK_WINDOWS: Array<[number, number]> = [[9, 12], [14, 18]]\n\nconst BEIJING_OFFSET_MS = 8 * 3_600_000\n\ntype Tier = 'pro' | 'flash' | 'vision'\n\n/** Flat rates in effect until 2026-08-17. */\nconst FLAT_RATES: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.025, input: 3, output: 6 },\n flash: { cacheHit: 0.02, input: 1, output: 2 },\n // The vision model billed at flash rates from day one, so its pre-switch\n // history is costed at the same flat prices as flash.\n vision: { cacheHit: 0.02, input: 1, output: 2 },\n}\n\n/** Peak rates from 2026-08-17; off-peak is exactly half of each. */\nconst PEAK_RATES_08_17: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.3, input: 9, output: 27 },\n flash: { cacheHit: 0.1, input: 3, output: 9 },\n // Official policy: the vision model is priced identically to flash; images\n // cost tokens, not their own multiplier.\n vision: { cacheHit: 0.1, input: 3, output: 9 },\n}\n\n/** Peak rates from 2026-09-10, the V4.1-Flash table; off-peak is half. */\nconst PEAK_RATES_09_10: Record<Tier, PricingRates> = {\n pro: { cacheHit: 0.3, input: 9, output: 27 },\n flash: { cacheHit: 0.04, input: 2, output: 8 },\n vision: { cacheHit: 0.04, input: 2, output: 8 },\n}\n\n/** One dated price table; `fromMs` is inclusive. */\ninterface PriceEra {\n readonly fromMs: number\n readonly peak: Record<Tier, PricingRates>\n /** Whether the peak windows apply Monday\u2013Friday only. */\n readonly weekdaysOnly: boolean\n}\n\n/** Oldest first \u2014 the last entry whose `fromMs` has passed is the one in force. */\nconst PRICE_ERAS: readonly PriceEra[] = [\n { fromMs: PEAK_PRICING_FROM_MS, peak: PEAK_RATES_08_17, weekdaysOnly: false },\n { fromMs: V41_FLASH_PRICING_FROM_MS, peak: PEAK_RATES_09_10, weekdaysOnly: true },\n]\n\n/** The price table in force at a moment. */\nfunction eraAt(timeMs: number): PriceEra {\n let era = PRICE_ERAS[0]\n for (const candidate of PRICE_ERAS) if (timeMs >= candidate.fromMs) era = candidate\n return era\n}\n\nconst halved = (rates: PricingRates): PricingRates => ({\n cacheHit: rates.cacheHit / 2,\n input: rates.input / 2,\n output: rates.output / 2,\n})\n\n/** Which price tier a model name falls into; anything unrecognised is billed\n * as pro, the conservative (more expensive) guess. Vision is matched first:\n * `deepseek-v4-flash-vision-exp` also contains \"flash\". */\nexport function tierOf(model: string): Tier {\n const name = model.toLowerCase()\n if (name.includes('vision')) return 'vision'\n if (name.includes('flash')) return 'flash'\n return 'pro'\n}\n\n/** The tier a model actually bills at: from 2026-09-14 `deepseek-v4-pro`\n * requests are served by V4.1-Flash and charged the Flash price. */\nfunction billedTierOf(timeMs: number, model: string): Tier {\n const tier = tierOf(model)\n return tier === 'pro' && timeMs >= PRO_ROUTED_TO_FLASH_FROM_MS ? 'flash' : tier\n}\n\n/** Beijing-time Monday\u2013Friday, which the peak windows honour from 2026-09-10. */\nfunction isBeijingWeekday(timeMs: number): boolean {\n const day = new Date(timeMs + BEIJING_OFFSET_MS).getUTCDay()\n return day >= 1 && day <= 5\n}\n\n/**\n * Image token conversion (DeepSeek official rule, Vision guide):\n * - Images below roughly 384\u00D7384 pixels are scaled UP preserving aspect\n * ratio; larger images are scaled DOWN so their pixel count is roughly that\n * of an 800\u00D7800 image.\n * - Tokens are proportional to the (resized) pixel count, capped at 384\n * tokens per image, so 2000\u00D72000 and 5000\u00D75000 cost the same.\n * - Each image is counted independently; `detail: low` caps at 512\u00D7512.\n *\n * The estimate is for the \"how much came from images\" breakdown; the exact\n * provider count is already folded into the usage record's `inputTokens`.\n * Returns tokens (possibly fractional) \u2014 0 for missing/invalid dimensions.\n */\nexport function estimateImageTokens(width: number, height: number): number {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return 0\n const area = width * height\n const scaledArea = Math.min(800 * 800, Math.max(384 * 384, area))\n return 384 * (scaledArea / (800 * 800))\n}\n\n/** Whether a moment falls in a peak window, judged in Beijing time so the\n * estimate does not drift with the machine's timezone. */\nexport function isPeak(timeMs: number): boolean {\n if (eraAt(timeMs).weekdaysOnly && !isBeijingWeekday(timeMs)) return false\n const hour = Math.floor((((timeMs + BEIJING_OFFSET_MS) % 86_400_000) + 86_400_000) % 86_400_000 / 3_600_000)\n return PEAK_WINDOWS.some(([from, to]) => hour >= from && hour < to)\n}\n\n/** Rates applying to one model at one moment. */\nexport function ratesAt(timeMs: number, model: string): PricingRates {\n if (timeMs < PEAK_PRICING_FROM_MS) return FLAT_RATES[tierOf(model)]\n const peak = eraAt(timeMs).peak[billedTierOf(timeMs, model)]\n return isPeak(timeMs) ? peak : halved(peak)\n}\n\n/**\n * What prefix caching saved on one record: the cache-hit tokens re-priced at\n * the cache-miss rate, minus what they actually cost.\n */\nexport function cacheSavingOf(timeMs: number, model: string, cache: number): number {\n const rates = ratesAt(timeMs, model)\n return (cache * (rates.input - rates.cacheHit)) / 1_000_000\n}\n\nconst applyRates = (rates: PricingRates, input: number, cache: number, output: number): number =>\n (input * rates.input + cache * rates.cacheHit + output * rates.output) / 1_000_000\n\n/** Estimated CNY cost of one usage record. */\nexport function costOf(timeMs: number, model: string, input: number, cache: number, output: number): number {\n return applyRates(ratesAt(timeMs, model), input, cache, output)\n}\n\n/**\n * The same record priced as if it had landed in an idle window \u2014 used to\n * answer \"what would shifting work off-peak save me\". Prices come from the\n * newest table, the one in force now: the question is about scheduling the\n * next batch, not about re-pricing history.\n */\nexport function costUnderPeakEra(timeMs: number, model: string, input: number, cache: number, output: number, forceOffPeak = false): number {\n const peak = PRICE_ERAS[PRICE_ERAS.length - 1].peak[billedTierOf(timeMs, model)]\n const rates = !forceOffPeak && isPeak(timeMs) ? peak : halved(peak)\n return applyRates(rates, input, cache, output)\n}\n\n/** The price table to show the user: the two models the official docs list,\n * so the rows match the page they come from \u2014 legacy names, image tokens and\n * the pro routing live in the small print next to the table. */\nexport function pricingInfo(nowMs: number): PricingInfo {\n const era = eraAt(nowMs)\n const row = (model: string, tier: Tier) => ({ model, peak: era.peak[tier], offPeak: halved(era.peak[tier]) })\n return {\n currency: 'CNY',\n switchDate: '2026-08-17',\n inPeakNow: isPeak(nowMs),\n peakWindows: ['09:00\u201312:00', '14:00\u201318:00'],\n tiers: [row('deepseek-flash', 'flash'), row('deepseek-v4-pro', 'pro')],\n }\n}\n", "/** All plugin styles in one sheet, injected once at client load. */\n\nexport const css = `\n/* The widget is injected into the host's overlay layer (z-index:20), which is a\n stacking context \u2014 its own z-index only orders it among that layer's children.\n 1 = above the host's in-layer content, never above a modal. */\n.dsh-quota-root{-webkit-text-size-adjust:100%;text-size-adjust:100%;position:absolute;right:16px;bottom:16px;z-index:1;pointer-events:auto;opacity:1;visibility:visible;font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.45;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary,#1f2328);--dq-text-success:#1a7f37;--dq-text-success:color-mix(in oklab,var(--dsw-alias-state-success-primary,#2da44e) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);--dq-text-warn:#9a6700;--dq-text-warn:color-mix(in oklab,var(--dsw-alias-state-warn-primary,#bf8700) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1),opacity .16s ease-out,visibility 0s linear}\n.dsh-quota-root.dsh-quota-root--hidden{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .14s ease-out,visibility 0s linear .14s}\n.dsh-quota-root.dsh-quota-dragging{transition:none}\n.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}\n.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}\n.dsh-quota-root.dsh-quota-dragging .dsh-quota-card{cursor:grabbing;box-shadow:0 12px 32px rgba(0,0,0,.28)}\n.dsh-quota-header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;min-width:0}\n.dsh-quota-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden}\n.dsh-quota-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-quota-grip{color:var(--dsw-alias-label-secondary,#59636e);opacity:.7;font-size:12px;letter-spacing:0;cursor:grab;flex:none}\n.dsh-quota-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#2da44e);flex:none}\n.dsh-quota-dot--error{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dsh-quota-dot--warn{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dsh-quota-total--low{color:var(--dq-text-warn)!important}\n.dsh-quota-dot--idle{background:var(--dsw-alias-label-secondary,#59636e);opacity:.6}\n.dsh-quota-collapsed-total-row{margin-top:6px}\n.dsh-quota-collapsed-total{font-weight:700;font-size:13px;color:var(--dsw-alias-state-business-primary,#0969da);font-variant-numeric:tabular-nums}\n.dsh-quota-actions{display:flex;gap:2px;flex:none}\n.dsh-quota-btn{border:none;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);padding:3px 7px;border-radius:6px;font-size:13px;line-height:1}\n.dsh-quota-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));color:var(--dsw-alias-label-primary,#1f2328)}\n.dsh-quota-btn:active:not(:disabled){transform:scale(.92)}\n.dsh-quota-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dsh-quota-btn:disabled{opacity:.5;cursor:default}\n.dsh-quota-body{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-remaining-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-bottom:2px}\n.dsh-quota-total{font-size:18px;font-weight:700;color:var(--dsw-alias-label-primary,#1f2328);letter-spacing:-.02em;line-height:1.2;font-variant-numeric:tabular-nums}\n.dsh-quota-currency{font-size:13px;font-weight:500;margin-left:4px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:12px}\n.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-message-cost{-webkit-text-size-adjust:100%;text-size-adjust:100%;position:relative;display:inline-flex;align-items:center;order:10;gap:10px;height:28px;color:var(--dsw-alias-label-tertiary,#59636e);font-size:12px;line-height:20px;font-variant-numeric:tabular-nums;white-space:nowrap;cursor:help}\n.dq-message-cost-separator{cursor:default}\n.dq-message-cost-amount{text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;text-underline-offset:4px}\n.dq-message-cost:hover{color:var(--dsw-alias-label-secondary,#3f4852)}\n.dq-message-cost:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px;border-radius:4px}\n.dq-message-cost::after{content:attr(data-dq-tooltip);position:absolute;left:0;bottom:calc(100% + 6px);top:auto;z-index:2147483001;width:max-content;max-width:min(240px,calc(100vw - 24px));padding:6px 9px;border-radius:8px;background:var(--dsw-alias-tooltip-bg,#1f2328);color:var(--dsw-static-neutral-bluish-00,#fff);box-shadow:0 6px 18px rgba(0,0,0,.22);font-size:12px;font-weight:400;line-height:1.5;text-align:left;white-space:normal;pointer-events:none;opacity:0;visibility:hidden;transform:translateY(3px);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear .12s}\n.dq-message-cost:hover::after,.dq-message-cost:focus-visible::after{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear}\n@media (hover:hover){\n [data-time-hover-root] .dq-message-cost{opacity:0;transition:opacity 80ms ease}\n [data-time-hover-root]:hover .dq-message-cost,[data-time-hover-root]:focus-within .dq-message-cost{opacity:1}\n}\n/* Composer-dock session cost pill: one more reading beside the host's own\n \u300C\u4F1A\u8BDD\u7EDF\u8BA1\u300D/\u300CToken \u7528\u91CF\u300Dpills (same slot, same compact skin). */\n.dq-cost-anchor{display:inline-flex;min-width:0;font-size:calc(var(--dsh-content-font-size-secondary,13px) - 1px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}\n.dq-cost-pill{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;max-width:100%;padding:1px 8px;border:0;border-radius:var(--dsw-radius-sm,8px);background:transparent;color:var(--dsw-alias-label-tertiary,#59636e);font:inherit;font-variant-numeric:tabular-nums;line-height:inherit;white-space:nowrap;cursor:pointer}\n.dq-cost-pill:hover,.dq-cost-pill[aria-expanded=\"true\"]{background:var(--dsw-alias-interactive-bg-hover,rgba(120,130,150,.12));color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cost-pill:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-cost-pill svg{flex:none}\n.dq-cost-pill-label{min-width:0;overflow:hidden;text-overflow:ellipsis}\n/* Click-open breakdown: the host stat-dialog skin (menu surface, prominent\n elevation, 12/18 rows), portaled to the body and placed above the pill. */\n.dq-cost-panel{position:fixed;z-index:1100;box-sizing:border-box;width:max-content;min-width:min(300px,calc(100vw - 24px));max-width:min(440px,calc(100vw - 24px));padding:16px;border:0;border-radius:var(--dsw-radius-lg,16px);background:var(--dsw-specific-menu,var(--dsw-alias-bg-overlay,#fff));-webkit-backdrop-filter:var(--dsw-menu-backdrop-filter,blur(40px) saturate(150%));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(40px) saturate(150%));box-shadow:var(--dsw-elevation-prominent,0 12px 32px rgba(0,0,0,.24));font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#59636e);cursor:default}\n.dq-cost-panel-title{display:flex;justify-content:space-between;gap:16px;margin-bottom:8px;color:var(--dsw-alias-label-primary,#1f2328);font-weight:500}\n.dq-cost-panel-title-label{display:inline-flex;align-items:center;gap:6px;min-width:0}\n.dq-cost-panel-title-label svg{flex:none}\n.dq-cost-panel-value{font-variant-numeric:tabular-nums}\n.dq-cost-panel-rule{margin-bottom:10px;border-top:.5px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}\n.dq-cost-details{display:grid;grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-cost-details dt,.dq-cost-details dd{min-width:0;margin:0}\n.dq-cost-details dd{color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;text-align:right}\n/* \u5361\u7247\u95F4\u8DDD\uFF08\u6B64\u5904 gap\uFF09\u523B\u610F\u5927\u4E8E\u5361\u5185\u5C0F\u8282\u95F4\u8DDD\uFF08margin-top:12/14/16px \u90A3\u4E00\u6863\uFF09\uFF0C\u5236\u9020\"\u5361\u7247\u5916\u758F\u3001\u5361\u7247\u5185\u5BC6\"\u7684\n \u758F\u5BC6\u5BF9\u6BD4\uFF1A24px \u76F8\u5BF9\u5361\u5185\u6700\u5927\u6863 16px \u4ECD\u6709 1.5 \u500D\u7EA7\u5DEE\uFF0C\u76F8\u5BF9\u5E38\u89C1\u6863 12px \u6709 2 \u500D\u7EA7\u5DEE\uFF0C\u4E0D\u4E0E .dq-card \u7684\n padding\uFF0816px/20px\uFF0C\u5361\u7247\u5185\u90E8\u547C\u5438\u611F\uFF0C\u8F6E\u6B21 36 \u5DF2\u5B9A\uFF09\u6DF7\u540C\u3002 */\n/* Width parity with the host composer: the dashboard column reserves the\n same max-width as the conversation reading column (860px, \u8F6E\u6B21 42 kept it\n deliberately), but on narrower viewports the fixed 860px would overhang\n the input box \u2014 measured in dashboard.tsx as --dq-composer-w, capped at\n the reading-column width so wide viewports are unchanged. */\n.dq-balance{-webkit-text-size-adjust:100%;text-size-adjust:100%;box-sizing:border-box;width:100%;min-width:0;display:flex;flex-direction:column;gap:32px;padding:20px 24px 48px;max-width:min(860px,var(--dq-composer-w,860px));margin:0 auto;font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.5;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary,#1f2328);--dq-text-success:#1a7f37;--dq-text-success:color-mix(in oklab,var(--dsw-alias-state-success-primary,#2da44e) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);--dq-text-warn:#9a6700;--dq-text-warn:color-mix(in oklab,var(--dsw-alias-state-warn-primary,#bf8700) 52%,var(--dsw-alias-label-primary,#1f2328) 48%);}\n@media (max-width:620px){.dq-balance{max-width:100%;gap:24px;padding:16px 12px calc(var(--dq-composer-h,126px) + 16px)}.dq-card{padding:16px}.dq-card--hero{padding:0 16px}.dq-status-row{padding:0 16px}}\n/* \u8F6E\u6B21 55\uFF1A\u53EA\u6709\u4E3B\u5361\u7247\u5E26\u6846\u3002\u6B21\u7EA7\u5206\u6790\u4E0E\u8BBE\u7F6E\u662F\u65E0\u6846\u5C0F\u8282\uFF0C\u9760 32px \u6BB5\u8DDD\u548C 13px \u4E3B\u8272\u6807\u9898\u5206\u7EC4\uFF1B\n \u5DE6\u53F3 20px \u5185\u8FB9\u8DDD\u8BA9\u5B83\u4EEC\u7684\u6587\u5B57\u8FB9\u4E0E\u4E3B\u5361\u7247\u5185\u6587\u5BF9\u9F50\uFF0C\u6574\u9875\u53EA\u6709\u4E00\u6761\u6587\u5B57\u5DE6\u8FB9\u7EBF\u3002 */\n.dq-card{box-sizing:border-box;min-width:0;max-width:100%;padding:20px;background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.10));border-radius:12px}\n.dq-card-title{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 8px;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 16px;letter-spacing:0;text-wrap:balance}\n.dq-card-caption{font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}\n.dq-card-head .dq-card-title{margin:0}\n.dq-card-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;min-width:0}\n/* \u4E3B\u5361\u7247\uFF08\u4F59\u989D/\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017/\u6D88\u8017\u6982\u89C8/\u7528\u91CF\u8D8B\u52BF\uFF0C\u8F6E\u6B21 45 \u65B0\u589E\u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300D\uFF09\u89C6\u89C9\u6743\u91CD\u9AD8\u4E8E\u6B21\u7EA7\u5206\u6790\n \u5361\u7247\u4E0E\u5BFC\u822A\u7C7B\u5361\u7247\uFF1A\u53EA\u8C03\u6392\u7248\u5C5E\u6027\u2014\u2014\u5185\u8FB9\u8DDD\u3001\u6807\u9898\u5B57\u53F7\u5B57\u91CD\u4E0E\u53D6\u8272\u3001\u8FB9\u6846\u6DF1\u6D45\u2014\u2014\u4E0D\u5F15\u5165\u65B0\u914D\u8272\u4F53\u7CFB\u3002\u4E24\u6761\u89C4\u5219\n \u4E0E\u4E0A\u9762\u7684\u57FA\u7840\u89C4\u5219\u540C\u4E3A\u5355\u7C7B\u9009\u62E9\u5668\u4E14\u6E90\u7801\u987A\u5E8F\u66F4\u9760\u540E\uFF0C\u5929\u7136\u8986\u76D6\uFF0C\u4E0D\u9700\u8981 !important\u3002\u6B21\u7EA7\u5206\u6790\u5361\u7247\uFF08\u7528\u91CF\n \u70ED\u529B\u56FE/\u9AD8\u5CF0\u95F2\u65F6/\u7F13\u5B58\u547D\u4E2D/\u6A21\u578B\u6392\u884C/\u4F1A\u8BDD\u6392\u884C\uFF09\u4E0E\u5BFC\u822A\u7C7B\u5361\u7247\uFF08\u8BBE\u7F6E\uFF0C\u542B\u8F6E\u6B21 39 \u5E76\u5165\u7684\u5B98\u65B9\u5E73\u53F0\u94FE\u63A5\uFF09\u90FD\u4E0D\u52A0\n \u8FD9\u4E2A\u4FEE\u9970\u7C7B\uFF0C\u7EF4\u6301\u539F\u6709 .dq-card \u57FA\u7EBF\uFF0C\u5F62\u6210\u4E24\u6863\u6743\u91CD\u3002\u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300D\u5347\u7EA7\u4E3A\u4E3B\u5361\u7247\u7684\u7406\u7531\uFF1A\u5B83\u548C\u4F59\u989D\u4E00\u6837\u662F\n \u6253\u5F00\u8FD9\u4E2A\u300C\u989D\u5EA6\u300Dtab \u65F6\u4E0A\u4E0B\u6587\u6700\u76F4\u63A5\u76F8\u5173\u7684\u6570\u5B57\uFF08\u8FD9\u4E2A tab \u6302\u5728\u5177\u4F53\u4F1A\u8BDD\u5185\u90E8\uFF0C\u89C1 DESIGN_NOTES\u300C\u4FE1\u606F\u5C42\u7EA7\u300D\uFF09\uFF0C\n \u4E0D\u5C5E\u4E8E\u539F\u6709\u8D26\u6237\u5168\u5C40\u5C42\u7EA7 1-3 \u7684\u4EFB\u4F55\u4E00\u7EA7\uFF0C\u800C\u662F\u4E0E\u4E4B\u6B63\u4EA4\u7684\u53E6\u4E00\u4E2A\u7EF4\u5EA6\uFF0C\u4F46\u540C\u6837\u662F\u9996\u5C4F\u5FC5\u8BFB\uFF0C\u56E0\u6B64\u540C\u6837\u7ED9\n primary \u6743\u91CD\uFF0C\u4E0D\u65B0\u5F00\u7B2C\u4E09\u6863\u3002 */\n.dq-card--primary{padding:20px;border-color:var(--dsw-alias-border-l3,rgba(0,0,0,.12))}\n/* \u4F59\u989D\u662F\u6574\u9875\u552F\u4E00\u7684 hero\uFF1A\u4E0D\u5957\u6846\uFF0C32px \u6570\u5B57\u72EC\u5360\u4E00\u6863\uFF0C\u8BA9\u5B83\u5728\u906E\u4F4F\u6587\u5B57\u65F6\u4ECD\u662F\u7B2C\u4E00\u773C\u3002 */\n.dq-card--hero{padding:0 20px;background:transparent;border:0;border-radius:0}\n.dq-card-pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(340px,100%),1fr));gap:24px;min-width:0}\n.dq-card--hero .dq-stat-label{font-size:13px;margin-bottom:2px}\n.dq-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.dq-card--hero .dq-balance-grid{align-items:stretch;gap:12px 48px}\n.dq-card--hero .dq-stat{display:flex;flex-direction:column;justify-content:space-between}\n/* hero \u6570\u5B57\u4E0D\u753B\u70B9\u72B6\u4E0B\u5212\u7EBF\uFF0840px \u4E0B\u592A\u91CD\uFF09\uFF1B\u53EF\u70B9\u6027\u9760\u60AC\u505C\u5E95\u8272\u548C title \u63D0\u793A\u3002 */\n.dq-card--hero details>summary{text-decoration:none;margin:-2px -6px;padding:2px 6px;border-radius:8px;transition:background .15s ease}\n.dq-card--hero details>summary:hover,.dq-card--hero details[open]>summary{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.05))}\n@media (max-width:620px){.dq-card{padding:16px}.dq-card--hero{padding:0 16px}}\n.dq-window-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.08))}\n.dq-window-btn{border:0;border-radius:6px;padding:4px 8px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;white-space:nowrap;cursor:pointer;transition:background .15s ease,color .15s ease,box-shadow .15s ease}\n.dq-window-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-window-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.12)}\n.dq-window-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n@media (max-width:620px){.dq-card-head{align-items:flex-start;flex-wrap:wrap}.dq-card-actions{width:100%;justify-content:space-between}}\n.dq-export{position:relative;flex:none}\n.dq-export-btn{min-width:58px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease,background .15s ease}\n.dq-export-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-export-btn--done{border-color:rgba(45,164,78,.35);color:var(--dsw-alias-state-success-primary,#1a7f37);background:rgba(45,164,78,.08)}\n.dq-export-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:180px;padding:6px;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);display:flex;flex-direction:column;gap:2px}\n.dq-export-menu button{display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;border:0;border-radius:6px;padding:7px 8px;background:transparent;color:var(--dsw-alias-label-primary,#1f2328);font-size:12px;text-align:left;cursor:pointer}\n.dq-export-menu button:hover,.dq-export-menu button:focus-visible{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-export-menu button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-1px}\n.dq-export-menu small{font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e);white-space:nowrap}\n/* Small-text tier system (\u8F6E\u6B21 41 \u6536\u655B): two whole-pixel tiers replace what used to be four values\n (11/11.5/12/12.5px) spaced only 0.5px apart \u2014 a gap browsers subpixel-round away, so it read as one\n size with extra maintenance cost, not an actual visual hierarchy. 11px = \"micro\" chrome the user\n scans rather than reads (dt-style stat/period labels, delta/status/coverage pills, share %, tags,\n the widget grip) \u2014 kept as-is. 12px = \"secondary text\" (section titles, hint/footnote/legend/sub\n prose, table cells, tooltip copy, alert/empty-state sentences, and filter/segmented-control button\n labels like .dq-window-btn/.dq-chart-switch-btn, which are the same control family and should share\n one size) \u2014 absorbed the old 11.5px and 12.5px selectors, all by rounding toward the nearer tier\n (11.5\u219212 grows slightly for legibility, safe because none of the affected containers are width-\n capped; 12.5\u219212 shrinks by 0.5px on two full-sentence blocks, imperceptible). Weight/color still do\n the job of separating titles from body text within the 12px tier, same as before this merge. Do not\n reintroduce a fractional-px value in this range; if a selector needs to stand apart from these two,\n it belongs in an already-established different tier (10px icon glyphs, 13px+ hero-adjacent text). */\n.dq-balance-grid{display:flex;flex-wrap:wrap;gap:12px 24px}\n.dq-stat{min-width:110px}\n.dq-stat-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-bottom:4px}\n.dq-stat-value{font-size:18px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-stat-value--ok{color:var(--dq-text-success)}\n.dq-stat-value--bad{color:var(--dsw-alias-state-error-primary,#cf222e)}\n/* \u8F6E\u6B21 43: .dq-runway is a controlled <details> (see dashboard.tsx) \u2014 hover/toggle state\n drives the real open attribute now, so .dq-runway-detail only needs to react to [open];\n an unopened <details>'s non-summary children don't actually render in current Chromium no\n matter what display value author CSS gives them (:hover{display:block} alone is a dead end). */\n.dq-runway{position:relative}\n.dq-runway>summary{display:inline-block;list-style:none;border-radius:4px;cursor:pointer;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-runway>summary::-webkit-details-marker{display:none}\n.dq-runway>summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:3px}\n.dq-runway-detail{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;max-width:240px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:normal;font-size:12px;font-weight:500;line-height:1.6;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-runway[open] .dq-runway-detail{display:block}\n/* hero number for the balance, matching .dq-period-cost; relies on cascade order (declared after\n .dq-stat-value, same specificity) to win over the .dq-stat-value it's paired with in JSX \u2014 keep it below */\n/* \u8F6E\u6B21 47: .dq-remaining is a controlled <details> too now (see dashboard.tsx), same reason as\n .dq-runway above \u2014 an unopened <details>'s non-summary children don't actually render in current\n Chromium regardless of author display value, so the old :hover{display:flex} branch was dead code. */\n.dq-remaining{position:relative;font-size:32px;font-weight:700;letter-spacing:-.025em;line-height:1.1}\n.dq-hero-unit{font-size:13px;font-weight:500;letter-spacing:0;margin-left:4px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-remaining>summary{display:inline-block;list-style:none;border-radius:4px;cursor:pointer;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-remaining>summary::-webkit-details-marker{display:none}\n.dq-remaining>summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:3px}\n.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-remaining[open] .dq-remaining-breakdown{display:flex}\n.dq-remaining-granted{color:var(--dsw-alias-label-secondary,#59636e);font-weight:400;font-size:12px}\n/* Low-balance top-up shortcut beside the runway value. It is an <a>, not a\n <button>, because it leaves the app; the \u2197 glyph states that. Colours come\n from the host's primary-button tokens (the same pair DSH's own filled\n buttons use) so the page keeps exactly one filled call to action instead of\n reading as another filter chip. Height stays on the runway text line so the\n hero row does not grow. */\n.dq-runway-line{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px}\n.dq-topup{display:inline-flex;align-items:center;gap:2px;height:26px;padding:0 10px;border-radius:var(--dsw-radius-sm,8px);background:var(--dsw-alias-button-primary-fill,#0969da);color:var(--dsw-alias-label-primary-foreground,#fff);font-size:12px;font-weight:600;line-height:1;text-decoration:none;white-space:nowrap;transition:background .15s ease}\n.dq-topup:hover{background:var(--dsw-alias-button-primary-hover,#0757ba)}\n.dq-topup:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-topup-arrow{font-size:10px;line-height:1;transform:translateY(-1px)}\n/* narrow screens: .dq-balance-grid wraps its 3 stats onto separate lines, so the absolutely-positioned\n .dq-remaining-breakdown/.dq-runway-detail popovers can float down over whichever stat now sits in the\n next row (e.g. \"\u4F59\u989D\u660E\u7EC6\" open covering \"\u9884\u8BA1\u53EF\u7528\"'s clickable summary) \u2014 force each stat onto its own\n full-width row and switch both popovers to normal in-flow layout so an open one pushes its own row\n taller instead of overlaying a sibling; desktop keeps the original hover-overlay behavior unchanged */\n@media (max-width:620px){\n .dq-card--hero .dq-balance-grid{gap:12px 32px}\n .dq-card--primary .dq-balance-grid,.dq-session-expand .dq-balance-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 16px}\n .dq-card--primary .dq-balance-grid .dq-stat,.dq-session-expand .dq-balance-grid .dq-stat{min-width:0}\n .dq-remaining-breakdown,.dq-runway-detail{position:static;margin-top:6px;box-shadow:none;max-width:none;white-space:normal}\n}\n.dq-period-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 32px}\n.dq-period{min-width:0}\n/* \u7A84\u5C4F\uFF1A\u4E09\u4E2A\u5468\u671F\u6539\u6210\u5217\u8868\u884C\u2014\u2014\u6807\u7B7E\u4E0E\u6DA8\u8DCC\u5728\u5DE6\u3001\u91D1\u989D\u53F3\u5BF9\u9F50\u3001\u660E\u7EC6\u5360\u7B2C\u4E8C\u884C\uFF0C\u4E09\u6BB5\u53EA\u5360\u7EA6 150px\u3002 */\n@media (max-width:620px){.dq-period-grid{grid-template-columns:1fr;gap:16px}.dq-period{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;align-items:center}.dq-period-head{margin:0}.dq-period-cost{grid-column:2;grid-row:1}.dq-period-sub{grid-column:1/-1;margin-top:2px}}\n.dq-period-head{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-bottom:8px}\n.dq-period-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-period-cost{font-size:18px;font-weight:700;letter-spacing:-.01em;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;line-height:1.2}\n.dq-period-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);margin-top:4px;font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-budget{margin-top:24px}\n.dq-budget--unset{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-budget-action{border:0;background:transparent;padding:3px 4px;border-radius:5px;color:var(--dsw-alias-state-business-primary,#0969da);font:inherit;font-weight:600;white-space:nowrap;cursor:pointer}\n.dq-budget-action:hover{text-decoration:underline;text-underline-offset:3px}\n.dq-budget-action:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-budget-head,.dq-budget-meta{display:flex;align-items:center;justify-content:space-between;gap:12px}\n.dq-budget-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-budget-amount{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-budget-track{height:8px;margin-top:8px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-budget-fill{width:100%;height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transform-origin:left center;transition:transform .35s cubic-bezier(.22,1,.36,1)}\n.dq-budget--risk .dq-budget-fill{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-budget--over .dq-budget-fill{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-budget-meta{margin-top:6px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-budget--risk .dq-budget-meta span:last-child{color:var(--dq-text-warn);font-weight:600}\n.dq-budget--over .dq-budget-meta{color:var(--dsw-alias-state-error-primary,#cf222e);font-weight:600}\n@media (max-width:620px){.dq-budget-head,.dq-budget-meta,.dq-budget--unset{align-items:flex-start;flex-direction:column;gap:4px}.dq-budget-action{margin-left:-4px}}\n.dq-delta{display:inline-flex;align-items:center;gap:3px;font-size:12px;font-weight:600;padding:1px 6px;border-radius:999px;white-space:nowrap;cursor:help;font-variant-numeric:tabular-nums}\n.dq-delta--up{color:var(--dq-text-warn);background:rgba(191,135,0,.14)}\n.dq-delta--down{color:var(--dq-text-success);background:rgba(45,164,78,.14)}\n.dq-delta--flat,.dq-delta--new{color:var(--dsw-alias-label-secondary,#59636e);background:rgba(120,130,150,.14);font-weight:500}\n.dq-delta-label{font-weight:400;opacity:.8}\n.dq-pricing{margin-top:16px}\n.dq-pricing-summary{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);cursor:pointer;list-style:none;width:fit-content;border-radius:6px;padding:2px 4px;margin-left:-4px}\n.dq-pricing-summary::-webkit-details-marker{display:none}\n.dq-pricing-summary::before{content:\"\";display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease}\n.dq-pricing[open] .dq-pricing-summary::before{transform:rotate(90deg)}\n.dq-pricing-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-pricing-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-pricing-now{font-size:12px;font-weight:600;padding:1px 7px;border-radius:999px;color:var(--dsw-alias-label-secondary,#59636e);background:rgba(120,130,150,.14)}\n.dq-pricing-now--peak{color:var(--dq-text-warn);background:rgba(191,135,0,.14)}\n.dq-pricing-body{margin-top:8px;overflow-x:auto}\n.dq-pricing-table{border-collapse:collapse;font-size:12px;font-variant-numeric:tabular-nums;min-width:100%}\n.dq-pricing-table th{text-align:left;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e);padding:4px 12px 4px 0;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-pricing-table td{padding:4px 12px 4px 0;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;vertical-align:top}\n/* Align by counting from the end: a peak row starts with the rowSpan'd model\n cell (5 cells) while its off-peak pair starts at \u65F6\u6BB5 (4 cells), so\n nth-child(n+3) left the off-peak cache-hit price stranded under \u65F6\u6BB5. The\n last three cells are the three price columns in both row shapes. */\n.dq-pricing-table th:nth-last-child(-n+3),.dq-pricing-table td:nth-last-child(-n+3){text-align:right}\n.dq-pricing-table th:last-child,.dq-pricing-table td:last-child{padding-right:0}\n.dq-pricing-table tbody td:first-child{font-weight:500}\n.dq-pricing-table tbody tr+tr td{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.05))}\n.dq-pricing-foot{margin:8px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-coverage{margin-top:24px}\n.dq-coverage-summary{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;cursor:pointer;list-style:none;width:fit-content;max-width:100%;margin-left:-4px;padding:3px 4px;border-radius:6px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-summary::-webkit-details-marker{display:none}\n.dq-coverage-summary::before{content:\"\";display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease}\n.dq-coverage[open] .dq-coverage-summary::before{transform:rotate(90deg)}\n.dq-coverage-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-coverage-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-coverage-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-status{padding:1px 7px;border-radius:999px;background:rgba(45,164,78,.14);color:var(--dq-text-success);font-size:12px;font-weight:600}\n.dq-coverage--warn .dq-coverage-status{background:rgba(191,135,0,.14);color:var(--dq-text-warn)}\n.dq-coverage-brief{font-size:12px;font-variant-numeric:tabular-nums}\n.dq-coverage-body{margin-top:8px;padding:12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-coverage-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 24px;margin:0}\n.dq-coverage-metrics div{min-width:0}\n.dq-coverage-metrics dt{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-coverage-metrics dd{margin:3px 0 0;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-coverage-range,.dq-coverage-note,.dq-coverage-warning{margin:8px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-coverage-range{font-variant-numeric:tabular-nums}\n.dq-coverage-warning{padding:8px 10px;border-radius:8px;background:rgba(191,135,0,.10);color:var(--dq-text-warn)}\n@media (max-width:620px){.dq-coverage-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.dq-coverage-brief{flex-basis:100%;margin-left:19px}}\n.dq-peak-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85;overflow:hidden}\n.dq-peak-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-peak-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-peak-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--peak{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-legend-swatch--offpeak{background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85}\n.dq-peak-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:16px}\n.dq-peak-foot{margin:12px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-clock{margin-bottom:16px}\n.dq-clock-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px}\n.dq-clock-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-clock-status{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;padding:2px 8px;border-radius:999px}\n.dq-clock-status::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor}\n.dq-clock-status--peak{color:var(--dq-text-warn);background:rgba(191,135,0,.12)}\n.dq-clock-status--off{color:var(--dq-text-success);background:rgba(45,164,78,.12)}\n.dq-clock-track{position:relative;display:flex;gap:1px;height:10px}\n.dq-clock-cell{flex:1 1 0;height:100%;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.55}\n.dq-clock-cell--peak{background:var(--dsw-alias-state-warning-primary,#bf8700);opacity:.92}\n.dq-clock-cell:first-child{border-radius:999px 0 0 999px}\n.dq-clock-cell:last-child{border-radius:0 999px 999px 0}\n.dq-clock-now{position:absolute;top:-3px;bottom:-3px;width:2px;background:var(--dsw-alias-label-primary,#1f2328);border-radius:2px;transform:translateX(-1px)}\n.dq-clock-now::before{content:'';position:absolute;top:-4px;left:50%;transform:translateX(-50%);width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-primary,#1f2328)}\n.dq-clock-scale{display:flex;justify-content:space-between;margin-top:4px;font-size:10px;color:var(--dsw-alias-label-tertiary,#59636e);font-variant-numeric:tabular-nums}\n.dq-clock-hint{margin:6px 0 0;font-size:11px;line-height:1.5;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cache-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-bottom:12px}\n@media (max-width:620px){.dq-cache-figures{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px 16px}.dq-cache-figures .dq-stat{min-width:0}}\n.dq-muted-value{color:var(--dsw-alias-label-secondary,#59636e)!important;font-weight:500}\n.dq-stat-value--warn{color:var(--dq-text-warn)}\n.dq-cache-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);overflow:hidden}\n.dq-cache-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-cache-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-cache-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--hit{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-legend-swatch--miss{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-cache-foot{margin:12px 0 0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e);text-wrap:pretty}\n.dq-sessions{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:16px}\n.dq-session{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dq-session-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-session-title{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-session-cost{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-session-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-session-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-business-primary,#4176e6);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-session-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n/* The \u300C\u5F53\u524D\u4F1A\u8BDD\u6D88\u8017\u300Dcard uses this class on a bare <p> (no flex-gap parent\n to lean on, unlike the .dq-session usage above), so it needs its own\n explicit spacing rather than falling back to the browser's implicit <p>\n margin \u2014 this project always declares spacing explicitly. */\n.dq-session-meta{margin:12px 0 0;display:flex;flex-direction:column;gap:2px}\n.dq-session-meta p.dq-session-sub{margin:0}\n.dq-session-meta+.dq-rank{margin-top:16px}\n.dq-session-foot{margin:12px 0 0;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n/* \u8F6E\u6B21 46: each ranking row is now a <details> whose <summary> wraps the existing\n head/track/sub trio unchanged (in a flex-column body div) plus a leading chevron \u2014\n same disclosure grammar as .dq-pricing/.dq-coverage above (hidden native marker,\n rotating glyph, :focus-visible ring), just applied to a multi-line summary instead\n of a single line. .dq-session-details needs its own min-width:0 because it is now\n the flex item inside .dq-session that the ellipsis chain must shrink through. */\n.dq-session-details{min-width:0}\n.dq-session-details>summary{list-style:none;cursor:pointer}\n.dq-session-details>summary::-webkit-details-marker{display:none}\n.dq-session-summary{display:flex;align-items:flex-start;gap:8px;border-radius:8px;padding:4px;margin:-4px}\n.dq-session-summary:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.05))}\n.dq-session-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n/* \u5C55\u5F00\u7BAD\u5934\uFF1A14px \u7EBF\u6761\u56FE\u6807\uFF08mask \u53D6 currentColor\uFF09\uFF0C\u66FF\u4EE3\u539F\u6765 10px \u7684\u300C\u25B8\u300D\u5B57\u7B26\u2014\u2014\u90A3\u4E2A\u5B57\u5F62\u592A\u5C0F\u3001\u592A\u6D45\uFF0C\u70B9\u51FB\u76EE\u6807\u4E5F\u96BE\u627E\u3002 */\n.dq-session-chevron{display:inline-block;flex:none;width:14px;height:14px;background:currentColor;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E\") center/contain no-repeat;transition:transform .15s ease;margin-top:3px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-session-details[open] .dq-session-chevron{transform:rotate(90deg)}\n.dq-session-summary-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}\n/* Expanded body reuses the same shaded-inset language as .dq-coverage-body (10px\n gap from the summary, 11px/12px padding, 10px radius, bg-layer-2) rather than\n inventing a new \"nested panel\" look. SessionUsageCard renders inside unchanged. */\n.dq-session-expand{margin-top:8px;padding:12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-rank{display:flex;flex-direction:column;gap:16px}\n.dq-rank-row{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dq-rank-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-rank-name{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-rank-cost{display:inline-flex;align-items:baseline;gap:8px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-rank-share{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e);min-width:30px;text-align:right}\n.dq-rank-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-rank-fill{height:100%;border-radius:999px;transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-rank-sub{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-alert{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:10px;font-size:12px;line-height:1.6;color:var(--dq-text-warn);background:rgba(191,135,0,.12);border:1px solid rgba(191,135,0,.35);text-wrap:pretty}\n.dq-alert-icon{flex:none;width:18px;height:18px;border-radius:50%;background:var(--dsw-alias-state-warning-primary,#bf8700);color:#fff;font-weight:700;font-size:12px;line-height:18px;text-align:center}\n.dq-alert strong{font-weight:600}\n.dq-alert-link{margin-left:8px;color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}\n.dq-setting{display:flex;align-items:flex-start;gap:16px;margin-top:24px}\n@media (max-width:620px){.dq-setting{flex-direction:column;gap:8px}.dq-setting-label{width:auto;padding-top:0}}\n.dq-setting-label{width:128px;font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328);padding-top:6px;flex:none}\n.dq-setting-control{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}\n.dq-setting-hint{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);line-height:1.5}\n.dq-setting-group{margin-top:28px}\n.dq-setting-group:first-of-type{margin-top:0}\n.dq-setting-group-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:0 0 10px;letter-spacing:.02em}\n.dq-setting-group .dq-toggle{margin-top:0}\n.dq-setting-group .dq-setting{margin-top:16px}\n/* Page footer: the package name + version, injected at build time from\n package.json (see build.mjs) so it can never drift from the release. */\n.dq-footer{margin:16px 0 0;font-size:12px;text-align:center;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-sectionnav{position:fixed;top:50%;transform:translateY(-50%);z-index:20;width:max-content;pointer-events:none}\n.dq-sectionnav--hidden{display:none}\n.dq-sectionnav ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;pointer-events:auto}\n.dq-sectionnav li{display:flex;justify-content:flex-end}\n.dq-sectionnav-dot{display:inline-flex;align-items:center;justify-content:flex-end;gap:8px;padding:4px 2px;border:0;background:transparent;border-radius:6px;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.2;white-space:nowrap;transition:color .15s ease,background .15s ease}\n.dq-sectionnav-dot:hover,.dq-sectionnav-dot:focus-visible{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10))}\n.dq-sectionnav-dot:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-sectionnav-label{font-size:12px;color:inherit}\n.dq-sectionnav-pip{flex:none;width:9px;height:9px;border-radius:50%;background:var(--dsw-alias-border-l2,rgba(0,0,0,.22));transition:background .15s ease,transform .15s ease}\n.dq-sectionnav-dot:hover .dq-sectionnav-pip{background:var(--dsw-alias-label-secondary,#59636e)}\n.dq-sectionnav-dot--active{color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}\n.dq-sectionnav-dot--active .dq-sectionnav-pip{background:var(--dsw-alias-state-business-primary,#0969da);transform:scale(1.25)}\n@media (max-width:1199px){.dq-sectionnav{display:none}}\n.dq-number{width:82px;padding:5px 8px;font-size:13px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-number:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;border-color:transparent}\n.dq-links{display:flex;flex-wrap:wrap;gap:8px}\n.dq-link{display:inline-flex;align-items:center;gap:4px;padding:8px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);text-decoration:none;font-size:13px;font-weight:500;cursor:pointer}\n.dq-link::after{content:\"\u2197\";font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-link:hover{border-color:var(--dsw-alias-label-secondary,#59636e);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n/* .dq-toggle is the first settings control after the links row (\u8F6E\u6B21 39 merge) \u2014 its own\n border-top separates the \"\u5FEB\u6377\u5165\u53E3\" links (originally the standalone \u5B98\u65B9\u5E73\u53F0 card, renamed\n in \u8F6E\u6B21 39 fix-round-1 to read as part of \u8BBE\u7F6E's own navigation area) from \u8BBE\u7F6E controls\n inside the merged card, same 14px/14px/border-l1 recipe as .dq-setting so the two\n sub-sections read at equal weight. */\n.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px;font-weight:500;margin-top:24px}\n.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}\n.dq-toggle-hint{margin:4px 0 0 26px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-widget-tabs{align-items:flex-start;flex-direction:column;gap:8px}\n.dq-widget-tab-list{display:flex;align-items:center;flex-wrap:wrap;gap:4px 16px}\n.dq-widget-tab{display:inline-flex;align-items:center;gap:7px;min-height:28px;color:var(--dsw-alias-label-primary,#1f2328);font-size:12px;font-weight:500;cursor:pointer}\n.dq-widget-tab input{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-toggle input:focus-visible,.dq-model-item input:focus-visible,.dq-widget-tab input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible,.dq-export-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-usage-totals{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px 24px;margin-bottom:20px}\n/* value itself (number+unit, e.g. \"9999.9\u4E07\") must never break across lines inside its own column \u2014\n nowrap+ellipsis is a defensive floor for all widths; the actual fix for the realistic 320px 2-col\n case is the font-size drop below, which keeps every measured stress value comfortably under the\n 83px column width without ever hitting the ellipsis fallback (see round 38 PROGRESS entry) */\n.dq-usage-totals .dq-stat-value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.dq-vision-share{display:inline-block;margin-left:6px;font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-vision-sessions{margin-top:12px;display:flex;flex-direction:column;gap:8px;min-width:0}\n/* The vision card's session rows reuse .dq-session-head, but \u2014 unlike the\n ranking card's rows \u2014 they sit directly under .dq-session with no\n .dq-session-summary-body wrapper to carry min-width:0. Without the chain\n below, a long session title (nowrap) sets the row's min-content width and\n can stretch the card past its siblings / the container. */\n.dq-vision-sessions .dq-session{min-width:0}\n.dq-vision-sessions .dq-session-head{min-width:0}\n.dq-vision-sessions .dq-session-title{flex:1 1 auto;min-width:0}\n@media (max-width:620px){.dq-usage-totals{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 24px}.dq-usage-totals .dq-stat{min-width:0}.dq-usage-totals .dq-stat-value{font-size:13px}}\n.dq-chart-peak{margin-left:8px;font-size:12px;font-weight:400;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-chart-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#1f2328);margin:16px 0 8px}\n.dq-chart-title:first-of-type{margin-top:0}\n.dq-chart-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 12px}\n.dq-chart-block-head .dq-chart-title{margin:0}\n.dq-chart-controls{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex:none;flex-wrap:wrap}\n@media (max-width:620px){.dq-chart-block-head{align-items:flex-start;flex-direction:column}.dq-chart-controls{width:100%;justify-content:flex-start}}\n.dq-model-picker{position:relative}\n.dq-model-btn{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.dq-model-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-model-btn::after{content:\"\u25BE\";font-size:10px;opacity:.7}\n.dq-model-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:190px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:6px;display:flex;flex-direction:column;gap:2px}\n.dq-model-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:12px;cursor:pointer;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-model-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-model-item input{width:14px;height:14px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-model-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-model-item--all{border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-bottom:8px;margin-bottom:2px;border-radius:6px}\n.dq-model-tag{color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;flex:none}\n.dq-bar-group{display:flex;flex-direction:column-reverse;width:100%}\n.dq-bar-group .dq-bar{flex:0 0 auto;width:100%;border-radius:0}\n.dq-bar-group .dq-bar:first-child{border-radius:0 0 2px 2px}\n.dq-bar-group .dq-bar:last-child{border-radius:2px 2px 0 0}\n.dq-bar-group .dq-bar:not(:last-child){box-shadow:inset 0 1px 0 rgba(0,0,0,.18)}\n.dq-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-legend-item{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch{width:10px;height:10px;border-radius:3px;flex:none}\n.dq-chart-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));border-radius:999px;flex:none}\n.dq-chart-switch-btn{border:none;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;transition:background .15s ease,color .15s ease}\n.dq-chart-switch-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-chart-switch-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.14)}\n.dq-chart-wrap{position:relative}\n.dq-plot{display:flex;align-items:flex-end;gap:8px}\n.dq-yaxis{flex:none;width:46px;display:flex;flex-direction:column;justify-content:space-between;margin-bottom:18px;font-size:11px;line-height:1;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;text-align:right;pointer-events:none}\n.dq-yaxis span{white-space:nowrap}\n.dq-bars-scroll{flex:1 1 auto;min-width:0;overflow-x:auto;overflow-y:hidden;padding-bottom:2px}\n.dq-tip{position:absolute;transform:translate(-50%,14px);z-index:40;pointer-events:none;background:var(--dsw-alias-tooltip-bg,#1f2328);color:var(--dsw-static-neutral-bluish-00,#fff);border-radius:8px;padding:7px 10px;font-size:12px;line-height:1.5;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.28);font-variant-numeric:tabular-nums}\n.dq-tip--above{transform:translate(-50%,calc(-100% - 8px))}\n.dq-tip-head{font-weight:600;margin-bottom:2px}\n.dq-tip-row{opacity:.85}\n.dq-bars{display:flex;align-items:flex-end;gap:2px;width:100%}\n.dq-bar-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}\n.dq-bar{background:var(--dsw-alias-state-business-primary,#4176e6);border-radius:2px 2px 0 0;min-height:1px;transition:filter .12s ease}\n.dq-bar-col{cursor:default}\n.dq-bar-col,.dq-bar,.dq-heat-cell{scroll-margin-block-start:24px;scroll-margin-block-end:160px}\n.dq-bar-col:hover .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-bar-col:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-2px;border-radius:3px}\n.dq-bar:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;filter:brightness(1.18) saturate(1.1);position:relative;z-index:2}\n.dq-bar-col--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:-2px;border-radius:3px}\n.dq-bar-col--pinned .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-bar--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;filter:brightness(1.18) saturate(1.1);position:relative;z-index:2}\n.dq-heat-cell:not(.dq-heat-cell--pad):hover{outline:1.5px solid var(--dsw-alias-label-primary,#1f2328);outline-offset:1px}\n.dq-heat-cell:not(.dq-heat-cell--pad):focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;position:relative;z-index:2}\n.dq-heat-cell--pinned{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;position:relative;z-index:2}\n.dq-bar-label{font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);text-align:center;margin-top:4px;overflow:visible;white-space:nowrap}\n.dq-heat{display:flex;flex-direction:column;gap:8px;max-width:100%}\n.dq-heat-scroll{overflow:hidden;padding-bottom:2px}\n.dq-heatmap{display:flex;gap:2px}\n.dq-heat-week{display:flex;flex:1 1 0;min-width:0;flex-direction:column;gap:2px}\n.dq-heat-cell{width:100%;aspect-ratio:1/1;border-radius:2px;flex:none;min-width:0}\n.dq-heat-cell--pad{background:transparent}\n.dq-heat-months{display:flex;gap:2px;margin-top:4px}\n.dq-heat-month{flex:1 1 0;min-width:0;font-size:12px;line-height:15px;color:var(--dsw-alias-label-secondary,#59636e);white-space:nowrap;overflow:visible}\n.dq-heat-key{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-scale{display:flex;align-items:center;gap:3px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);align-self:flex-end}\n.dq-heat-scale>span:first-child{margin-right:2px}\n.dq-heat-scale>span:last-child{margin-left:2px}\n.dq-muted{color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-warn{color:var(--dq-text-warn)}\n.dq-crash{margin:10px 0 14px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10));border-radius:8px;font-size:12px;line-height:1.6;color:var(--dsw-alias-state-error-primary,#cf222e);white-space:pre-wrap;word-break:break-word;font-family:var(--ds-font-family-code,ui-monospace,SFMono-Regular,Menlo,monospace)}\n.dq-empty{color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.6;padding:6px 0;text-wrap:pretty}\n/* Error-state modifier for a card body that has nothing else to show (mirrors the .dq-stat-value--ok/\n --bad/--warn pattern: same layout as .dq-empty, declared after it so this color wins at equal\n specificity). Used by the current-session card when its own fetch failed and there is no prior\n data to fall back to \u2014 the status-row .dq-error/.dq-warn spans are for the account-wide balance/\n usage fetch, this is the per-card equivalent. */\n.dq-empty--error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-skel{background:linear-gradient(90deg,rgba(125,135,155,.10) 25%,rgba(125,135,155,.20) 37%,rgba(125,135,155,.10) 63%);background-size:400% 100%;border-radius:5px;animation:dq-shimmer 1.5s ease-in-out infinite}\n.dq-stat .dq-skel+.dq-skel{margin-top:6px}\n.dq-skel-bars{display:flex;align-items:flex-end;gap:2px;width:100%;height:160px;margin-top:12px}\n.dq-skel-bar{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0}\n@keyframes dq-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}\n.dq-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:20px;padding:0 20px;margin-bottom:-12px}\n.dq-status-messages{display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0}\n.dq-status-row .dq-warn,.dq-status-row .dq-error{font-size:12px;line-height:1.5}\n.dq-sync{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-sync-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--dsw-alias-label-tertiary,#8c959f)}\n.dq-sync--fresh .dq-sync-dot{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-sync--syncing .dq-sync-dot{background:var(--dsw-alias-state-business-primary,#4176e6);animation:dq-sync-pulse 1.2s ease-in-out infinite}\n.dq-sync--fallback{color:var(--dq-text-warn)}\n.dq-sync--fallback .dq-sync-dot{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-sync--error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-sync--error .dq-sync-dot{background:var(--dsw-alias-state-error-primary,#cf222e)}\n@keyframes dq-sync-pulse{50%{opacity:.35;transform:scale(.8)}}\n.dq-refresh-btn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-status-actions{display:flex;align-items:center;gap:8px;flex:none}\n.dq-settings-btn{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-settings-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-settings-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-settings-caret{font-size:10px;line-height:1;transition:transform .2s cubic-bezier(.16,1,.3,1)}\n.dq-settings-caret--open{transform:rotate(180deg)}\n.dq-settings-panel{box-sizing:border-box;min-width:0;max-width:100%;padding:20px;background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.10));border-radius:12px}\n/* Motion: eased (easeOutExpo) arrivals. Operate surface \u2014 fast, purposeful,\n and fully disabled under prefers-reduced-motion (see the global reduce block). */\n.dq-export-menu,.dq-model-menu{transform-origin:top right;animation:dq-pop .18s cubic-bezier(.16,1,.3,1)}\n@keyframes dq-pop{from{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:none}}\n.dq-alert{animation:dq-alert-in .28s cubic-bezier(.16,1,.3,1)}\n@keyframes dq-alert-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}\n@media (max-width:620px){.dq-settings-panel{padding:16px}}\n.dq-refresh-btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-refresh-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-refresh-btn:disabled{cursor:default;opacity:.6}\n.dq-refresh-icon{display:inline-block;line-height:1}\n.dq-refresh-icon--spin{animation:dq-spin .9s linear infinite}\n@keyframes dq-spin{to{transform:rotate(360deg)}}\n/* ============================================================================\n Host chrome: the \u300C\u989D\u5EA6\u300Dconversation view does not use the chat composer.\n The attribute is set by index.tsx only when the dashboard is mounted inside\n the conversation scrollport, so the account-wide panel never hides it.\n '!important' because the composer's slot anchor is a \"display:contents\"\n wrapper whose display we must beat regardless of host rule order.\n ============================================================================ */\nhtml[data-dq-quota-view] [data-slot=\"conversation.composer\"]{display:none!important}\n/* The narrow-viewport rule pads for the fixed composer; with it hidden there\n is nothing to clear, so fall back to the page's own bottom breathing room. */\nhtml[data-dq-quota-view] .dq-balance{padding-bottom:48px}\n/* ============================================================================\n Account-wide \u300C\u989D\u5EA6\u300Dpanel (the optional sidebar entry opens this main\n keyed panel). The dashboard keeps its own width/padding; the panel only\n supplies the page title row and the scrolling box the main column lacks.\n ============================================================================ */\n/* Account-wide page frame: mirrors DSH's first-level pages (Plugins /\n Scheduled tasks) \u2014 full-height scroll box, 28px top inset on the heading,\n a 960px centred column, clamp(24px,4vw,48px) inline + 48px bottom insets and\n a 20px/28px/500 page title, so the three sibling entries line up. */\n.dq-panel{box-sizing:border-box;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;padding:0 clamp(24px,4vw,48px) 48px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-family:var(--dsw-font-family,-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif);font-size:13px;line-height:1.5}\n.dq-panel-head{box-sizing:border-box;display:flex;flex-direction:column;align-items:flex-start;gap:4px;width:100%;max-width:960px;margin:0 auto 32px;padding-top:28px}\n.dq-panel-title{margin:0;font-size:20px;font-weight:500;line-height:28px;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-panel-caption{font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-panel .dq-balance{box-sizing:border-box;width:100%;max-width:960px;padding:0}\n/* macOS hiddenInset titlebar: the frame's top clearance keeps the heading\n below the window's top strip, matching the host's sibling pages. */\n[data-platform=\"darwin\"] .dq-panel-head{padding-top:calc(28px + var(--dsh-frame-top-clearance,0px))}\n@media (max-width:620px){\n .dq-panel-head{padding-top:24px;margin-bottom:24px}\n .dq-panel .dq-balance{max-width:100%;padding:0}\n}\n/* Optional sidebar entry. Top placement joins the host's global-panel icon\n row (only the glyph is ours); bottom placement renders a row beside\n Settings, collapsing to a square rail button with the sidebar. */\n/* The glyph is an SVG matching the host's 16px stroke icons; color inherits\n from the sidebar row so selected/hover states stay the host's business. */\n.dq-side-icon{flex:none;display:block}\n.dq-side-entry{display:flex;align-items:center;gap:8px;box-sizing:border-box;width:100%;border:0;border-radius:8px;padding:7px 8px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font:inherit;font-size:13px;line-height:1.3;text-align:left;cursor:pointer}\n.dq-side-entry:hover{background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.10));color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-side-entry:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-side-entry[aria-pressed=\"true\"]{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-side-entry--rail{justify-content:center;width:32px;height:32px;margin:0 auto;padding:0}\n.dq-side-entry-icon{flex:none;display:inline-flex;align-items:center;justify-content:center}\n.dq-side-entry-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* ============================================================================\n Settings controls for the two layout preferences: a compact select and the\n draggable tab-order strip.\n ============================================================================ */\n.dq-select{font:inherit;font-size:13px;line-height:1.3;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));border-radius:8px;padding:5px 8px;min-width:96px;cursor:pointer}\n.dq-select:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-tab-order{display:flex;flex-wrap:wrap;align-items:center;gap:6px;box-sizing:border-box;max-width:100%;min-height:32px;padding:4px;border:1px dashed var(--dsw-alias-border-l2,rgba(0,0,0,.16));border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06))}\n.dq-tab-chip{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));border-radius:999px;background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1.4;white-space:nowrap}\n.dq-tab-chip--current{cursor:grab;color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-state-business-primary,#0969da);font-weight:600;user-select:none;-webkit-user-select:none;touch-action:none}\n.dq-tab-chip--current:active{cursor:grabbing}\n.dq-tab-chip--current:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dq-tab-chip--dragging{opacity:.55}\n.dq-tab-chip--drop-target{border-style:dashed;border-color:var(--dsw-alias-state-business-primary,#0969da)}\n/* ============================================================================\n \u300C\u56FE\u7247 / \u591A\u6A21\u6001\u7528\u91CF\u300Dlives inside the usage-trend card. The grid-rows 0fr\u21921fr\n trick animates the section's real height as a window range makes it appear\n or disappear; opacity/translate make the change read as a reveal rather\n than a reflow. The body keeps 14px of top room in both states (clipped by\n the 0fr row when closed) so opening never jumps.\n ============================================================================ */\n.dq-vision-inline{display:grid;grid-template-rows:0fr;margin-top:0;opacity:0;transform:translateY(-3px);overflow:hidden;transition:grid-template-rows .32s cubic-bezier(.22,1,.36,1),margin-top .32s cubic-bezier(.22,1,.36,1),opacity .2s ease,transform .32s cubic-bezier(.22,1,.36,1)}\n.dq-vision-inline[data-open=\"true\"]{grid-template-rows:1fr;margin-top:24px;opacity:1;transform:none}\n.dq-vision-inline-body{min-height:0;overflow:hidden}\n.dq-vision-inline-body>.dq-chart-title{margin-top:0}\n.dq-vision-inline-body>.dq-chart-title{margin-top:0}\n\n@media (prefers-reduced-motion:reduce){\n .dsh-quota-root,.dsh-quota-root *,\n .dsh-quota-root *::before,.dsh-quota-root *::after,\n .dq-message-cost,.dq-message-cost::after,\n .dq-balance,.dq-balance *,\n .dq-balance *::before,.dq-balance *::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}\n}\n`\n", "/** The draggable bottom-right floating balance widget.\n *\n * Where it sits (corner) and whether it is collapsed are user choices, so both\n * are persisted (see ./prefs.ts) and restored before the first paint; the\n * widget also re-snaps to its corner when the frame resizes (window resize,\n * sidebar collapse) instead of stranding itself at stale pixel coordinates.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react'\nimport {\n fetchBalance,\n fetchSessionUsage,\n fetchUsage,\n getCachedBalance,\n getCachedSessionUsage,\n getCachedUsage,\n getCachedUsageAt,\n subscribeSessionUsage,\n subscribeUsage,\n} from './api.ts'\nimport { fmt } from './charts.tsx'\nimport type { BalanceData, SessionUsageData, UsageData } from '../contract.ts'\nimport { getActiveConversationViewId, getComposerElement, getMainColumn, getShellFrame, slotBox } from './dom.ts'\nimport { localizeApiError, useI18n } from './i18n.tsx'\nimport { fmtTurnCost } from './message-cost.tsx'\nimport { isBoolean, loadPref, savePref } from './prefs.ts'\nimport { currentSessionIdOf, type SessionListStateFace } from './sessions.ts'\nimport { lowBalanceStore, quotaViewActiveStore, widgetTabIdsStore, widgetVisibleStore } from './store.ts'\nimport type { ConversationViewTab, ConversationViewsSource } from './views.ts'\n\nconst MARGIN = 16\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br'\n\nconst CORNER_KEY = 'widget.corner'\nconst COLLAPSED_KEY = 'widget.collapsed'\n\nconst isCorner = (value: unknown): boolean =>\n value === 'tl' || value === 'tr' || value === 'bl' || value === 'br'\n\ninterface Bounds {\n left: number\n top: number\n right: number\n bottom: number\n}\n\ninterface DragSession {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n width: number\n height: number\n bounds: Bounds\n}\n\n/** Below this the region is too short to park a widget in, so an exclusion is\n * skipped rather than squeezing the widget out of the frame. */\nconst MIN_REGION_HEIGHT = 140\n\n/**\n * Draggable area = the main column minus the session header and the composer.\n *\n * Using the main column (rather than the whole frame minus the sidebar) also\n * keeps the widget clear of the right-hand details panel when it is open.\n * The header is excluded so the widget can never park on the Chat / Trajectory\n * / \u989D\u5EA6 tab row and swallow its clicks, and the composer is excluded because a\n * bottom-right widget otherwise covers the model picker and the send button \u2014\n * the two controls the user reaches for most.\n */\nfunction getBounds(node: HTMLElement | null): Bounds {\n const fallback: Bounds = { left: 0, top: 0, right: 100000, bottom: 100000 }\n if (node === null) return fallback\n const frame = getShellFrame(node)\n if (frame === null) return fallback\n const frameRect = frame.getBoundingClientRect()\n let left = frameRect.left\n let right = frameRect.right\n let top = frameRect.top\n const mainRect = getMainColumn(frame)?.getBoundingClientRect() ?? null\n if (mainRect !== null && mainRect.width > 0) {\n left = mainRect.left\n right = mainRect.right\n top = mainRect.top\n } else {\n const sidebarRect = (frame.children[0] as HTMLElement | undefined)?.getBoundingClientRect() ?? null\n if (sidebarRect !== null) left = sidebarRect.right\n }\n let bottom = frameRect.bottom\n const headerRect = slotBox(frame, 'conversation.session.header', 'child')\n if (headerRect !== null && headerRect.bottom > top && headerRect.bottom < bottom - MIN_REGION_HEIGHT) {\n top = headerRect.bottom\n }\n // Only a composer docked along the bottom edge competes with the widget's\n // corner. The no-session screen renders the same composer centred in the\n // pane, and dodging that would park the widget in mid-air.\n const composerRect = getComposerElement(frame)?.getBoundingClientRect() ?? null\n if (composerRect !== null && composerRect.top < bottom && composerRect.top > top + (bottom - top) / 2) {\n bottom = composerRect.top\n }\n return { left, top, right, bottom }\n}\n\nfunction cornerPos(corner: Corner, node: HTMLElement | null, bounds: Bounds): { x: number; y: number } {\n const rect = node?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const xLeft = bounds.left + MARGIN\n const yTop = bounds.top + MARGIN\n const xRight = bounds.right - w - MARGIN\n const yBottom = bounds.bottom - h - MARGIN\n if (corner === 'tl') return { x: xLeft, y: yTop }\n if (corner === 'tr') return { x: xRight, y: yTop }\n if (corner === 'bl') return { x: xLeft, y: yBottom }\n return { x: xRight, y: yBottom }\n}\n\nexport type UseSessionsHook = <T>(selector: (state: SessionListStateFace) => T) => T\n\nexport function QuotaWidget(props: {\n useSessions: UseSessionsHook\n views: ConversationViewsSource\n}): ReactElement | null {\n const { t } = useI18n()\n const sessionId = props.useSessions(currentSessionIdOf)\n const [visible, setVisible] = useState(widgetVisibleStore.get())\n useEffect(() => widgetVisibleStore.subscribe(() => setVisible(widgetVisibleStore.get())), [])\n const [quotaViewActive, setQuotaViewActive] = useState(quotaViewActiveStore.get())\n useEffect(() => quotaViewActiveStore.subscribe(() => setQuotaViewActive(quotaViewActiveStore.get())), [])\n const [lowBalance, setLowBalance] = useState(lowBalanceStore.get())\n useEffect(() => lowBalanceStore.subscribe(() => setLowBalance(lowBalanceStore.get())), [])\n const [selectedTabIds, setSelectedTabIds] = useState(widgetTabIdsStore.get())\n useEffect(() => widgetTabIdsStore.subscribe(() => setSelectedTabIds(widgetTabIdsStore.get())), [])\n const [viewTabs, setViewTabs] = useState<ConversationViewTab[]>(() => props.views.list())\n useEffect(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views])\n const [activeViewId, setActiveViewId] = useState<string | null>(null)\n\n const cachedBalance = getCachedBalance()\n const [data, setData] = useState<BalanceData | null>(cachedBalance?.data ?? null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(cachedBalance === null)\n const [collapsed, setCollapsed] = useState(() => loadPref<boolean>(COLLAPSED_KEY, isBoolean, false))\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null)\n const [corner, setCorner] = useState<Corner>(() => loadPref<Corner>(CORNER_KEY, isCorner, 'br'))\n const [dragging, setDragging] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const dragRef = useRef<DragSession | null>(null)\n\n // Today's spend comes from the shared usage cache \u2014 never fetched on the\n // widget's own poll, since aggregating the session logs takes seconds. A\n // manual refresh (below) is the one place the widget pays for it.\n const readUsage = (): { data: UsageData | null; at: number | null } => {\n const cached = getCachedUsage()\n return { data: cached?.ok === true ? cached.data ?? null : null, at: getCachedUsageAt() }\n }\n const [usage, setUsage] = useState(readUsage)\n useEffect(() => subscribeUsage(() => setUsage(readUsage())), [])\n\n const readSessionUsage = (id: string | undefined): SessionUsageData | null => {\n if (id === undefined) return null\n const response = getCachedSessionUsage(id)\n return response?.ok === true ? response.data ?? null : null\n }\n const [sessionUsage, setSessionUsage] = useState<SessionUsageData | null>(() => readSessionUsage(sessionId))\n useEffect(() => {\n setSessionUsage(readSessionUsage(sessionId))\n if (sessionId === undefined) return\n const unsubscribe = subscribeSessionUsage(sessionId, () => setSessionUsage(readSessionUsage(sessionId)))\n void fetchSessionUsage(sessionId)\n return unsubscribe\n }, [sessionId])\n\n // The root-scoped overlay does not receive the session's active view store.\n // Read the host's semantic tablist instead and map its selected button by\n // index to the same live slot ledger used to build that tablist.\n useLayoutEffect(() => {\n const viewIds = viewTabs.map(tab => tab.id)\n const read = (): void => {\n const next = getActiveConversationViewId(getShellFrame(rootRef.current), viewIds)\n setActiveViewId(previous => previous === next ? previous : next)\n }\n read()\n const frame = getShellFrame(rootRef.current)\n let observer: MutationObserver | null = null\n if (frame !== null && typeof MutationObserver === 'function') {\n observer = new MutationObserver(read)\n observer.observe(frame, { subtree: true, childList: true, attributes: true, attributeFilter: ['aria-selected'] })\n }\n const poll = setInterval(read, 1000)\n return () => {\n observer?.disconnect()\n clearInterval(poll)\n }\n }, [sessionId, viewTabs])\n\n const load = async (showLoading: boolean, force = false): Promise<void> => {\n if (showLoading) setLoading(true)\n try {\n const res = await fetchBalance(force)\n if (res.ok && res.data !== undefined) {\n setData(res.data)\n setError(null)\n } else {\n setData(null)\n setError(res.error ?? '')\n }\n } catch (err) {\n setData(null)\n setError((err as { message?: string } | null)?.message ?? String(err))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void load(true)\n const id = setInterval(() => { void load(false) }, 60_000)\n return () => clearInterval(id)\n }, [])\n\n /**\n * Keep the widget parked in its corner: on mount (restoring the persisted\n * corner before the first paint), when collapse/expand changes its size, and\n * whenever the layout moves under it \u2014 window resize, sidebar collapse or\n * the details panel opening (observed), plus a slow poll that catches the\n * one change no observer reports: the session header mounting *after* the\n * overlay, which would otherwise leave the widget parked over the tab row.\n *\n * `place` keeps the previous object when the corner has not actually moved,\n * so repeated triggers cost one rect read and no re-render.\n */\n useLayoutEffect(() => {\n if (!visible || quotaViewActive) return\n const node = rootRef.current\n if (node === null) return\n const place = (): void => {\n if (dragRef.current !== null) return\n const next = cornerPos(corner, node, getBounds(node))\n setPos(prev => (prev !== null && prev.x === next.x && prev.y === next.y ? prev : next))\n }\n place()\n const frame = getShellFrame(node)\n let observer: ResizeObserver | null = null\n if (frame !== null && typeof ResizeObserver === 'function') {\n observer = new ResizeObserver(place)\n observer.observe(frame)\n const main = getMainColumn(frame)\n if (main !== null) observer.observe(main)\n }\n window.addEventListener('resize', place)\n const poll = setInterval(place, 1000)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', place)\n clearInterval(poll)\n }\n }, [visible, quotaViewActive, corner, collapsed])\n\n const snapToNearest = (session: DragSession): void => {\n const node = rootRef.current\n if (node === null) return\n const { width: w, height: h, bounds: b } = session\n const corners: Array<{ c: Corner; x: number; y: number }> = [\n { c: 'tl', x: b.left + MARGIN, y: b.top + MARGIN },\n { c: 'tr', x: b.right - w - MARGIN, y: b.top + MARGIN },\n { c: 'bl', x: b.left + MARGIN, y: b.bottom - h - MARGIN },\n { c: 'br', x: b.right - w - MARGIN, y: b.bottom - h - MARGIN },\n ]\n const rect = node.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n let best = corners[0]\n let bestDistance = Number.POSITIVE_INFINITY\n for (const candidate of corners) {\n const ccx = candidate.x + w / 2\n const ccy = candidate.y + h / 2\n const distance = (ccx - cx) ** 2 + (ccy - cy) ** 2\n if (distance < bestDistance) {\n bestDistance = distance\n best = candidate\n }\n }\n setCorner(best.c)\n savePref(CORNER_KEY, best.c)\n setPos({ x: best.x, y: best.y })\n }\n\n /** Idempotent end-of-drag; also the missed-pointerup backstop. */\n const endDrag = (snap: boolean): void => {\n const session = dragRef.current\n if (session === null) return\n dragRef.current = null\n setDragging(false)\n const node = rootRef.current\n if (node !== null && typeof node.releasePointerCapture === 'function') {\n try {\n node.releasePointerCapture(session.pointerId)\n } catch {\n // capture already released\n }\n }\n if (snap) {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => snapToNearest(session))\n } else {\n snapToNearest(session)\n }\n }\n }\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return\n const target = e.target as Element | null\n if (target !== null && typeof target.closest === 'function' && target.closest('button') !== null) return\n const node = rootRef.current\n if (node === null) return\n const bounds = getBounds(node)\n const rect = node.getBoundingClientRect()\n dragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: rect.left,\n originY: rect.top,\n width: rect.width,\n height: rect.height,\n bounds,\n }\n node.setPointerCapture(e.pointerId)\n setDragging(true)\n e.preventDefault()\n }\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n if ((e.buttons & 1) === 0) {\n endDrag(true)\n return\n }\n const dx = e.clientX - session.startX\n const dy = e.clientY - session.startY\n const maxX = session.bounds.right - session.width - MARGIN\n const maxY = session.bounds.bottom - session.height - MARGIN\n const minX = session.bounds.left + MARGIN\n const minY = session.bounds.top + MARGIN\n setPos({\n x: Math.max(minX, Math.min(session.originX + dx, maxX)),\n y: Math.max(minY, Math.min(session.originY + dy, maxY)),\n })\n }\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const session = dragRef.current\n if (session === null || session.pointerId !== e.pointerId) return\n endDrag(true)\n }\n\n if (!visible) return null\n\n const allowedOnActiveView = activeViewId === null\n ? sessionId === undefined\n : activeViewId !== 'balance' && (selectedTabIds === null || selectedTabIds.includes(activeViewId))\n const hidden = quotaViewActive || !allowedOnActiveView\n\n const primary = data !== null && data.balances.length > 0 ? data.balances[0] : null\n const balanceValue = primary !== null ? Number(primary.total) : Number.NaN\n const low = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance\n const dotClass = primary === null\n ? 'dsh-quota-dot dsh-quota-dot--idle'\n : data?.isAvailable === false\n ? 'dsh-quota-dot dsh-quota-dot--error'\n : low ? 'dsh-quota-dot dsh-quota-dot--warn' : 'dsh-quota-dot'\n\n // The usage figure can be minutes old (it is only refreshed on demand), so\n // say how old rather than presenting it as live.\n const ageMinutes = usage.at === null ? null : Math.floor((Date.now() - usage.at) / 60_000)\n const usageAgeText = ageMinutes === null || ageMinutes < 1\n ? t('widget.updatedNow')\n : t('widget.stale', { minutes: ageMinutes })\n const sessionCostRow = sessionUsage === null ? null : (\n <div className=\"dsh-quota-row\" title={t('widget.sessionCostTitle')}>\n <span className=\"dsh-quota-label\">{t('widget.sessionCost')}</span>\n <span className=\"dsh-quota-value\">\u00A5{fmtTurnCost(sessionUsage.cost)}</span>\n </div>\n )\n\n let body: ReactElement | null = null\n if (!collapsed) {\n if (loading && data === null && error === null) {\n body = <div className=\"dsh-quota-body\"><div>{t('widget.loading')}</div>{sessionCostRow}</div>\n } else if (error !== null && data === null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-error\">{localizeApiError(error, t, 'error.query')}</div>\n {sessionCostRow}\n </div>\n )\n } else if (primary !== null) {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-remaining-label\">{t('balance.remaining')}</div>\n <div title={low ? t('widget.lowTitle', { amount: fmt(lowBalance) }) : undefined}>\n <span className={`dsh-quota-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)}</span>\n <span className=\"dsh-quota-currency\">{primary.currency}</span>\n </div>\n {usage.data !== null && (\n <div className=\"dsh-quota-row\" title={t('widget.todayCostTitle', { age: usageAgeText })}>\n <span className=\"dsh-quota-label\">{t('widget.todayCost')}</span>\n <span className=\"dsh-quota-value\">\u00A5{fmt(usage.data.summary.today.cost)}</span>\n </div>\n )}\n {sessionCostRow}\n {data?.isAvailable === false && (\n <div className=\"dsh-quota-row\">\n <span className=\"dsh-quota-label\">{t('common.status')}</span>\n <span className=\"dsh-quota-value dsh-quota-error\">{t('common.unavailable')}</span>\n </div>\n )}\n </div>\n )\n } else {\n body = (\n <div className=\"dsh-quota-body\">\n <div className=\"dsh-quota-error\">{t('widget.noBalance')}</div>\n {sessionCostRow}\n </div>\n )\n }\n }\n\n const style: CSSProperties | undefined = pos !== null\n ? { left: `${pos.x}px`, top: `${pos.y}px`, right: 'auto', bottom: 'auto' }\n : undefined\n\n return (\n <div\n className={`dsh-quota-root${dragging ? ' dsh-quota-dragging' : ''}${hidden ? ' dsh-quota-root--hidden' : ''}`}\n style={style}\n aria-hidden={hidden}\n >\n <div\n ref={rootRef}\n className=\"dsh-quota-card\"\n title={t('widget.dragCard')}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={() => endDrag(false)}\n onLostPointerCapture={() => endDrag(false)}\n >\n <div className=\"dsh-quota-header\">\n <div className=\"dsh-quota-title\">\n <span className=\"dsh-quota-grip\" title={t('widget.dragGrip')}>\u2807</span>\n <span className={dotClass} />\n <span className=\"dsh-quota-name\">{t('widget.title')}</span>\n </div>\n <div className=\"dsh-quota-actions\">\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={t('widget.refresh')}\n aria-label={t('widget.refresh')}\n disabled={loading}\n onClick={() => {\n void load(true, true)\n void fetchUsage(true)\n if (sessionId !== undefined) void fetchSessionUsage(sessionId, true)\n }}\n >\n \u21BB\n </button>\n <button\n className=\"dsh-quota-btn\"\n type=\"button\"\n title={collapsed ? t('widget.expand') : t('widget.collapse')}\n aria-label={collapsed ? t('widget.expandAria') : t('widget.collapseAria')}\n aria-expanded={!collapsed}\n onClick={() => {\n const next = !collapsed\n setCollapsed(next)\n savePref(COLLAPSED_KEY, next)\n }}\n >\n {collapsed ? '+' : '\u2212'}\n </button>\n </div>\n </div>\n {collapsed && primary !== null && (\n <div className=\"dsh-quota-collapsed-total-row\">\n <span className={`dsh-quota-collapsed-total${low ? ' dsh-quota-total--low' : ''}`}>{fmt(primary.total)} {primary.currency}</span>\n </div>\n )}\n {body}\n </div>\n </div>\n )\n}\n", "/**\n * Structural face of the host's session-list state, and the one selector this\n * plugin needs from it.\n *\n * The hosts this plugin runs on speak two dialects. 0.1.5-era hosts kept a\n * flat `current` field; 0.1.6+ removed it and mark the open session through\n * `byId[*].retainedBy.mainView` \u2014 the same signal the host's own document\n * title and sidebar selection read. Both fields stay optional so neither\n * generation fails, and consumers keep working across a host upgrade without\n * a plugin re-release.\n */\n\n/** One session row; only the fields the selector reads. */\nexport interface SessionSummaryFace {\n id?: string\n retainedBy?: { mainView?: number }\n}\n\nexport interface SessionListStateFace {\n byId?: Readonly<Record<string, SessionSummaryFace | undefined>>\n /** 0.1.5-era hosts: the flat current-session field. */\n current?: string\n}\n\n/** The session currently shown in the main panel, if any. */\nexport function currentSessionIdOf(state: SessionListStateFace): string | undefined {\n const retained = Object.values(state.byId ?? {})\n .find(row => (row?.retainedBy?.mainView ?? 0) > 0)\n return retained?.id ?? state.current\n}\n", "/** Live projection of the host's `conversation.view` slot ledger. */\n\nexport interface ConversationViewTab {\n id: string\n label: string\n}\n\nexport interface ConversationViewsSource {\n list(): ConversationViewTab[]\n subscribe(fn: () => void): () => void\n}\n\nexport interface ConversationViewSlotEntry {\n options: {\n id?: string\n order?: number\n label?: string | (() => string)\n }\n}\n\nexport interface ConversationViewSlots {\n entries(name: string): ConversationViewSlotEntry[]\n subscribe(name: string, fn: () => void): () => void\n}\n\nconst labelOf = (entry: ConversationViewSlotEntry): string => {\n const { id = '', label } = entry.options\n try {\n const resolved = typeof label === 'function' ? label() : label\n return typeof resolved === 'string' && resolved !== '' ? resolved : id\n } catch {\n return id\n }\n}\n\n/** Build a source once at plugin apply-time. The ledger owns ordering, so the\n * same index also maps to the host's rendered tab buttons without relying on\n * hashed class names or translated labels. */\nexport function conversationViewsSource(slots: ConversationViewSlots): ConversationViewsSource {\n return {\n list: () => slots.entries('conversation.view')\n .flatMap(entry => entry.options.id === undefined\n ? []\n : [{ id: entry.options.id, label: labelOf(entry) }]),\n subscribe: fn => slots.subscribe('conversation.view', fn),\n }\n}\n"],
5
+ "mappings": "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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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",
6
6
  "names": ["import_react", "window", "import_react", "import_react", "import_react", "import_jsx_runtime", "name", "import_jsx_runtime", "el", "BEIJING_OFFSET_MS", "PREFIX", "import_jsx_runtime", "height", "animation", "name", "rate", "frame", "composer", "input", "window", "import_react", "import_jsx_runtime", "turn", "import_react", "BEIJING_OFFSET_MS", "name", "BEIJING_OFFSET_MS", "import_jsx_runtime", "cachedData", "import_react", "import_jsx_runtime", "quotaViewActive", "import_jsx_runtime"]
7
7
  }