@kenz1117/dsh-ui-usage-billing 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -24,7 +24,7 @@ window.__ModuleLoader__.load({
24
24
  }
25
25
  //#endregion
26
26
  //#region \0dsh-css:/Users/ken/deepseek-harness/packages/client/ui-usage-billing/src/client/UsageBilling.module.css.mjs
27
- const css = ".VWh0dG_railButton{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 28%, var(--dsw-alias-border-l2));background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-static-blue-500) 14%, var(--dsw-alias-bg-layer-1)), var(--dsw-alias-bg-layer-1));width:36px;height:36px;color:var(--dsw-static-blue-500);cursor:pointer;border-radius:10px;justify-content:center;align-items:center;padding:0;transition:border-color .16s,box-shadow .16s,transform .16s,color .16s;display:flex}.VWh0dG_railButton:hover,.VWh0dG_railButton:focus-visible{border-color:color-mix(in srgb, var(--dsw-static-blue-500) 48%, var(--dsw-alias-border-l2));box-shadow:0 4px 14px -6px color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent);color:var(--dsw-static-blue-400);outline:none;transform:translateY(-1px)}.VWh0dG_railButton svg{stroke-width:2px;width:18px;height:18px}.VWh0dG_trigger{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 20%, var(--dsw-alias-border-l1));background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 12%, transparent), transparent 55%), radial-gradient(150% 200% at 100% 110%, color-mix(in srgb, var(--dsw-static-blue-400) 9%, transparent), transparent 60%), var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:12px;align-items:center;gap:12px;padding:10px 14px;transition:border-color .16s,box-shadow .16s,transform .16s;display:flex;position:relative;overflow:hidden}@supports (backdrop-filter:blur(1px)){.VWh0dG_trigger{background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 14%, transparent), transparent 55%), radial-gradient(150% 200% at 100% 110%, color-mix(in srgb, var(--dsw-static-blue-400) 10%, transparent), transparent 60%), color-mix(in srgb, var(--dsw-alias-bg-layer-1) 72%, transparent);backdrop-filter:blur(12px)}}.VWh0dG_trigger:hover,.VWh0dG_trigger:focus-visible{border-color:color-mix(in srgb, var(--dsw-static-blue-500) 42%, var(--dsw-alias-border-l1));box-shadow:0 8px 24px -10px color-mix(in srgb, var(--dsw-static-blue-500) 45%, transparent);outline:none;transform:translateY(-1px)}.VWh0dG_triggerIcon{background:linear-gradient(135deg, var(--dsw-static-blue-500), var(--dsw-static-blue-400));width:28px;height:28px;color:var(--dsw-static-neutral-bluish-00);box-shadow:0 2px 8px -2px color-mix(in srgb, var(--dsw-static-blue-500) 60%, transparent);border-radius:8px;flex:none;justify-content:center;align-items:center;display:inline-flex}.VWh0dG_triggerIcon svg{stroke-width:1.8px;width:15px;height:15px}.VWh0dG_triggerToday,.VWh0dG_triggerMonth{align-items:baseline;gap:4px;min-width:0;display:flex}.VWh0dG_triggerDivider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px}.VWh0dG_triggerAmount{color:var(--dsw-alias-label-primary);letter-spacing:-.01em;font-variant-numeric:tabular-nums;white-space:nowrap;font-size:18px;font-weight:600;line-height:22px}.VWh0dG_triggerAmountSub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:13px;font-weight:600;line-height:18px}.VWh0dG_triggerMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:10.5px;line-height:14px}.VWh0dG_dashboardModal{background:linear-gradient(var(--dsw-alias-bg-layer-2), var(--dsw-alias-bg-layer-2)) padding-box, linear-gradient(135deg, color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent), color-mix(in srgb, var(--dsw-static-blue-400) 22%, transparent) 45%, color-mix(in srgb, var(--dsw-static-blue-500) 38%, transparent)) border-box;width:min(760px,100vw - 48px);max-height:min(760px,88vh);box-shadow:var(--dsw-shadow-lv3), 0 24px 80px -24px color-mix(in srgb, var(--dsw-static-blue-500) 35%, transparent);border:1px solid #0000;animation:.18s ease-out VWh0dG_dashboardIn}@keyframes VWh0dG_dashboardIn{0%{opacity:0;transform:translateY(8px)scale(.98)}to{opacity:1;transform:none}}div[role=presentation]:has(>.dsh-billing-modal)>div[aria-hidden=true]:first-child{backdrop-filter:blur(8px)saturate(1.25)}.VWh0dG_dashboard{flex-direction:column;width:100%;max-height:min(760px,88vh);display:flex}.VWh0dG_dashboardHead{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:flex-start;gap:12px;padding:20px 24px 14px;display:flex}.VWh0dG_dashboardTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:17px;font-weight:600;line-height:24px}.VWh0dG_dashboardSubtitle{color:var(--dsw-alias-label-caption);margin:3px 0 0;font-size:12px;line-height:17px}.VWh0dG_closeButton{width:30px;height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;transition:background-color .14s;display:inline-flex}.VWh0dG_closeButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.VWh0dG_closeButton svg{stroke-width:2px;width:16px;height:16px}.VWh0dG_dashboardBody{flex-direction:column;gap:14px;padding:16px 24px 24px;display:flex;overflow-y:auto}.VWh0dG_tabNav{border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:4px;padding:10px 24px;display:flex}.VWh0dG_tabButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;padding:5px 14px;font-size:12.5px;font-weight:500;line-height:18px;transition:background-color .16s,color .16s,box-shadow .16s}.VWh0dG_tabButton:hover,.VWh0dG_tabButton:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);outline:none}.VWh0dG_tabButtonActive,.VWh0dG_tabButtonActive:hover,.VWh0dG_tabButtonActive:focus-visible{background:linear-gradient(135deg, var(--dsw-static-blue-500), color-mix(in srgb, var(--dsw-static-blue-500) 72%, var(--dsw-static-blue-400)));color:var(--dsw-static-neutral-bluish-00);box-shadow:0 2px 10px -3px color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent);font-weight:600}.VWh0dG_tabPanel{flex-direction:column;gap:14px;animation:.14s ease-out VWh0dG_tabPanelIn;display:flex}@keyframes VWh0dG_tabPanelIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.VWh0dG_hero{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 16%, var(--dsw-alias-border-l1));background:radial-gradient(90% 150% at 6% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 10%, transparent), transparent 60%), radial-gradient(70% 130% at 96% 100%, color-mix(in srgb, var(--dsw-static-blue-400) 8%, transparent), transparent 55%), var(--dsw-alias-bg-layer-1);border-radius:16px;justify-content:space-between;align-items:center;gap:24px;padding:20px 24px;display:flex;position:relative;overflow:hidden}.VWh0dG_heroMain{flex-direction:column;gap:4px;min-width:0;display:flex}.VWh0dG_heroLabel{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroValue{letter-spacing:-.02em;font-variant-numeric:tabular-nums;white-space:nowrap;background:linear-gradient(120deg, var(--dsw-alias-label-primary) 25%, color-mix(in srgb, var(--dsw-static-blue-500) 85%, var(--dsw-alias-label-primary)));color:#0000;-webkit-text-fill-color:transparent;-webkit-background-clip:text;background-clip:text;font-size:44px;font-weight:600;line-height:52px}.VWh0dG_heroMeta{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroSide{border-left:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;gap:10px;padding-left:24px;display:flex}.VWh0dG_heroSideItem{align-items:baseline;gap:8px;display:flex}.VWh0dG_heroSideLabel{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroSideValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:16px;font-weight:600;line-height:22px}.VWh0dG_delta{align-items:center;gap:2px;margin-left:4px;font-size:11px;font-weight:600;line-height:17px;display:inline-flex}.VWh0dG_deltaUp{color:var(--dsw-static-green-500)}.VWh0dG_deltaDown{color:var(--dsw-static-red-500)}.VWh0dG_kpiGrid{grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;display:grid}.VWh0dG_kpiTile{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;flex-direction:column;gap:3px;padding:14px 15px;transition:border-color .16s,background-color .16s,transform .16s,box-shadow .16s;display:flex;position:relative;overflow:hidden}.VWh0dG_kpiTile:before{content:\"\";background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-static-blue-500) 70%, transparent), transparent);opacity:.7;height:2px;position:absolute;inset:0 0 auto}.VWh0dG_kpiTile:has(.VWh0dG_kpiGreen):before{background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-static-green-500) 70%, transparent), transparent)}.VWh0dG_kpiTile:hover{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);box-shadow:0 6px 16px -8px color-mix(in srgb, var(--dsw-alias-label-primary) 35%, transparent);transform:translateY(-1px)}.VWh0dG_kpiLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:15px}.VWh0dG_kpiValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:21px;font-weight:600;line-height:27px}.VWh0dG_kpiGreen{color:var(--dsw-static-green-500)}.VWh0dG_kpiDetail{color:var(--dsw-alias-label-caption);white-space:nowrap;text-overflow:ellipsis;font-size:11px;line-height:15px;overflow:hidden}.VWh0dG_panel{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:16px;flex-direction:column;gap:10px;padding:16px 18px;display:flex}.VWh0dG_panelHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.VWh0dG_panelTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;font-weight:600;line-height:20px}.VWh0dG_panelHint{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:11px;line-height:16px}.VWh0dG_rangeToggle{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:8px;gap:2px;padding:2px;display:inline-flex}.VWh0dG_rangeButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background-color .14s,color .14s}.VWh0dG_rangeButtonActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font-weight:600}.VWh0dG_budget{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;flex-direction:column;gap:8px;padding:12px 16px;display:flex}.VWh0dG_budgetHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.VWh0dG_budgetLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:17px}.VWh0dG_budgetValue{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_budgetControls{align-items:center;gap:8px;min-width:0;display:inline-flex}.VWh0dG_budgetInputWrap{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:6px;align-items:center;gap:2px;padding:2px 6px;display:inline-flex}.VWh0dG_budgetInputWrap:focus-within{border-color:var(--dsw-alias-border-l3)}.VWh0dG_budgetUnit{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.VWh0dG_budgetInput{width:64px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:right;background:0 0;border:none;padding:0;font-size:12px;line-height:16px}.VWh0dG_budgetInput:focus-visible{outline:none}.VWh0dG_switch{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);cursor:pointer;border-radius:999px;flex:none;width:30px;height:17px;padding:0;transition:background-color .16s,border-color .16s;position:relative}.VWh0dG_switchOn{border-color:var(--dsw-static-blue-500);background:var(--dsw-static-blue-500)}.VWh0dG_switchKnob{background:var(--dsw-static-neutral-bluish-00);border-radius:50%;width:11px;height:11px;transition:transform .16s;position:absolute;top:2px;left:2px}.VWh0dG_switchOn .VWh0dG_switchKnob{transform:translate(13px)}.VWh0dG_budgetTrack{background:var(--dsw-alias-bg-module-platform);border-radius:999px;height:6px;overflow:hidden}.VWh0dG_budgetFill{background:var(--dsw-static-blue-500);border-radius:999px;height:100%;transition:width .2s}.VWh0dG_budgetFillOver{background:var(--dsw-static-red-500);animation:1.6s ease-in-out infinite VWh0dG_budgetOverPulse}@keyframes VWh0dG_budgetOverPulse{50%{opacity:.55}}.VWh0dG_chartWrap{width:100%;position:relative}.VWh0dG_chartSvg{width:100%;height:auto;display:block}.VWh0dG_chartEmpty{height:140px;color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;font-size:13px;display:flex}.VWh0dG_emptyRow{text-align:center;color:var(--dsw-alias-label-caption);padding:28px 0;font-size:13px}.VWh0dG_chartGrid{stroke:var(--dsw-alias-border-l1);stroke-width:1px}.VWh0dG_chartAxisLabel{fill:var(--dsw-alias-label-tertiary);font-size:10px}.VWh0dG_chartBar{fill:var(--dsw-static-blue-500);opacity:.35}.VWh0dG_chartBar:hover{opacity:.6}.VWh0dG_chartStack{stroke:var(--dsw-alias-bg-layer-1);stroke-width:.75px}.VWh0dG_chartStack:hover{opacity:.85}.VWh0dG_chartLine{stroke:var(--dsw-static-blue-500);stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}.VWh0dG_chartCrosshair{stroke:var(--dsw-alias-label-dimmed);stroke-width:1px;stroke-dasharray:3 3}.VWh0dG_chartDot{fill:var(--dsw-static-neutral-bluish-00);stroke:var(--dsw-static-blue-500);stroke-width:2.5px}.VWh0dG_chartTooltip{pointer-events:none;z-index:2;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);box-shadow:var(--dsw-shadow-lv2);white-space:nowrap;border-radius:10px;padding:8px 10px;position:absolute;transform:translate(-50%,calc(-100% - 10px))}.VWh0dG_chartTooltipDate{color:var(--dsw-alias-label-primary);margin-bottom:3px;font-size:11px;font-weight:600}.VWh0dG_chartTooltipRow{color:var(--dsw-alias-label-secondary);align-items:center;gap:5px;font-size:11px;line-height:17px;display:flex}.VWh0dG_chartTooltipRow strong{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-weight:600}.VWh0dG_chartLegendLine{background:var(--dsw-static-blue-500);border-radius:2px;width:10px;height:3px;display:inline-block}.VWh0dG_chartLegendBar{background:var(--dsw-static-blue-500);opacity:.5;border-radius:2px;width:7px;height:7px;display:inline-block}.VWh0dG_chartTooltipSwatch{border-radius:3px;flex:none;width:8px;height:8px;display:inline-block}.VWh0dG_chartLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-end;gap:14px;margin-top:2px;font-size:11px;display:flex}.VWh0dG_chartLegend span{align-items:center;gap:5px;display:inline-flex}.VWh0dG_tableScroll{border:1px solid var(--dsw-alias-border-l1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;overflow:auto}.VWh0dG_modelTable,.VWh0dG_pricingTable{border-collapse:collapse;width:100%;font-size:12.5px}.VWh0dG_modelTable th,.VWh0dG_modelTable td,.VWh0dG_pricingTable th,.VWh0dG_pricingTable td{border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;white-space:nowrap;padding:9px 12px}.VWh0dG_modelTable tbody tr:last-child td,.VWh0dG_pricingTable tbody tr:last-child td{border-bottom:0}.VWh0dG_modelTable thead th,.VWh0dG_pricingTable thead th{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);font-size:11px;font-weight:500}.VWh0dG_modelTable tbody tr,.VWh0dG_pricingTable tbody tr{transition:background-color .12s}.VWh0dG_modelTable tbody tr:hover,.VWh0dG_pricingTable tbody tr:hover{background:var(--dsw-alias-interactive-bg-hover)}.VWh0dG_numCol{text-align:right;font-variant-numeric:tabular-nums}.VWh0dG_costCol{color:var(--dsw-static-blue-500);font-weight:600}.VWh0dG_na{color:var(--dsw-alias-label-dimmed)}.VWh0dG_modelCell{align-items:center;gap:8px;display:inline-flex}.VWh0dG_modelDot{width:9px;height:9px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-bg-layer-1) 60%, transparent);border-radius:50%;flex:none}.VWh0dG_modelName{color:var(--dsw-alias-label-primary);font-weight:500;line-height:16px;display:block}.VWh0dG_modelProvider{color:var(--dsw-alias-label-caption);font-size:10.5px;line-height:14px;display:block}.VWh0dG_pricingToggle{cursor:pointer;text-align:left;background:0 0;border:none;justify-content:space-between;align-items:center;gap:10px;width:100%;padding:0;display:flex}.VWh0dG_pricingToggle:hover .VWh0dG_panelTitle,.VWh0dG_pricingToggle:focus-visible .VWh0dG_panelTitle{color:var(--dsw-static-blue-500)}.VWh0dG_rateBadge{vertical-align:1px;white-space:nowrap;border-radius:999px;align-items:center;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:500;line-height:14px;display:inline-flex}.VWh0dG_rateBadgeLive{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 10%, transparent)}.VWh0dG_rateBadgeBuiltin{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform)}.VWh0dG_pricingToggleText{align-items:baseline;gap:10px;min-width:0;display:flex}.VWh0dG_pricingChevron{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.VWh0dG_pricingChevronOpen{transform:rotate(180deg)}.VWh0dG_bandPrice{align-items:baseline;gap:6px;display:inline-flex}.VWh0dG_bandPriceOff{color:var(--dsw-alias-label-caption)}.VWh0dG_bandPriceOff:before{content:\"/\";color:var(--dsw-alias-label-dimmed);margin-right:4px}.VWh0dG_bandTag{color:var(--dsw-alias-label-secondary);flex-direction:column;gap:1px;font-size:10.5px;line-height:14px;display:inline-flex}.VWh0dG_bandTagOff{color:var(--dsw-static-green-500);font-weight:600}.VWh0dG_flatTag{color:var(--dsw-alias-label-caption);font-size:10.5px;line-height:14px}.VWh0dG_healthDot{border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.VWh0dG_healthOk{background:var(--dsw-static-green-500);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-static-green-500) 18%, transparent)}.VWh0dG_healthBad{background:var(--dsw-static-red-500);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-static-red-500) 18%, transparent)}.VWh0dG_healthIdle{background:var(--dsw-static-neutral-bluish-400)}.VWh0dG_dashboardRight{align-items:center;gap:8px;min-width:0;display:flex}.VWh0dG_healthBadge{white-space:nowrap;border-radius:999px;align-items:center;gap:6px;padding:3px 9px;font-size:11px;line-height:16px;display:inline-flex}.VWh0dG_healthBadgeOk{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 10%, transparent)}.VWh0dG_healthBadgeBad{color:var(--dsw-static-red-500);background:color-mix(in srgb, var(--dsw-static-red-500) 10%, transparent)}.VWh0dG_planTag{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 12%, transparent);border-radius:999px;align-items:center;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.VWh0dG_uncataloguedTag{vertical-align:1px;color:var(--dsw-static-amber-500);background:color-mix(in srgb, var(--dsw-static-amber-500) 12%, transparent);border-radius:999px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;line-height:16px;display:inline-block}.VWh0dG_estimatedTag{vertical-align:1px;color:var(--dsw-static-blue-500);background:color-mix(in srgb, var(--dsw-static-blue-500) 12%, transparent);border-radius:999px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;line-height:16px;display:inline-block}.VWh0dG_liveCostBar{color:var(--dsw-static-neutral-400);font-variant-numeric:tabular-nums;align-items:center;gap:6px;font-size:11px;line-height:16px;display:inline-flex}.VWh0dG_liveCostItem{white-space:nowrap}.VWh0dG_liveCostSep{color:var(--dsw-static-neutral-300)}.VWh0dG_balanceCell{flex-direction:column;align-items:flex-end;gap:2px;display:inline-flex}.VWh0dG_balanceDays{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:10.5px;line-height:14px}.VWh0dG_balanceDaysLow{color:var(--dsw-static-red-500);font-weight:600}body[data-zine-mode] .VWh0dG_trigger,body[data-zine-mode] .VWh0dG_railButton{display:none}body[data-zine-mode] .VWh0dG_dashboardHead{background:#000;border-bottom:2px solid #e8ff00}body[data-zine-mode] .VWh0dG_headTitleRow{align-items:center;gap:8px;margin-top:4px;display:flex}body[data-zine-mode] .VWh0dG_dashboardTitle{color:#e8ff00;letter-spacing:.04em;text-transform:uppercase;text-shadow:0 0 8px #e8ff0066;font-weight:900}body[data-zine-mode] .VWh0dG_dashboardSubtitle{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;font-size:10px}body[data-zine-mode] .VWh0dG_closeButton{color:#0a0a05;background:#ff2d95;border:1.5px solid #ff2d95;border-radius:0;box-shadow:0 0 10px #ff2d9573}body[data-zine-mode] .VWh0dG_hero{background:#000;border:2.5px solid #e8ff00;border-radius:0;position:relative;box-shadow:0 0 0 1px #0009,0 0 24px #e8ff002e}body[data-zine-mode] .VWh0dG_heroLabel{color:#c9d98a;letter-spacing:.12em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_heroValue{color:#e8ff00;letter-spacing:-.02em;text-shadow:0 0 12px #e8ff0073;-webkit-text-fill-color:#e8ff00;background:0 0;font-size:38px;font-weight:900}body[data-zine-mode] .VWh0dG_heroMeta{color:#c9d98a;letter-spacing:.06em;text-transform:uppercase;font-size:10.5px}body[data-zine-mode] .VWh0dG_heroSideLabel{color:#c9d98a;letter-spacing:.1em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_heroSideValue{color:#e8ff00;text-shadow:0 0 6px #e8ff0059}body[data-zine-mode] .VWh0dG_delta{font-weight:900}body[data-zine-mode] .VWh0dG_deltaUp{color:#ff2d95}body[data-zine-mode] .VWh0dG_deltaDown{color:#c9d98a}body[data-zine-mode] .VWh0dG_tabNav{background:#000;border-bottom:2px solid #e8ff00}body[data-zine-mode] .VWh0dG_tabButton{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;border-radius:0;font-size:10.5px;font-weight:900}body[data-zine-mode] .VWh0dG_tabButton:hover,body[data-zine-mode] .VWh0dG_tabButton:focus-visible{color:#e8ff00;background:#e8ff001f}body[data-zine-mode] .VWh0dG_tabButtonActive,body[data-zine-mode] .VWh0dG_tabButtonActive:hover,body[data-zine-mode] .VWh0dG_tabButtonActive:focus-visible{color:#0a0a05;background:#e8ff00;box-shadow:0 0 10px #e8ff0073}body[data-zine-mode] .VWh0dG_panel{background:#000;border:2px solid #e8ff00;border-radius:0}body[data-zine-mode] .VWh0dG_trendPanel{position:relative}body[data-zine-mode] .VWh0dG_panelTitle{color:#e8ff00;letter-spacing:.06em;text-transform:uppercase;text-shadow:0 0 6px #e8ff0066;font-weight:900}body[data-zine-mode] .VWh0dG_panelHint{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_modelTableScroll{background:#000;border:1.5px solid #e8ff0080;border-radius:0}.VWh0dG_currencyToggle{border:1px solid var(--dsw-alias-border-muted,#3a4250);background:var(--dsw-alias-bg-layer-2,#232a33);border-radius:6px;align-items:center;gap:2px;margin-right:8px;padding:2px;display:inline-flex}.VWh0dG_currencyButton{color:var(--dsw-alias-text-secondary,#9aa5b1);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:4px 7px;font-size:11px;font-weight:700;line-height:1}.VWh0dG_currencyButtonActive{background:var(--dsw-alias-accent-muted,#2f6fed);color:#fff}.VWh0dG_subscriptionGrid{grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;margin-top:10px;display:grid}.VWh0dG_subscriptionCard{border:1px solid var(--dsw-alias-border-muted,#3a4250);background:var(--dsw-alias-bg-layer-2,#232a33);border-radius:8px;padding:10px 12px}.VWh0dG_subscriptionHead{align-items:baseline;gap:8px;margin-bottom:6px;display:flex}.VWh0dG_subscriptionName{font-size:13px;font-weight:700}.VWh0dG_subscriptionPlan{color:var(--dsw-alias-text-secondary,#9aa5b1);font-size:11px}.VWh0dG_subscriptionStatus{color:var(--dsw-alias-warning,#e0a63c);margin-bottom:6px;font-size:11px}.VWh0dG_subscriptionWindow{align-items:center;gap:8px;margin-top:6px;font-size:11px;display:flex}.VWh0dG_subscriptionWindowLabel{color:var(--dsw-alias-text-secondary,#9aa5b1);flex:0 0 44px}.VWh0dG_subscriptionTrack{background:var(--dsw-alias-bg-layer-3,#1a2028);border-radius:3px;flex:1;height:5px;overflow:hidden}.VWh0dG_subscriptionFill{background:var(--dsw-alias-accent,#3b82f6);border-radius:3px;height:100%;display:block}.VWh0dG_subscriptionPct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:52px}.VWh0dG_subscriptionReset{color:var(--dsw-alias-text-secondary,#9aa5b1);flex:none}.VWh0dG_providerGroupList{flex-direction:column;gap:10px;display:flex}.VWh0dG_providerGroup{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:12px 14px}.VWh0dG_providerGroupHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.VWh0dG_providerGroupTitle{align-items:center;gap:7px;min-width:0;display:inline-flex}.VWh0dG_providerGroupName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:18px}.VWh0dG_providerGroupMeta{flex:none;align-items:center;gap:10px;display:inline-flex}.VWh0dG_providerGroupBadge{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 12%, transparent);border-radius:999px;align-items:center;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.VWh0dG_providerGroupBalance{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;align-items:baseline;gap:6px;font-size:12px;line-height:17px;display:inline-flex}.VWh0dG_providerGroupBalanceLabel{color:var(--dsw-alias-label-caption);font-size:11px;line-height:17px}.VWh0dG_roundsFlagBadge{color:#fff;background:#ef4444;border-radius:999px;margin-left:8px;padding:1px 7px;font-size:10px;font-weight:800}.VWh0dG_rounds{margin-top:10px}.VWh0dG_roundsBars{align-items:flex-end;gap:3px;height:110px;padding:4px 2px 0;display:flex;overflow-x:auto}.VWh0dG_roundsBarCol{flex-direction:column;flex:1 0 28px;justify-content:flex-end;align-items:stretch;height:100%;display:flex}.VWh0dG_roundsBarLabel{text-align:center;color:var(--dsw-alias-text-secondary,#9aa5b1);white-space:nowrap;text-overflow:ellipsis;max-width:100%;margin-bottom:2px;font-size:8px;line-height:1;overflow:hidden}.VWh0dG_roundsBarWrap{flex:1;align-items:flex-end;min-height:0;display:flex}.VWh0dG_roundsBar{background:var(--dsw-alias-accent,#3b82f6);border-radius:2px 2px 0 0;width:100%;min-height:2px;position:relative}.VWh0dG_roundsBarFlagged{outline-offset:1px;background:#ef4444;border-radius:2px 2px 0 0;outline:1.5px solid #ef4444;width:100%;min-height:2px;position:relative}.VWh0dG_roundsFlagMark{background:#ef4444;border-radius:50%;width:7px;height:7px;position:absolute;top:-3px;right:-3px;box-shadow:0 0 4px #ef4444}.VWh0dG_roundsAxis{color:var(--dsw-alias-text-secondary,#9aa5b1);justify-content:space-between;margin-top:6px;font-size:10px;display:flex}.VWh0dG_roundsEmpty{color:var(--dsw-alias-text-secondary,#9aa5b1);margin-top:10px;font-size:12px}.VWh0dG_heatmap{margin-top:10px}.VWh0dG_heatmapGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:8px;display:grid}.VWh0dG_heatmapCellEmpty{background:var(--dsw-alias-bg-layer-1);height:30px;color:var(--dsw-alias-label-dimmed,#6b7480);font-variant-numeric:tabular-nums;border-radius:8px;justify-content:center;align-items:center;font-size:11px;display:flex}.VWh0dG_heatmapCell{font-variant-numeric:tabular-nums;cursor:pointer;border:0;border-radius:8px;justify-content:center;align-items:center;height:30px;padding:0;font-size:11px;display:flex}.VWh0dG_heatmapCell[data-level=\"0\"],.VWh0dG_heatmapCell[data-level=\"1\"],.VWh0dG_heatmapCell[data-level=\"2\"]{color:var(--dsw-alias-label-primary)}.VWh0dG_heatmapCell[data-level=\"3\"],.VWh0dG_heatmapCell[data-level=\"4\"]{color:var(--dsw-static-neutral-bluish-00,#fff)}.VWh0dG_heatmapFooter{color:var(--dsw-alias-text-secondary,#9aa5b1);align-items:center;gap:8px;margin-top:10px;font-size:10px;display:flex}.VWh0dG_heatmapLegend{gap:3px;display:inline-flex}.VWh0dG_heatmapLegend i{border-radius:4px;width:14px;height:14px;display:block}.VWh0dG_heatmapHover{font-variant-numeric:tabular-nums;margin-left:auto}@media (width<=640px){.VWh0dG_kpiGrid{grid-template-columns:repeat(2,minmax(0,1fr))}.VWh0dG_hero{flex-direction:column;align-items:flex-start;gap:14px}.VWh0dG_heroSide{border-left:none;border-top:1px solid var(--dsw-alias-border-l1);flex-direction:row;align-self:stretch;gap:20px;padding-top:14px;padding-left:0}}";
27
+ const css = ".VWh0dG_railButton{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 28%, var(--dsw-alias-border-l2));background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-static-blue-500) 14%, var(--dsw-alias-bg-layer-1)), var(--dsw-alias-bg-layer-1));width:36px;height:36px;color:var(--dsw-static-blue-500);cursor:pointer;border-radius:10px;justify-content:center;align-items:center;padding:0;transition:border-color .16s,box-shadow .16s,transform .16s,color .16s;display:flex}.VWh0dG_railButton:hover,.VWh0dG_railButton:focus-visible{border-color:color-mix(in srgb, var(--dsw-static-blue-500) 48%, var(--dsw-alias-border-l2));box-shadow:0 4px 14px -6px color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent);color:var(--dsw-static-blue-400);outline:none;transform:translateY(-1px)}.VWh0dG_railButton svg{stroke-width:2px;width:18px;height:18px}.VWh0dG_trigger{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 20%, var(--dsw-alias-border-l1));background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 12%, transparent), transparent 55%), radial-gradient(150% 200% at 100% 110%, color-mix(in srgb, var(--dsw-static-blue-400) 9%, transparent), transparent 60%), var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:12px;align-items:center;gap:12px;padding:10px 14px;transition:border-color .16s,box-shadow .16s,transform .16s;display:flex;position:relative;overflow:hidden}@supports (backdrop-filter:blur(1px)){.VWh0dG_trigger{background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 14%, transparent), transparent 55%), radial-gradient(150% 200% at 100% 110%, color-mix(in srgb, var(--dsw-static-blue-400) 10%, transparent), transparent 60%), color-mix(in srgb, var(--dsw-alias-bg-layer-1) 72%, transparent);backdrop-filter:blur(12px)}}.VWh0dG_trigger:hover,.VWh0dG_trigger:focus-visible{border-color:color-mix(in srgb, var(--dsw-static-blue-500) 42%, var(--dsw-alias-border-l1));box-shadow:0 8px 24px -10px color-mix(in srgb, var(--dsw-static-blue-500) 45%, transparent);outline:none;transform:translateY(-1px)}.VWh0dG_triggerIcon{background:linear-gradient(135deg, var(--dsw-static-blue-500), var(--dsw-static-blue-400));width:28px;height:28px;color:var(--dsw-static-neutral-bluish-00);box-shadow:0 2px 8px -2px color-mix(in srgb, var(--dsw-static-blue-500) 60%, transparent);border-radius:8px;flex:none;justify-content:center;align-items:center;display:inline-flex}.VWh0dG_triggerIcon svg{stroke-width:1.8px;width:15px;height:15px}.VWh0dG_triggerToday,.VWh0dG_triggerMonth{align-items:baseline;gap:4px;min-width:0;display:flex}.VWh0dG_triggerDivider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px}.VWh0dG_triggerAmount{color:var(--dsw-alias-label-primary);letter-spacing:-.01em;font-variant-numeric:tabular-nums;white-space:nowrap;font-size:18px;font-weight:600;line-height:22px}.VWh0dG_triggerAmountSub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:13px;font-weight:600;line-height:18px}.VWh0dG_triggerMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:10.5px;line-height:14px}.VWh0dG_triggerWrap{width:100%;display:block;position:relative}.VWh0dG_triggerPop{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 22%, var(--dsw-alias-border-l1));background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 12%, transparent), transparent 55%), var(--dsw-alias-bg-layer-2);box-shadow:0 12px 32px -12px color-mix(in srgb, var(--dsw-alias-label-primary) 30%, transparent);opacity:0;pointer-events:none;z-index:10;border-radius:12px;flex-direction:column;gap:6px;padding:12px 14px;transition:opacity .16s,transform .16s;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;right:0;transform:translateY(4px)}@supports (backdrop-filter:blur(1px)){.VWh0dG_triggerPop{background:radial-gradient(130% 180% at 0% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 14%, transparent), transparent 55%), color-mix(in srgb, var(--dsw-alias-bg-layer-2) 82%, transparent);backdrop-filter:blur(14px)}}.VWh0dG_triggerWrap:hover .VWh0dG_triggerPop,.VWh0dG_triggerWrap:focus-within .VWh0dG_triggerPop{opacity:1;transform:translateY(0)}.VWh0dG_triggerPopRow{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.VWh0dG_triggerPopLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.VWh0dG_triggerPopValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:13px;font-weight:600;line-height:18px}.VWh0dG_triggerPopBars{border-top:1px solid var(--dsw-alias-border-l1);align-items:flex-end;gap:4px;height:22px;margin-top:4px;padding-top:8px;display:flex}.VWh0dG_triggerPopBar{background:linear-gradient(180deg, var(--dsw-static-blue-400), var(--dsw-static-blue-500));border-radius:2px;flex:1;transition:height .2s}.VWh0dG_dashboardModal{background:linear-gradient(var(--dsw-alias-bg-layer-2), var(--dsw-alias-bg-layer-2)) padding-box, linear-gradient(135deg, color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent), color-mix(in srgb, var(--dsw-static-blue-400) 22%, transparent) 45%, color-mix(in srgb, var(--dsw-static-blue-500) 38%, transparent)) border-box;width:min(760px,100vw - 48px);max-height:min(760px,88vh);box-shadow:var(--dsw-shadow-lv3), 0 24px 80px -24px color-mix(in srgb, var(--dsw-static-blue-500) 35%, transparent);border:1px solid #0000;animation:.18s ease-out VWh0dG_dashboardIn}@keyframes VWh0dG_dashboardIn{0%{opacity:0;transform:translateY(8px)scale(.98)}to{opacity:1;transform:none}}div[role=presentation]:has(>.dsh-billing-modal)>div[aria-hidden=true]:first-child{backdrop-filter:blur(8px)saturate(1.25)}.VWh0dG_dashboard{flex-direction:column;width:100%;max-height:min(760px,88vh);display:flex}.VWh0dG_dashboardHead{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:flex-start;gap:12px;padding:20px 24px 14px;display:flex}.VWh0dG_dashboardTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:17px;font-weight:600;line-height:24px}.VWh0dG_dashboardSubtitle{color:var(--dsw-alias-label-caption);margin:3px 0 0;font-size:12px;line-height:17px}.VWh0dG_closeButton{width:30px;height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;transition:background-color .14s;display:inline-flex}.VWh0dG_closeButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.VWh0dG_closeButton svg{stroke-width:2px;width:16px;height:16px}.VWh0dG_dashboardBody{flex-direction:column;gap:14px;padding:16px 24px 24px;display:flex;overflow-y:auto}.VWh0dG_tabNav{border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:4px;padding:10px 24px;display:flex}.VWh0dG_tabButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;padding:5px 14px;font-size:12.5px;font-weight:500;line-height:18px;transition:background-color .16s,color .16s,box-shadow .16s}.VWh0dG_tabButton:hover,.VWh0dG_tabButton:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);outline:none}.VWh0dG_tabButtonActive,.VWh0dG_tabButtonActive:hover,.VWh0dG_tabButtonActive:focus-visible{background:linear-gradient(135deg, var(--dsw-static-blue-500), color-mix(in srgb, var(--dsw-static-blue-500) 72%, var(--dsw-static-blue-400)));color:var(--dsw-static-neutral-bluish-00);box-shadow:0 2px 10px -3px color-mix(in srgb, var(--dsw-static-blue-500) 55%, transparent);font-weight:600}.VWh0dG_tabPanel{flex-direction:column;gap:14px;animation:.14s ease-out VWh0dG_tabPanelIn;display:flex}@keyframes VWh0dG_tabPanelIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.VWh0dG_hero{border:1px solid color-mix(in srgb, var(--dsw-static-blue-500) 16%, var(--dsw-alias-border-l1));background:radial-gradient(90% 150% at 6% 0%, color-mix(in srgb, var(--dsw-static-blue-500) 10%, transparent), transparent 60%), radial-gradient(70% 130% at 96% 100%, color-mix(in srgb, var(--dsw-static-blue-400) 8%, transparent), transparent 55%), var(--dsw-alias-bg-layer-1);border-radius:16px;justify-content:space-between;align-items:center;gap:24px;padding:20px 24px;display:flex;position:relative;overflow:hidden}.VWh0dG_heroMain{flex-direction:column;gap:4px;min-width:0;display:flex}.VWh0dG_heroLabel{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroValue{letter-spacing:-.02em;font-variant-numeric:tabular-nums;white-space:nowrap;background:linear-gradient(120deg, var(--dsw-alias-label-primary) 25%, color-mix(in srgb, var(--dsw-static-blue-500) 85%, var(--dsw-alias-label-primary)));color:#0000;-webkit-text-fill-color:transparent;-webkit-background-clip:text;background-clip:text;font-size:44px;font-weight:600;line-height:52px}.VWh0dG_heroMeta{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroSide{border-left:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;gap:10px;padding-left:24px;display:flex}.VWh0dG_heroSideItem{align-items:baseline;gap:8px;display:flex}.VWh0dG_heroSideLabel{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_heroSideValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:16px;font-weight:600;line-height:22px}.VWh0dG_delta{align-items:center;gap:2px;margin-left:4px;font-size:11px;font-weight:600;line-height:17px;display:inline-flex}.VWh0dG_deltaUp{color:var(--dsw-static-green-500)}.VWh0dG_deltaDown{color:var(--dsw-static-red-500)}.VWh0dG_kpiGrid{grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;display:grid}.VWh0dG_kpiTile{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;flex-direction:column;gap:3px;padding:14px 15px;transition:border-color .16s,background-color .16s,transform .16s,box-shadow .16s;display:flex;position:relative;overflow:hidden}.VWh0dG_kpiTile:before{content:\"\";background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-static-blue-500) 70%, transparent), transparent);opacity:.7;height:2px;position:absolute;inset:0 0 auto}.VWh0dG_kpiTile:has(.VWh0dG_kpiGreen):before{background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-static-green-500) 70%, transparent), transparent)}.VWh0dG_kpiTile:hover{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);box-shadow:0 6px 16px -8px color-mix(in srgb, var(--dsw-alias-label-primary) 35%, transparent);transform:translateY(-1px)}.VWh0dG_kpiLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:15px}.VWh0dG_kpiValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:21px;font-weight:600;line-height:27px}.VWh0dG_kpiGreen{color:var(--dsw-static-green-500)}.VWh0dG_kpiDetail{color:var(--dsw-alias-label-caption);white-space:nowrap;text-overflow:ellipsis;font-size:11px;line-height:15px;overflow:hidden}.VWh0dG_panel{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:16px;flex-direction:column;gap:10px;padding:16px 18px;display:flex}.VWh0dG_panelHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.VWh0dG_panelTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;font-weight:600;line-height:20px}.VWh0dG_panelHint{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:11px;line-height:16px}.VWh0dG_rangeToggle{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:8px;gap:2px;padding:2px;display:inline-flex}.VWh0dG_rangeButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background-color .14s,color .14s}.VWh0dG_rangeButtonActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font-weight:600}.VWh0dG_exportBar{justify-content:flex-end;align-items:center;gap:8px;display:flex}.VWh0dG_exportLabel{color:var(--dsw-alias-label-caption);font-size:11px;line-height:16px}.VWh0dG_exportButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);cursor:pointer;border-radius:999px;padding:4px 12px;font-size:11.5px;line-height:16px;transition:border-color .16s,color .16s,background-color .16s}.VWh0dG_exportButton:hover,.VWh0dG_exportButton:focus-visible{border-color:color-mix(in srgb, var(--dsw-static-blue-500) 40%, var(--dsw-alias-border-l1));color:var(--dsw-static-blue-500);outline:none}.VWh0dG_shareTrack{background:var(--dsw-alias-bg-module-platform);border-radius:999px;height:10px;display:flex;overflow:hidden}.VWh0dG_shareSeg{height:100%;transition:width .2s}.VWh0dG_shareSegPeak{background:linear-gradient(90deg, var(--dsw-static-blue-500), var(--dsw-static-blue-400))}.VWh0dG_shareSegOff{background:color-mix(in srgb, var(--dsw-static-blue-500) 30%, var(--dsw-alias-bg-module-platform))}.VWh0dG_shareSegUser{background:linear-gradient(90deg, var(--dsw-static-blue-500), var(--dsw-static-blue-400))}.VWh0dG_shareSegAssistant{background:linear-gradient(90deg, var(--dsw-static-green-500), color-mix(in srgb, var(--dsw-static-green-500) 70%, var(--dsw-static-blue-400)))}.VWh0dG_shareSegTool{background:color-mix(in srgb, var(--dsw-static-amber-500) 80%, var(--dsw-alias-bg-module-platform))}.VWh0dG_shareLegend{align-items:center;gap:16px;display:flex}.VWh0dG_shareItem{color:var(--dsw-alias-label-secondary);align-items:baseline;gap:6px;font-size:12px;line-height:17px;display:inline-flex}.VWh0dG_shareDot{border-radius:50%;flex:none;align-self:center;width:8px;height:8px}.VWh0dG_shareValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-weight:600}.VWh0dG_budget{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;flex-direction:column;gap:8px;padding:12px 16px;display:flex}.VWh0dG_budgetHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.VWh0dG_budgetLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:17px}.VWh0dG_budgetValue{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:17px}.VWh0dG_budgetControls{align-items:center;gap:8px;min-width:0;display:inline-flex}.VWh0dG_budgetInputWrap{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:6px;align-items:center;gap:2px;padding:2px 6px;display:inline-flex}.VWh0dG_budgetInputWrap:focus-within{border-color:var(--dsw-alias-border-l3)}.VWh0dG_budgetUnit{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.VWh0dG_budgetInput{width:64px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:right;background:0 0;border:none;padding:0;font-size:12px;line-height:16px}.VWh0dG_budgetInput:focus-visible{outline:none}.VWh0dG_switch{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);cursor:pointer;border-radius:999px;flex:none;width:30px;height:17px;padding:0;transition:background-color .16s,border-color .16s;position:relative}.VWh0dG_switchOn{border-color:var(--dsw-static-blue-500);background:var(--dsw-static-blue-500)}.VWh0dG_switchKnob{background:var(--dsw-static-neutral-bluish-00);border-radius:50%;width:11px;height:11px;transition:transform .16s;position:absolute;top:2px;left:2px}.VWh0dG_switchOn .VWh0dG_switchKnob{transform:translate(13px)}.VWh0dG_budgetTrack{background:var(--dsw-alias-bg-module-platform);border-radius:999px;height:6px;overflow:hidden}.VWh0dG_budgetFill{background:var(--dsw-static-blue-500);border-radius:999px;height:100%;transition:width .2s}.VWh0dG_budgetFillWarn{background:var(--dsw-static-amber-500)}.VWh0dG_budgetFillOver{background:var(--dsw-static-red-500);animation:1.6s ease-in-out infinite VWh0dG_budgetOverPulse}@keyframes VWh0dG_budgetOverPulse{50%{opacity:.55}}.VWh0dG_chartWrap{width:100%;position:relative}.VWh0dG_chartSvg{width:100%;height:auto;display:block}.VWh0dG_chartEmpty{height:140px;color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;font-size:13px;display:flex}.VWh0dG_emptyRow{text-align:center;color:var(--dsw-alias-label-caption);padding:28px 0;font-size:13px}.VWh0dG_chartGrid{stroke:var(--dsw-alias-border-l1);stroke-width:1px}.VWh0dG_chartAxisLabel{fill:var(--dsw-alias-label-tertiary);font-size:10px}.VWh0dG_chartBar{fill:var(--dsw-static-blue-500);opacity:.35}.VWh0dG_chartBar:hover{opacity:.6}.VWh0dG_chartStack{stroke:var(--dsw-alias-bg-layer-1);stroke-width:.75px}.VWh0dG_chartStack:hover{opacity:.85}.VWh0dG_chartLine{stroke:var(--dsw-static-blue-500);stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}.VWh0dG_chartCrosshair{stroke:var(--dsw-alias-label-dimmed);stroke-width:1px;stroke-dasharray:3 3}.VWh0dG_chartDot{fill:var(--dsw-static-neutral-bluish-00);stroke:var(--dsw-static-blue-500);stroke-width:2.5px}.VWh0dG_chartTooltip{pointer-events:none;z-index:2;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);box-shadow:var(--dsw-shadow-lv2);white-space:nowrap;border-radius:10px;padding:8px 10px;position:absolute;transform:translate(-50%,calc(-100% - 10px))}.VWh0dG_chartTooltipDate{color:var(--dsw-alias-label-primary);margin-bottom:3px;font-size:11px;font-weight:600}.VWh0dG_chartTooltipRow{color:var(--dsw-alias-label-secondary);align-items:center;gap:5px;font-size:11px;line-height:17px;display:flex}.VWh0dG_chartTooltipRow strong{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-weight:600}.VWh0dG_chartLegendLine{background:var(--dsw-static-blue-500);border-radius:2px;width:10px;height:3px;display:inline-block}.VWh0dG_chartLegendBar{background:var(--dsw-static-blue-500);opacity:.5;border-radius:2px;width:7px;height:7px;display:inline-block}.VWh0dG_chartTooltipSwatch{border-radius:3px;flex:none;width:8px;height:8px;display:inline-block}.VWh0dG_chartLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-end;gap:14px;margin-top:2px;font-size:11px;display:flex}.VWh0dG_chartLegend span{align-items:center;gap:5px;display:inline-flex}.VWh0dG_tableScroll{border:1px solid var(--dsw-alias-border-l1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;overflow:auto}.VWh0dG_modelTable,.VWh0dG_pricingTable{border-collapse:collapse;width:100%;font-size:12.5px}.VWh0dG_modelTable th,.VWh0dG_modelTable td,.VWh0dG_pricingTable th,.VWh0dG_pricingTable td{border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;white-space:nowrap;padding:9px 12px}.VWh0dG_modelTable tbody tr:last-child td,.VWh0dG_pricingTable tbody tr:last-child td{border-bottom:0}.VWh0dG_modelTable thead th,.VWh0dG_pricingTable thead th{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);font-size:11px;font-weight:500}.VWh0dG_modelTable tbody tr,.VWh0dG_pricingTable tbody tr{transition:background-color .12s}.VWh0dG_modelTable tbody tr:hover,.VWh0dG_pricingTable tbody tr:hover{background:var(--dsw-alias-interactive-bg-hover)}.VWh0dG_numCol{text-align:right;font-variant-numeric:tabular-nums}.VWh0dG_costCol{color:var(--dsw-static-blue-500);font-weight:600}.VWh0dG_na{color:var(--dsw-alias-label-dimmed)}.VWh0dG_modelCell{align-items:center;gap:8px;display:inline-flex}.VWh0dG_modelDot{width:9px;height:9px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-bg-layer-1) 60%, transparent);border-radius:50%;flex:none}.VWh0dG_modelName{color:var(--dsw-alias-label-primary);font-weight:500;line-height:16px;display:block}.VWh0dG_modelProvider{color:var(--dsw-alias-label-caption);font-size:10.5px;line-height:14px;display:block}.VWh0dG_pricingToggle{cursor:pointer;text-align:left;background:0 0;border:none;justify-content:space-between;align-items:center;gap:10px;width:100%;padding:0;display:flex}.VWh0dG_pricingToggle:hover .VWh0dG_panelTitle,.VWh0dG_pricingToggle:focus-visible .VWh0dG_panelTitle{color:var(--dsw-static-blue-500)}.VWh0dG_rateBadge{vertical-align:1px;white-space:nowrap;border-radius:999px;align-items:center;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:500;line-height:14px;display:inline-flex}.VWh0dG_rateBadgeLive{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 10%, transparent)}.VWh0dG_rateBadgeBuiltin{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform)}.VWh0dG_pricingToggleText{align-items:baseline;gap:10px;min-width:0;display:flex}.VWh0dG_pricingChevron{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.VWh0dG_pricingChevronOpen{transform:rotate(180deg)}.VWh0dG_bandPrice{align-items:baseline;gap:6px;display:inline-flex}.VWh0dG_bandPriceOff{color:var(--dsw-alias-label-caption)}.VWh0dG_bandPriceOff:before{content:\"/\";color:var(--dsw-alias-label-dimmed);margin-right:4px}.VWh0dG_bandTag{color:var(--dsw-alias-label-secondary);flex-direction:column;gap:1px;font-size:10.5px;line-height:14px;display:inline-flex}.VWh0dG_bandTagOff{color:var(--dsw-static-green-500);font-weight:600}.VWh0dG_flatTag{color:var(--dsw-alias-label-caption);font-size:10.5px;line-height:14px}.VWh0dG_healthDot{border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.VWh0dG_healthOk{background:var(--dsw-static-green-500);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-static-green-500) 18%, transparent)}.VWh0dG_healthBad{background:var(--dsw-static-red-500);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-static-red-500) 18%, transparent)}.VWh0dG_healthIdle{background:var(--dsw-static-neutral-bluish-400)}.VWh0dG_dashboardRight{align-items:center;gap:8px;min-width:0;display:flex}.VWh0dG_healthBadge{white-space:nowrap;border-radius:999px;align-items:center;gap:6px;padding:3px 9px;font-size:11px;line-height:16px;display:inline-flex}.VWh0dG_healthBadgeOk{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 10%, transparent)}.VWh0dG_healthBadgeBad{color:var(--dsw-static-red-500);background:color-mix(in srgb, var(--dsw-static-red-500) 10%, transparent)}.VWh0dG_planTag{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 12%, transparent);border-radius:999px;align-items:center;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.VWh0dG_uncataloguedTag{vertical-align:1px;color:var(--dsw-static-amber-500);background:color-mix(in srgb, var(--dsw-static-amber-500) 12%, transparent);border-radius:999px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;line-height:16px;display:inline-block}.VWh0dG_estimatedTag{vertical-align:1px;color:var(--dsw-static-blue-500);background:color-mix(in srgb, var(--dsw-static-blue-500) 12%, transparent);border-radius:999px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;line-height:16px;display:inline-block}.VWh0dG_liveCostBar{color:var(--dsw-static-neutral-400);font-variant-numeric:tabular-nums;align-items:center;gap:6px;font-size:11px;line-height:16px;display:inline-flex}.VWh0dG_liveCostItem{white-space:nowrap}.VWh0dG_liveCostSep{color:var(--dsw-static-neutral-300)}.VWh0dG_liveTierPeak{color:var(--dsw-static-blue-500);font-weight:600}.VWh0dG_liveTierOff{color:var(--dsw-static-green-500);font-weight:600}.VWh0dG_liveQuotaWarn{color:var(--dsw-static-amber-500);font-weight:600}.VWh0dG_liveQuotaCrit{color:var(--dsw-static-red-500);font-weight:600}.VWh0dG_balanceCell{flex-direction:column;align-items:flex-end;gap:2px;display:inline-flex}.VWh0dG_balanceDays{color:var(--dsw-alias-label-caption);white-space:nowrap;font-size:10.5px;line-height:14px}.VWh0dG_balanceDaysLow{color:var(--dsw-static-red-500);font-weight:600}body[data-zine-mode] .VWh0dG_trigger,body[data-zine-mode] .VWh0dG_triggerPop,body[data-zine-mode] .VWh0dG_railButton{display:none}body[data-zine-mode] .VWh0dG_dashboardHead{background:#000;border-bottom:2px solid #e8ff00}body[data-zine-mode] .VWh0dG_headTitleRow{align-items:center;gap:8px;margin-top:4px;display:flex}body[data-zine-mode] .VWh0dG_dashboardTitle{color:#e8ff00;letter-spacing:.04em;text-transform:uppercase;text-shadow:0 0 8px #e8ff0066;font-weight:900}body[data-zine-mode] .VWh0dG_dashboardSubtitle{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;font-size:10px}body[data-zine-mode] .VWh0dG_closeButton{color:#0a0a05;background:#ff2d95;border:1.5px solid #ff2d95;border-radius:0;box-shadow:0 0 10px #ff2d9573}body[data-zine-mode] .VWh0dG_hero{background:#000;border:2.5px solid #e8ff00;border-radius:0;position:relative;box-shadow:0 0 0 1px #0009,0 0 24px #e8ff002e}body[data-zine-mode] .VWh0dG_heroLabel{color:#c9d98a;letter-spacing:.12em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_heroValue{color:#e8ff00;letter-spacing:-.02em;text-shadow:0 0 12px #e8ff0073;-webkit-text-fill-color:#e8ff00;background:0 0;font-size:38px;font-weight:900}body[data-zine-mode] .VWh0dG_heroMeta{color:#c9d98a;letter-spacing:.06em;text-transform:uppercase;font-size:10.5px}body[data-zine-mode] .VWh0dG_heroSideLabel{color:#c9d98a;letter-spacing:.1em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_heroSideValue{color:#e8ff00;text-shadow:0 0 6px #e8ff0059}body[data-zine-mode] .VWh0dG_delta{font-weight:900}body[data-zine-mode] .VWh0dG_deltaUp{color:#ff2d95}body[data-zine-mode] .VWh0dG_deltaDown{color:#c9d98a}body[data-zine-mode] .VWh0dG_tabNav{background:#000;border-bottom:2px solid #e8ff00}body[data-zine-mode] .VWh0dG_tabButton{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;border-radius:0;font-size:10.5px;font-weight:900}body[data-zine-mode] .VWh0dG_tabButton:hover,body[data-zine-mode] .VWh0dG_tabButton:focus-visible{color:#e8ff00;background:#e8ff001f}body[data-zine-mode] .VWh0dG_tabButtonActive,body[data-zine-mode] .VWh0dG_tabButtonActive:hover,body[data-zine-mode] .VWh0dG_tabButtonActive:focus-visible{color:#0a0a05;background:#e8ff00;box-shadow:0 0 10px #e8ff0073}body[data-zine-mode] .VWh0dG_panel{background:#000;border:2px solid #e8ff00;border-radius:0}body[data-zine-mode] .VWh0dG_trendPanel{position:relative}body[data-zine-mode] .VWh0dG_panelTitle{color:#e8ff00;letter-spacing:.06em;text-transform:uppercase;text-shadow:0 0 6px #e8ff0066;font-weight:900}body[data-zine-mode] .VWh0dG_panelHint{color:#c9d98a;letter-spacing:.08em;text-transform:uppercase;font-size:10px;font-weight:900}body[data-zine-mode] .VWh0dG_modelTableScroll{background:#000;border:1.5px solid #e8ff0080;border-radius:0}.VWh0dG_currencyToggle{border:1px solid var(--dsw-alias-border-muted,#3a4250);background:var(--dsw-alias-bg-layer-2,#232a33);border-radius:6px;align-items:center;gap:2px;margin-right:8px;padding:2px;display:inline-flex}.VWh0dG_currencyButton{color:var(--dsw-alias-text-secondary,#9aa5b1);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:4px 7px;font-size:11px;font-weight:700;line-height:1}.VWh0dG_currencyButtonActive{background:var(--dsw-alias-accent-muted,#2f6fed);color:#fff}.VWh0dG_subscriptionGrid{grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;margin-top:10px;display:grid}.VWh0dG_subscriptionCard{border:1px solid var(--dsw-alias-border-muted,#3a4250);background:var(--dsw-alias-bg-layer-2,#232a33);border-radius:8px;padding:10px 12px}.VWh0dG_subscriptionHead{align-items:baseline;gap:8px;margin-bottom:6px;display:flex}.VWh0dG_subscriptionName{font-size:13px;font-weight:700}.VWh0dG_subscriptionPlan{color:var(--dsw-alias-text-secondary,#9aa5b1);font-size:11px}.VWh0dG_subscriptionStatus{color:var(--dsw-alias-warning,#e0a63c);margin-bottom:6px;font-size:11px}.VWh0dG_subscriptionWindow{align-items:center;gap:8px;margin-top:6px;font-size:11px;display:flex}.VWh0dG_subscriptionWindowLabel{color:var(--dsw-alias-text-secondary,#9aa5b1);flex:0 0 44px}.VWh0dG_subscriptionTrack{background:var(--dsw-alias-bg-layer-3,#1a2028);border-radius:3px;flex:1;height:5px;overflow:hidden}.VWh0dG_subscriptionFill{background:var(--dsw-alias-accent,#3b82f6);border-radius:3px;height:100%;transition:width .2s;display:block}.VWh0dG_subscriptionFillWarn{background:var(--dsw-static-amber-500)}.VWh0dG_subscriptionFillOver{background:var(--dsw-static-red-500)}.VWh0dG_subscriptionPct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:52px}.VWh0dG_subscriptionExhausted{color:var(--dsw-static-red-500);min-width:52px;font-weight:600}.VWh0dG_subscriptionReset{color:var(--dsw-alias-text-secondary,#9aa5b1);flex:none}.VWh0dG_providerGroupList{flex-direction:column;gap:10px;display:flex}.VWh0dG_providerGroup{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:12px 14px}.VWh0dG_providerGroupHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.VWh0dG_providerGroupTitle{align-items:center;gap:7px;min-width:0;display:inline-flex}.VWh0dG_providerGroupName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:18px}.VWh0dG_providerGroupMeta{flex:none;align-items:center;gap:10px;display:inline-flex}.VWh0dG_providerGroupBadge{color:var(--dsw-static-green-500);background:color-mix(in srgb, var(--dsw-static-green-500) 12%, transparent);border-radius:999px;align-items:center;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.VWh0dG_providerGroupBalance{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;align-items:baseline;gap:6px;font-size:12px;line-height:17px;display:inline-flex}.VWh0dG_providerGroupBalanceLabel{color:var(--dsw-alias-label-caption);font-size:11px;line-height:17px}.VWh0dG_roundsFlagBadge{color:#fff;background:#ef4444;border-radius:999px;margin-left:8px;padding:1px 7px;font-size:10px;font-weight:800}.VWh0dG_rounds{margin-top:10px}.VWh0dG_roundsBars{align-items:flex-end;gap:3px;height:110px;padding:4px 2px 0;display:flex;overflow-x:auto}.VWh0dG_roundsBarCol{flex-direction:column;flex:1 0 28px;justify-content:flex-end;align-items:stretch;height:100%;display:flex}.VWh0dG_roundsBarLabel{text-align:center;color:var(--dsw-alias-text-secondary,#9aa5b1);white-space:nowrap;text-overflow:ellipsis;max-width:100%;margin-bottom:2px;font-size:8px;line-height:1;overflow:hidden}.VWh0dG_roundsBarWrap{flex:1;align-items:flex-end;min-height:0;display:flex}.VWh0dG_roundsBar{background:var(--dsw-alias-accent,#3b82f6);border-radius:2px 2px 0 0;width:100%;min-height:2px;position:relative}.VWh0dG_roundsBarFlagged{outline-offset:1px;background:#ef4444;border-radius:2px 2px 0 0;outline:1.5px solid #ef4444;width:100%;min-height:2px;position:relative}.VWh0dG_roundsFlagMark{background:#ef4444;border-radius:50%;width:7px;height:7px;position:absolute;top:-3px;right:-3px;box-shadow:0 0 4px #ef4444}.VWh0dG_roundsAxis{color:var(--dsw-alias-text-secondary,#9aa5b1);justify-content:space-between;margin-top:6px;font-size:10px;display:flex}.VWh0dG_roundsEmpty{color:var(--dsw-alias-text-secondary,#9aa5b1);margin-top:10px;font-size:12px}.VWh0dG_heatmap{margin-top:10px}.VWh0dG_heatmapGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:8px;display:grid}.VWh0dG_heatmapCellEmpty{background:var(--dsw-alias-bg-layer-1);height:30px;color:var(--dsw-alias-label-dimmed,#6b7480);font-variant-numeric:tabular-nums;border-radius:8px;justify-content:center;align-items:center;font-size:11px;display:flex}.VWh0dG_heatmapCell{font-variant-numeric:tabular-nums;cursor:pointer;border:0;border-radius:8px;justify-content:center;align-items:center;height:30px;padding:0;font-size:11px;display:flex}.VWh0dG_heatmapCell[data-level=\"0\"],.VWh0dG_heatmapCell[data-level=\"1\"],.VWh0dG_heatmapCell[data-level=\"2\"]{color:var(--dsw-alias-label-primary)}.VWh0dG_heatmapCell[data-level=\"3\"],.VWh0dG_heatmapCell[data-level=\"4\"]{color:var(--dsw-static-neutral-bluish-00,#fff)}.VWh0dG_heatmapFooter{color:var(--dsw-alias-text-secondary,#9aa5b1);align-items:center;gap:8px;margin-top:10px;font-size:10px;display:flex}.VWh0dG_heatmapLegend{gap:3px;display:inline-flex}.VWh0dG_heatmapLegend i{border-radius:4px;width:14px;height:14px;display:block}.VWh0dG_heatmapHover{font-variant-numeric:tabular-nums;margin-left:auto}@media (width<=640px){.VWh0dG_kpiGrid{grid-template-columns:repeat(2,minmax(0,1fr))}.VWh0dG_hero{flex-direction:column;align-items:flex-start;gap:14px}.VWh0dG_heroSide{border-left:none;border-top:1px solid var(--dsw-alias-border-l1);flex-direction:row;align-self:stretch;gap:20px;padding-top:14px;padding-left:0}}";
28
28
  const tagId = "@kenz1117/dsh-ui-usage-billing/UsageBilling.module.css";
29
29
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
30
30
  const tag = document.createElement("style");
@@ -34,170 +34,199 @@ window.__ModuleLoader__.load({
34
34
  document.head.appendChild(tag);
35
35
  }
36
36
  var UsageBilling_module_css_default = {
37
- "panelHead": "VWh0dG_panelHead",
38
- "bandPrice": "VWh0dG_bandPrice",
39
- "chartDot": "VWh0dG_chartDot",
40
- "healthBadgeOk": "VWh0dG_healthBadgeOk",
41
- "headTitleRow": "VWh0dG_headTitleRow",
42
- "estimatedTag": "VWh0dG_estimatedTag",
43
- "tabButtonActive": "VWh0dG_tabButtonActive",
44
- "flatTag": "VWh0dG_flatTag",
37
+ "subscriptionStatus": "VWh0dG_subscriptionStatus",
38
+ "delta": "VWh0dG_delta",
39
+ "currencyButtonActive": "VWh0dG_currencyButtonActive",
40
+ "healthBad": "VWh0dG_healthBad",
41
+ "subscriptionGrid": "VWh0dG_subscriptionGrid",
42
+ "chartWrap": "VWh0dG_chartWrap",
43
+ "subscriptionFill": "VWh0dG_subscriptionFill",
44
+ "kpiTile": "VWh0dG_kpiTile",
45
+ "chartTooltipDate": "VWh0dG_chartTooltipDate",
46
+ "deltaDown": "VWh0dG_deltaDown",
47
+ "healthOk": "VWh0dG_healthOk",
48
+ "liveQuotaWarn": "VWh0dG_liveQuotaWarn",
49
+ "heroMain": "VWh0dG_heroMain",
50
+ "subscriptionCard": "VWh0dG_subscriptionCard",
51
+ "railButton": "VWh0dG_railButton",
52
+ "subscriptionPlan": "VWh0dG_subscriptionPlan",
53
+ "providerGroup": "VWh0dG_providerGroup",
54
+ "heatmapGrid": "VWh0dG_heatmapGrid",
55
+ "uncataloguedTag": "VWh0dG_uncataloguedTag",
45
56
  "roundsBarFlagged": "VWh0dG_roundsBarFlagged",
57
+ "roundsEmpty": "VWh0dG_roundsEmpty",
58
+ "kpiLabel": "VWh0dG_kpiLabel",
59
+ "kpiValue": "VWh0dG_kpiValue",
60
+ "triggerIcon": "VWh0dG_triggerIcon",
61
+ "rangeButtonActive": "VWh0dG_rangeButtonActive",
62
+ "modelName": "VWh0dG_modelName",
63
+ "healthIdle": "VWh0dG_healthIdle",
64
+ "budget": "VWh0dG_budget",
65
+ "trigger": "VWh0dG_trigger",
66
+ "panelHead": "VWh0dG_panelHead",
67
+ "pricingToggleText": "VWh0dG_pricingToggleText",
68
+ "liveCostItem": "VWh0dG_liveCostItem",
69
+ "deltaUp": "VWh0dG_deltaUp",
70
+ "pricingChevron": "VWh0dG_pricingChevron",
71
+ "rateBadgeLive": "VWh0dG_rateBadgeLive",
46
72
  "rangeToggle": "VWh0dG_rangeToggle",
47
- "liveCostSep": "VWh0dG_liveCostSep",
48
- "heatmapCellEmpty": "VWh0dG_heatmapCellEmpty",
49
- "triggerAmount": "VWh0dG_triggerAmount",
50
- "kpiDetail": "VWh0dG_kpiDetail",
51
- "chartSvg": "VWh0dG_chartSvg",
52
- "subscriptionReset": "VWh0dG_subscriptionReset",
53
- "rateBadge": "VWh0dG_rateBadge",
54
- "roundsBarCol": "VWh0dG_roundsBarCol",
55
- "chartLegendLine": "VWh0dG_chartLegendLine",
73
+ "chartBar": "VWh0dG_chartBar",
74
+ "dashboardRight": "VWh0dG_dashboardRight",
75
+ "budgetInputWrap": "VWh0dG_budgetInputWrap",
76
+ "triggerToday": "VWh0dG_triggerToday",
77
+ "exportButton": "VWh0dG_exportButton",
78
+ "chartCrosshair": "VWh0dG_chartCrosshair",
79
+ "triggerPopBar": "VWh0dG_triggerPopBar",
80
+ "dashboardTitle": "VWh0dG_dashboardTitle",
81
+ "costCol": "VWh0dG_costCol",
82
+ "flatTag": "VWh0dG_flatTag",
56
83
  "healthBadge": "VWh0dG_healthBadge",
57
- "heroMeta": "VWh0dG_heroMeta",
58
- "tabPanelIn": "VWh0dG_tabPanelIn",
59
- "chartEmpty": "VWh0dG_chartEmpty",
60
- "subscriptionPct": "VWh0dG_subscriptionPct",
61
- "budgetOverPulse": "VWh0dG_budgetOverPulse",
84
+ "liveTierPeak": "VWh0dG_liveTierPeak",
85
+ "providerGroupHead": "VWh0dG_providerGroupHead",
62
86
  "subscriptionHead": "VWh0dG_subscriptionHead",
63
- "dashboardBody": "VWh0dG_dashboardBody",
64
- "chartTooltipRow": "VWh0dG_chartTooltipRow",
65
- "liveCostBar": "VWh0dG_liveCostBar",
66
- "budgetUnit": "VWh0dG_budgetUnit",
67
- "currencyButton": "VWh0dG_currencyButton",
68
- "budget": "VWh0dG_budget",
87
+ "trendPanel": "VWh0dG_trendPanel",
69
88
  "switchKnob": "VWh0dG_switchKnob",
70
- "panelTitle": "VWh0dG_panelTitle",
71
- "healthOk": "VWh0dG_healthOk",
72
- "currencyToggle": "VWh0dG_currencyToggle",
73
- "heroValue": "VWh0dG_heroValue",
74
- "triggerMeta": "VWh0dG_triggerMeta",
75
- "heroSide": "VWh0dG_heroSide",
76
- "providerGroupList": "VWh0dG_providerGroupList",
77
- "rateBadgeBuiltin": "VWh0dG_rateBadgeBuiltin",
78
- "chartAxisLabel": "VWh0dG_chartAxisLabel",
89
+ "providerGroupBalanceLabel": "VWh0dG_providerGroupBalanceLabel",
90
+ "heatmap": "VWh0dG_heatmap",
79
91
  "dashboard": "VWh0dG_dashboard",
92
+ "triggerPopValue": "VWh0dG_triggerPopValue",
93
+ "triggerPopLabel": "VWh0dG_triggerPopLabel",
94
+ "budgetHead": "VWh0dG_budgetHead",
95
+ "triggerAmount": "VWh0dG_triggerAmount",
96
+ "healthBadgeOk": "VWh0dG_healthBadgeOk",
97
+ "triggerWrap": "VWh0dG_triggerWrap",
98
+ "triggerAmountSub": "VWh0dG_triggerAmountSub",
99
+ "shareDot": "VWh0dG_shareDot",
100
+ "balanceDaysLow": "VWh0dG_balanceDaysLow",
101
+ "panel": "VWh0dG_panel",
102
+ "budgetLabel": "VWh0dG_budgetLabel",
80
103
  "pricingChevronOpen": "VWh0dG_pricingChevronOpen",
81
- "roundsEmpty": "VWh0dG_roundsEmpty",
82
- "bandTag": "VWh0dG_bandTag",
83
- "chartGrid": "VWh0dG_chartGrid",
84
- "roundsBars": "VWh0dG_roundsBars",
85
- "modelTable": "VWh0dG_modelTable",
86
- "heroSideItem": "VWh0dG_heroSideItem",
87
- "kpiLabel": "VWh0dG_kpiLabel",
88
- "kpiGreen": "VWh0dG_kpiGreen",
89
- "budgetFill": "VWh0dG_budgetFill",
90
- "kpiTile": "VWh0dG_kpiTile",
91
- "trigger": "VWh0dG_trigger",
92
- "bandPriceOff": "VWh0dG_bandPriceOff",
93
- "liveCostItem": "VWh0dG_liveCostItem",
94
- "subscriptionTrack": "VWh0dG_subscriptionTrack",
95
- "na": "VWh0dG_na",
96
- "delta": "VWh0dG_delta",
97
- "heroSideLabel": "VWh0dG_heroSideLabel",
98
- "pricingToggleText": "VWh0dG_pricingToggleText",
99
- "rangeButtonActive": "VWh0dG_rangeButtonActive",
104
+ "kpiGrid": "VWh0dG_kpiGrid",
105
+ "chartLegend": "VWh0dG_chartLegend",
106
+ "balanceDays": "VWh0dG_balanceDays",
107
+ "subscriptionExhausted": "VWh0dG_subscriptionExhausted",
100
108
  "budgetFillOver": "VWh0dG_budgetFillOver",
109
+ "subscriptionWindow": "VWh0dG_subscriptionWindow",
110
+ "roundsAxis": "VWh0dG_roundsAxis",
101
111
  "chartStack": "VWh0dG_chartStack",
102
- "closeButton": "VWh0dG_closeButton",
103
- "budgetLabel": "VWh0dG_budgetLabel",
104
- "heroLabel": "VWh0dG_heroLabel",
105
- "numCol": "VWh0dG_numCol",
106
- "rangeButton": "VWh0dG_rangeButton",
107
- "balanceCell": "VWh0dG_balanceCell",
108
- "balanceDaysLow": "VWh0dG_balanceDaysLow",
109
- "currencyButtonActive": "VWh0dG_currencyButtonActive",
110
- "deltaDown": "VWh0dG_deltaDown",
111
- "heroSideValue": "VWh0dG_heroSideValue",
112
- "switchOn": "VWh0dG_switchOn",
112
+ "triggerMonth": "VWh0dG_triggerMonth",
113
+ "kpiDetail": "VWh0dG_kpiDetail",
114
+ "triggerPop": "VWh0dG_triggerPop",
115
+ "tabButtonActive": "VWh0dG_tabButtonActive",
116
+ "shareSeg": "VWh0dG_shareSeg",
117
+ "triggerDivider": "VWh0dG_triggerDivider",
118
+ "dashboardModal": "VWh0dG_dashboardModal",
119
+ "heroMeta": "VWh0dG_heroMeta",
120
+ "shareLegend": "VWh0dG_shareLegend",
113
121
  "emptyRow": "VWh0dG_emptyRow",
114
- "modelTableScroll": "VWh0dG_modelTableScroll",
115
- "heroMain": "VWh0dG_heroMain",
116
- "budgetTrack": "VWh0dG_budgetTrack",
117
- "chartBar": "VWh0dG_chartBar",
118
- "budgetValue": "VWh0dG_budgetValue",
119
- "chartLegend": "VWh0dG_chartLegend",
120
- "rounds": "VWh0dG_rounds",
121
- "modelDot": "VWh0dG_modelDot",
122
- "switch": "VWh0dG_switch",
123
- "panel": "VWh0dG_panel",
124
- "roundsBarLabel": "VWh0dG_roundsBarLabel",
125
- "pricingTable": "VWh0dG_pricingTable",
122
+ "budgetOverPulse": "VWh0dG_budgetOverPulse",
123
+ "shareValue": "VWh0dG_shareValue",
124
+ "numCol": "VWh0dG_numCol",
125
+ "liveTierOff": "VWh0dG_liveTierOff",
126
+ "headTitleRow": "VWh0dG_headTitleRow",
127
+ "currencyButton": "VWh0dG_currencyButton",
128
+ "tableScroll": "VWh0dG_tableScroll",
126
129
  "dashboardHead": "VWh0dG_dashboardHead",
127
- "healthDot": "VWh0dG_healthDot",
128
- "triggerMonth": "VWh0dG_triggerMonth",
129
- "providerGroupHead": "VWh0dG_providerGroupHead",
130
- "modelProvider": "VWh0dG_modelProvider",
131
- "triggerAmountSub": "VWh0dG_triggerAmountSub",
132
- "triggerToday": "VWh0dG_triggerToday",
133
- "deltaUp": "VWh0dG_deltaUp",
134
- "heatmapGrid": "VWh0dG_heatmapGrid",
135
- "chartWrap": "VWh0dG_chartWrap",
136
- "subscriptionFill": "VWh0dG_subscriptionFill",
137
- "subscriptionStatus": "VWh0dG_subscriptionStatus",
138
- "subscriptionWindowLabel": "VWh0dG_subscriptionWindowLabel",
139
- "roundsFlagMark": "VWh0dG_roundsFlagMark",
140
- "heatmapCell": "VWh0dG_heatmapCell",
141
- "providerGroupTitle": "VWh0dG_providerGroupTitle",
142
- "tabPanel": "VWh0dG_tabPanel",
143
- "dashboardRight": "VWh0dG_dashboardRight",
144
- "triggerIcon": "VWh0dG_triggerIcon",
145
- "subscriptionCard": "VWh0dG_subscriptionCard",
146
- "providerGroup": "VWh0dG_providerGroup",
147
- "tabNav": "VWh0dG_tabNav",
148
130
  "subscriptionName": "VWh0dG_subscriptionName",
149
- "budgetInputWrap": "VWh0dG_budgetInputWrap",
150
- "subscriptionPlan": "VWh0dG_subscriptionPlan",
151
- "triggerDivider": "VWh0dG_triggerDivider",
152
- "heatmap": "VWh0dG_heatmap",
153
- "subscriptionGrid": "VWh0dG_subscriptionGrid",
131
+ "subscriptionPct": "VWh0dG_subscriptionPct",
154
132
  "providerGroupName": "VWh0dG_providerGroupName",
155
- "dashboardIn": "VWh0dG_dashboardIn",
156
- "panelHint": "VWh0dG_panelHint",
157
- "chartLine": "VWh0dG_chartLine",
133
+ "providerGroupMeta": "VWh0dG_providerGroupMeta",
134
+ "roundsBarCol": "VWh0dG_roundsBarCol",
135
+ "heatmapCell": "VWh0dG_heatmapCell",
136
+ "chartGrid": "VWh0dG_chartGrid",
137
+ "providerGroupTitle": "VWh0dG_providerGroupTitle",
138
+ "chartTooltipRow": "VWh0dG_chartTooltipRow",
139
+ "tabPanelIn": "VWh0dG_tabPanelIn",
140
+ "chartLegendLine": "VWh0dG_chartLegendLine",
158
141
  "budgetInput": "VWh0dG_budgetInput",
159
- "budgetControls": "VWh0dG_budgetControls",
160
- "chartTooltip": "VWh0dG_chartTooltip",
161
- "tableScroll": "VWh0dG_tableScroll",
162
- "dashboardModal": "VWh0dG_dashboardModal",
163
- "healthBad": "VWh0dG_healthBad",
164
- "trendPanel": "VWh0dG_trendPanel",
142
+ "rounds": "VWh0dG_rounds",
143
+ "bandPrice": "VWh0dG_bandPrice",
144
+ "panelTitle": "VWh0dG_panelTitle",
145
+ "roundsBars": "VWh0dG_roundsBars",
146
+ "exportLabel": "VWh0dG_exportLabel",
147
+ "heroLabel": "VWh0dG_heroLabel",
148
+ "budgetUnit": "VWh0dG_budgetUnit",
149
+ "healthBadgeBad": "VWh0dG_healthBadgeBad",
150
+ "providerGroupBalance": "VWh0dG_providerGroupBalance",
151
+ "hero": "VWh0dG_hero",
152
+ "shareSegPeak": "VWh0dG_shareSegPeak",
153
+ "budgetTrack": "VWh0dG_budgetTrack",
154
+ "subscriptionTrack": "VWh0dG_subscriptionTrack",
155
+ "dashboardBody": "VWh0dG_dashboardBody",
156
+ "budgetFillWarn": "VWh0dG_budgetFillWarn",
157
+ "pricingToggle": "VWh0dG_pricingToggle",
158
+ "providerGroupList": "VWh0dG_providerGroupList",
159
+ "roundsFlagMark": "VWh0dG_roundsFlagMark",
160
+ "tabPanel": "VWh0dG_tabPanel",
165
161
  "heatmapFooter": "VWh0dG_heatmapFooter",
166
162
  "heatmapHover": "VWh0dG_heatmapHover",
163
+ "roundsBar": "VWh0dG_roundsBar",
167
164
  "tabButton": "VWh0dG_tabButton",
165
+ "shareSegOff": "VWh0dG_shareSegOff",
166
+ "modelCell": "VWh0dG_modelCell",
167
+ "chartSvg": "VWh0dG_chartSvg",
168
+ "shareSegUser": "VWh0dG_shareSegUser",
169
+ "switchOn": "VWh0dG_switchOn",
170
+ "rangeButton": "VWh0dG_rangeButton",
171
+ "triggerMeta": "VWh0dG_triggerMeta",
172
+ "heroValue": "VWh0dG_heroValue",
173
+ "triggerPopBars": "VWh0dG_triggerPopBars",
174
+ "subscriptionFillOver": "VWh0dG_subscriptionFillOver",
175
+ "exportBar": "VWh0dG_exportBar",
176
+ "modelTable": "VWh0dG_modelTable",
177
+ "shareTrack": "VWh0dG_shareTrack",
168
178
  "chartTooltipSwatch": "VWh0dG_chartTooltipSwatch",
169
- "healthIdle": "VWh0dG_healthIdle",
170
- "budgetHead": "VWh0dG_budgetHead",
171
- "balanceDays": "VWh0dG_balanceDays",
172
- "subscriptionWindow": "VWh0dG_subscriptionWindow",
173
- "roundsBar": "VWh0dG_roundsBar",
174
- "kpiValue": "VWh0dG_kpiValue",
175
- "pricingChevron": "VWh0dG_pricingChevron",
176
- "roundsAxis": "VWh0dG_roundsAxis",
177
- "providerGroupBadge": "VWh0dG_providerGroupBadge",
178
- "dashboardTitle": "VWh0dG_dashboardTitle",
179
- "costCol": "VWh0dG_costCol",
180
- "modelName": "VWh0dG_modelName",
181
- "kpiGrid": "VWh0dG_kpiGrid",
182
- "pricingToggle": "VWh0dG_pricingToggle",
183
- "heatmapLegend": "VWh0dG_heatmapLegend",
179
+ "subscriptionWindowLabel": "VWh0dG_subscriptionWindowLabel",
180
+ "heroSideItem": "VWh0dG_heroSideItem",
181
+ "rateBadge": "VWh0dG_rateBadge",
182
+ "roundsBarWrap": "VWh0dG_roundsBarWrap",
183
+ "budgetValue": "VWh0dG_budgetValue",
184
+ "chartEmpty": "VWh0dG_chartEmpty",
185
+ "na": "VWh0dG_na",
186
+ "chartDot": "VWh0dG_chartDot",
187
+ "heatmapCellEmpty": "VWh0dG_heatmapCellEmpty",
188
+ "liveQuotaCrit": "VWh0dG_liveQuotaCrit",
189
+ "balanceCell": "VWh0dG_balanceCell",
190
+ "switch": "VWh0dG_switch",
191
+ "estimatedTag": "VWh0dG_estimatedTag",
192
+ "shareItem": "VWh0dG_shareItem",
193
+ "chartLine": "VWh0dG_chartLine",
194
+ "panelHint": "VWh0dG_panelHint",
184
195
  "planTag": "VWh0dG_planTag",
185
- "roundsFlagBadge": "VWh0dG_roundsFlagBadge",
186
- "healthBadgeBad": "VWh0dG_healthBadgeBad",
187
- "rateBadgeLive": "VWh0dG_rateBadgeLive",
188
- "providerGroupMeta": "VWh0dG_providerGroupMeta",
189
- "modelCell": "VWh0dG_modelCell",
196
+ "heroSideLabel": "VWh0dG_heroSideLabel",
197
+ "shareSegTool": "VWh0dG_shareSegTool",
198
+ "subscriptionFillWarn": "VWh0dG_subscriptionFillWarn",
199
+ "budgetControls": "VWh0dG_budgetControls",
200
+ "heroSideValue": "VWh0dG_heroSideValue",
190
201
  "bandTagOff": "VWh0dG_bandTagOff",
191
- "providerGroupBalanceLabel": "VWh0dG_providerGroupBalanceLabel",
192
- "roundsBarWrap": "VWh0dG_roundsBarWrap",
193
- "hero": "VWh0dG_hero",
194
- "dashboardSubtitle": "VWh0dG_dashboardSubtitle",
195
- "uncataloguedTag": "VWh0dG_uncataloguedTag",
196
- "chartCrosshair": "VWh0dG_chartCrosshair",
202
+ "liveCostBar": "VWh0dG_liveCostBar",
203
+ "providerGroupBadge": "VWh0dG_providerGroupBadge",
204
+ "bandPriceOff": "VWh0dG_bandPriceOff",
197
205
  "chartLegendBar": "VWh0dG_chartLegendBar",
198
- "chartTooltipDate": "VWh0dG_chartTooltipDate",
199
- "providerGroupBalance": "VWh0dG_providerGroupBalance",
200
- "railButton": "VWh0dG_railButton"
206
+ "subscriptionReset": "VWh0dG_subscriptionReset",
207
+ "chartAxisLabel": "VWh0dG_chartAxisLabel",
208
+ "heatmapLegend": "VWh0dG_heatmapLegend",
209
+ "chartTooltip": "VWh0dG_chartTooltip",
210
+ "budgetFill": "VWh0dG_budgetFill",
211
+ "modelDot": "VWh0dG_modelDot",
212
+ "bandTag": "VWh0dG_bandTag",
213
+ "dashboardSubtitle": "VWh0dG_dashboardSubtitle",
214
+ "closeButton": "VWh0dG_closeButton",
215
+ "rateBadgeBuiltin": "VWh0dG_rateBadgeBuiltin",
216
+ "liveCostSep": "VWh0dG_liveCostSep",
217
+ "shareSegAssistant": "VWh0dG_shareSegAssistant",
218
+ "tabNav": "VWh0dG_tabNav",
219
+ "healthDot": "VWh0dG_healthDot",
220
+ "triggerPopRow": "VWh0dG_triggerPopRow",
221
+ "kpiGreen": "VWh0dG_kpiGreen",
222
+ "modelTableScroll": "VWh0dG_modelTableScroll",
223
+ "pricingTable": "VWh0dG_pricingTable",
224
+ "heroSide": "VWh0dG_heroSide",
225
+ "currencyToggle": "VWh0dG_currencyToggle",
226
+ "roundsFlagBadge": "VWh0dG_roundsFlagBadge",
227
+ "dashboardIn": "VWh0dG_dashboardIn",
228
+ "modelProvider": "VWh0dG_modelProvider",
229
+ "roundsBarLabel": "VWh0dG_roundsBarLabel"
201
230
  };
202
231
  //#endregion
203
232
  //#region src/client/pricing.ts
@@ -212,6 +241,8 @@ window.__ModuleLoader__.load({
212
241
  /** 运行时实时覆盖:undefined = 用内置目录与内置汇率(默认值降级)。 */
213
242
  let liveRate;
214
243
  let livePrices;
244
+ let liveExtraModels;
245
+ let liveCatalogModels;
215
246
  /**
216
247
  * Apply the node half's live pricing snapshot. Absent fields keep the
217
248
  * built-in catalog and rate; callers never fabricate values.
@@ -220,6 +251,16 @@ window.__ModuleLoader__.load({
220
251
  function applyLivePricing(pricing) {
221
252
  liveRate = pricing.rate;
222
253
  livePrices = pricing.prices;
254
+ liveExtraModels = pricing.extraModels;
255
+ }
256
+ /**
257
+ * 注入探活得到的「系统里实际配置/预制的模型」清单(host 的 llm.models 返回
258
+ * groups[].models[],含模型 id/name,无价格)。费率表据此对标现实可用模型——
259
+ * 有价的补价(内置目录 / models.dev 补充),无价的标「未收录」。纯内存状态,
260
+ * 供 `catalogEntries()` 渲染。
261
+ */
262
+ function applyLiveCatalogModels(models) {
263
+ liveCatalogModels = models;
223
264
  }
224
265
  /** 当前汇率:实时覆盖优先,缺省回退内置固定值。 */
225
266
  function currentRate() {
@@ -238,6 +279,77 @@ window.__ModuleLoader__.load({
238
279
  /** Default share of traffic assumed to fall in the peak band (0..1). */
239
280
  const DEFAULT_PEAK_SHARE = .5;
240
281
  /**
282
+ * 高峰时段判定(北京时间,UTC+8,无夏令时):09:00–12:00、14:00–18:00。
283
+ * @param beijingHour - 北京时间的小时数(0–23)。
284
+ */
285
+ function isPeakHour(beijingHour) {
286
+ return beijingHour >= 9 && beijingHour < 12 || beijingHour >= 14 && beijingHour < 18;
287
+ }
288
+ /**
289
+ * 由时刻(epoch 毫秒)推断计费时段;时刻未知/非法时按高峰计(保守:未知
290
+ * 时刻不低估成本,与社区 dsh-usage-chart 的 tierAt 语义一致)。
291
+ * @param timeMs - Unix epoch 毫秒;null/undefined/NaN 视为未知。
292
+ */
293
+ function tierAt(timeMs) {
294
+ if (timeMs === null || timeMs === void 0 || !Number.isFinite(timeMs)) return "peak";
295
+ return isPeakHour((new Date(timeMs).getUTCHours() + 8) % 24) ? "peak" : "offPeak";
296
+ }
297
+ /** 峰谷切换边界(北京时间的当日分钟数):09:00 / 12:00 / 14:00 / 18:00。 */
298
+ const TIER_BOUNDARY_MINUTES = [
299
+ 540,
300
+ 720,
301
+ 840,
302
+ 1080
303
+ ];
304
+ /** 北京时间的当日毫秒数(0–86,400,000)。 */
305
+ function beijingMillisOfDay(timeMs) {
306
+ return ((timeMs + 8 * 36e5) % 864e5 + 864e5) % 864e5;
307
+ }
308
+ /**
309
+ * 当前峰谷档位与距下次切换的时长。导出供测试:纯函数。
310
+ * @param nowMs - 当前时刻(epoch 毫秒)。
311
+ * @returns 当前档位与到下一个切换边界的毫秒数。
312
+ */
313
+ function tierCountdown(nowMs) {
314
+ const dayMs = beijingMillisOfDay(nowMs);
315
+ for (const boundary of TIER_BOUNDARY_MINUTES) {
316
+ const boundaryMs = boundary * 6e4;
317
+ if (dayMs < boundaryMs) return {
318
+ tier: tierAt(nowMs),
319
+ nextSwitchInMs: boundaryMs - dayMs
320
+ };
321
+ }
322
+ return {
323
+ tier: tierAt(nowMs),
324
+ nextSwitchInMs: 864e5 - dayMs + TIER_BOUNDARY_MINUTES[0] * 6e4
325
+ };
326
+ }
327
+ /**
328
+ * 峰/谷切换预告:距下次切换不足 leadMs 时返回即将进入的档位与切换时刻,
329
+ * 否则 null。导出供测试:纯函数。
330
+ * @param nowMs - 当前时刻(epoch 毫秒)。
331
+ * @param leadMs - 提前量(毫秒)。
332
+ */
333
+ function upcomingTierSwitch(nowMs, leadMs) {
334
+ const { nextSwitchInMs } = tierCountdown(nowMs);
335
+ if (nextSwitchInMs > leadMs) return null;
336
+ const atMs = nowMs + nextSwitchInMs;
337
+ return {
338
+ entering: tierAt(atMs),
339
+ atMs
340
+ };
341
+ }
342
+ /**
343
+ * 切换倒计时短格式:`1h23m` / `45m` / `3m`。导出供测试:纯函数。
344
+ * @param ms - 剩余毫秒数。
345
+ */
346
+ function formatSwitchCountdown(ms) {
347
+ const minutes = Math.max(1, Math.ceil(ms / 6e4));
348
+ const hours = Math.floor(minutes / 60);
349
+ const rest = minutes % 60;
350
+ return hours > 0 ? `${hours}h${String(rest).padStart(2, "0")}m` : `${rest}m`;
351
+ }
352
+ /**
241
353
  * Built-in catalog of current mainstream models as of 2026-08-16, priced from
242
354
  * each provider's official price page. Domestic providers are OpenAI-API
243
355
  * compatible and publish RMB prices directly; overseas providers publish USD
@@ -755,11 +867,13 @@ window.__ModuleLoader__.load({
755
867
  /** Lookup a model by its stats key; falls back to the generic `other` entry. */
756
868
  function modelOf(key) {
757
869
  const resolved = MODEL_KEY_ALIASES[key] ?? key;
758
- const base = MODEL_CATALOG.find((entry) => entry.key === resolved) ?? (() => {
870
+ const found = MODEL_CATALOG.find((entry) => entry.key === resolved);
871
+ const extra = liveExtraModels?.find((item) => item.key === resolved);
872
+ const base = found ?? (extra !== void 0 ? extraEntryOf(extra) : (() => {
759
873
  const fallback = MODEL_CATALOG.at(-1);
760
874
  if (fallback !== void 0) return fallback;
761
875
  throw new Error("MODEL_CATALOG must not be empty");
762
- })();
876
+ })());
763
877
  const live = livePrices?.[resolved];
764
878
  if (live === void 0) return base;
765
879
  return {
@@ -772,6 +886,57 @@ window.__ModuleLoader__.load({
772
886
  }
773
887
  };
774
888
  }
889
+ /** models.dev 补充条目转为目录条目:USD 直价(走汇率换算),无峰谷分档。 */
890
+ function extraEntryOf(extra) {
891
+ return {
892
+ key: extra.key,
893
+ name: extra.name,
894
+ provider: extra.provider,
895
+ colorVar: "dsw-static-neutral-400",
896
+ price: {
897
+ currency: "USD",
898
+ input: extra.price.input,
899
+ cacheHit: extra.price.cacheHit,
900
+ output: extra.price.output
901
+ }
902
+ };
903
+ }
904
+ /**
905
+ * 费率表渲染的完整目录:内置 + models.dev 补充条目 + 探活模型(无价标记)。
906
+ * 探活模型去重(按归一化 id):内置/补充已有的不再重复;无价的保留并标记
907
+ * `uncatalogued`,费率表据此显示「未收录」。
908
+ */
909
+ function catalogEntries() {
910
+ const entries = [...MODEL_CATALOG, ...(liveExtraModels ?? []).map(extraEntryOf)];
911
+ const known = new Set(entries.map((entry) => entry.key.toLowerCase()));
912
+ for (const model of liveCatalogModels ?? []) {
913
+ const rawKey = model.id.toLowerCase();
914
+ if ((() => {
915
+ const aliasKey = MODEL_KEY_ALIASES[model.id] ?? model.id;
916
+ return MODEL_CATALOG.find((item) => item.key === aliasKey);
917
+ })() !== void 0) continue;
918
+ if (known.has(rawKey)) continue;
919
+ const extra = (liveExtraModels ?? []).find((item) => item.key === rawKey);
920
+ let entry;
921
+ if (extra !== void 0) entry = { ...extraEntryOf(extra) };
922
+ else entry = {
923
+ key: MODEL_KEY_ALIASES[model.id] ?? model.id,
924
+ name: model.name ?? model.id,
925
+ provider: model.provider,
926
+ colorVar: "dsw-static-neutral-400",
927
+ price: {
928
+ currency: "USD",
929
+ input: 0,
930
+ cacheHit: 0,
931
+ output: 0
932
+ },
933
+ uncatalogued: true
934
+ };
935
+ known.add(entry.key.toLowerCase());
936
+ entries.push(entry);
937
+ }
938
+ return entries;
939
+ }
775
940
  /** Resolve a price-table row by its CSS variable name (theme token or fallback color). */
776
941
  function resolveToken(name) {
777
942
  const value = getComputedStyle(document.documentElement).getPropertyValue(`--${name}`).trim();
@@ -1429,6 +1594,64 @@ window.__ModuleLoader__.load({
1429
1594
  return flags;
1430
1595
  }
1431
1596
  //#endregion
1597
+ //#region src/client/export.ts
1598
+ /** CSV 单元格转义:含逗号 / 引号 / 换行的值加双引号并内层引号双写。 */
1599
+ function csvCell(value) {
1600
+ return /[",\n]/.test(value) ? `"${value.replace(/"/g, "\"\"")}"` : value;
1601
+ }
1602
+ /** 金额保留两位小数字符串(导出对账用,不做千分位)。 */
1603
+ function money(value) {
1604
+ return value.toFixed(2);
1605
+ }
1606
+ /** 按日 CSV:日期,调用,输入,输出,缓存命中,缓存未命中,费用(元)。 */
1607
+ function dayRowsCsv(byDay) {
1608
+ return ["date,calls,input,output,cache_hit,cache_miss,cost_cny", ...Object.keys(byDay).sort().map((date) => {
1609
+ const day = byDay[date];
1610
+ if (day === void 0) return "";
1611
+ return [
1612
+ date,
1613
+ day.calls,
1614
+ day.input,
1615
+ day.output,
1616
+ day.cacheHit,
1617
+ day.cacheMiss,
1618
+ money(day.cost)
1619
+ ].join(",");
1620
+ })].join("\n");
1621
+ }
1622
+ /** 项目名取 cwd 末级目录(与统计 Tab 的会话明细同口径)。 */
1623
+ function projectOf(cwd) {
1624
+ if (cwd === void 0) return "";
1625
+ return cwd.split(/[\\/]/).filter(Boolean).pop() ?? cwd;
1626
+ }
1627
+ /** 按会话 CSV:会话 id,标题,项目,调用,费用(元),最后活跃(ISO)。 */
1628
+ function sessionRowsCsv(rows) {
1629
+ return ["session_id,title,project,calls,cost_cny,last_active", ...rows.map((row) => [
1630
+ csvCell(row.id),
1631
+ csvCell(row.title ?? ""),
1632
+ csvCell(projectOf(row.cwd)),
1633
+ row.calls,
1634
+ money(row.cost),
1635
+ row.lastActive > 0 ? new Date(row.lastActive).toISOString() : ""
1636
+ ].join(","))].join("\n");
1637
+ }
1638
+ /** 导出文件名:带日期范围(usage-2026-08-01_2026-08-22.csv);无日期时只带前缀。 */
1639
+ function exportFileName(prefix, ext, dates) {
1640
+ const sorted = [...dates].sort();
1641
+ const first = sorted[0];
1642
+ const last = sorted.at(-1);
1643
+ return `${prefix}${first !== void 0 && last !== void 0 ? `-${first}_${last}` : ""}.${ext}`;
1644
+ }
1645
+ /** 触发浏览器下载(唯一 DOM 副作用;调用方在 click 手势里使用)。 */
1646
+ function downloadText(filename, text, mime) {
1647
+ const url = URL.createObjectURL(new Blob([text], { type: mime }));
1648
+ const anchor = document.createElement("a");
1649
+ anchor.href = url;
1650
+ anchor.download = filename;
1651
+ anchor.click();
1652
+ URL.revokeObjectURL(url);
1653
+ }
1654
+ //#endregion
1432
1655
  //#region src/client/UsageBilling.tsx
1433
1656
  /**
1434
1657
  * UsageBilling: sidebar footer trigger + full billing dashboard modal.
@@ -1475,6 +1698,12 @@ window.__ModuleLoader__.load({
1475
1698
  if (cwd === void 0) return void 0;
1476
1699
  return cwd.split(/[\\/]/).filter(Boolean).pop() ?? cwd;
1477
1700
  }
1701
+ /** 预算提醒档位(百分比):跨档时桌面通知,每档每天最多一次。 */
1702
+ const BUDGET_ALERT_TIERS = [
1703
+ 50,
1704
+ 80,
1705
+ 100
1706
+ ];
1478
1707
  /** Idle health state before the probe settles. */
1479
1708
  const IDLE_HEALTH = {
1480
1709
  checked: false,
@@ -1645,6 +1874,41 @@ window.__ModuleLoader__.load({
1645
1874
  if (avg <= 0) return 0;
1646
1875
  return avg * monthLen;
1647
1876
  }
1877
+ /**
1878
+ * 峰谷时段费用分摊:按每轮的起始时刻(北京时间高峰 9-12 / 14-18)把费用
1879
+ * 归入高峰 / 空闲两档。导出供测试:纯函数。
1880
+ * @param turns - 每轮费用行(需带 startedAt 与 cost)。
1881
+ * @returns 两档费用合计(人民币元)。
1882
+ */
1883
+ function peakOffpeakCost(turns) {
1884
+ let peak = 0;
1885
+ let offPeak = 0;
1886
+ for (const turn of turns) if (tierAt(turn.startedAt) === "peak") peak += turn.cost;
1887
+ else offPeak += turn.cost;
1888
+ return {
1889
+ peak,
1890
+ offPeak
1891
+ };
1892
+ }
1893
+ /**
1894
+ * 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
1895
+ * 导出供测试:纯函数(日期取本地时区)。
1896
+ * @param byDay - 按日费用表。
1897
+ * @returns 7 个 `{ date, cost }`,最旧在前。
1898
+ */
1899
+ function lastSevenDays(byDay) {
1900
+ const out = [];
1901
+ for (let offset = 6; offset >= 0; offset -= 1) {
1902
+ const day = /* @__PURE__ */ new Date();
1903
+ day.setDate(day.getDate() - offset);
1904
+ const stamp = localDayStamp(day.getTime());
1905
+ out.push({
1906
+ date: stamp,
1907
+ cost: byDay[stamp]?.cost ?? 0
1908
+ });
1909
+ }
1910
+ return out;
1911
+ }
1648
1912
  /** Resolve one provider's dot state: green when live, red when failed, gray when unknown. */
1649
1913
  function providerDot(health, provider) {
1650
1914
  if (!health.checked) return UsageBilling_module_css_default.healthIdle;
@@ -1679,7 +1943,7 @@ window.__ModuleLoader__.load({
1679
1943
  /** Path to the account-balance endpoint served by this plugin's node half. */
1680
1944
  const BALANCE_PATH = "/api/billing/balance";
1681
1945
  /** Path to the subscription-plan quota endpoint served by this plugin's node half. */
1682
- const SUBSCRIPTIONS_PATH = "/api/billing/subscriptions";
1946
+ const SUBSCRIPTIONS_PATH$1 = "/api/billing/subscriptions";
1683
1947
  /** 弹窗打开期间统计与定价的自动刷新间隔(毫秒)。 */
1684
1948
  const STATS_REFRESH_INTERVAL_MS = 3e4;
1685
1949
  /**
@@ -1746,7 +2010,8 @@ window.__ModuleLoader__.load({
1746
2010
  ...typeof candidate.lowBalanceThreshold === "number" ? { lowBalanceThreshold: candidate.lowBalanceThreshold } : {},
1747
2011
  ...Array.isArray(candidate.bySession) ? { bySession: candidate.bySession } : {},
1748
2012
  ...Array.isArray(candidate.byTurn) ? { byTurn: candidate.byTurn } : {},
1749
- ...Array.isArray(candidate.byWorkspace) ? { byWorkspace: candidate.byWorkspace } : {}
2013
+ ...Array.isArray(candidate.byWorkspace) ? { byWorkspace: candidate.byWorkspace } : {},
2014
+ ...candidate.byRole !== null && typeof candidate.byRole === "object" ? { byRole: candidate.byRole } : {}
1750
2015
  };
1751
2016
  } catch {
1752
2017
  return null;
@@ -1800,7 +2065,7 @@ window.__ModuleLoader__.load({
1800
2065
  */
1801
2066
  async function fetchSubscriptions() {
1802
2067
  try {
1803
- const response = await fetch(SUBSCRIPTIONS_PATH);
2068
+ const response = await fetch(SUBSCRIPTIONS_PATH$1);
1804
2069
  if (!response.ok) return [];
1805
2070
  const text = await response.text();
1806
2071
  const parsed = JSON.parse(text);
@@ -1817,7 +2082,7 @@ window.__ModuleLoader__.load({
1817
2082
  * @param props - framework props plus `wide` column state.
1818
2083
  */
1819
2084
  function UsageBillingTrigger(props) {
1820
- const { wide, t, onOpen, monthCost, todayCost } = props;
2085
+ const { wide, t, onOpen, monthCost, todayCost, weekCost, days } = props;
1821
2086
  const cardIcon = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1822
2087
  viewBox: "0 0 24 24",
1823
2088
  fill: "none",
@@ -1849,42 +2114,91 @@ window.__ModuleLoader__.load({
1849
2114
  title: `${t("billing.title")} · ${formatMoney(monthCost)}`,
1850
2115
  children: cardIcon
1851
2116
  });
1852
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1853
- type: "button",
1854
- className: UsageBilling_module_css_default.trigger,
1855
- "data-testid": "billing-trigger",
1856
- onClick: onOpen,
1857
- title: `${t("billing.title")} · 本月 ${formatMoney(monthCost)}`,
1858
- children: [
1859
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1860
- className: UsageBilling_module_css_default.triggerIcon,
1861
- "data-testid": "billing-trigger-icon",
1862
- children: cardIcon
1863
- }),
1864
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1865
- className: UsageBilling_module_css_default.triggerToday,
1866
- "data-testid": "billing-trigger-today",
1867
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1868
- className: UsageBilling_module_css_default.triggerMeta,
1869
- children: "今日"
1870
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1871
- className: UsageBilling_module_css_default.triggerAmount,
1872
- children: formatMoney(todayCost)
1873
- })]
1874
- }),
1875
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: UsageBilling_module_css_default.triggerDivider }),
1876
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1877
- className: UsageBilling_module_css_default.triggerMonth,
1878
- "data-testid": "billing-trigger-month",
1879
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1880
- className: UsageBilling_module_css_default.triggerMeta,
1881
- children: "当月"
1882
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1883
- className: UsageBilling_module_css_default.triggerAmountSub,
1884
- children: formatMoney(monthCost)
1885
- })]
1886
- })
1887
- ]
2117
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2118
+ className: UsageBilling_module_css_default.triggerWrap,
2119
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2120
+ type: "button",
2121
+ className: UsageBilling_module_css_default.trigger,
2122
+ "data-testid": "billing-trigger",
2123
+ onClick: onOpen,
2124
+ title: `${t("billing.title")} · 本月 ${formatMoney(monthCost)}`,
2125
+ children: [
2126
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2127
+ className: UsageBilling_module_css_default.triggerIcon,
2128
+ "data-testid": "billing-trigger-icon",
2129
+ children: cardIcon
2130
+ }),
2131
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2132
+ className: UsageBilling_module_css_default.triggerToday,
2133
+ "data-testid": "billing-trigger-today",
2134
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2135
+ className: UsageBilling_module_css_default.triggerMeta,
2136
+ children: "今日"
2137
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2138
+ className: UsageBilling_module_css_default.triggerAmount,
2139
+ children: formatMoney(todayCost)
2140
+ })]
2141
+ }),
2142
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: UsageBilling_module_css_default.triggerDivider }),
2143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2144
+ className: UsageBilling_module_css_default.triggerMonth,
2145
+ "data-testid": "billing-trigger-month",
2146
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2147
+ className: UsageBilling_module_css_default.triggerMeta,
2148
+ children: "当月"
2149
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2150
+ className: UsageBilling_module_css_default.triggerAmountSub,
2151
+ children: formatMoney(monthCost)
2152
+ })]
2153
+ })
2154
+ ]
2155
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2156
+ className: UsageBilling_module_css_default.triggerPop,
2157
+ "data-testid": "billing-trigger-pop",
2158
+ "aria-hidden": "true",
2159
+ children: [
2160
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2161
+ className: UsageBilling_module_css_default.triggerPopRow,
2162
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2163
+ className: UsageBilling_module_css_default.triggerPopLabel,
2164
+ children: t("billing.todayCost")
2165
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2166
+ className: UsageBilling_module_css_default.triggerPopValue,
2167
+ children: formatMoney(todayCost)
2168
+ })]
2169
+ }),
2170
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2171
+ className: UsageBilling_module_css_default.triggerPopRow,
2172
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2173
+ className: UsageBilling_module_css_default.triggerPopLabel,
2174
+ children: t("billing.weekCost")
2175
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2176
+ className: UsageBilling_module_css_default.triggerPopValue,
2177
+ children: formatMoney(weekCost)
2178
+ })]
2179
+ }),
2180
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2181
+ className: UsageBilling_module_css_default.triggerPopRow,
2182
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2183
+ className: UsageBilling_module_css_default.triggerPopLabel,
2184
+ children: t("billing.monthCost")
2185
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2186
+ className: UsageBilling_module_css_default.triggerPopValue,
2187
+ children: formatMoney(monthCost)
2188
+ })]
2189
+ }),
2190
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2191
+ className: UsageBilling_module_css_default.triggerPopBars,
2192
+ children: (() => {
2193
+ const max = Math.max(...days.map((d) => d.cost), 0);
2194
+ return days.map((d) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2195
+ className: UsageBilling_module_css_default.triggerPopBar,
2196
+ style: { height: `${max > 0 ? 4 + d.cost / max * 18 : 4}px` }
2197
+ }, d.date));
2198
+ })()
2199
+ })
2200
+ ]
2201
+ })]
1888
2202
  });
1889
2203
  }
1890
2204
  /**
@@ -1898,6 +2212,33 @@ window.__ModuleLoader__.load({
1898
2212
  const rateInfo = getRateInfo();
1899
2213
  const money = (cny) => formatMoney(currency === "usd" ? cnyToUsd(cny) : cny, currency);
1900
2214
  const roundFlags = (0, react.useMemo)(() => flagAnomalies([...turns].reverse()), [turns]);
2215
+ const peakShare = (0, react.useMemo)(() => peakOffpeakCost(turns), [turns]);
2216
+ const roleRows = (0, react.useMemo)(() => {
2217
+ const role = stats.byRole;
2218
+ if (role === void 0) return [];
2219
+ const total = role.user + role.assistant + role.tool;
2220
+ if (total <= 0) return [];
2221
+ return [
2222
+ {
2223
+ label: t("billing.roleUser"),
2224
+ value: role.user,
2225
+ seg: UsageBilling_module_css_default.shareSegUser
2226
+ },
2227
+ {
2228
+ label: t("billing.roleAssistant"),
2229
+ value: role.assistant,
2230
+ seg: UsageBilling_module_css_default.shareSegAssistant
2231
+ },
2232
+ {
2233
+ label: t("billing.roleTool"),
2234
+ value: role.tool,
2235
+ seg: UsageBilling_module_css_default.shareSegTool
2236
+ }
2237
+ ].map((row) => ({
2238
+ ...row,
2239
+ pct: row.value / total * 100
2240
+ }));
2241
+ }, [stats.byRole, t]);
1901
2242
  const dailyBurn = dailyBurnRate(byDay, localDayStamp());
1902
2243
  const balanceFor = (provider) => balances.find((balance) => normalizeProvider(balance.provider) === normalizeProvider(provider));
1903
2244
  const renderBalance = (balance) => {
@@ -2014,13 +2355,25 @@ window.__ModuleLoader__.load({
2014
2355
  if (list === void 0) modelsByVendor.set(row.provider, [row]);
2015
2356
  else list.push(row);
2016
2357
  }
2017
- return [...new Set([...modelsByVendor.keys(), ...subscriptionsByVendor.keys()])].map((name) => ({
2358
+ const groups = [...new Set([...modelsByVendor.keys(), ...subscriptionsByVendor.keys()])].map((name) => ({
2018
2359
  name,
2019
2360
  models: modelsByVendor.get(name) ?? [],
2020
2361
  subscriptions: subscriptionsByVendor.get(name) ?? [],
2021
2362
  balance: balanceFor(name),
2022
2363
  dot: providerDot(health, name)
2023
- })).sort((a, b) => {
2364
+ }));
2365
+ const claimed = new Set(groups.map((group) => normalizeProvider(group.name)));
2366
+ for (const balance of balances) {
2367
+ if (claimed.has(normalizeProvider(balance.provider))) continue;
2368
+ if (balance.error === void 0 || balance.provider.startsWith("custom:")) groups.push({
2369
+ name: balance.displayName,
2370
+ models: [],
2371
+ subscriptions: [],
2372
+ balance,
2373
+ dot: providerDot(health, balance.displayName)
2374
+ });
2375
+ }
2376
+ return groups.sort((a, b) => {
2024
2377
  const costOf = (group) => group.models.reduce((sum, m) => sum + (m.actual ?? m.estimated), 0);
2025
2378
  const diff = costOf(b) - costOf(a);
2026
2379
  if (diff !== 0) return diff;
@@ -2279,7 +2632,7 @@ window.__ModuleLoader__.load({
2279
2632
  className: UsageBilling_module_css_default.budgetTrack,
2280
2633
  "data-testid": "billing-budget-track",
2281
2634
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2282
- className: clsx(UsageBilling_module_css_default.budgetFill, pct >= 100 && UsageBilling_module_css_default.budgetFillOver),
2635
+ className: clsx(UsageBilling_module_css_default.budgetFill, pct >= 100 && UsageBilling_module_css_default.budgetFillOver, pct >= 80 && pct < 100 && UsageBilling_module_css_default.budgetFillWarn),
2283
2636
  style: { width: `${Math.min(pct, 100)}%` }
2284
2637
  })
2285
2638
  });
@@ -2387,79 +2740,156 @@ window.__ModuleLoader__.load({
2387
2740
  className: UsageBilling_module_css_default.panelHead,
2388
2741
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2389
2742
  className: UsageBilling_module_css_default.panelTitle,
2390
- children: t("billing.heatmap")
2391
- })
2392
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageHeatmap, {
2393
- days: heatmapDays,
2743
+ children: t("billing.heatmap")
2744
+ })
2745
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageHeatmap, {
2746
+ days: heatmapDays,
2747
+ currency,
2748
+ t
2749
+ })]
2750
+ })
2751
+ ]
2752
+ }),
2753
+ tab === "trends" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2754
+ className: UsageBilling_module_css_default.tabPanel,
2755
+ "data-testid": "billing-tab-panel-trends",
2756
+ children: [
2757
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2758
+ className: clsx(UsageBilling_module_css_default.panel, UsageBilling_module_css_default.trendPanel),
2759
+ "data-testid": "billing-panel-trend",
2760
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2761
+ className: UsageBilling_module_css_default.panelHead,
2762
+ children: [
2763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2764
+ className: UsageBilling_module_css_default.panelTitle,
2765
+ children: t("billing.trend")
2766
+ }),
2767
+ renderSlot("billing.dashboard.decor", { position: "trend" }),
2768
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2769
+ className: UsageBilling_module_css_default.rangeToggle,
2770
+ role: "group",
2771
+ "aria-label": t("billing.trend"),
2772
+ children: [7, 30].map((days) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2773
+ type: "button",
2774
+ className: clsx(UsageBilling_module_css_default.rangeButton, trendDays === days && UsageBilling_module_css_default.rangeButtonActive),
2775
+ "aria-pressed": trendDays === days,
2776
+ "data-testid": `billing-trend-${days}d`,
2777
+ onClick: () => {
2778
+ setTrendDays(days);
2779
+ },
2780
+ children: days === 7 ? t("billing.trend7d") : t("billing.trend30d")
2781
+ }, days))
2782
+ }),
2783
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2784
+ className: UsageBilling_module_css_default.panelHint,
2785
+ children: latestDate
2786
+ })
2787
+ ]
2788
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
2789
+ data: trend,
2790
+ models: chartModels,
2791
+ currency
2792
+ })]
2793
+ }),
2794
+ turns.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2795
+ className: UsageBilling_module_css_default.panel,
2796
+ "data-testid": "billing-panel-rounds",
2797
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2798
+ className: UsageBilling_module_css_default.panelHead,
2799
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2800
+ className: UsageBilling_module_css_default.panelTitle,
2801
+ children: t("billing.rounds")
2802
+ }), roundFlags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2803
+ className: UsageBilling_module_css_default.roundsFlagBadge,
2804
+ "data-testid": "billing-rounds-flag-count",
2805
+ children: [
2806
+ roundFlags.length,
2807
+ " ",
2808
+ t("billing.anomaly")
2809
+ ]
2810
+ })]
2811
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoundCostChart, {
2812
+ rounds: turns,
2813
+ flags: roundFlags,
2394
2814
  currency,
2395
2815
  t
2396
2816
  })]
2397
- })
2398
- ]
2399
- }),
2400
- tab === "trends" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2401
- className: UsageBilling_module_css_default.tabPanel,
2402
- "data-testid": "billing-tab-panel-trends",
2403
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2404
- className: clsx(UsageBilling_module_css_default.panel, UsageBilling_module_css_default.trendPanel),
2405
- "data-testid": "billing-panel-trend",
2406
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2407
- className: UsageBilling_module_css_default.panelHead,
2408
- children: [
2409
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2410
- className: UsageBilling_module_css_default.panelTitle,
2411
- children: t("billing.trend")
2412
- }),
2413
- renderSlot("billing.dashboard.decor", { position: "trend" }),
2414
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2415
- className: UsageBilling_module_css_default.rangeToggle,
2416
- role: "group",
2417
- "aria-label": t("billing.trend"),
2418
- children: [7, 30].map((days) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2419
- type: "button",
2420
- className: clsx(UsageBilling_module_css_default.rangeButton, trendDays === days && UsageBilling_module_css_default.rangeButtonActive),
2421
- "aria-pressed": trendDays === days,
2422
- "data-testid": `billing-trend-${days}d`,
2423
- onClick: () => {
2424
- setTrendDays(days);
2425
- },
2426
- children: days === 7 ? t("billing.trend7d") : t("billing.trend30d")
2427
- }, days))
2428
- }),
2429
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2430
- className: UsageBilling_module_css_default.panelHint,
2431
- children: latestDate
2432
- })
2433
- ]
2434
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
2435
- data: trend,
2436
- models: chartModels,
2437
- currency
2438
- })]
2439
- }), turns.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2440
- className: UsageBilling_module_css_default.panel,
2441
- "data-testid": "billing-panel-rounds",
2442
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2443
- className: UsageBilling_module_css_default.panelHead,
2444
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2445
- className: UsageBilling_module_css_default.panelTitle,
2446
- children: t("billing.rounds")
2447
- }), roundFlags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2448
- className: UsageBilling_module_css_default.roundsFlagBadge,
2449
- "data-testid": "billing-rounds-flag-count",
2817
+ }),
2818
+ turns.length > 0 && (() => {
2819
+ const shareTotal = peakShare.peak + peakShare.offPeak;
2820
+ if (shareTotal <= 0) return null;
2821
+ const peakPct = peakShare.peak / shareTotal * 100;
2822
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2823
+ className: UsageBilling_module_css_default.panel,
2824
+ "data-testid": "billing-panel-share",
2450
2825
  children: [
2451
- roundFlags.length,
2452
- " ",
2453
- t("billing.anomaly")
2826
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2827
+ className: UsageBilling_module_css_default.panelHead,
2828
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2829
+ className: UsageBilling_module_css_default.panelTitle,
2830
+ children: t("billing.peakShare")
2831
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2832
+ className: UsageBilling_module_css_default.panelHint,
2833
+ children: t("billing.peakShareHint").replace("{count}", String(turns.length))
2834
+ })]
2835
+ }),
2836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2837
+ className: UsageBilling_module_css_default.shareTrack,
2838
+ "data-testid": "billing-share-track",
2839
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2840
+ className: clsx(UsageBilling_module_css_default.shareSeg, UsageBilling_module_css_default.shareSegPeak),
2841
+ style: { width: `${peakPct}%` }
2842
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2843
+ className: clsx(UsageBilling_module_css_default.shareSeg, UsageBilling_module_css_default.shareSegOff),
2844
+ style: { width: `${100 - peakPct}%` }
2845
+ })]
2846
+ }),
2847
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2848
+ className: UsageBilling_module_css_default.shareLegend,
2849
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2850
+ className: UsageBilling_module_css_default.shareItem,
2851
+ children: [
2852
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2853
+ className: UsageBilling_module_css_default.shareDot,
2854
+ style: { background: "var(--dsw-static-blue-500)" }
2855
+ }),
2856
+ t("billing.peak"),
2857
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2858
+ className: UsageBilling_module_css_default.shareValue,
2859
+ "data-testid": "billing-share-peak",
2860
+ children: [
2861
+ money(peakShare.peak),
2862
+ " · ",
2863
+ peakPct.toFixed(1),
2864
+ "%"
2865
+ ]
2866
+ })
2867
+ ]
2868
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2869
+ className: UsageBilling_module_css_default.shareItem,
2870
+ children: [
2871
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2872
+ className: UsageBilling_module_css_default.shareDot,
2873
+ style: { background: "color-mix(in srgb, var(--dsw-static-blue-500) 30%, var(--dsw-alias-bg-module-platform))" }
2874
+ }),
2875
+ t("billing.offPeak"),
2876
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2877
+ className: UsageBilling_module_css_default.shareValue,
2878
+ "data-testid": "billing-share-offpeak",
2879
+ children: [
2880
+ money(peakShare.offPeak),
2881
+ " · ",
2882
+ (100 - peakPct).toFixed(1),
2883
+ "%"
2884
+ ]
2885
+ })
2886
+ ]
2887
+ })]
2888
+ })
2454
2889
  ]
2455
- })]
2456
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoundCostChart, {
2457
- rounds: turns,
2458
- flags: roundFlags,
2459
- currency,
2460
- t
2461
- })]
2462
- })]
2890
+ });
2891
+ })()
2892
+ ]
2463
2893
  }),
2464
2894
  tab === "providers" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2465
2895
  className: UsageBilling_module_css_default.tabPanel,
@@ -2624,31 +3054,35 @@ window.__ModuleLoader__.load({
2624
3054
  className: UsageBilling_module_css_default.subscriptionStatus,
2625
3055
  children: t("billing.subscriptionNoApi")
2626
3056
  }),
2627
- quota.windows.map((window) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2628
- className: UsageBilling_module_css_default.subscriptionWindow,
2629
- children: [
2630
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2631
- className: UsageBilling_module_css_default.subscriptionWindowLabel,
2632
- children: subscriptionWindowLabel(window.kind, t)
2633
- }),
2634
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2635
- className: UsageBilling_module_css_default.subscriptionTrack,
2636
- "aria-hidden": "true",
2637
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2638
- className: UsageBilling_module_css_default.subscriptionFill,
2639
- style: { width: `${Math.min(100, Math.max(0, window.remainingPercent))}%` }
3057
+ quota.windows.map((window) => (() => {
3058
+ const used = Math.min(100, Math.max(0, window.usedPercent));
3059
+ const exhausted = Math.min(100, Math.max(0, window.remainingPercent)) <= 0;
3060
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3061
+ className: UsageBilling_module_css_default.subscriptionWindow,
3062
+ children: [
3063
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3064
+ className: UsageBilling_module_css_default.subscriptionWindowLabel,
3065
+ children: subscriptionWindowLabel(window.kind, t)
3066
+ }),
3067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3068
+ className: UsageBilling_module_css_default.subscriptionTrack,
3069
+ "aria-hidden": "true",
3070
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3071
+ className: clsx(UsageBilling_module_css_default.subscriptionFill, used >= 100 && UsageBilling_module_css_default.subscriptionFillOver, used >= 80 && used < 100 && UsageBilling_module_css_default.subscriptionFillWarn),
3072
+ style: { width: `${used}%` }
3073
+ })
3074
+ }),
3075
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3076
+ className: clsx(UsageBilling_module_css_default.subscriptionPct, exhausted && UsageBilling_module_css_default.subscriptionExhausted),
3077
+ children: exhausted ? t("billing.subscriptionExhausted") : t("billing.subscriptionRemaining").replace("{pct}", String(window.remainingPercent))
3078
+ }),
3079
+ window.resetsAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3080
+ className: UsageBilling_module_css_default.subscriptionReset,
3081
+ children: t("billing.subscriptionReset").replace("{date}", window.resetsAt.slice(0, 10))
2640
3082
  })
2641
- }),
2642
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2643
- className: UsageBilling_module_css_default.subscriptionPct,
2644
- children: t("billing.subscriptionRemaining").replace("{pct}", String(window.remainingPercent))
2645
- }),
2646
- window.resetsAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2647
- className: UsageBilling_module_css_default.subscriptionReset,
2648
- children: t("billing.subscriptionReset").replace("{date}", window.resetsAt.slice(0, 10))
2649
- })
2650
- ]
2651
- }, window.kind))
3083
+ ]
3084
+ }, window.kind);
3085
+ })())
2652
3086
  ]
2653
3087
  }, quota.provider);
2654
3088
  })
@@ -2661,130 +3095,215 @@ window.__ModuleLoader__.load({
2661
3095
  tab === "details" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2662
3096
  className: UsageBilling_module_css_default.tabPanel,
2663
3097
  "data-testid": "billing-tab-panel-details",
2664
- children: [stats.byWorkspace !== void 0 && stats.byWorkspace.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2665
- className: UsageBilling_module_css_default.panel,
2666
- "data-testid": "billing-panel-workspaces",
2667
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2668
- className: UsageBilling_module_css_default.panelHead,
2669
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2670
- className: UsageBilling_module_css_default.panelTitle,
2671
- children: t("billing.workspaces")
2672
- })
2673
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2674
- className: UsageBilling_module_css_default.tableScroll,
2675
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
2676
- className: UsageBilling_module_css_default.modelTable,
2677
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
2678
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.project") }),
2679
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2680
- className: UsageBilling_module_css_default.numCol,
2681
- children: t("billing.calls")
2682
- }),
2683
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2684
- className: UsageBilling_module_css_default.numCol,
2685
- children: t("billing.inputTokens")
2686
- }),
2687
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2688
- className: UsageBilling_module_css_default.numCol,
2689
- children: t("billing.outputTokens")
2690
- }),
2691
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2692
- className: UsageBilling_module_css_default.numCol,
2693
- children: t("billing.actual")
2694
- }),
2695
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2696
- className: UsageBilling_module_css_default.numCol,
2697
- children: t("billing.lastActive")
2698
- })
2699
- ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: stats.byWorkspace.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
2700
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2701
- className: UsageBilling_module_css_default.modelName,
2702
- children: row.name
2703
- }) }),
2704
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2705
- className: UsageBilling_module_css_default.numCol,
2706
- children: row.calls.toLocaleString()
2707
- }),
2708
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2709
- className: UsageBilling_module_css_default.numCol,
2710
- children: formatTokens(row.input)
2711
- }),
2712
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2713
- className: UsageBilling_module_css_default.numCol,
2714
- children: formatTokens(row.output)
2715
- }),
2716
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2717
- className: UsageBilling_module_css_default.numCol,
2718
- children: money(row.cost)
2719
- }),
2720
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2721
- className: UsageBilling_module_css_default.numCol,
2722
- children: row.lastActive > 0 ? `${localDayStamp(row.lastActive)}` : "—"
2723
- })
2724
- ] }, row.name)) })]
2725
- })
2726
- })]
2727
- }), stats.bySession !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2728
- className: UsageBilling_module_css_default.panel,
2729
- "data-testid": "billing-panel-sessions",
2730
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2731
- className: UsageBilling_module_css_default.panelHead,
2732
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2733
- className: UsageBilling_module_css_default.panelTitle,
2734
- children: t("billing.sessions")
2735
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2736
- className: UsageBilling_module_css_default.panelHint,
2737
- children: stats.bySession.length > SESSION_DISPLAY_LIMIT ? t("billing.sessionOverflow").replace("{limit}", String(SESSION_DISPLAY_LIMIT)).replace("{total}", String(stats.bySession.length)) : `${stats.bySession.length}`
3098
+ children: [
3099
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3100
+ className: UsageBilling_module_css_default.exportBar,
3101
+ "data-testid": "billing-export-bar",
3102
+ role: "group",
3103
+ "aria-label": t("billing.export"),
3104
+ children: [
3105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3106
+ className: UsageBilling_module_css_default.exportLabel,
3107
+ children: t("billing.export")
3108
+ }),
3109
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3110
+ type: "button",
3111
+ className: UsageBilling_module_css_default.exportButton,
3112
+ "data-testid": "billing-export-day",
3113
+ onClick: () => {
3114
+ downloadText(exportFileName("usage-daily", "csv", Object.keys(byDay)), dayRowsCsv(byDay), "text/csv");
3115
+ },
3116
+ children: t("billing.exportCsvDay")
3117
+ }),
3118
+ stats.bySession !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3119
+ type: "button",
3120
+ className: UsageBilling_module_css_default.exportButton,
3121
+ "data-testid": "billing-export-sessions",
3122
+ onClick: () => {
3123
+ downloadText(exportFileName("usage-sessions", "csv", Object.keys(byDay)), sessionRowsCsv(stats.bySession ?? []), "text/csv");
3124
+ },
3125
+ children: t("billing.exportCsvSession")
3126
+ }),
3127
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3128
+ type: "button",
3129
+ className: UsageBilling_module_css_default.exportButton,
3130
+ "data-testid": "billing-export-json",
3131
+ onClick: () => {
3132
+ downloadText(exportFileName("usage-stats", "json", Object.keys(byDay)), JSON.stringify(stats, null, 2), "application/json");
3133
+ },
3134
+ children: t("billing.exportJson")
3135
+ })
3136
+ ]
3137
+ }),
3138
+ roleRows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3139
+ className: UsageBilling_module_css_default.panel,
3140
+ "data-testid": "billing-panel-roles",
3141
+ children: [
3142
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3143
+ className: UsageBilling_module_css_default.panelHead,
3144
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3145
+ className: UsageBilling_module_css_default.panelTitle,
3146
+ children: t("billing.roleCost")
3147
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3148
+ className: UsageBilling_module_css_default.panelHint,
3149
+ children: t("billing.roleHint")
3150
+ })]
3151
+ }),
3152
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3153
+ className: UsageBilling_module_css_default.shareTrack,
3154
+ "data-testid": "billing-role-track",
3155
+ children: roleRows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3156
+ className: clsx(UsageBilling_module_css_default.shareSeg, row.seg),
3157
+ style: { width: `${row.pct}%` }
3158
+ }, row.label))
3159
+ }),
3160
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3161
+ className: UsageBilling_module_css_default.shareLegend,
3162
+ children: roleRows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3163
+ className: UsageBilling_module_css_default.shareItem,
3164
+ children: [
3165
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: clsx(UsageBilling_module_css_default.shareDot, row.seg) }),
3166
+ row.label,
3167
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3168
+ className: UsageBilling_module_css_default.shareValue,
3169
+ children: [
3170
+ money(row.value),
3171
+ " · ",
3172
+ row.pct.toFixed(1),
3173
+ "%"
3174
+ ]
3175
+ })
3176
+ ]
3177
+ }, row.label))
3178
+ })
3179
+ ]
3180
+ }),
3181
+ stats.byWorkspace !== void 0 && stats.byWorkspace.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3182
+ className: UsageBilling_module_css_default.panel,
3183
+ "data-testid": "billing-panel-workspaces",
3184
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3185
+ className: UsageBilling_module_css_default.panelHead,
3186
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3187
+ className: UsageBilling_module_css_default.panelTitle,
3188
+ children: t("billing.workspaces")
3189
+ })
3190
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3191
+ className: UsageBilling_module_css_default.tableScroll,
3192
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
3193
+ className: UsageBilling_module_css_default.modelTable,
3194
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
3195
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.project") }),
3196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3197
+ className: UsageBilling_module_css_default.numCol,
3198
+ children: t("billing.calls")
3199
+ }),
3200
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3201
+ className: UsageBilling_module_css_default.numCol,
3202
+ children: t("billing.inputTokens")
3203
+ }),
3204
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3205
+ className: UsageBilling_module_css_default.numCol,
3206
+ children: t("billing.outputTokens")
3207
+ }),
3208
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3209
+ className: UsageBilling_module_css_default.numCol,
3210
+ children: t("billing.actual")
3211
+ }),
3212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3213
+ className: UsageBilling_module_css_default.numCol,
3214
+ children: t("billing.lastActive")
3215
+ })
3216
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: stats.byWorkspace.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
3217
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3218
+ className: UsageBilling_module_css_default.modelName,
3219
+ children: row.name
3220
+ }) }),
3221
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3222
+ className: UsageBilling_module_css_default.numCol,
3223
+ children: row.calls.toLocaleString()
3224
+ }),
3225
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3226
+ className: UsageBilling_module_css_default.numCol,
3227
+ children: formatTokens(row.input)
3228
+ }),
3229
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3230
+ className: UsageBilling_module_css_default.numCol,
3231
+ children: formatTokens(row.output)
3232
+ }),
3233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3234
+ className: UsageBilling_module_css_default.numCol,
3235
+ children: money(row.cost)
3236
+ }),
3237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3238
+ className: UsageBilling_module_css_default.numCol,
3239
+ children: row.lastActive > 0 ? `${localDayStamp(row.lastActive)}` : "—"
3240
+ })
3241
+ ] }, row.name)) })]
3242
+ })
2738
3243
  })]
2739
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2740
- className: UsageBilling_module_css_default.tableScroll,
2741
- "data-testid": "billing-sessions-table",
2742
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
2743
- className: UsageBilling_module_css_default.modelTable,
2744
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
2745
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.sessions") }),
2746
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.project") }),
2747
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2748
- className: UsageBilling_module_css_default.numCol,
2749
- children: t("billing.calls")
2750
- }),
2751
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2752
- className: UsageBilling_module_css_default.numCol,
2753
- children: t("billing.actual")
2754
- }),
2755
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
2756
- className: UsageBilling_module_css_default.numCol,
2757
- children: t("billing.lastActive")
2758
- })
2759
- ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [stats.bySession.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2760
- colSpan: 5,
2761
- className: UsageBilling_module_css_default.emptyRow,
2762
- children: t("billing.noData")
2763
- }) }), stats.bySession.slice(0, SESSION_DISPLAY_LIMIT).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
2764
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2765
- className: UsageBilling_module_css_default.modelName,
2766
- children: row.title ?? row.id.slice(0, 8)
2767
- }) }),
2768
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2769
- className: UsageBilling_module_css_default.modelProvider,
2770
- children: projectName(row.cwd) ?? "—"
2771
- }) }),
2772
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2773
- className: UsageBilling_module_css_default.numCol,
2774
- children: row.calls.toLocaleString()
2775
- }),
2776
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2777
- className: UsageBilling_module_css_default.numCol,
2778
- children: money(row.cost)
2779
- }),
2780
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2781
- className: UsageBilling_module_css_default.numCol,
2782
- children: row.lastActive > 0 ? `${localDayStamp(row.lastActive)} ${formatClock(row.lastActive)}` : "—"
2783
- })
2784
- ] }, row.id))] })]
2785
- })
2786
- })]
2787
- })]
3244
+ }),
3245
+ stats.bySession !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3246
+ className: UsageBilling_module_css_default.panel,
3247
+ "data-testid": "billing-panel-sessions",
3248
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3249
+ className: UsageBilling_module_css_default.panelHead,
3250
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3251
+ className: UsageBilling_module_css_default.panelTitle,
3252
+ children: t("billing.sessions")
3253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3254
+ className: UsageBilling_module_css_default.panelHint,
3255
+ children: stats.bySession.length > SESSION_DISPLAY_LIMIT ? t("billing.sessionOverflow").replace("{limit}", String(SESSION_DISPLAY_LIMIT)).replace("{total}", String(stats.bySession.length)) : `${stats.bySession.length}`
3256
+ })]
3257
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3258
+ className: UsageBilling_module_css_default.tableScroll,
3259
+ "data-testid": "billing-sessions-table",
3260
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
3261
+ className: UsageBilling_module_css_default.modelTable,
3262
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
3263
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.sessions") }),
3264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.project") }),
3265
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3266
+ className: UsageBilling_module_css_default.numCol,
3267
+ children: t("billing.calls")
3268
+ }),
3269
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3270
+ className: UsageBilling_module_css_default.numCol,
3271
+ children: t("billing.actual")
3272
+ }),
3273
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
3274
+ className: UsageBilling_module_css_default.numCol,
3275
+ children: t("billing.lastActive")
3276
+ })
3277
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [stats.bySession.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3278
+ colSpan: 5,
3279
+ className: UsageBilling_module_css_default.emptyRow,
3280
+ children: t("billing.noData")
3281
+ }) }), stats.bySession.slice(0, SESSION_DISPLAY_LIMIT).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
3282
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3283
+ className: UsageBilling_module_css_default.modelName,
3284
+ children: row.title ?? row.id.slice(0, 8)
3285
+ }) }),
3286
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3287
+ className: UsageBilling_module_css_default.modelProvider,
3288
+ children: projectName(row.cwd) ?? "—"
3289
+ }) }),
3290
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3291
+ className: UsageBilling_module_css_default.numCol,
3292
+ children: row.calls.toLocaleString()
3293
+ }),
3294
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3295
+ className: UsageBilling_module_css_default.numCol,
3296
+ children: money(row.cost)
3297
+ }),
3298
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3299
+ className: UsageBilling_module_css_default.numCol,
3300
+ children: row.lastActive > 0 ? `${localDayStamp(row.lastActive)} ${formatClock(row.lastActive)}` : "—"
3301
+ })
3302
+ ] }, row.id))] })]
3303
+ })
3304
+ })]
3305
+ })
3306
+ ]
2788
3307
  }),
2789
3308
  tab === "pricing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2790
3309
  className: UsageBilling_module_css_default.tabPanel,
@@ -2828,65 +3347,81 @@ window.__ModuleLoader__.load({
2828
3347
  children: t("billing.output")
2829
3348
  }),
2830
3349
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("billing.band") })
2831
- ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: MODEL_CATALOG.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
2832
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2833
- className: UsageBilling_module_css_default.modelCell,
2834
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2835
- className: UsageBilling_module_css_default.modelDot,
2836
- style: { background: resolveToken(entry.colorVar) }
2837
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2838
- className: UsageBilling_module_css_default.modelName,
2839
- children: entry.name
2840
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2841
- className: UsageBilling_module_css_default.modelProvider,
2842
- children: entry.provider
2843
- })] })]
2844
- }) }),
2845
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2846
- className: UsageBilling_module_css_default.numCol,
2847
- children: entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2848
- className: UsageBilling_module_css_default.bandPrice,
2849
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.input, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2850
- className: UsageBilling_module_css_default.bandPriceOff,
2851
- children: formatUnitPrice(entry.price.offPeak.input, entry.price.currency)
2852
- })]
2853
- }) : formatUnitPrice(entry.price.input, entry.price.currency)
2854
- }),
2855
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2856
- className: UsageBilling_module_css_default.numCol,
2857
- children: entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2858
- className: UsageBilling_module_css_default.bandPrice,
2859
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.cacheHit, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2860
- className: UsageBilling_module_css_default.bandPriceOff,
2861
- children: formatUnitPrice(entry.price.offPeak.cacheHit, entry.price.currency)
2862
- })]
2863
- }) : formatUnitPrice(entry.price.cacheHit, entry.price.currency)
2864
- }),
2865
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
2866
- className: UsageBilling_module_css_default.numCol,
2867
- children: entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2868
- className: UsageBilling_module_css_default.bandPrice,
2869
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.output, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2870
- className: UsageBilling_module_css_default.bandPriceOff,
2871
- children: formatUnitPrice(entry.price.offPeak.output, entry.price.currency)
3350
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: catalogEntries().map((entry) => {
3351
+ const hasPrice = entry.price.input > 0 || entry.price.output > 0;
3352
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
3353
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3354
+ className: UsageBilling_module_css_default.modelCell,
3355
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3356
+ className: UsageBilling_module_css_default.modelDot,
3357
+ style: { background: resolveToken(entry.colorVar) }
3358
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3359
+ className: UsageBilling_module_css_default.modelName,
3360
+ children: [entry.name, entry.uncatalogued && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3361
+ className: UsageBilling_module_css_default.uncataloguedTag,
3362
+ "data-testid": "billing-price-uncatalogued",
3363
+ children: t("billing.uncatalogued")
3364
+ })]
3365
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3366
+ className: UsageBilling_module_css_default.modelProvider,
3367
+ children: entry.provider
3368
+ })] })]
3369
+ }) }),
3370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3371
+ className: UsageBilling_module_css_default.numCol,
3372
+ children: hasPrice ? entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3373
+ className: UsageBilling_module_css_default.bandPrice,
3374
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.input, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3375
+ className: UsageBilling_module_css_default.bandPriceOff,
3376
+ children: formatUnitPrice(entry.price.offPeak.input, entry.price.currency)
3377
+ })]
3378
+ }) : formatUnitPrice(entry.price.input, entry.price.currency) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3379
+ className: UsageBilling_module_css_default.na,
3380
+ children: "—"
3381
+ })
3382
+ }),
3383
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3384
+ className: UsageBilling_module_css_default.numCol,
3385
+ children: hasPrice ? entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3386
+ className: UsageBilling_module_css_default.bandPrice,
3387
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.cacheHit, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3388
+ className: UsageBilling_module_css_default.bandPriceOff,
3389
+ children: formatUnitPrice(entry.price.offPeak.cacheHit, entry.price.currency)
3390
+ })]
3391
+ }) : formatUnitPrice(entry.price.cacheHit, entry.price.currency) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3392
+ className: UsageBilling_module_css_default.na,
3393
+ children: "—"
3394
+ })
3395
+ }),
3396
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
3397
+ className: UsageBilling_module_css_default.numCol,
3398
+ children: hasPrice ? entry.price.offPeak !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3399
+ className: UsageBilling_module_css_default.bandPrice,
3400
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatUnitPrice(entry.price.output, entry.price.currency) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3401
+ className: UsageBilling_module_css_default.bandPriceOff,
3402
+ children: formatUnitPrice(entry.price.offPeak.output, entry.price.currency)
3403
+ })]
3404
+ }) : formatUnitPrice(entry.price.output, entry.price.currency) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3405
+ className: UsageBilling_module_css_default.na,
3406
+ children: "—"
3407
+ })
3408
+ }),
3409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: entry.price.offPeak !== void 0 && entry.peakHours !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3410
+ className: UsageBilling_module_css_default.bandTag,
3411
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
3412
+ t("billing.peak"),
3413
+ " ",
3414
+ entry.peakHours
3415
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3416
+ className: UsageBilling_module_css_default.bandTagOff,
3417
+ children: [t("billing.offPeak"), " 50%"]
2872
3418
  })]
2873
- }) : formatUnitPrice(entry.price.output, entry.price.currency)
2874
- }),
2875
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: entry.price.offPeak !== void 0 && entry.peakHours !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2876
- className: UsageBilling_module_css_default.bandTag,
2877
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2878
- t("billing.peak"),
2879
- " ",
2880
- entry.peakHours
2881
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2882
- className: UsageBilling_module_css_default.bandTagOff,
2883
- children: [t("billing.offPeak"), " 50%"]
2884
- })]
2885
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2886
- className: UsageBilling_module_css_default.flatTag,
2887
- children: t("billing.flat")
2888
- }) })
2889
- ] }, entry.key)) })]
3419
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3420
+ className: UsageBilling_module_css_default.flatTag,
3421
+ children: t("billing.flat")
3422
+ }) })
3423
+ ] }, entry.key);
3424
+ }) })]
2890
3425
  })
2891
3426
  })]
2892
3427
  })
@@ -2945,7 +3480,9 @@ window.__ModuleLoader__.load({
2945
3480
  (0, react.useEffect)(() => {
2946
3481
  let mounted = true;
2947
3482
  checkModels().then((result) => {
2948
- if (mounted) setHealth(result);
3483
+ if (!mounted) return;
3484
+ setHealth(result);
3485
+ applyLiveCatalogModels(result.catalog ?? []);
2949
3486
  });
2950
3487
  return () => {
2951
3488
  mounted = false;
@@ -2954,9 +3491,12 @@ window.__ModuleLoader__.load({
2954
3491
  const today = localDayStamp();
2955
3492
  const monthCost = Object.entries(stats.byDay).filter(([date]) => date.startsWith(today.slice(0, 7))).reduce((sum, [, day]) => sum + day.cost, 0);
2956
3493
  const todayCost = stats.byDay[today]?.cost ?? 0;
3494
+ const weekCost = lastSevenDays(stats.byDay).reduce((sum, d) => sum + d.cost, 0);
3495
+ const last7 = (0, react.useMemo)(() => lastSevenDays(stats.byDay), [stats.byDay]);
2957
3496
  const budgetEnabled = useStore((s) => s.enabled);
2958
3497
  const budgetAmount = useStore((s) => s.amount);
2959
- const budgetAlertedDay = useStore((s) => s.lastAlertDay);
3498
+ const tierAlertDays = useStore((s) => s.tierAlertDays);
3499
+ const lastTierSwitchAt = useStore((s) => s.lastTierSwitchAt);
2960
3500
  const effectiveBudget = budgetAmount > 0 ? budgetAmount : stats.budget ?? 0;
2961
3501
  const toggleBudget = (0, react.useCallback)(() => {
2962
3502
  const next = !budgetEnabled;
@@ -2966,12 +3506,13 @@ window.__ModuleLoader__.load({
2966
3506
  (0, react.useEffect)(() => {
2967
3507
  if (!budgetEnabled || effectiveBudget <= 0) return;
2968
3508
  const pct = monthCost / effectiveBudget * 100;
2969
- if (pct < 100) return;
2970
3509
  const day = localDayStamp();
2971
- if (budgetAlertedDay === day) return;
2972
- actions.markAlerted(day);
3510
+ const crossed = BUDGET_ALERT_TIERS.filter((tier) => pct >= tier && tierAlertDays?.[String(tier)] !== day);
3511
+ if (crossed.length === 0) return;
3512
+ const top = crossed[crossed.length - 1] ?? 100;
3513
+ actions.markTierAlerted(crossed, day);
2973
3514
  if (typeof Notification === "undefined" || Notification.permission !== "granted") return;
2974
- const body = t("billing.budgetOverBody").replace("{cost}", formatMoney(monthCost)).replace("{budget}", formatMoney(effectiveBudget)).replace("{pct}", pct.toFixed(0));
3515
+ const body = t("billing.budgetTierBody").replace("{cost}", formatMoney(monthCost)).replace("{budget}", formatMoney(effectiveBudget)).replace("{pct}", String(top));
2975
3516
  try {
2976
3517
  new Notification(t("billing.budget"), { body });
2977
3518
  } catch {}
@@ -2979,7 +3520,25 @@ window.__ModuleLoader__.load({
2979
3520
  budgetEnabled,
2980
3521
  effectiveBudget,
2981
3522
  monthCost,
2982
- budgetAlertedDay,
3523
+ tierAlertDays,
3524
+ actions,
3525
+ t
3526
+ ]);
3527
+ (0, react.useEffect)(() => {
3528
+ const leadMs = 2 * 6e4;
3529
+ const now = Date.now();
3530
+ const upcoming = upcomingTierSwitch(now, leadMs);
3531
+ if (upcoming === null) return;
3532
+ if (upcoming.atMs === lastTierSwitchAt) return;
3533
+ actions.markTierSwitchAlerted(upcoming.atMs);
3534
+ if (typeof Notification === "undefined" || Notification.permission !== "granted") return;
3535
+ const minutes = Math.max(1, Math.round((upcoming.atMs - now) / 6e4));
3536
+ const body = upcoming.entering === "peak" ? t("billing.tierAlertEnterPeak").replace("{minutes}", String(minutes)) : t("billing.tierAlertEnterOff").replace("{minutes}", String(minutes));
3537
+ try {
3538
+ new Notification(t("billing.budget"), { body });
3539
+ } catch {}
3540
+ }, [
3541
+ lastTierSwitchAt,
2983
3542
  actions,
2984
3543
  t
2985
3544
  ]);
@@ -3038,7 +3597,9 @@ window.__ModuleLoader__.load({
3038
3597
  ...props,
3039
3598
  onOpen: openDashboard,
3040
3599
  monthCost,
3041
- todayCost
3600
+ todayCost,
3601
+ weekCost,
3602
+ days: last7
3042
3603
  }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BillingDashboard, {
3043
3604
  stats,
3044
3605
  t,
@@ -3069,6 +3630,11 @@ window.__ModuleLoader__.load({
3069
3630
  * the current session id off the framework snapshot (`useSession` parent of
3070
3631
  * `sessionId`) and matches `bySession` (session total) and `byTurn` (latest
3071
3632
  * turn cost). Rendering is a pure function of the snapshot, never a side effect.
3633
+ *
3634
+ * The bar also carries two ambient signals: the current peak/off-peak pricing
3635
+ * tier with a switch countdown (DeepSeek time-of-day pricing), and quota chips
3636
+ * for subscription plans running low (≤20% remaining), so cost pressure is
3637
+ * visible without opening the dashboard.
3072
3638
  */
3073
3639
  /**
3074
3640
  * 当前会话累计费用:bySession 里会话 id 匹配的那行;缺省为 0。
@@ -3102,8 +3668,31 @@ window.__ModuleLoader__.load({
3102
3668
  }
3103
3669
  return latest;
3104
3670
  }
3671
+ /**
3672
+ * 低额度预警 chips:查询成功(ok)且任一窗口剩余 ≤ threshold 的套餐,
3673
+ * 按剩余升序、最多 3 枚。导出供测试:纯函数。
3674
+ * @param quotas - 订阅额度行切片。
3675
+ * @param threshold - 剩余百分比阈值(默认 20%)。
3676
+ */
3677
+ function lowQuotaChips(quotas, threshold = 20) {
3678
+ const chips = [];
3679
+ for (const quota of quotas) {
3680
+ if (quota.status !== "ok") continue;
3681
+ for (const win of quota.windows) {
3682
+ if (win.remainingPercent > threshold) continue;
3683
+ chips.push({
3684
+ name: quota.displayName,
3685
+ kind: win.kind,
3686
+ pct: win.remainingPercent
3687
+ });
3688
+ }
3689
+ }
3690
+ return chips.sort((a, b) => a.pct - b.pct).slice(0, 3);
3691
+ }
3105
3692
  /** Endpoint the node half serves (same constant the dashboard uses). */
3106
3693
  const USAGE_STATS_PATH = "/api/billing/usage-stats";
3694
+ /** 订阅额度端点(额度预警 chips 的数据源)。 */
3695
+ const SUBSCRIPTIONS_PATH = "/api/billing/subscriptions";
3107
3696
  /** Refresh cadence (ms): matching the dashboard so the bar stays current. */
3108
3697
  const REFRESH_INTERVAL_MS = 3e4;
3109
3698
  /** Load the thin stats slice; null when the endpoint does not answer valid JSON. */
@@ -3123,6 +3712,28 @@ window.__ModuleLoader__.load({
3123
3712
  return null;
3124
3713
  }
3125
3714
  }
3715
+ /** Load subscription quota slices; empty list on any failure. */
3716
+ async function loadQuotas() {
3717
+ try {
3718
+ const response = await fetch(SUBSCRIPTIONS_PATH);
3719
+ if (!response.ok) return [];
3720
+ const parsed = JSON.parse(await response.text());
3721
+ if (parsed === null || typeof parsed !== "object" || !("quotas" in parsed)) return [];
3722
+ const quotas = parsed.quotas;
3723
+ return Array.isArray(quotas) ? quotas : [];
3724
+ } catch {
3725
+ return [];
3726
+ }
3727
+ }
3728
+ /** 额度窗口类型 → 文案 key(本次 / 本周 / 本月 / 计费周期)。 */
3729
+ function windowLabelKey(kind) {
3730
+ switch (kind) {
3731
+ case "session": return "billing.subscriptionSession";
3732
+ case "weekly": return "billing.subscriptionWeekly";
3733
+ case "monthly": return "billing.subscriptionMonthly";
3734
+ default: return "billing.subscriptionBilling";
3735
+ }
3736
+ }
3126
3737
  /**
3127
3738
  * Render the live cost ticker for the current session.
3128
3739
  * @param props - framework session snapshot hook and locale.
@@ -3130,12 +3741,18 @@ window.__ModuleLoader__.load({
3130
3741
  function LiveCostBar({ useSession, t }) {
3131
3742
  const sessionId = useSession((s) => s.sessionId);
3132
3743
  const [stats, setStats] = (0, react.useState)(null);
3744
+ const [quotas, setQuotas] = (0, react.useState)([]);
3745
+ const [nowMs, setNowMs] = (0, react.useState)(() => Date.now());
3133
3746
  (0, react.useEffect)(() => {
3134
3747
  let cancelled = false;
3135
3748
  const load = () => {
3136
3749
  loadLiveStats().then((data) => {
3137
3750
  if (!cancelled && data !== null) setStats(data);
3138
3751
  });
3752
+ loadQuotas().then((list) => {
3753
+ if (!cancelled) setQuotas(list);
3754
+ });
3755
+ if (!cancelled) setNowMs(Date.now());
3139
3756
  };
3140
3757
  load();
3141
3758
  const timer = setInterval(load, REFRESH_INTERVAL_MS);
@@ -3146,35 +3763,72 @@ window.__ModuleLoader__.load({
3146
3763
  }, [sessionId]);
3147
3764
  const sessionCost = (0, react.useMemo)(() => sessionCostOf(stats, sessionId), [stats, sessionId]);
3148
3765
  const turnCost = (0, react.useMemo)(() => turnCostOf(stats, sessionId), [stats, sessionId]);
3766
+ const tier = tierCountdown(nowMs);
3767
+ const chips = (0, react.useMemo)(() => lowQuotaChips(quotas), [quotas]);
3149
3768
  const money = (cny) => formatMoney(cny, "cny");
3150
- if (sessionId === void 0 || sessionCost <= 0 && turnCost <= 0) return null;
3769
+ if (sessionId === void 0) return null;
3770
+ const hasCost = sessionCost > 0 || turnCost > 0;
3151
3771
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3152
3772
  className: UsageBilling_module_css_default.liveCostBar,
3153
3773
  "data-testid": "billing-live-cost-bar",
3154
3774
  children: [
3155
3775
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3156
- className: UsageBilling_module_css_default.liveCostItem,
3157
- "data-testid": "billing-live-turn",
3776
+ className: tier.tier === "peak" ? UsageBilling_module_css_default.liveTierPeak : UsageBilling_module_css_default.liveTierOff,
3777
+ "data-testid": "billing-live-tier",
3158
3778
  children: [
3159
- t("billing.liveTurn"),
3779
+ tier.tier === "peak" ? t("billing.tierPeak") : t("billing.tierOff"),
3780
+ " · ",
3781
+ formatSwitchCountdown(tier.nextSwitchInMs),
3160
3782
  " ",
3161
- money(turnCost)
3783
+ tier.tier === "peak" ? t("billing.tierToOff") : t("billing.tierToPeak")
3162
3784
  ]
3163
3785
  }),
3164
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3786
+ hasCost && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3787
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3788
+ className: UsageBilling_module_css_default.liveCostSep,
3789
+ "aria-hidden": "true",
3790
+ children: "·"
3791
+ }),
3792
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3793
+ className: UsageBilling_module_css_default.liveCostItem,
3794
+ "data-testid": "billing-live-turn",
3795
+ children: [
3796
+ t("billing.liveTurn"),
3797
+ " ",
3798
+ money(turnCost)
3799
+ ]
3800
+ }),
3801
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3802
+ className: UsageBilling_module_css_default.liveCostSep,
3803
+ "aria-hidden": "true",
3804
+ children: "·"
3805
+ }),
3806
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3807
+ className: UsageBilling_module_css_default.liveCostItem,
3808
+ "data-testid": "billing-live-session",
3809
+ children: [
3810
+ t("billing.liveSession"),
3811
+ " ",
3812
+ money(sessionCost)
3813
+ ]
3814
+ })
3815
+ ] }),
3816
+ chips.map((chip) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3165
3817
  className: UsageBilling_module_css_default.liveCostSep,
3166
3818
  "aria-hidden": "true",
3167
3819
  children: "·"
3168
- }),
3169
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3170
- className: UsageBilling_module_css_default.liveCostItem,
3171
- "data-testid": "billing-live-session",
3820
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3821
+ className: chip.pct <= 10 ? UsageBilling_module_css_default.liveQuotaCrit : UsageBilling_module_css_default.liveQuotaWarn,
3822
+ "data-testid": "billing-live-quota",
3172
3823
  children: [
3173
- t("billing.liveSession"),
3824
+ chip.name,
3825
+ " ",
3826
+ t(windowLabelKey(chip.kind)),
3174
3827
  " ",
3175
- money(sessionCost)
3828
+ chip.pct,
3829
+ "%"
3176
3830
  ]
3177
- })
3831
+ })] }, `${chip.name}:${chip.kind}`))
3178
3832
  ]
3179
3833
  });
3180
3834
  }
@@ -3207,7 +3861,7 @@ window.__ModuleLoader__.load({
3207
3861
  "billing.project": "项目",
3208
3862
  "billing.lastActive": "最后活跃",
3209
3863
  "billing.sessionOverflow": "仅显示花费前 {limit} 个,共 {total} 个会话",
3210
- "billing.budgetOverBody": "本月花费 {cost} 已超过预算 {budget}({pct}%)",
3864
+ "billing.budgetTierBody": "本月花费 {cost} 已达预算 {budget} 的 {pct}%",
3211
3865
  "billing.models": "模型计费明细",
3212
3866
  "billing.providerBilling": "厂商计费与订阅",
3213
3867
  "billing.estimated": "估算",
@@ -3250,6 +3904,7 @@ window.__ModuleLoader__.load({
3250
3904
  "billing.subscriptionMonthly": "本月",
3251
3905
  "billing.subscriptionBilling": "计费周期",
3252
3906
  "billing.subscriptionRemaining": "剩余 {pct}%",
3907
+ "billing.subscriptionExhausted": "已用尽",
3253
3908
  "billing.subscriptionReset": "{date} 重置",
3254
3909
  "billing.subscriptionNoApi": "该厂商暂未提供用量查询接口",
3255
3910
  "billing.heatmapLess": "少",
@@ -3271,7 +3926,25 @@ window.__ModuleLoader__.load({
3271
3926
  "billing.tabTrends": "趋势",
3272
3927
  "billing.tabProviders": "明细",
3273
3928
  "billing.tabDetails": "统计",
3274
- "billing.tabPricing": "费率"
3929
+ "billing.tabPricing": "费率",
3930
+ "billing.export": "导出",
3931
+ "billing.exportCsvDay": "按日 CSV",
3932
+ "billing.exportCsvSession": "按会话 CSV",
3933
+ "billing.exportJson": "全量 JSON",
3934
+ "billing.peakShare": "峰谷时段占比",
3935
+ "billing.peakShareHint": "近 {count} 轮",
3936
+ "billing.weekCost": "本周",
3937
+ "billing.roleCost": "费用构成",
3938
+ "billing.roleUser": "用户输入",
3939
+ "billing.roleAssistant": "助手输出",
3940
+ "billing.roleTool": "工具结果",
3941
+ "billing.roleHint": "估算:输出按实测计价,输入按消息长度摊分",
3942
+ "billing.tierPeak": "峰时",
3943
+ "billing.tierOff": "平价",
3944
+ "billing.tierToPeak": "后转峰时",
3945
+ "billing.tierToOff": "后转平价",
3946
+ "billing.tierAlertEnterPeak": "{minutes} 分钟后进入峰时(DeepSeek 高峰价 ×2),不急的调用可稍等",
3947
+ "billing.tierAlertEnterOff": "{minutes} 分钟后进入平价(价格减半)"
3275
3948
  };
3276
3949
  const en = {
3277
3950
  "billing.title": "Usage",
@@ -3299,7 +3972,7 @@ window.__ModuleLoader__.load({
3299
3972
  "billing.project": "Project",
3300
3973
  "billing.lastActive": "Last active",
3301
3974
  "billing.sessionOverflow": "Top {limit} of {total} sessions by cost",
3302
- "billing.budgetOverBody": "This month {cost} exceeded the budget {budget} ({pct}%)",
3975
+ "billing.budgetTierBody": "This month {cost} reached {pct}% of the budget {budget}",
3303
3976
  "billing.models": "Model billing",
3304
3977
  "billing.providerBilling": "Provider billing & subscriptions",
3305
3978
  "billing.estimated": "Est.",
@@ -3342,6 +4015,7 @@ window.__ModuleLoader__.load({
3342
4015
  "billing.subscriptionMonthly": "Monthly",
3343
4016
  "billing.subscriptionBilling": "Billing",
3344
4017
  "billing.subscriptionRemaining": "{pct}% left",
4018
+ "billing.subscriptionExhausted": "Exhausted",
3345
4019
  "billing.subscriptionReset": "Resets {date}",
3346
4020
  "billing.subscriptionNoApi": "Provider does not offer a usage API",
3347
4021
  "billing.heatmapLess": "Less",
@@ -3363,7 +4037,25 @@ window.__ModuleLoader__.load({
3363
4037
  "billing.tabTrends": "Trends",
3364
4038
  "billing.tabProviders": "Details",
3365
4039
  "billing.tabDetails": "Stats",
3366
- "billing.tabPricing": "Rates"
4040
+ "billing.tabPricing": "Rates",
4041
+ "billing.export": "Export",
4042
+ "billing.exportCsvDay": "Daily CSV",
4043
+ "billing.exportCsvSession": "Sessions CSV",
4044
+ "billing.exportJson": "Full JSON",
4045
+ "billing.peakShare": "Peak vs off-peak",
4046
+ "billing.peakShareHint": "last {count} turns",
4047
+ "billing.weekCost": "This week",
4048
+ "billing.roleCost": "Cost breakdown",
4049
+ "billing.roleUser": "User input",
4050
+ "billing.roleAssistant": "Assistant output",
4051
+ "billing.roleTool": "Tool results",
4052
+ "billing.roleHint": "Estimated: output priced exactly, input split by message size",
4053
+ "billing.tierPeak": "Peak",
4054
+ "billing.tierOff": "Off-peak",
4055
+ "billing.tierToPeak": "until peak",
4056
+ "billing.tierToOff": "until off-peak",
4057
+ "billing.tierAlertEnterPeak": "Peak pricing (2x) starts in {minutes} min — non-urgent calls can wait",
4058
+ "billing.tierAlertEnterOff": "Off-peak pricing (50% off) starts in {minutes} min"
3367
4059
  };
3368
4060
  //#endregion
3369
4061
  //#region src/client/billing-service.ts
@@ -3414,8 +4106,9 @@ window.__ModuleLoader__.load({
3414
4106
  init: () => ({
3415
4107
  enabled: false,
3416
4108
  amount: 0,
3417
- lastAlertDay: "",
3418
- lastBalanceAlertDay: ""
4109
+ tierAlertDays: {},
4110
+ lastBalanceAlertDay: "",
4111
+ lastTierSwitchAt: 0
3419
4112
  }),
3420
4113
  persist: "dsh.ui-usage-billing.budget",
3421
4114
  actions: {
@@ -3425,11 +4118,15 @@ window.__ModuleLoader__.load({
3425
4118
  setAmount: (d, value) => {
3426
4119
  d.amount = Number.isFinite(value) && value > 0 ? value : 0;
3427
4120
  },
3428
- markAlerted: (d, day) => {
3429
- d.lastAlertDay = day;
4121
+ markTierAlerted: (d, tiers, day) => {
4122
+ d.tierAlertDays ??= {};
4123
+ for (const tier of tiers) d.tierAlertDays[String(tier)] = day;
3430
4124
  },
3431
4125
  markBalanceAlerted: (d, day) => {
3432
4126
  d.lastBalanceAlertDay = day;
4127
+ },
4128
+ markTierSwitchAlerted: (d, at) => {
4129
+ d.lastTierSwitchAt = at;
3433
4130
  }
3434
4131
  }
3435
4132
  });
@@ -3476,13 +4173,20 @@ window.__ModuleLoader__.load({
3476
4173
  okProviders: [],
3477
4174
  badProviders: []
3478
4175
  };
4176
+ const catalog = [];
4177
+ for (const group of result.value.groups) for (const model of group.models) catalog.push({
4178
+ id: model.id,
4179
+ ...typeof model.name === "string" && model.name !== "" ? { name: model.name } : {},
4180
+ provider: group.name
4181
+ });
3479
4182
  return {
3480
4183
  checked: true,
3481
4184
  available: result.value.groups.length > 0,
3482
4185
  models: result.value.groups.reduce((sum, group) => sum + group.models.length, 0),
3483
4186
  failures: result.value.failures.length,
3484
4187
  okProviders: result.value.groups.map((group) => group.name),
3485
- badProviders: result.value.failures.map((failure) => failure.name)
4188
+ badProviders: result.value.failures.map((failure) => failure.name),
4189
+ catalog
3486
4190
  };
3487
4191
  } catch {
3488
4192
  return {