From 8d15551e7f35a19424c7e8e3d5eb25299bfdb52c Mon Sep 17 00:00:00 2001 From: Catie Date: Thu, 10 Sep 2026 17:51:04 +0800 Subject: [PATCH] feat: usage dashboard on the account page Balances only ever went down on the account page with no explanation of where they went, even though RequestLog and the quota ledger already held everything needed. Adds GET /api/account/usage, scoped to the session user (an admin sees their own usage here, not the installation's). The view is a KPI row plus two single-series charts: daily spend as columns and a per-model breakdown. Costs are one series, so every mark wears the theme accent (--blue, verified at 4.02:1 light / 4.24:1 dark against the card surface) - never a value ramp, which would re-encode bar length as colour. The range control scopes both charts and the model ranking. Rendering the real component in a headless browser caught three defects that neither the type checker nor the tests would have: - a zero-cost day still drew a 2px stub, so a day with no spend showed a mark - the axis only had 1/2/5/10 steps, so a 2.47 peak was charted against 5.00 and used barely half the plot; adds 1.5/2.5/3/4/6/8 and maps the axis to 88% of the plot so the peak's label keeps headroom - the hover tooltip was anchored above the plot, where it covered the block heading; it now sits inside the card above the tick band Also makes clean:dist fail loudly instead of silently leaving old bundles behind. Removed 51MB of accumulated stale bundles this way once already, and the same silent partial delete recurred here while the API server held the files - the build now exits non-zero rather than shipping a dist/ that still contains superseded assets. Co-Authored-By: Claude Code --- cmd/capi/main.go | 193 ++++++++++ cmd/capi/main_test.go | 111 ++++++ ...{index-ssd4aOT1.css => index-699x73P2.css} | 2 +- dist/assets/index-BW0kmUgI.js | 43 --- dist/assets/index-Cv9ZCWeR.js | 43 +++ dist/index.html | 4 +- package.json | 2 +- src/App.tsx | 272 ++++++++++++++ src/styles.css | 342 ++++++++++++++++++ 9 files changed, 965 insertions(+), 47 deletions(-) rename dist/assets/{index-ssd4aOT1.css => index-699x73P2.css} (53%) delete mode 100644 dist/assets/index-BW0kmUgI.js create mode 100644 dist/assets/index-Cv9ZCWeR.js diff --git a/cmd/capi/main.go b/cmd/capi/main.go index b8cd67e..c1ae63c 100644 --- a/cmd/capi/main.go +++ b/cmd/capi/main.go @@ -930,6 +930,7 @@ func (s *Server) registerRoutes(router *gin.Engine) { account := api.Group("/account") account.Use(s.accountMiddleware()) account.GET("/me", s.accountMe) + account.GET("/usage", s.accountUsage) account.GET("/check-in", s.checkInStatus) account.POST("/check-in", s.claimCheckIn) account.POST("/api-keys", s.createOwnAPIKey) @@ -2137,6 +2138,198 @@ func (s *Server) accountMe(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"user": user, "account": account, "apiKeys": keys, "session": session}) } +// usageAccumulator sums the log fields the account page reports on. Successes +// is tracked only to derive a rate and never serialised. +type usageAccumulator struct { + Requests int + Cost float64 + InputTokens int + OutputTokens int + Successes int +} + +func (u *usageAccumulator) add(log RequestLog) { + u.Requests++ + u.Cost += log.Cost + u.InputTokens += log.InputTokens + u.OutputTokens += log.OutputTokens + if log.Status == "success" { + u.Successes++ + } +} + +func (u usageAccumulator) successRate() int { + if u.Requests == 0 { + return 0 + } + return int(math.Round(float64(u.Successes) / float64(u.Requests) * 100)) +} + +type usageStats struct { + Requests int `json:"requests"` + Cost float64 `json:"cost"` + InputTokens int `json:"inputTokens"` + OutputTokens int `json:"outputTokens"` + SuccessRate int `json:"successRate"` +} + +func (u usageAccumulator) stats() usageStats { + return usageStats{ + Requests: u.Requests, + Cost: round4(u.Cost), + InputTokens: u.InputTokens, + OutputTokens: u.OutputTokens, + SuccessRate: u.successRate(), + } +} + +// accountUsage aggregates the caller's own request logs so the account page can +// show where the balance went. It is scoped to the session user: an admin sees +// their own usage here, not the whole installation's (that is /api/overview). +func (s *Server) accountUsage(c *gin.Context) { + session, ok := s.sessionFromRequest(c) + if !ok { + c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"message": "Login required"}}) + return + } + // Mirrors /api/overview: the client sends its JS getTimezoneOffset so daily + // buckets follow the reader's calendar rather than UTC. + timezoneOffset, err := strconv.Atoi(c.DefaultQuery("timezoneOffset", "0")) + if err != nil || timezoneOffset < -840 || timezoneOffset > 840 { + timezoneOffset = 0 + } + location := time.FixedZone("account", -timezoneOffset*60) + rangeDays := queryInt(c, "days", 14, 1, 90) + + now := time.Now().In(location) + dayKeys := make([]string, 0, rangeDays) + daily := map[string]*usageAccumulator{} + for offset := rangeDays - 1; offset >= 0; offset-- { + key := now.AddDate(0, 0, -offset).Format("2006-01-02") + dayKeys = append(dayKeys, key) + // Pre-seed so a day with no traffic renders as zero instead of + // vanishing from the series. + daily[key] = &usageAccumulator{} + } + rangeStart := dayKeys[0] + todayKey := now.Format("2006-01-02") + yesterdayKey := now.AddDate(0, 0, -1).Format("2006-01-02") + monthPrefix := now.Format("2006-01") + + s.mu.Lock() + defer s.mu.Unlock() + + var today, yesterday, month, total usageAccumulator + models := map[string]*usageAccumulator{} + for _, log := range s.state.Logs { + if log.UserID == nil || *log.UserID != session.UserID { + continue + } + total.add(log) + + createdAt, err := time.Parse(time.RFC3339Nano, log.CreatedAt) + if err != nil { + // Still counted in the totals above; it just cannot be placed on a day. + continue + } + day := createdAt.In(location).Format("2006-01-02") + + if entry, ok := daily[day]; ok { + entry.add(log) + } + switch day { + case todayKey: + today.add(log) + case yesterdayKey: + yesterday.add(log) + } + if strings.HasPrefix(day, monthPrefix) { + month.add(log) + } + // The range filter scopes the model breakdown, matching the daily series. + if day >= rangeStart { + modelID := "未知模型" + if log.Model != nil && strings.TrimSpace(*log.Model) != "" { + modelID = strings.TrimSpace(*log.Model) + } + if models[modelID] == nil { + models[modelID] = &usageAccumulator{} + } + models[modelID].add(log) + } + } + + type usagePoint struct { + Day string `json:"day"` + Requests int `json:"requests"` + Cost float64 `json:"cost"` + InputTokens int `json:"inputTokens"` + OutputTokens int `json:"outputTokens"` + } + dailyPoints := make([]usagePoint, 0, len(dayKeys)) + for _, key := range dayKeys { + entry := daily[key] + dailyPoints = append(dailyPoints, usagePoint{ + Day: key, + Requests: entry.Requests, + Cost: round4(entry.Cost), + InputTokens: entry.InputTokens, + OutputTokens: entry.OutputTokens, + }) + } + + type modelPoint struct { + Model string `json:"model"` + Requests int `json:"requests"` + Cost float64 `json:"cost"` + InputTokens int `json:"inputTokens"` + OutputTokens int `json:"outputTokens"` + } + ranked := make([]modelPoint, 0, len(models)) + for modelID, entry := range models { + ranked = append(ranked, modelPoint{ + Model: modelID, + Requests: entry.Requests, + Cost: round4(entry.Cost), + InputTokens: entry.InputTokens, + OutputTokens: entry.OutputTokens, + }) + } + sort.Slice(ranked, func(i, j int) bool { + if ranked[i].Cost != ranked[j].Cost { + return ranked[i].Cost > ranked[j].Cost + } + if ranked[i].Requests != ranked[j].Requests { + return ranked[i].Requests > ranked[j].Requests + } + return ranked[i].Model < ranked[j].Model + }) + // Keep the list short enough to read at a glance; the tail folds into one + // row rather than being dropped. + const topModelCount = 6 + if len(ranked) > topModelCount+1 { + other := modelPoint{Model: "其他"} + for _, entry := range ranked[topModelCount:] { + other.Requests += entry.Requests + other.Cost += entry.Cost + other.InputTokens += entry.InputTokens + other.OutputTokens += entry.OutputTokens + } + other.Cost = round4(other.Cost) + ranked = append(ranked[:topModelCount], other) + } + + c.JSON(http.StatusOK, gin.H{"usage": gin.H{ + "rangeDays": rangeDays, + "today": today.stats(), + "yesterday": yesterday.stats(), + "month": month.stats(), + "total": total.stats(), + "daily": dailyPoints, + "models": ranked, + }}) +} + func (s *Server) updateAccountProfile(c *gin.Context) { session, ok := s.sessionFromRequest(c) if !ok { diff --git a/cmd/capi/main_test.go b/cmd/capi/main_test.go index 8c7f0da..d8d7d1d 100644 --- a/cmd/capi/main_test.go +++ b/cmd/capi/main_test.go @@ -5199,3 +5199,114 @@ func TestPublicCatalogFiltersBySessionGroup(t *testing.T) { t.Fatalf("catalog dropped a reachable model: %s", signedIn.Body.String()) } } + +func TestAccountUsageAggregatesOwnLogsOnly(t *testing.T) { + withEnv(t, map[string]string{"PERSISTENCE": "memory"}) + server, router := testServerRouter(t) + + const userID = "usr_usage" + const otherID = "usr_other" + + server.mu.Lock() + server.state.Users = []User{ + {ID: userID, Name: "Usage User", Role: "user", Status: "active"}, + {ID: otherID, Name: "Other User", Role: "user", Status: "active"}, + } + account := Account{ID: "acct_usage", UserID: userID, Username: "usage", Role: "user", Status: "active"} + server.state.Accounts = []Account{account} + + utc := time.Now().UTC() + stamp := func(offsetDays int) string { + return utc.AddDate(0, 0, offsetDays).Format(time.RFC3339Nano) + } + const modelA, modelB = "gpt-5.5", "deepseek-v4" + server.state.Logs = []RequestLog{ + {ID: "log_today_1", UserID: stringPtr(userID), Model: stringPtr(modelA), Status: "success", Cost: 1.5, InputTokens: 100, OutputTokens: 50, CreatedAt: stamp(0)}, + {ID: "log_today_2", UserID: stringPtr(userID), Model: stringPtr(modelA), Status: "failed", Cost: 0.5, InputTokens: 10, OutputTokens: 0, CreatedAt: stamp(0)}, + {ID: "log_yesterday", UserID: stringPtr(userID), Model: stringPtr(modelB), Status: "success", Cost: 2.0, InputTokens: 200, OutputTokens: 20, CreatedAt: stamp(-1)}, + {ID: "log_in_range", UserID: stringPtr(userID), Model: stringPtr(modelB), Status: "success", Cost: 4.0, InputTokens: 400, OutputTokens: 40, CreatedAt: stamp(-3)}, + {ID: "log_out_of_range", UserID: stringPtr(userID), Model: stringPtr(modelB), Status: "success", Cost: 8.0, InputTokens: 800, OutputTokens: 80, CreatedAt: stamp(-20)}, + {ID: "log_other_user", UserID: stringPtr(otherID), Model: stringPtr(modelA), Status: "success", Cost: 99.0, InputTokens: 1, OutputTokens: 1, CreatedAt: stamp(0)}, + } + server.mu.Unlock() + + // The endpoint is session-scoped. + anonymous := perform(router, http.MethodGet, "/api/account/usage", "", nil) + if anonymous.Code != http.StatusUnauthorized { + t.Fatalf("anonymous usage status = %d body = %s", anonymous.Code, anonymous.Body.String()) + } + + session := server.createAccountSession(account, "Usage User", "password") + headers := map[string]string{"Cookie": "capi_session=" + session.ID} + response := perform(router, http.MethodGet, "/api/account/usage?days=7&timezoneOffset=0", "", headers) + if response.Code != http.StatusOK { + t.Fatalf("usage status = %d body = %s", response.Code, response.Body.String()) + } + + var payload struct { + Usage struct { + RangeDays int `json:"rangeDays"` + Today usageStats `json:"today"` + Yesterday usageStats `json:"yesterday"` + Total usageStats `json:"total"` + Daily []struct { + Day string `json:"day"` + Requests int `json:"requests"` + Cost float64 `json:"cost"` + } `json:"daily"` + Models []struct { + Model string `json:"model"` + Cost float64 `json:"cost"` + } `json:"models"` + } `json:"usage"` + } + if err := json.Unmarshal(response.Body.Bytes(), &payload); err != nil { + t.Fatalf("decode usage: %v", err) + } + + // Only this user's logs count: 1.5 + 0.5 + 2.0 + 4.0 + 8.0. Never the other user's 99. + if payload.Usage.Total.Requests != 5 || payload.Usage.Total.Cost != 16 { + t.Fatalf("total = %#v, want 5 requests and cost 16", payload.Usage.Total) + } + if payload.Usage.Today.Requests != 2 || payload.Usage.Today.Cost != 2 { + t.Fatalf("today = %#v, want 2 requests and cost 2", payload.Usage.Today) + } + if payload.Usage.Today.SuccessRate != 50 { + t.Fatalf("today success rate = %d, want 50", payload.Usage.Today.SuccessRate) + } + if payload.Usage.Yesterday.Cost != 2 { + t.Fatalf("yesterday = %#v, want cost 2", payload.Usage.Yesterday) + } + + if payload.Usage.RangeDays != 7 || len(payload.Usage.Daily) != 7 { + t.Fatalf("daily series has %d points for %d days", len(payload.Usage.Daily), payload.Usage.RangeDays) + } + zeroDays := 0 + for _, point := range payload.Usage.Daily { + if point.Day == "" { + t.Fatal("a daily point is missing its day key") + } + if point.Requests == 0 { + zeroDays++ + } + } + // Empty days must render as zero rather than vanishing from the series. + if zeroDays < 4 { + t.Fatalf("expected empty days to be present as zero, got %d: %#v", zeroDays, payload.Usage.Daily) + } + + // The model breakdown is scoped to the same range, so the 20-day-old log + // must not appear here even though it counts toward the totals. + var modelCost float64 + seen := map[string]bool{} + for _, model := range payload.Usage.Models { + modelCost += model.Cost + seen[model.Model] = true + } + if !seen[modelA] || !seen[modelB] { + t.Fatalf("model breakdown missing a model: %#v", payload.Usage.Models) + } + if modelCost != 8 { + t.Fatalf("model breakdown cost = %v, want 8 (range-scoped)", modelCost) + } +} diff --git a/dist/assets/index-ssd4aOT1.css b/dist/assets/index-699x73P2.css similarity index 53% rename from dist/assets/index-ssd4aOT1.css rename to dist/assets/index-699x73P2.css index 35182e8..10a9e12 100644 --- a/dist/assets/index-ssd4aOT1.css +++ b/dist/assets/index-699x73P2.css @@ -1 +1 @@ -:root{color:#1d1d1f;background:#f2f2f7;font-family:-apple-system,BlinkMacSystemFont,SF Pro Display,Segoe UI,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh}button,input,select,textarea{font:inherit}button{border:0}.app-shell select:not([multiple]){appearance:none;padding-right:38px!important;background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%)!important;background-position:calc(100% - 17px) 50%,calc(100% - 12px) 50%!important;background-size:5px 5px,5px 5px!important;background-repeat:no-repeat!important;cursor:pointer}.app-shell[data-theme=dark] select{color-scheme:dark}.app-shell[data-theme=dark] select option{color:#f5f5f7;background:#2c2c2e}.app-shell input[type=datetime-local],.app-shell input[type=date],.app-shell input[type=time]{color-scheme:dark}.app-shell input[type=datetime-local]::-webkit-calendar-picker-indicator,.app-shell input[type=date]::-webkit-calendar-picker-indicator,.app-shell input[type=time]::-webkit-calendar-picker-indicator{opacity:.72;cursor:pointer}.app-shell input[type=number]{appearance:textfield}.app-shell input[type=number]::-webkit-inner-spin-button,.app-shell input[type=number]::-webkit-outer-spin-button{margin:0;appearance:none}.app-shell{--bg: #f2f2f7;--surface: rgba(255, 255, 255, .78);--surface-solid: #ffffff;--group: #f4f5f7;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .12);--hairline-strong: rgba(60, 60, 67, .2);--blue: #007aff;--green: #34c759;--red: #ff3b30;--orange: #ff9500;--teal: #30b0c7;--shadow: 0 2px 8px rgba(0, 0, 0, .04), 0 12px 32px rgba(0, 0, 0, .06);--shadow-lg: 0 4px 12px rgba(0, 0, 0, .05), 0 20px 48px rgba(0, 0, 0, .1);--row-height: 58px;display:grid;grid-template-columns:264px 1fr;min-height:100vh;color:var(--text);background:var(--bg)}.app-shell[data-theme=dark]{--bg: #0a0a0c;--surface: rgba(22, 22, 26, .8);--surface-solid: #161618;--group: rgba(255, 255, 255, .04);--text: #f5f5f7;--muted: #8e8e93;--hairline: rgba(255, 255, 255, .06);--hairline-strong: rgba(255, 255, 255, .1);--shadow: 0 2px 8px rgba(0, 0, 0, .2), 0 12px 32px rgba(0, 0, 0, .25);--shadow-lg: 0 4px 12px rgba(0, 0, 0, .3), 0 24px 56px rgba(0, 0, 0, .4);background:var(--bg);color-scheme:dark}.app-shell[data-density=compact]{--row-height: 48px}.sidebar{position:sticky;top:0;height:100vh;padding:16px 14px;background:var(--surface-solid);border-right:1px solid var(--hairline);box-shadow:2px 0 12px #00000008}.app-shell[data-theme=dark] .sidebar{background:#111113;border-right-color:#ffffff0d;box-shadow:2px 0 16px #00000040}.ios-window-dots{display:flex;gap:7px;padding:4px 10px 18px;cursor:default}.ios-window-dots span{width:12px;height:12px;border-radius:50%;opacity:.85;transition:opacity .16s ease,transform .16s ease}.ios-window-dots:hover span{opacity:1}.ios-window-dots span:hover{transform:scale(1.18)}.ios-window-dots span:nth-child(1){background:#ff5f57}.ios-window-dots span:nth-child(2){background:#ffbd2e}.ios-window-dots span:nth-child(3){background:#28c840}.brand{display:flex;align-items:center;gap:12px;padding:0 10px 24px}.brand-mark{display:grid;place-items:center;width:42px;height:42px;color:#fff;background:#1d1d1f;border-radius:13px;font-weight:800;box-shadow:inset 0 1px #ffffff2e}.app-shell[data-theme=dark] .brand-mark{color:#fff;background:#76768033;border:0}.brand strong,.brand span{display:block}.brand span{margin-top:2px;color:var(--muted);font-size:13px}nav{display:grid;gap:6px}.nav-item{position:relative;display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:0 12px;color:var(--muted);background:transparent;border-radius:12px;cursor:pointer;text-align:left}.nav-item:hover{color:var(--text);background:var(--group)}.nav-item.active{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000000f,inset 0 0 0 1px var(--hairline)}.app-shell[data-theme=dark] .nav-item:hover{background:#ffffff0d}.app-shell[data-theme=dark] .nav-item.active{color:#fff;background:#ffffff14;box-shadow:0 1px 6px #0003,inset 0 0 0 1px #ffffff0f}.sidebar-footer{position:absolute;left:14px;right:14px;bottom:16px;display:flex;justify-content:space-between;align-items:center;min-height:44px;padding:0 12px;color:var(--muted);background:var(--group);border-radius:14px;font-size:13px}.sidebar-footer strong{display:inline-flex;align-items:center;gap:7px;color:var(--green)}.sidebar-footer .pulse-dot{width:7px;height:7px}.icon{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}.content{width:calc(100vw - 264px);padding:28px 30px 44px;background:var(--bg)}.topbar{position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;gap:18px;margin:-28px -30px 24px;padding:24px 30px 18px;background:color-mix(in srgb,var(--bg) 82%,transparent);border-bottom:1px solid var(--hairline);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.app-shell[data-theme=dark] .topbar{background:#000000d1;border-bottom-color:#ffffff14}.topbar-actions,.panel-toolbar,.setting-value{display:flex;align-items:center;gap:10px}.eyebrow{margin:0 0 5px;color:var(--muted);font-size:13px}h1,h2,h3,p{margin:0}h1{font-size:34px;line-height:1.08;letter-spacing:0}h2{font-size:18px;letter-spacing:0}h3{margin:6px 0 10px;font-size:14px;color:var(--muted)}.primary-button,.secondary-button,.danger-button,.icon-button,.theme-toggle{display:inline-flex;align-items:center;justify-content:center;min-height:38px;border-radius:999px;cursor:pointer;text-decoration:none}.primary-button{padding:0 18px;color:#fff;background:var(--blue);font-weight:700;box-shadow:0 2px 6px #007aff40;box-shadow:0 5px 14px color-mix(in srgb,var(--blue) 24%,transparent)}.secondary-button{padding:0 16px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline-strong);font-weight:650;box-shadow:0 1px 3px #0000000a}.danger-button{padding:0 16px;color:#d70015;background:color-mix(in srgb,var(--red) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--red) 28%,var(--hairline));font-weight:700}.compact-button{min-height:32px;padding:0 12px;font-size:13px}.icon-button{width:38px;color:var(--text);background:var(--group);border:1px solid var(--hairline)}.theme-toggle{gap:8px;padding:0 14px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline)}.app-shell[data-theme=dark] .secondary-button,.app-shell[data-theme=dark] .icon-button,.app-shell[data-theme=dark] .theme-toggle,.app-shell[data-theme=dark] .compact-button{background:#ffffff14;border-color:#ffffff1a;box-shadow:0 1px 4px #00000026}.primary-button:disabled,.secondary-button:disabled,.danger-button:disabled,.icon-button:disabled,.theme-toggle:disabled{cursor:not-allowed;opacity:.55}.muted-inline{color:var(--muted);font-size:13px}.status-button{display:inline-flex;justify-content:flex-start;padding:0;background:transparent;border:0;cursor:pointer}.segmented-control{display:inline-grid;grid-auto-flow:column;gap:2px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.app-shell[data-theme=dark] .segmented-control,.app-shell[data-theme=dark] .user-filter-row,.app-shell[data-theme=dark] .model-filter-actions,.app-shell[data-theme=dark] .log-status-filter,.app-shell[data-theme=dark] .settings-tabs,.app-shell[data-theme=dark] .registration-mode-control{background:#7676801f;border-color:transparent}.segmented-control button{min-width:54px;height:30px;padding:0 12px;color:var(--muted);background:transparent;border-radius:999px;cursor:pointer}.segmented-control button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.app-shell[data-theme=dark] .segmented-control button.selected,.app-shell[data-theme=dark] .user-filter-row button.selected,.app-shell[data-theme=dark] .model-filter-actions button.selected,.app-shell[data-theme=dark] .log-status-filter button.selected,.app-shell[data-theme=dark] .settings-tabs button.selected,.app-shell[data-theme=dark] .registration-mode-control button.selected{background:#ffffff1f;box-shadow:none}.page-stack{display:grid;gap:18px}.hero-strip{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:128px;padding:24px;background:var(--surface);border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.hero-strip span,.metric span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.hero-strip strong{display:block;font-size:22px;letter-spacing:0}.hero-strip p{max-width:620px;margin-top:8px;color:var(--muted);line-height:1.55}.live-island{display:inline-flex;align-items:center;gap:8px;min-width:92px;height:34px;padding:0 14px;color:#fff;background:#1d1d1f;border:1px solid var(--hairline);border-radius:999px;font-weight:700;box-shadow:inset 0 1px #ffffff29}.app-shell[data-theme=dark] .live-island{color:var(--muted);background:var(--group)}.hero-strip .live-island{margin-right:4px}.pulse-dot{width:9px;height:9px;background:var(--green);border-radius:50%;box-shadow:0 0 0 5px color-mix(in srgb,var(--green) 20%,transparent);animation:status-pulse 1.8s ease-out infinite}.quick-actions{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.quick-action{display:flex;align-items:center;justify-content:center;gap:9px;min-height:48px;padding:0 14px;color:var(--text);background:var(--surface);border:1px solid var(--hairline);border-radius:999px;cursor:pointer;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.quick-action:nth-child(1){color:var(--blue)}.quick-action:nth-child(2){color:var(--teal)}.quick-action:nth-child(3){color:var(--green)}.quick-action:nth-child(4){color:var(--orange)}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}.metric,.panel{background:var(--surface-solid);border:1px solid var(--hairline);box-shadow:var(--shadow)}.app-shell[data-theme=dark] .quick-action,.app-shell[data-theme=dark] .metric,.app-shell[data-theme=dark] .panel,.app-shell[data-theme=dark] .hero-strip,.app-shell[data-theme=dark] .flow-panel,.app-shell[data-theme=dark] .model-hero{background:var(--surface-solid);border-color:var(--hairline);box-shadow:var(--shadow)}.metric{min-height:118px;padding:18px;border-radius:22px}.metric strong{display:block;overflow:hidden;font-size:31px;letter-spacing:0;text-overflow:ellipsis;white-space:nowrap}.split-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}.flow-panel{display:grid;grid-template-columns:minmax(190px,.7fr) minmax(0,1.3fr);gap:18px;align-items:center;padding:18px;background:var(--surface);border:1px solid var(--hairline);border-radius:24px;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.flow-copy span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.flow-copy strong{display:block;font-size:20px;line-height:1.3}.flow-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.flow-step{position:relative;min-height:104px;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.flow-step:not(:last-child):after{content:"";position:absolute;top:50%;right:-10px;width:10px;height:1px;background:var(--hairline-strong)}.flow-index{display:grid;place-items:center;width:28px;height:28px;margin-bottom:12px;color:#fff;background:var(--blue);border-radius:50%;font-size:13px;font-weight:800}.flow-step strong,.flow-step span{display:block}.flow-step span{margin-top:4px;color:var(--muted);font-size:13px}.panel{padding:20px;border-radius:20px;min-width:0}.app-shell[data-theme=dark] .panel{border-radius:18px}.panel-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding:0 2px}.panel-title h2{font-size:17px;font-weight:700}.app-shell[data-theme=dark] .panel-title{padding-bottom:14px;border-bottom:1px solid rgba(255,255,255,.06)}.list-row,.setting{display:flex;align-items:center;justify-content:space-between;gap:14px;min-height:var(--row-height);padding:10px 2px;border-top:1px solid var(--hairline)}.list-row:first-of-type,.setting:first-child{border-top:0}.list-row>div,.setting>div{min-width:0}.row-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:8px;flex-shrink:0}.list-row strong,.list-row span,.setting span,.setting strong,.table-row span,.table-row strong,.table-row small{min-width:0}.list-row strong,.list-row span{display:block}.list-row span,.table-row small{margin-top:3px;color:var(--muted);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overview-channel-row>div{flex:1 1 auto;overflow:hidden}.overview-channel-row>.badge{flex:0 0 auto;min-width:54px;overflow:visible}.badge{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:54px;height:27px;padding:0 11px;color:var(--muted);background:var(--group);border-radius:999px;font-size:12px;font-weight:650;letter-spacing:.01em;white-space:nowrap}.app-shell[data-theme=dark] .badge{background:#76768024;border:0}.badge.tone-active:before,.badge.tone-healthy:before,.badge.tone-available:before,.badge.tone-success:before,.badge.tone-disabled:before,.badge.tone-failed:before,.badge.tone-limited:before,.badge.tone-overdue:before,.badge.tone-standby:before{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;background:currentColor;flex:0 0 auto}.tone-active,.tone-healthy,.tone-available,.tone-success{color:#118446;background:color-mix(in srgb,var(--green) 16%,transparent)}.tone-disabled,.tone-failed{color:#d70015;background:color-mix(in srgb,var(--red) 14%,transparent)}.tone-limited,.tone-overdue,.tone-standby{color:#a05a00;background:color-mix(in srgb,var(--orange) 15%,transparent)}.users-layout{display:grid;grid-template-columns:minmax(780px,1.55fr) minmax(380px,.7fr);gap:18px;align-items:start}.users-layout .panel:first-child{padding:14px}.users-layout .panel:first-child .table{background:transparent;border:0;border-radius:0;gap:8px}.users-layout .panel:first-child .table-head{min-height:34px;padding:0 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-head{background:#7676801a;border-color:transparent}.users-layout .panel:first-child .table-row{min-height:56px;padding:0 14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:16px}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row{background:#1c1c1ec7;border-color:#ffffff0d}.users-layout .panel:first-child .table-row:hover{background:var(--group)}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row:hover{background:#2c2c2ee0}.users-layout .panel:first-child .table-row.selected{border-color:color-mix(in srgb,var(--blue) 45%,var(--hairline));box-shadow:inset 3px 0 0 var(--blue)}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row.selected{background:#76768029;border-color:transparent;box-shadow:none}.user-summary-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:12px}.user-summary-strip span{min-height:50px;padding:10px 12px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:14px;font-size:13px}.user-summary-strip strong{display:block;color:var(--text);font-size:20px}.user-filter-row{display:flex;gap:4px;width:fit-content;margin-bottom:12px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.user-filter-row button{min-height:30px;padding:0 13px;color:var(--muted);background:transparent;border-radius:999px;cursor:pointer;font-weight:700}.user-filter-row button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.mobile-bulk-select{display:none;margin-bottom:12px}.bulk-action-bar{display:grid;grid-template-columns:auto 100px minmax(160px,1fr) auto auto auto minmax(130px,auto) auto;align-items:center;gap:8px;margin-bottom:12px;padding:10px;background:color-mix(in srgb,var(--blue) 8%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 25%,var(--hairline));border-radius:12px}.bulk-group-select{min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.bulk-group-select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.app-shell[data-theme=dark] .bulk-group-select{background:#7676801f;border-color:transparent}.auth-default-balance select{min-width:0;width:180px;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.auth-default-balance select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.app-shell[data-theme=dark] .auth-default-balance select{background:#7676801f;border-color:transparent}.bulk-action-bar input,.auth-default-balance input{min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.bulk-action-bar input:focus,.auth-default-balance input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.pagination-bar{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:12px;color:var(--muted);font-weight:700}.models-page{display:grid;gap:18px;width:100%}.model-hero{padding:18px 22px;background:var(--surface);border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.model-hero span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.model-hero strong{display:block;font-size:24px;line-height:1.3}.model-hero p{margin-top:8px;color:var(--muted)}.model-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.model-list{display:grid;gap:10px}.model-list-toolbar{justify-content:space-between;align-items:center}.model-list-toolbar input{flex:1 1 460px;width:auto;max-width:720px;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-list-toolbar input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-filter-actions{display:inline-flex;gap:6px;padding:4px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.model-filter-actions button{height:32px;padding:0 12px;color:var(--muted);background:transparent;border:0;border-radius:999px}.model-filter-actions button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.model-provider-filter{display:flex;gap:8px;margin:14px 0;padding-bottom:2px;overflow-x:auto;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 45%,transparent) transparent}.model-provider-filter button{display:grid;grid-template-columns:34px minmax(0,1fr) auto;align-items:center;gap:10px;flex:0 0 240px;min-height:58px;padding:10px;color:var(--text);text-align:left;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.model-provider-filter button.selected{background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 46%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 28%,transparent)}.app-shell[data-theme=dark] .model-provider-filter button.selected,.app-shell[data-theme=dark] .provider-chip-grid button.selected,.app-shell[data-theme=dark] .stream-mode-grid button.selected{background:#ffffff1f;border-color:transparent;box-shadow:none}.model-provider-filter strong,.model-provider-filter small{display:block;min-width:0}.model-provider-filter strong{overflow-wrap:anywhere}.model-provider-filter small{color:var(--muted);font-weight:800}.provider-icon-all{display:grid;place-items:center;flex:0 0 38px;width:38px;height:38px;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.02em;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 26%,var(--hairline));border-radius:10px}.model-list-summary{display:inline-flex;align-items:baseline;gap:6px;margin-bottom:10px;color:var(--muted);font-size:13px}.model-list-summary strong{color:var(--text);font-size:20px}.model-provider-groups{display:grid;gap:14px}.model-provider-group{overflow:hidden;border:1px solid var(--hairline);border-radius:14px}.model-provider-group>header{display:flex;align-items:center;gap:10px;min-height:58px;padding:9px 12px;background:var(--group);border-bottom:1px solid var(--hairline)}.model-provider-group>header div{display:grid;gap:2px}.model-provider-group>header span{color:var(--muted);font-size:12px}.provider-icon,.provider-icon svg{display:block;width:38px;height:38px;flex:0 0 38px}.provider-icon svg rect{fill:var(--surface-solid);stroke:var(--hairline)}.provider-icon svg text{fill:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:17px;font-weight:800}.provider-icon svg path{fill:currentColor}.provider-icon-google svg text{fill:#4285f4}.provider-icon-openai{color:var(--text)}.provider-icon-deepseek,.provider-icon-deepseek svg,.provider-icon-deepseek svg path{color:#4d6bfe;fill:#4d6bfe}.provider-icon-openrouter svg text{fill:#ef4444}.provider-icon-groq svg text{fill:#f55036}.provider-icon-moonshot svg text{fill:#16a34a}.model-compact-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr))}.model-compact-row{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;gap:9px;min-width:0;min-height:78px;padding:12px;border-bottom:1px solid var(--hairline)}.model-compact-row:last-child{border-bottom:0}.model-compact-main{min-width:0}.model-compact-main strong,.model-compact-main small{display:block;min-width:0;overflow-wrap:anywhere}.model-compact-main small{margin-top:3px;color:var(--muted);font-size:12px;line-height:1.35}.model-compact-main span{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}.model-compact-main em{max-width:120px;overflow:hidden;padding:3px 7px;color:var(--muted);font-size:11px;font-style:normal;text-overflow:ellipsis;white-space:nowrap;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:999px}.model-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:0;flex-wrap:wrap}.model-row-actions .compact-button{min-height:32px;padding-inline:11px}.model-row-actions{gap:6px}.model-row-actions .icon-button{width:32px;min-height:32px;color:var(--muted);background:transparent;border-color:transparent}.model-recommended-mark{padding:4px 8px;color:var(--orange);background:color-mix(in srgb,var(--orange) 10%,transparent);border-radius:999px;font-size:11px;font-weight:700}.model-row-menu{position:relative}.model-row-menu>summary{width:32px;min-height:32px;color:var(--muted);line-height:27px;text-align:center;letter-spacing:1px;list-style:none;background:transparent;border:1px solid transparent;border-radius:10px;cursor:pointer}.model-row-menu>summary::-webkit-details-marker{display:none}.model-row-menu>summary:hover{color:var(--text);background:var(--group)}.model-row-menu>div{position:absolute;right:0;bottom:calc(100% + 6px);z-index:8;display:grid;width:max-content;gap:2px;padding:6px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:var(--shadow)}.model-row-menu button{min-height:34px;padding:0 10px;color:var(--text);text-align:left;background:transparent;border:0;border-radius:8px;cursor:pointer;font-size:13px}.model-row-menu button:hover{background:var(--group)}.model-row-menu button.is-danger{color:var(--red)}.model-row-menu button.is-danger:hover{background:color-mix(in srgb,var(--red) 10%,var(--surface-solid))}.settings-tabs{display:flex;flex-wrap:wrap;width:fit-content;max-width:100%;padding:4px;gap:2px;overflow-x:auto;background:var(--group);border-radius:14px}.settings-tabs button{display:inline-flex;flex:0 0 auto;align-items:center;min-height:34px;padding:0 12px;border-radius:10px}.settings-tabs button small{display:none}.settings-tab-note{display:flex;align-items:baseline;gap:8px;min-height:18px;color:var(--muted);font-size:13px}.settings-tab-note strong{color:var(--text);font-size:14px}.logs-table{grid-template-columns:minmax(280px,1.55fr) minmax(220px,1fr) minmax(180px,.9fr) 82px}.logs-layout{display:block}.log-entry .table-row{min-height:58px}.log-entry .table-row>span:nth-child(2),.log-entry .table-row>span:nth-child(3){overflow:hidden;color:var(--muted);text-overflow:ellipsis;white-space:nowrap}.log-inspector{position:relative;top:auto;grid-template-columns:minmax(220px,.8fr) minmax(0,1.6fr) auto;align-items:start;margin-top:14px;padding:16px;border-radius:16px}.log-inspector header{padding:6px 14px 6px 0;border-right:1px solid var(--hairline);border-bottom:0}.log-detail{grid-template-columns:repeat(4,minmax(0,1fr))}.log-detail>div{padding:9px 10px;border-radius:10px}.log-actions{align-self:center;justify-content:flex-end}@media(max-width:980px){.log-inspector{grid-template-columns:1fr}.log-inspector header{padding:0 0 12px;border-right:0;border-bottom:1px solid var(--hairline)}.log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}}.logs-layout.has-detail{display:grid;grid-template-columns:minmax(0,1.65fr) minmax(360px,.75fr);gap:14px;align-items:start}.logs-layout.has-detail .log-inspector{position:sticky;top:92px;display:grid;grid-template-columns:1fr;margin-top:0;padding:16px}.logs-layout.has-detail .log-inspector header{padding:0 0 12px;border-right:0;border-bottom:1px solid var(--hairline)}.logs-layout.has-detail .log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}@media(max-width:980px){.logs-layout.has-detail{grid-template-columns:1fr}.logs-layout.has-detail .log-inspector{position:static}}@media(max-width:720px){.settings-tabs{flex-wrap:nowrap;width:100%}.settings-tab-note{align-items:flex-start;flex-direction:column;gap:2px}}.pager{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:12px}.pager span{color:var(--muted);font-size:13px;font-weight:700}.model-create-form{display:grid;grid-template-columns:repeat(3,minmax(0,1fr)) auto;gap:10px;align-items:center}.model-create-form input,.model-create-form select{width:100%;min-width:0;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-create-form select{appearance:none}.model-create-form input:focus,.model-create-form select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-create-wide{grid-column:span 2}.model-create-message{grid-column:1 / -1;min-height:18px;color:#ff3b30;font-size:13px}.drawing-channel-models{display:flex;flex-wrap:wrap;gap:8px}.drawing-channel-models span{max-width:100%;padding:7px 10px;color:var(--muted);font-size:12px;font-weight:750;background:var(--group);border:1px solid var(--hairline);border-radius:999px;overflow-wrap:anywhere}.model-card{display:grid;gap:12px;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.model-card.featured{min-height:210px}.model-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.model-card-head strong,.model-card-head span{display:block}.model-card-head span{margin-top:4px;color:var(--muted);font-size:13px}.model-card p{color:var(--muted);line-height:1.55}.model-card-actions{display:flex;justify-content:flex-end;gap:8px}.alias-row,.model-meta{display:flex;flex-wrap:wrap;gap:8px}.alias-row span,.model-meta span{display:inline-flex;align-items:center;min-height:28px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px;font-weight:700}.model-meta span{color:var(--muted);font-weight:650}.model-id{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;padding:0 0 0 12px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.model-id code{overflow:hidden;color:var(--text);text-overflow:ellipsis;white-space:nowrap}.panel-toolbar{margin-bottom:12px}.search-box{display:flex;align-items:center;gap:8px;width:100%;height:42px;padding:0 13px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px}.app-shell[data-theme=dark] .search-box,.app-shell[data-theme=dark] .model-list-toolbar input,.app-shell[data-theme=dark] .model-create-form input,.app-shell[data-theme=dark] .model-create-form select,.app-shell[data-theme=dark] .channel-form-grid input,.app-shell[data-theme=dark] .channel-form-grid textarea,.app-shell[data-theme=dark] .channel-editor input,.app-shell[data-theme=dark] .provider-picker-trigger,.app-shell[data-theme=dark] .key-editor-grid input,.app-shell[data-theme=dark] .settings-form-grid input,.app-shell[data-theme=dark] .settings-form-grid textarea,.app-shell[data-theme=dark] .maintenance-control input,.app-shell[data-theme=dark] .bulk-action-bar input,.app-shell[data-theme=dark] .auth-default-balance input{background:#7676801f;border-color:transparent}.search-box input{width:100%;border:0;outline:0;background:transparent;color:var(--text)}.search-box input::placeholder{color:var(--muted)}.table{display:grid;overflow:hidden;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .table{background:#1c1c1eb8;border-color:#ffffff0d}.table:has(.channel-editor){overflow:visible}.table-head,.table-row{display:grid;gap:12px;align-items:center;min-height:var(--row-height);padding:0 14px;text-align:left}.table-head{color:var(--muted);font-size:12px;font-weight:700;background:var(--group);border-bottom:1px solid var(--hairline)}.app-shell[data-theme=dark] .table-head{background:#7676801a;border-bottom-color:#ffffff0d}.table-row{width:100%;color:var(--text);background:transparent;border-bottom:1px solid var(--hairline)}.app-shell[data-theme=dark] .table-row{border-bottom-color:#ffffff0d}.table-row small{display:block}.table-row:last-child{border-bottom:0}button.table-row{cursor:pointer}button.table-row:hover{background:var(--group)}.app-shell[data-theme=dark] button.table-row:hover,.app-shell[data-theme=dark] .log-entry .table-row:hover,.app-shell[data-theme=dark] .log-entry .table-row.selected{background:#7676801f}.users-table{grid-template-columns:22px minmax(220px,1fr) 86px minmax(120px,.45fr) 68px}.users-table>span:nth-child(4),.users-table>span:nth-child(5){justify-self:end;text-align:right}.users-table.table-row>span:nth-child(4){max-width:100%;overflow:hidden;font-variant-numeric:tabular-nums;text-overflow:ellipsis}.users-table>input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--blue);cursor:pointer}.channels-table{grid-template-columns:minmax(220px,1.4fr) 90px 64px minmax(150px,.8fr) minmax(240px,1fr)}.channels-stack{display:grid;gap:14px}.channel-create-form{margin-bottom:14px}.channel-create-form .channel-form-grid{grid-template-columns:1fr 1fr;gap:14px}.channel-create-form .channel-form-wide{grid-column:1 / -1}.channel-card{display:grid;gap:14px;padding:16px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .channel-card,.app-shell[data-theme=dark] .model-card,.app-shell[data-theme=dark] .log-inspector,.app-shell[data-theme=dark] .settings-group,.app-shell[data-theme=dark] .provider-picker-menu{background:#1c1c1eb8;border-color:#ffffff0f}.channel-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.channel-card-head>div:first-child{min-width:0}.channel-card-head-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;flex-shrink:0}.channel-card-head strong,.channel-card-head span{display:block}.channel-card-head span{margin-top:4px;color:var(--muted);font-size:13px}.channel-card-head small{display:block;max-width:100%;margin-top:6px;color:var(--muted);font-size:12px;line-height:1.45;overflow-wrap:anywhere}.provider-chip-grid{display:flex;flex-wrap:wrap;gap:8px}.provider-chip-grid button{min-height:34px;padding:0 12px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;cursor:pointer;font-weight:750}.provider-chip-grid button.selected{color:var(--text);background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 42%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 30%,transparent)}.stream-mode-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}.stream-mode-grid button{display:grid;gap:3px;min-height:58px;padding:9px 11px;color:var(--muted);text-align:left;background:var(--group);border:1px solid var(--hairline);border-radius:14px;cursor:pointer}.stream-mode-grid button strong{color:var(--text);font-size:14px}.stream-mode-grid button span{overflow:hidden;font-size:12px;text-overflow:ellipsis;white-space:nowrap}.stream-mode-grid button.selected{background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 42%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 30%,transparent)}.app-shell[data-theme=dark] .provider-chip-grid button.selected,.app-shell[data-theme=dark] .stream-mode-grid button.selected{background:#ffffff1f;border-color:transparent;box-shadow:none}.channel-form-grid{display:grid;grid-template-columns:1.4fr .5fr .7fr;gap:12px}.channel-form-grid label{display:grid;min-width:0;gap:7px;color:var(--muted);font-size:13px;font-weight:700}.channel-model-field{display:grid;min-width:0;gap:7px}.field-label-row{display:flex;align-items:center;justify-content:space-between;gap:10px;color:var(--muted);font-size:13px;font-weight:700}.field-label-row small{font-size:12px;font-weight:700}.field-label-row .model-pull-button{min-height:28px;padding:0 12px;color:var(--blue);background:color-mix(in srgb,var(--blue) 10%,transparent);border:1px solid color-mix(in srgb,var(--blue) 26%,transparent);border-radius:999px;font-size:12.5px;font-weight:650;white-space:nowrap;cursor:pointer;transition:background .12s ease,transform .1s ease}.field-label-row .model-pull-button:hover{background:color-mix(in srgb,var(--blue) 16%,transparent)}.field-label-row .model-pull-button:active{transform:scale(.97)}.channel-form-wide{grid-column:span 2}.channel-billing-note{grid-column:1 / -1;color:var(--muted);font-size:12px}.channel-form-grid input,.channel-form-grid textarea{width:100%;min-width:0;min-height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.channel-form-grid textarea{min-height:72px;padding:10px 12px;resize:vertical;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.channel-form-grid input:focus,.channel-form-grid textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.channel-model-actions{display:flex;flex-wrap:wrap;gap:8px}.channel-card-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:10px}.channel-card-actions .model-create-message{flex:1;min-width:180px}.channel-editor{align-items:start;padding-block:12px}.channel-editor input,.provider-picker-trigger{width:100%;min-width:0;height:36px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.provider-picker{position:relative;z-index:2}.provider-picker-trigger{display:grid;grid-template-columns:minmax(0,1fr) 12px;align-items:center;gap:8px;text-align:left;cursor:pointer}.provider-picker-trigger span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.provider-picker-trigger i{width:7px;height:7px;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:translateY(-2px) rotate(45deg)}.provider-picker-menu{position:absolute;top:calc(100% + 6px);left:0;display:grid;width:min(240px,70vw);max-height:280px;padding:6px;overflow:auto;background:color-mix(in srgb,var(--surface-solid) 94%,transparent);border:1px solid var(--hairline);border-radius:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.provider-picker-menu button{min-height:34px;padding:0 10px;color:var(--text);background:transparent;border-radius:9px;text-align:left;cursor:pointer}.provider-picker-menu button:hover,.provider-picker-menu button.selected{background:var(--group)}.provider-picker-menu button.selected{color:var(--blue);font-weight:800}.channel-editor strong{display:block;margin-bottom:8px}.channel-actions{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;align-items:center}.logs-table{grid-template-columns:minmax(210px,1.35fr) minmax(170px,1fr) minmax(150px,.9fr) 78px 78px 86px 80px}.logs-layout{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(420px,.75fr);gap:14px;align-items:start}.logs-toolbar{display:grid;grid-template-columns:minmax(260px,1fr) auto auto;align-items:center;gap:12px;margin-bottom:14px}.log-status-filter{display:flex;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:10px}.log-status-filter button{min-height:32px;padding:0 12px;color:var(--muted);background:transparent;border-radius:7px;cursor:pointer}.log-status-filter button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 3px #0000001f}.log-entry+.log-entry{border-top:1px solid var(--hairline)}.log-entry .table-row{border:0;cursor:pointer}.log-entry .table-row:hover,.log-entry .table-row.selected{background:var(--group)}.log-inspector{position:sticky;top:92px;display:grid;gap:14px;min-width:0;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .flow-step{background:#7676801a;border-color:transparent}.log-inspector header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid var(--hairline)}.log-inspector header div{display:grid;gap:4px;min-width:0}.log-inspector header span,.empty-inspector{color:var(--muted);font-size:13px}.app-shell[data-theme=dark] .sidebar-footer{background:#7676801f;border:0}.log-inspector header strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.empty-inspector{min-height:180px;place-items:center}.log-detail{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.log-detail>div{display:grid;gap:5px;min-width:0;padding:12px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.app-shell[data-theme=dark] .log-detail>div,.app-shell[data-theme=dark] .user-summary-strip span,.app-shell[data-theme=dark] .model-provider-group,.app-shell[data-theme=dark] .model-provider-filter button,.app-shell[data-theme=dark] .model-id,.app-shell[data-theme=dark] .alias-row span,.app-shell[data-theme=dark] .model-meta span{background:#7676801a;border-color:transparent}.log-detail span{color:var(--muted);font-size:12px}.log-detail strong{overflow:hidden;font-size:13px;text-overflow:ellipsis;white-space:nowrap}.log-actions{display:flex;justify-content:flex-end;gap:8px}.detail-stack{display:grid;gap:14px}.user-hero{display:grid;grid-template-columns:52px 1fr auto;align-items:center;gap:12px;padding:4px 2px 16px;border-bottom:1px solid var(--hairline)}.user-hero h2{margin-bottom:3px;font-size:21px}.user-hero p{color:var(--muted);font-size:13px}.avatar{display:grid;place-items:center;width:52px;height:52px;color:#fff;background:var(--blue);border-radius:50%;font-weight:800;box-shadow:inset 0 1px #ffffff4d}.settings-group{overflow:hidden;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:16px;padding:4px 16px;box-shadow:0 1px 3px #0000000a}.app-shell[data-theme=dark] .settings-group{box-shadow:0 1px 2px #0003}.registration-mode-control{display:inline-grid;grid-auto-flow:column;gap:3px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.registration-mode-control button{min-width:74px;height:30px;padding:0 10px;color:var(--muted);background:transparent;border-radius:999px;font-weight:700;cursor:pointer}.registration-mode-control button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.settings-layout{display:grid;gap:20px}.settings-tabs{display:flex;flex-wrap:wrap;gap:6px;width:fit-content;max-width:100%;padding:5px;overflow-x:auto;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.settings-tabs button{display:flex;align-items:center;gap:6px;min-width:0;min-height:40px;padding:0 14px;color:var(--muted);text-align:left;background:transparent;border-radius:11px;cursor:pointer;transition:color .14s ease,background .14s ease,box-shadow .14s ease}.settings-tabs button:hover:not(.selected){color:var(--text);background:color-mix(in srgb,var(--surface-solid) 50%,transparent)}.settings-tabs button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f}.settings-tabs strong,.settings-tabs small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.settings-tabs strong{font-size:13px;font-weight:700}.settings-tabs small,.settings-tab-note{display:none}.discord-settings{display:grid;gap:18px}.discord-toggle-row,.settings-save-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.discord-toggle-row{min-height:56px;padding:0 2px 16px;border-bottom:1px solid var(--hairline)}.discord-toggle-row strong,.discord-toggle-row span{display:block}.discord-toggle-row span,.settings-save-row span{margin-top:3px;color:var(--muted);font-size:13px}.backup-actions label{display:inline-flex;align-items:center;cursor:pointer}.backup-actions input{display:none}.channel-import-actions{display:flex;align-items:center;flex-wrap:wrap;gap:10px}.channel-import-actions label{cursor:pointer}.channel-import-actions input,.channel-card-actions input[type=file]{display:none}.account-pool-list{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));margin-top:14px}.account-filter-bar{display:flex;flex-wrap:wrap;gap:7px;margin:10px 0 2px}.account-filter-bar button{padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--muted);cursor:pointer;font:inherit;font-size:12px}.account-filter-bar input{min-width:180px;flex:1 1 220px;padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--text);font:inherit;font-size:12px}.account-filter-bar select{padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--text);font:inherit;font-size:12px}.app-shell[data-theme=dark] .account-filter-bar select,.app-shell[data-theme=dark] .account-filter-bar input{background:#7676802e;border-color:#ffffff1a;color:#f5f5f7}.account-filter-bar button.selected{border-color:var(--accent);color:var(--accent)}.channel-capability-tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:5px}.channel-capability-tags span{padding:2px 7px;border:1px solid var(--hairline);border-radius:999px;color:var(--muted);font-size:11px}.account-pool-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:12px;padding:10px 12px;border:1px solid var(--hairline);border-radius:12px;background:var(--control)}.account-pool-main{display:grid;gap:8px;min-width:0}.account-pool-main>div{display:grid;gap:3px;min-width:0}.account-pool-title{display:flex;align-items:center;gap:8px;min-width:0}.account-pool-title strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.account-pool-main>div>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:12px}.account-pool-meta{display:flex;flex-shrink:0;align-items:center;gap:8px;justify-content:flex-end}.account-pool-more{display:flex;align-items:center;justify-content:space-between;gap:12px;grid-column:1 / -1;padding:6px 2px 0}.account-pool-more-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.account-pool-more-actions .secondary-button{flex-shrink:0}.quota-bars{display:grid;gap:6px}.quota-bar{display:grid;gap:4px}.quota-bar-label{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px}.quota-bar-label strong{color:var(--text)}.quota-bar-track{height:5px;overflow:hidden;border-radius:999px;background:var(--hairline)}.quota-bar-track span{display:block;height:100%;border-radius:inherit;background:var(--green)}.key-editor{display:grid;gap:14px;padding:16px;border:1px solid var(--hairline);border-radius:22px;background:var(--surface-solid)}.app-shell[data-theme=dark] .key-editor{background:#1c1c1eb8;border-color:#ffffff0f}.key-editor+.key-editor{margin-top:12px}.key-editor-collapsible{gap:0;padding:0;overflow:hidden;border-radius:16px}.key-editor-collapsible[open]{gap:0}.key-editor-collapsible>summary{min-height:74px;padding:14px 16px;cursor:pointer;list-style:none}.key-editor-collapsible>summary::-webkit-details-marker{display:none}.key-editor-collapsible[open]>summary{border-bottom:1px solid var(--hairline)}.key-editor-body{display:grid;gap:14px;padding:16px}.key-expand-hint{padding:5px 10px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px}.key-editor-collapsible[open] .key-expand-hint:after{content:"中"}.key-editor-head{display:flex;align-items:center;justify-content:space-between;gap:16px}.key-editor-head strong,.key-editor-head span{display:block}.key-editor-head span{margin-top:4px;color:var(--muted);font-size:13px}.key-editor-grid{display:grid;grid-template-columns:minmax(160px,.8fr) minmax(240px,1.4fr) minmax(180px,1fr) minmax(140px,.8fr);gap:12px}.key-editor-grid label{display:grid;gap:7px;color:var(--muted);font-size:13px}.key-editor-grid input{width:100%;min-width:0;height:40px;padding:0 12px;color:var(--text);color-scheme:dark;background:var(--group);border:1px solid var(--hairline);border-radius:14px;outline:none}.key-editor-grid input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.key-editor-grid input::placeholder{color:var(--muted);opacity:.72}.key-editor-actions{display:flex;gap:8px;justify-content:flex-end}.settings-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.settings-form-grid label{display:grid;min-width:0;gap:7px;color:var(--muted);font-size:13px}.settings-form-grid input{width:100%;min-width:0;height:44px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.settings-form-grid input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-form-grid textarea{width:100%;min-width:0;min-height:88px;padding:10px 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none;resize:vertical;font:inherit;line-height:1.5;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.settings-form-grid textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-form-grid small{color:var(--muted);font-size:12px;line-height:1.45}.settings-form-grid input::placeholder{color:var(--muted);opacity:.72}.settings-form-wide{grid-column:1 / -1}.settings-save-row{min-height:44px}.settings-save-row .primary-button:disabled{cursor:wait;opacity:.58}.setting{min-height:52px}.setting span{color:var(--muted);font-size:14px}.setting-value{display:flex;align-items:center;gap:10px}.setting-value strong{color:var(--text);font-size:14px;font-weight:600}.setting>span small{display:block;margin-top:3px;color:var(--muted);font-size:12px}.auth-default-balance input{width:130px}.check-in-settings-row{align-items:center}.check-in-reward-inputs{display:grid;grid-template-columns:repeat(2,120px);gap:10px}.check-in-reward-inputs label{display:grid;gap:5px;color:var(--muted);font-size:12px}.check-in-reward-inputs input{width:100%;height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.check-in-reward-inputs input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.maintenance-control input{width:150px;height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.maintenance-control input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-save-row{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:12px;border-top:1px solid var(--hairline)}.settings-save-row span{margin-right:auto;color:var(--muted);font-size:13px}.ios-switch{position:relative;flex:0 0 auto;width:49px;height:30px;padding:2px;background:#d1d1d6;border-radius:999px;cursor:pointer;transition:background .16s ease}.ios-switch span{display:block;width:26px;height:26px;margin:0;background:#fff;border-radius:50%;box-shadow:0 2px 5px #0000003d;transition:transform .16s ease}.ios-switch.is-on{background:var(--green)}.ios-switch.is-on span{transform:translate(19px)}.action-row{display:flex;flex-wrap:wrap;gap:10px}.balance-adjuster{display:grid;gap:12px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.balance-adjuster-title,.balance-adjuster-actions{display:flex;align-items:center;gap:10px}.balance-adjuster-title{justify-content:space-between}.balance-adjuster-title span,.balance-adjuster-actions span,.balance-adjuster-fields label>span{color:var(--muted);font-size:12px}.balance-adjuster-fields{display:grid;grid-template-columns:110px minmax(0,1fr);gap:10px}.balance-adjuster-fields label{display:grid;gap:6px}.balance-adjuster-fields input{width:100%;min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.balance-adjuster-fields input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.balance-adjuster-actions span{min-width:0;overflow-wrap:anywhere}.empty{display:grid;place-items:center;min-height:160px;color:var(--muted);background:var(--group);border:1px dashed var(--hairline-strong);border-radius:18px}.toast{position:fixed;left:50%;bottom:28px;transform:translate(-50%);padding:10px 14px;color:#fff;background:#1d1d1feb;border-radius:999px;font-size:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.secret-dialog-backdrop{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:20px;background:#0000006b;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.secret-dialog{display:grid;gap:18px;width:min(520px,100%);padding:22px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px;box-shadow:var(--shadow)}.secret-dialog>p{color:var(--muted);line-height:1.55}.secret-dialog code{overflow-x:auto;padding:13px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;white-space:nowrap}.secret-dialog-actions{display:flex;justify-content:flex-end;gap:10px}.auth-page,.account-page{--bg: #f2f2f7;--surface-solid: #ffffff;--group: #f9f9fb;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .16);--blue: #007aff;--green: #34c759;--shadow: 0 18px 45px rgba(0, 0, 0, .08);min-height:100vh;color:var(--text);background:var(--bg)}.auth-page[data-theme=dark],.account-page[data-theme=dark]{--bg: #000000;--surface-solid: #1c1c1e;--group: #2c2c2e;--text: #f5f5f7;--muted: #a1a1aa;--hairline: rgba(255, 255, 255, .12);--shadow: 0 24px 60px rgba(0, 0, 0, .36)}.auth-topbar,.account-topbar{display:flex;align-items:center;justify-content:space-between;width:min(1120px,calc(100% - 40px));min-height:76px;margin:0 auto;border-bottom:1px solid var(--hairline)}.auth-brand{display:inline-flex;align-items:center;gap:10px;padding:0;color:var(--text);background:transparent;cursor:pointer}.auth-brand .brand-mark{width:36px;height:36px;border-radius:10px}.auth-stage{display:grid;grid-template-columns:minmax(0,.9fr) minmax(360px,1fr);align-items:start;width:min(920px,calc(100% - 40px));gap:72px;margin:0 auto;padding:72px 0}.auth-intro{padding-top:24px}.auth-intro>span{color:var(--blue);font-size:13px;font-weight:700}.auth-intro h1{margin:10px 0 14px;font-size:42px}.auth-intro p{max-width:390px;color:var(--muted);line-height:1.65}.auth-form{display:grid;gap:15px;padding:24px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px;box-shadow:var(--shadow)}.auth-form label{display:grid;gap:7px;color:var(--muted);font-size:13px}.auth-form input,.auth-form select{width:100%;height:46px;padding:0 12px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:14px;outline:none}[data-theme=dark] .auth-form input,[data-theme=dark] .auth-form select{color-scheme:dark;background:var(--group)}.auth-form input:focus,.auth-form select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.setup-options{display:grid;gap:12px;padding:14px;border:1px solid var(--hairline);border-radius:18px;background:var(--group)}.setup-options .setting{padding:0;border:0}.setup-options label{gap:7px}.auth-message{min-height:18px;color:#ff3b30;font-size:13px}.auth-submit,.discord-login-button{min-height:44px;width:100%}.auth-submit:disabled{cursor:wait;opacity:.58}.discord-login-button{display:grid;place-items:center;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-weight:700;text-decoration:none}.auth-discord-register{display:grid;gap:10px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.auth-discord-register span{color:var(--muted);font-size:13px;line-height:1.5}.auth-switch{display:flex;justify-content:center}.auth-switch button{padding:6px 10px;color:var(--blue);background:transparent;cursor:pointer}.account-actions,.account-section-title,.account-heading{display:flex;align-items:center;justify-content:space-between;gap:14px}.account-section-title>div{display:grid;gap:3px}.account-content{display:grid;width:min(1120px,calc(100% - 40px));gap:18px;margin:0 auto;padding:42px 0 72px}.account-heading{padding-bottom:18px;border-bottom:1px solid var(--hairline)}.account-balance{text-align:right}.account-balance span,.account-balance strong{display:block}.account-balance span{color:var(--muted);font-size:13px}.account-balance strong{margin-top:4px;font-size:26px}.account-section{display:grid;gap:16px;padding:20px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.check-in-section{overflow:hidden;background:radial-gradient(circle at 100% 0,color-mix(in srgb,var(--blue) 22%,transparent),transparent 48%),var(--glass);border:1px solid var(--glass-border);box-shadow:var(--glass-shadow);-webkit-backdrop-filter:blur(26px) saturate(180%);backdrop-filter:blur(26px) saturate(180%)}.check-in-section .account-section-title>div{display:grid;gap:4px}.check-in-section .eyebrow,.check-in-section h2{margin:0}.check-in-section .primary-button:disabled{cursor:default;opacity:.62}.check-in-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.check-in-summary>div{display:grid;gap:6px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.check-in-summary span,.check-in-note{color:var(--muted);font-size:13px}.check-in-summary strong{font-size:15px}.check-in-note{margin:0;line-height:1.5}.check-in-message{color:var(--blue)}.one-time-secret{overflow-x:auto;padding:13px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px}.account-message{color:var(--muted);font-size:13px}.account-key-list{display:grid}.account-key-list>div{display:flex;align-items:center;gap:13px;min-height:66px;padding:13px 6px;border-top:1px solid var(--hairline)}.account-key-list>div:first-child{border-top:0}.account-key-list .empty{justify-content:center}.account-key-mark{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:40px;height:40px;color:var(--blue);background:color-mix(in srgb,var(--blue) 13%,transparent);border-radius:12px}.account-key-mark .icon{width:19px;height:19px}.account-key-info{display:flex;flex-direction:column;gap:3px;flex:1 1 auto;min-width:0}.account-key-info strong{font-size:15px;font-weight:650;line-height:1.25}.account-key-info code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;letter-spacing:.01em;color:var(--muted);overflow-wrap:anywhere}.account-key-list .badge{flex:0 0 auto;align-self:center}.account-model-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.account-model-empty{grid-column:1 / -1;padding:26px 18px;color:var(--muted);text-align:center;font-size:13px;background:color-mix(in srgb,var(--group) 60%,transparent);border:1px dashed var(--hairline);border-radius:14px}.account-model-grid article{display:grid;gap:9px;min-width:0;padding:16px;background:var(--group);border:1px solid var(--hairline);border-radius:8px}.account-model-grid article>span,.account-model-grid article p{color:var(--muted);font-size:13px}.account-model-grid article p{line-height:1.5}.account-model-grid code{overflow:hidden;text-overflow:ellipsis}.public-home{--bg: #f4f5f8;--surface: rgba(255, 255, 255, .86);--surface-solid: #ffffff;--group: #eef1f6;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .16);--hairline-strong: rgba(60, 60, 67, .24);--blue: #007aff;--violet: #8b5cf6;--green: #34c759;--orange: #ff9500;--shadow: 0 28px 80px rgba(16, 24, 40, .16);--glow: rgba(0, 122, 255, .15);position:relative;min-height:100vh;padding:22px;color:var(--text);background:var(--bg);overflow:hidden}.public-home:before,.public-home:after{content:"";position:absolute;border-radius:50%;filter:blur(120px);opacity:.5;pointer-events:none;z-index:0}.public-home:before{top:-10%;right:5%;width:600px;height:600px;background:var(--glow)}.public-home:after{bottom:-15%;left:-5%;width:500px;height:500px;background:#8b5cf61f}.public-home>*{position:relative;z-index:1}.public-home[data-theme=dark]{--bg: #050508;--surface: rgba(12, 17, 24, .84);--surface-solid: #0d1117;--group: #0b1017;--text: #f5f5f7;--muted: #8f969f;--hairline: rgba(255, 255, 255, .08);--hairline-strong: rgba(255, 255, 255, .16);--shadow: 0 38px 90px rgba(0, 0, 0, .5);--glow: rgba(0, 122, 255, .25);background:var(--bg)}.public-home[data-theme=dark]:before{opacity:.35}.public-home[data-theme=dark]:after{background:#8b5cf62e;opacity:.4}.home-topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;max-width:1180px;margin:0 auto}.home-brand,.home-actions,.home-cta{display:flex;align-items:center;gap:12px}.home-brand span{display:block;margin-top:2px;color:var(--muted);font-size:13px}.home-hero{display:grid;grid-template-columns:minmax(0,.88fr) minmax(460px,.92fr);gap:clamp(38px,7vw,86px);align-items:center;max-width:1180px;min-height:calc(100vh - 250px);margin:0 auto;padding:clamp(72px,10vw,128px) 0 68px}.home-copy{display:grid;gap:22px;align-content:center}.home-kicker{width:fit-content;padding:8px 13px;color:var(--blue);background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 28%,var(--hairline));border-radius:999px;font-size:13px;font-weight:700}.home-copy h1{max-width:680px;font-size:clamp(42px,4.8vw,58px);line-height:1.08;letter-spacing:0}.home-copy h1 span{display:block;width:fit-content;color:var(--blue);white-space:nowrap}.home-copy p{max-width:620px;color:var(--muted);font-size:17px;font-weight:600;line-height:1.8}.public-home .home-cta .primary-button{gap:8px;min-height:54px;padding:0 28px;color:#fff;background:var(--blue);border-radius:16px;box-shadow:0 4px 14px #007aff59,inset 0 1px #fff3;font-size:15px;font-weight:700}.public-home .home-cta .primary-button:hover{box-shadow:0 6px 20px #007aff73,inset 0 1px #fff3}.public-home[data-theme=dark] .home-cta .primary-button{color:#111318;background:#fff;box-shadow:0 4px 16px #ffffff26,inset 0 1px #ffffff80}.public-home[data-theme=dark] .home-cta .primary-button:hover{box-shadow:0 6px 24px #ffffff38,inset 0 1px #ffffff80}.public-home .home-cta .secondary-button{min-height:54px;padding:0 24px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline-strong);border-radius:16px;box-shadow:0 2px 8px #0000000f;font-size:15px;font-weight:700}.public-home[data-theme=dark] .home-cta .secondary-button{background:#ffffff14;border-color:#ffffff1f;box-shadow:0 2px 10px #0003}.integration-row{display:grid;gap:12px;margin-top:18px;color:var(--muted);font-size:13px;font-weight:700}.integration-row>div{display:flex;flex-wrap:wrap;gap:10px}.integration-row>div span{min-height:40px;padding:11px 18px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:0 2px 6px #0000000a,inset 0 1px #fff9;transition:transform .18s ease,box-shadow .18s ease}.integration-row>div span:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014,inset 0 1px #fff9}.public-home[data-theme=dark] .integration-row>div span{background:#ffffff0f;border-color:#ffffff1a;box-shadow:0 2px 8px #0003,inset 0 1px #ffffff0d}.public-home[data-theme=dark] .integration-row>div span:hover{background:#ffffff1a;box-shadow:0 4px 16px #0000004d,inset 0 1px #ffffff14}.gateway-terminal{position:relative;overflow:hidden;min-height:500px;color:#d7dde7;background:#0a0e14;border:1px solid rgba(255,255,255,.08);border-radius:24px;box-shadow:0 0 0 1px #ffffff0d,0 25px 60px -12px #0006,0 0 40px #007aff14}.gateway-terminal:before{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(255,255,255,.03) 0%,transparent 30%);pointer-events:none}.terminal-titlebar{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;min-height:54px;padding:0 18px;color:#9aa5b4;background:#111821;border-bottom:1px solid rgba(255,255,255,.08);font-size:13px}.terminal-dots{display:flex;gap:6px}.terminal-dots span{width:9px;height:9px;background:#445061;border-radius:50%}.terminal-status{display:inline-flex;align-items:center;gap:8px;color:#d7dde7}.terminal-status .pulse-dot{width:8px;height:8px}.terminal-endpoint{display:flex;align-items:center;gap:12px;min-height:56px;padding:0 22px;background:#0c1118;border-bottom:1px solid rgba(255,255,255,.08)}.terminal-endpoint span{padding:4px 8px;color:var(--green);background:#34c7591f;border-radius:8px;font-size:11px;font-weight:900}.terminal-endpoint strong{overflow:hidden;color:#f2f5f9;font-size:16px;text-overflow:ellipsis;white-space:nowrap}.terminal-body{display:grid;gap:18px;padding:22px}.terminal-block{display:grid;gap:10px}.terminal-block>span{color:#758194;font-size:12px;font-weight:900;letter-spacing:.14em}.terminal-block pre{overflow-x:auto;margin:0;padding:0;color:#8fd5ff;background:transparent;border:0;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:13px;font-weight:700;line-height:1.75}.terminal-block.response pre{color:#76e4a6}.terminal-route{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.terminal-route div{min-width:0;padding:12px;background:#111821;border:1px solid rgba(255,255,255,.08);border-radius:14px}.terminal-route span{display:block;margin-bottom:6px;color:#758194;font-size:11px;font-weight:800}.terminal-route strong{overflow:hidden;display:block;color:#f2f5f9;font-size:13px;text-overflow:ellipsis;white-space:nowrap}@keyframes status-pulse{0%{box-shadow:0 0 color-mix(in srgb,var(--green) 42%,transparent)}70%{box-shadow:0 0 0 9px color-mix(in srgb,var(--green) 0%,transparent)}to{box-shadow:0 0 color-mix(in srgb,var(--green) 0%,transparent)}}@media(prefers-reduced-motion:reduce){.pulse-dot{animation:none}}.home-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;max-width:1120px;margin:0 auto;padding-bottom:34px}.home-feature{display:grid;gap:9px;min-height:150px;padding:18px;background:var(--surface);border:1px solid var(--hairline);border-radius:24px;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.home-feature .icon{color:var(--blue)}.home-feature span{color:var(--muted);line-height:1.5}@media(max-width:1280px){.users-layout{grid-template-columns:1fr}}@media(max-width:980px){.app-shell{grid-template-columns:1fr}.sidebar{position:fixed;inset:auto 12px 12px;z-index:30;height:auto;padding:8px;border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow)}.ios-window-dots,.brand,.sidebar-footer{display:none}nav{grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.nav-item{flex-direction:column;justify-content:center;gap:4px;min-height:54px;padding:0 4px;border-radius:18px;font-size:11px}.content{width:100%;padding:20px 14px calc(108px + env(safe-area-inset-bottom))}.topbar{margin:-20px -14px 20px;padding:18px 14px 14px}.metrics-grid,.split-grid,.users-layout,.flow-panel,.user-summary-strip,.channel-form-grid{grid-template-columns:1fr}.stream-mode-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.bulk-action-bar{grid-template-columns:auto 100px minmax(160px,1fr)}.bulk-group-select,.auth-default-balance select{width:100%}.channel-form-wide{grid-column:auto}.model-grid{grid-template-columns:1fr}.model-list-toolbar{align-items:stretch;flex-direction:column}.model-list-toolbar input{width:100%}.model-compact-grid{grid-template-columns:1fr}.model-compact-row,.model-compact-row:nth-child(odd),.model-compact-row:nth-last-child(-n+2){border-right:0;border-bottom:1px solid var(--hairline)}.model-compact-row:last-child{border-bottom:0}.flow-steps{grid-template-columns:repeat(4,minmax(136px,1fr));overflow-x:auto;padding-bottom:2px;scroll-snap-type:x mandatory}.flow-step{scroll-snap-align:start}.channels-table,.logs-table{grid-template-columns:minmax(140px,1.3fr) 90px 70px}.logs-toolbar{grid-template-columns:1fr auto}.logs-toolbar .search-box{grid-column:1 / -1}.logs-layout{grid-template-columns:1fr}.log-inspector{position:static}.log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}.channels-table span:nth-child(4),.channels-table span:nth-child(5),.logs-table span:nth-child(3),.logs-table span:nth-child(4),.logs-table span:nth-child(5),.logs-table span:nth-child(6){display:none}}@media(max-width:900px){.home-hero,.home-grid{grid-template-columns:1fr}.home-hero{min-height:0}.model-create-form{grid-template-columns:1fr}.model-create-wide{grid-column:auto}.model-compact-grid{grid-template-columns:1fr}.model-compact-row{grid-template-columns:1fr;align-items:stretch}.model-row-actions{justify-content:flex-start;flex-wrap:wrap}.auth-stage{grid-template-columns:1fr;gap:28px;max-width:560px;padding:38px 0 64px}.auth-intro{padding-top:0}.account-model-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:680px){.app-shell{display:block;min-height:100dvh}.topbar{position:sticky;top:0;align-items:flex-start;flex-direction:column;gap:12px}.topbar-actions{width:100%;display:grid;grid-template-columns:1fr auto auto auto}.segmented-control{flex:1}.segmented-control button{min-width:0}.theme-toggle span{display:none}.theme-toggle{width:40px;padding:0}.topbar-actions .home-link{display:none}.quick-actions{display:flex;overflow-x:auto;padding-bottom:2px;scroll-snap-type:x mandatory}.bulk-action-bar{grid-template-columns:1fr 1fr}.bulk-action-bar strong,.bulk-action-bar input[aria-label=调整原因]{grid-column:1 / -1}.balance-adjuster-fields{grid-template-columns:1fr}.user-filter-row{width:100%;overflow-x:auto}.user-filter-row button{flex:1 0 auto}.auth-default-balance{width:100%}.auth-default-balance input{flex:1;width:auto}.quick-action{min-width:132px;scroll-snap-align:start}.settings-form-grid{grid-template-columns:1fr}.settings-form-wide{grid-column:auto}.settings-save-row{align-items:stretch;flex-direction:column}.settings-save-row .primary-button{width:100%}.auth-topbar,.account-topbar,.auth-stage,.account-content{width:min(100% - 28px,560px)}.auth-intro h1{font-size:34px}.auth-form{padding:18px}.account-model-grid,.check-in-summary{grid-template-columns:1fr}.check-in-section .account-section-title{align-items:stretch;flex-direction:column}.check-in-section .primary-button{width:100%}.check-in-reward-inputs{width:100%;grid-template-columns:repeat(2,minmax(0,1fr))}.account-heading{align-items:flex-start}.public-home{padding:14px}.home-topbar{align-items:flex-start;flex-direction:column}.home-actions{width:100%}.home-actions .primary-button{flex:1}.home-hero{gap:20px;padding:34px 0 20px}.home-copy p{font-size:16px}.home-cta{align-items:stretch;flex-direction:column}.gateway-terminal{min-height:0;border-radius:24px}.terminal-titlebar{grid-template-columns:auto 1fr}.terminal-status{grid-column:1 / -1;justify-content:center;padding:8px 12px;background:#0c1118;border:1px solid rgba(255,255,255,.08);border-radius:999px}.terminal-body,.terminal-endpoint{padding-right:18px;padding-left:18px}.terminal-block pre{font-size:12px}.terminal-route{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:560px){nav{grid-template-columns:repeat(7,minmax(0,1fr))}h1{font-size:30px}.home-copy h1 span{white-space:normal}.metrics-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.setting{align-items:flex-start;flex-direction:column}.registration-mode-control{width:100%}.registration-mode-control button{min-width:0}.hero-strip{align-items:stretch;flex-direction:column;min-height:0;padding:18px}.hero-strip strong{font-size:20px}.live-island{justify-content:center;width:100%}.flow-panel{padding:14px}.flow-steps{display:flex;overflow-x:auto}.flow-step{min-width:136px}.flow-step:not(:last-child):after{display:none}.table{gap:10px;overflow:visible;background:transparent;border:0;border-radius:0}.table-head{display:none}.table-row,.users-table,.channels-table,.logs-table{display:grid;grid-template-columns:1fr auto;gap:8px 12px;min-height:0;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.table-row span:nth-child(n+3){display:none}.users-table.table-row{grid-template-columns:22px minmax(0,1fr) auto}.users-table.table-row>:nth-child(3){display:inline-flex}.mobile-bulk-select{display:inline-flex;width:100%}.channel-editor.channels-table{grid-template-columns:1fr}.channel-editor span:nth-child(n+3),.channel-actions{display:grid}.channel-actions{grid-template-columns:1fr}.table-head,.table-head.users-table,.table-head.channels-table,.table-head.logs-table{display:none}.panel{padding:14px;border-radius:22px}.user-hero{grid-template-columns:48px 1fr}.user-hero .badge{grid-column:1 / -1;justify-self:start}}.modal-backdrop{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;padding:20px;background:#00000073;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.modal-card{width:100%;max-width:520px;max-height:88vh;overflow-y:auto;padding:22px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:20px;box-shadow:0 20px 60px #00000059}.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.modal-head strong{font-size:18px}.modal-head>div{display:grid;gap:4px}.modal-head>div>span{color:var(--muted);font-size:13px}.account-add-modal{max-width:680px}.account-add-options{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:20px}.account-add-option{position:relative;display:grid;justify-items:start;gap:7px;min-width:0;padding:18px;color:var(--text);text-align:left;cursor:pointer;background:var(--group);border:1px solid var(--hairline);border-radius:16px;transition:border-color .16s ease,background .16s ease,transform .16s ease}.account-add-option:hover:not(:disabled):not(.disabled){transform:translateY(-2px);background:color-mix(in srgb,var(--blue) 7%,var(--group));border-color:color-mix(in srgb,var(--blue) 36%,var(--hairline))}.account-add-option.recommended:after{content:"推荐";position:absolute;top:12px;right:12px;padding:3px 8px;color:var(--blue);font-size:11px;font-weight:700;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border-radius:999px}.account-add-option small{color:var(--muted);line-height:1.45}.account-add-option input{display:none}.account-add-option.disabled{cursor:not-allowed;opacity:.55}.account-add-icon{display:grid;width:34px;height:34px;place-items:center;color:var(--blue);font-size:13px;font-weight:800;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border-radius:11px}.account-add-modal .modal-actions{margin-top:18px}@media(max-width:760px){.channel-card-head{flex-direction:column}.channel-card-head-actions{width:100%;justify-content:flex-start}.account-add-options{grid-template-columns:1fr}}.oauth-steps{margin:16px 0 0;padding-left:18px;display:flex;flex-direction:column;gap:18px}.oauth-steps li{line-height:1.6}.oauth-steps label{display:block;margin-bottom:8px;font-weight:600}.oauth-steps input{width:100%;box-sizing:border-box;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:10px;font-size:14px}.oauth-link{margin-top:10px;display:flex;flex-direction:column;gap:6px}.modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}.model-picker-modal{max-width:560px}.model-picker-toolbar{display:flex;align-items:center;gap:8px}.model-picker-search{flex:1 1 auto;min-width:0;height:38px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-picker-search:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-picker-count{margin:10px 2px 8px;color:var(--muted);font-size:12.5px;font-weight:600}.model-picker-list{display:grid;gap:4px;max-height:46vh;overflow-y:auto;padding:4px;border:1px solid var(--hairline);border-radius:14px;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.model-picker-row{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:10px;cursor:pointer}.model-picker-row:hover{background:var(--group)}.model-picker-row.checked{background:color-mix(in srgb,var(--blue) 10%,var(--group))}.model-picker-row input[type=checkbox]{flex:0 0 auto;width:17px;height:17px;accent-color:var(--blue);cursor:pointer}.model-picker-name{flex:1 1 auto;min-width:0;font-size:13.5px;color:var(--text);overflow-wrap:anywhere}.model-picker-tag{flex:0 0 auto;padding:2px 8px;color:var(--blue);background:color-mix(in srgb,var(--blue) 14%,transparent);border-radius:999px;font-size:11px;font-weight:650}.model-picker-status{padding:26px 12px;color:var(--muted);text-align:center;font-size:13px}.model-picker-error{color:#d70015}.form-error{margin-top:14px;padding:10px 12px;color:#d70015;background:color-mix(in srgb,var(--red) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--red) 28%,var(--hairline));border-radius:10px;font-size:13px}.source-guide{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px}.source-guide-item{padding:14px 16px;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.source-guide-item strong{display:block;margin-bottom:4px;font-size:14px}.source-guide-item span{color:var(--muted);font-size:13px;line-height:1.5}.channel-card-collapsible>summary{cursor:pointer;list-style:none}.channel-card-collapsible>summary::-webkit-details-marker{display:none}.channel-card-collapsible>summary:after{content:"展开";align-self:center;margin-left:10px;padding:4px 10px;color:var(--muted);font-size:12px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.channel-card-collapsible[open]>summary:after{content:"收起"}.manual-add{display:inline-block}.manual-add>summary{cursor:pointer;list-style:none}.manual-add>summary::-webkit-details-marker{display:none}.manual-add-body{margin-top:10px;padding:12px;display:flex;flex-direction:column;gap:10px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.manual-add-actions{display:flex;flex-wrap:wrap;gap:8px}.source-tag{flex:0 0 auto;padding:1px 8px;font-size:11px;font-weight:700;border-radius:999px;vertical-align:middle}.source-tag-web{color:#0a7d28;background:color-mix(in srgb,#34c759 16%,var(--surface-solid));border:1px solid color-mix(in srgb,#34c759 32%,var(--hairline))}.source-tag-manual{color:var(--muted);background:var(--group);border:1px solid var(--hairline)}@media(max-width:720px){.source-guide{grid-template-columns:1fr}.account-pool-list{grid-template-columns:minmax(0,1fr)}}.form-success{color:var(--success);font-size:13px}.authsession-field{display:grid;gap:8px;margin-top:18px;color:var(--muted);font-size:13px;font-weight:700}.authsession-field textarea{width:100%;min-height:120px;padding:12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;resize:vertical;outline:none}.authsession-field textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.primary-button,.secondary-button,.danger-button,.icon-button,.theme-toggle{transition:transform .16s ease,background .16s ease,border-color .16s ease,box-shadow .16s ease}.primary-button:hover:not(:disabled){box-shadow:0 8px 20px color-mix(in srgb,var(--blue) 32%,transparent);transform:translateY(-1px)}.secondary-button:hover:not(:disabled),.icon-button:hover:not(:disabled){background:color-mix(in srgb,var(--blue) 9%,var(--surface-solid));border-color:color-mix(in srgb,var(--blue) 18%,var(--hairline))}.channel-page-intro{display:flex;align-items:center;justify-content:space-between;gap:24px;margin:-2px 0 20px;padding:18px 20px;background:linear-gradient(120deg,color-mix(in srgb,var(--blue) 10%,var(--surface-solid)),var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 18%,var(--hairline));border-radius:16px}.channel-page-intro strong,.channel-page-intro span{display:block}.channel-page-intro strong{margin-bottom:5px;font-size:16px}.channel-page-intro>div>span{color:var(--muted);font-size:13px}.channel-page-summary{display:flex;flex:0 0 auto;gap:20px}.channel-page-summary span{color:var(--muted);font-size:12px;white-space:nowrap}.channel-page-summary b{margin-right:4px;color:var(--text);font-size:18px}.channel-toolbar{padding-bottom:14px;border-bottom:1px solid var(--hairline)}.channels-stack{gap:10px}.channel-card-collapsible{gap:0;padding:0;overflow:hidden;border-radius:16px}.channel-card-collapsible[open]{gap:18px;padding:18px}.channel-list-row{display:grid;grid-template-columns:minmax(240px,1.4fr) minmax(130px,.55fr) minmax(150px,.75fr) auto;align-items:center;gap:20px;min-height:86px;padding:14px 18px}.channel-card-collapsible[open] .channel-list-row{min-height:0;padding:0 0 18px;border-bottom:1px solid var(--hairline)}.channel-card-collapsible>.channel-list-row:after{content:none}.channel-identity strong{font-size:15px}.channel-identity span,.channel-identity small{overflow:hidden;max-width:100%;text-overflow:ellipsis;white-space:nowrap}.channel-identity span{margin-top:4px;color:var(--text);font-size:12px;font-weight:650}.channel-identity small{margin-top:4px}.channel-list-meta{display:flex;flex-wrap:wrap;gap:6px 12px;color:var(--muted);font-size:12px}.channel-list-meta b{color:var(--text)}.channel-check-result{display:grid;gap:4px;min-width:0}.channel-check-result>span{margin:0;color:var(--muted);font-size:11px}.channel-check-result b{overflow:hidden;color:var(--muted);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.channel-check-result b.is-ok{color:var(--green)}.channel-check-result b.is-error{color:var(--red)}.channel-list-status{display:flex;align-items:center;justify-content:flex-end;gap:10px}.channel-expand-hint{padding:5px 10px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px}.channel-card-collapsible[open] .channel-expand-hint:after{content:"中"}.channel-editor-controls{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.channel-select-field{display:grid;gap:7px;color:var(--muted);font-size:13px;font-weight:700}.channel-select-field select{width:100%;min-height:40px;padding:0 34px 0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.channel-select-field select:focus{border-color:var(--blue)}.channel-choice-menu{position:relative}.channel-choice-menu>summary{display:flex;align-items:center;justify-content:space-between;min-height:40px;padding:0 12px;color:var(--text);list-style:none;background:var(--group);border:1px solid var(--hairline);border-radius:12px;cursor:pointer}.channel-choice-menu>summary::-webkit-details-marker{display:none}.channel-choice-menu>summary:after{content:"⌄";margin-left:12px;color:var(--muted)}.channel-choice-menu>summary>span{font-weight:650}.channel-choice-menu>summary>small{color:var(--muted);font-size:12px;font-weight:500}.channel-choice-menu>div{position:absolute;top:calc(100% + 7px);right:0;left:0;z-index:20;display:grid;gap:2px;padding:6px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.app-shell[data-theme=dark] .channel-choice-menu>div{background:#2c2c2e;border-color:#ffffff1f}.channel-choice-menu button{display:grid;gap:3px;width:100%;padding:9px 10px;color:var(--text);text-align:left;background:transparent;border:0;border-radius:9px;cursor:pointer}.channel-choice-menu button strong{font-size:13px}.channel-choice-menu button span{color:var(--muted);font-size:12px}.channel-choice-menu button:hover,.channel-choice-menu button.selected{background:color-mix(in srgb,var(--blue) 10%,var(--group))}.channel-choice-menu button.selected strong{color:var(--blue)}.channel-more-actions{position:relative}.channel-more-actions>summary{min-height:36px;padding:0 12px;color:var(--muted);line-height:36px;list-style:none;background:var(--group);border:1px solid var(--hairline);border-radius:10px;cursor:pointer;font-size:13px;font-weight:700}.channel-more-actions>summary::-webkit-details-marker{display:none}.channel-more-actions>summary:after{content:"⌄";margin-left:7px}.channel-more-actions>div{position:absolute;right:0;bottom:calc(100% + 8px);z-index:4;display:grid;width:max-content;gap:6px;padding:8px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:var(--shadow)}.channel-more-actions label{cursor:pointer}.channel-more-actions input{display:none}.channel-card-actions{gap:4px}.channel-card-actions>.secondary-button,.channel-card-actions .channel-more-actions>summary,.channel-model-actions .secondary-button{min-height:34px;padding-inline:10px;color:var(--muted);background:transparent;border-color:transparent;box-shadow:none}.channel-card-actions>.secondary-button:hover:not(:disabled),.channel-card-actions .channel-more-actions>summary:hover,.channel-model-actions .secondary-button:hover:not(:disabled){color:var(--text);background:color-mix(in srgb,var(--blue) 9%,var(--group));border-color:transparent}.channel-card-actions>.primary-button{min-height:36px;padding-inline:15px}.channel-more-actions>summary{line-height:34px}.channel-more-actions>div{padding:6px;border-radius:14px}.channel-more-actions>div .secondary-button,.channel-more-actions>div .danger-button{justify-content:flex-start;min-height:34px;padding-inline:10px;background:transparent;border-color:transparent;border-radius:9px}.channel-more-actions>div .secondary-button:hover:not(:disabled){background:var(--group);border-color:transparent}.channel-more-actions>div .danger-button:hover:not(:disabled){background:color-mix(in srgb,var(--red) 10%,var(--surface-solid));border-color:transparent}@media(max-width:780px){.channel-page-intro{align-items:flex-start;flex-direction:column;gap:14px}.channel-list-row{grid-template-columns:minmax(0,1fr) auto;gap:12px}.channel-list-meta,.channel-check-result{grid-column:1 / -1}.channel-list-meta{order:3}.channel-check-result{order:4}.channel-list-status{grid-column:2;grid-row:1}.channel-editor-controls{grid-template-columns:1fr}}.gateway-terminal .terminal-block{opacity:0;animation:terminal-rise .5s ease-out forwards}.gateway-terminal .terminal-block.response{animation-delay:.45s}.gateway-terminal .terminal-route div{opacity:0;animation:terminal-rise .4s ease-out forwards}.gateway-terminal .terminal-route div:nth-child(1){animation-delay:.18s}.gateway-terminal .terminal-route div:nth-child(2){animation-delay:.28s}.gateway-terminal .terminal-route div:nth-child(3){animation-delay:.38s}.gateway-terminal .terminal-route div:nth-child(4){animation-delay:.48s}.terminal-caret{display:inline-block;width:7px;height:15px;margin-left:2px;vertical-align:text-bottom;background:#76e4a6;border-radius:1px;animation:terminal-caret-blink 1.1s step-end infinite}@keyframes terminal-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes terminal-caret-blink{0%,50%{opacity:1}50.01%,to{opacity:0}}@media(prefers-reduced-motion:reduce){.gateway-terminal .terminal-block,.gateway-terminal .terminal-route div{opacity:1;animation:none}.terminal-caret{animation:none}}.panel,.metric,.hero-strip,.flow-panel,.model-hero,.channel-card,.model-card,.settings-group,.account-pool-row,.model-provider-group,.model-provider-filter button,.table-row,.list-row,.channel-choice-menu button,.provider-picker-menu button,.model-row-menu button{transition:background .16s ease,border-color .16s ease,box-shadow .16s ease}button.table-row:hover,.log-entry .table-row:hover{box-shadow:inset 0 0 0 1px var(--hairline)}.metric:hover{border-color:var(--hairline-strong)}.cli-intro{margin:0 0 16px;color:var(--muted);font-size:14px;line-height:1.6}.cli-credentials{display:grid;gap:8px;margin-bottom:20px}.cli-credential{display:flex;align-items:center;gap:12px;min-height:48px;padding:10px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.cli-credential span{min-width:72px;color:var(--muted);font-size:13px;font-weight:600}.cli-credential code{flex:1;overflow:hidden;padding:0;color:var(--text);background:transparent;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:13px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.cli-credential .copy-button{display:grid;place-items:center;flex-shrink:0;width:32px;height:32px;color:var(--muted);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;cursor:pointer;transition:color .14s ease,border-color .14s ease}.cli-credential .copy-button:hover{color:var(--text);border-color:var(--hairline-strong)}.cli-credential .copy-button .icon{width:15px;height:15px}.cli-tools{display:grid;gap:10px}.cli-tool{overflow:hidden;background:var(--group);border:1px solid var(--hairline);border-radius:14px;transition:border-color .16s ease}.cli-tool[open]{border-color:var(--hairline-strong)}.cli-tool summary{display:flex;align-items:center;gap:12px;min-height:52px;padding:12px 16px;cursor:pointer;list-style:none}.cli-tool summary::-webkit-details-marker{display:none}.cli-tool summary:before{content:"";display:block;width:6px;height:6px;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:rotate(-45deg);transition:transform .16s ease}.cli-tool[open] summary:before{transform:rotate(45deg)}.cli-tool summary strong{flex:1;color:var(--text);font-size:14px;font-weight:700}.cli-tool summary span{color:var(--muted);font-size:12px}.cli-tool>p,.cli-tool>pre{margin:0 16px 14px}.cli-tool>p{color:var(--muted);font-size:13px;line-height:1.55}.cli-tool>p code{padding:2px 6px;color:var(--text);background:var(--surface-solid);border-radius:5px;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:12px}.cli-tool>pre{overflow-x:auto;padding:14px 16px;color:#8fd5ff;background:#0d1117;border-radius:10px;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:12px;font-weight:600;line-height:1.7;white-space:pre-wrap;word-break:break-all}.app-shell[data-theme=dark] .cli-tool>pre{background:#0006}.cli-tool>pre+pre{margin-top:-4px}.cli-message{margin:16px 0 0;padding:10px 14px;color:var(--green);background:color-mix(in srgb,var(--green) 8%,transparent);border-radius:10px;font-size:13px;font-weight:600}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes slide-down{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}@keyframes pop{0%{transform:scale(1)}50%{transform:scale(.95)}to{transform:scale(1)}}@keyframes toast-in{0%{opacity:0;transform:translateY(16px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.content{animation:fade-in .25s ease-out}.panel,.settings-group,.flow-panel,.hero-strip{animation:slide-up .3s ease-out backwards}.panel:nth-child(1),.settings-group:nth-child(1){animation-delay:0ms}.panel:nth-child(2),.settings-group:nth-child(2){animation-delay:50ms}.panel:nth-child(3),.settings-group:nth-child(3){animation-delay:.1s}.panel:nth-child(4),.settings-group:nth-child(4){animation-delay:.15s}.metric,.channel-card,.model-card,.cli-tool,.cli-credential{animation:slide-up .28s ease-out backwards}.metric:nth-child(1),.channel-card:nth-child(1),.model-card:nth-child(1){animation-delay:0ms}.metric:nth-child(2),.channel-card:nth-child(2),.model-card:nth-child(2){animation-delay:40ms}.metric:nth-child(3),.channel-card:nth-child(3),.model-card:nth-child(3){animation-delay:80ms}.metric:nth-child(4),.channel-card:nth-child(4),.model-card:nth-child(4){animation-delay:.12s}.metric:nth-child(5),.channel-card:nth-child(5),.model-card:nth-child(5){animation-delay:.16s}.metric:nth-child(6),.channel-card:nth-child(6),.model-card:nth-child(6){animation-delay:.2s}.table-row,.list-row{animation:fade-in .2s ease-out backwards}.primary-button,.secondary-button,.danger-button{transition:transform .12s ease,box-shadow .12s ease,background .14s ease,border-color .14s ease}.primary-button:hover,.secondary-button:hover,.danger-button:hover{transform:translateY(-1px)}.primary-button:active,.secondary-button:active,.danger-button:active{transform:translateY(0) scale(.98)}.ios-switch{transition:background .18s ease}.ios-switch span{transition:transform .2s cubic-bezier(.34,1.56,.64,1)}.metric:hover,.channel-card:hover,.model-card:hover{transform:translateY(-2px);box-shadow:0 6px 20px #00000014}.app-shell[data-theme=dark] .metric:hover,.app-shell[data-theme=dark] .channel-card:hover,.app-shell[data-theme=dark] .model-card:hover{box-shadow:0 6px 24px #00000047}.metric,.channel-card,.model-card{transition:transform .18s ease,box-shadow .18s ease,border-color .16s ease}.nav-item{transition:background .14s ease,color .14s ease,transform .1s ease}.nav-item:hover{transform:translate(2px)}.nav-item:active{transform:translate(0) scale(.98)}.settings-tabs button{transition:transform .12s ease,color .14s ease,background .14s ease,box-shadow .14s ease}.settings-tabs button:active{transform:scale(.97)}.toast{animation:toast-in .28s cubic-bezier(.34,1.25,.64,1)}.secret-dialog-backdrop{animation:fade-in .2s ease-out}.secret-dialog{animation:scale-in .25s cubic-bezier(.34,1.25,.64,1)}.copy-button,.cli-credential .copy-button{transition:transform .1s ease,color .14s ease,border-color .14s ease,background .14s ease}.copy-button:active,.cli-credential .copy-button:active{transform:scale(.9)}.channel-choice-menu>div,.provider-picker-menu>div,.model-row-menu{animation:slide-down .18s ease-out}@keyframes pulse-subtle{0%,to{opacity:1}50%{opacity:.7}}.pulse-dot{animation:pulse-subtle 2s ease-in-out infinite}.cli-tool summary{transition:background .14s ease}.cli-tool summary:hover{background:color-mix(in srgb,var(--surface-solid) 50%,transparent)}.cli-tool summary:before{transition:transform .2s cubic-bezier(.34,1.25,.64,1)}.icon{transition:transform .14s ease}button:hover .icon{transform:scale(1.08)}button:active .icon{transform:scale(.95)}.segmented-control button{transition:color .14s ease,background .14s ease,box-shadow .14s ease,transform .1s ease}.segmented-control button:active{transform:scale(.96)}.theme-toggle{transition:transform .12s ease,background .14s ease,border-color .14s ease}.theme-toggle:hover{transform:scale(1.03)}.theme-toggle:active{transform:scale(.97)}input,select,textarea{transition:border-color .14s ease,box-shadow .14s ease}.auth-form{animation:scale-in .3s cubic-bezier(.34,1.15,.64,1)}.account-section{animation:slide-up .3s ease-out backwards}.account-section:nth-child(1){animation-delay:0ms}.account-section:nth-child(2){animation-delay:80ms}.account-section:nth-child(3){animation-delay:.16s}.home-hero{animation:fade-in .4s ease-out}.home-copy{animation:slide-up .4s ease-out .1s backwards}.brand{transition:transform .14s ease}.brand:hover{transform:scale(1.02)}.quick-action{transition:transform .14s ease,background .14s ease,border-color .14s ease,box-shadow .14s ease}.quick-action:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014}.quick-action:active{transform:translateY(0) scale(.98)}.table-row{transition:background .12s ease,box-shadow .12s ease,transform .1s ease}button.table-row:active{transform:scale(.995)}.badge:before{transition:transform .2s ease,opacity .2s ease}.badge:hover:before{transform:scale(1.3)}.model-list-toolbar input,.user-filter-row input,.search-input{transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}.model-list-toolbar input:focus,.user-filter-row input:focus,.search-input:focus{background:var(--surface-solid)}.pager button{transition:transform .1s ease,background .12s ease,border-color .12s ease}.pager button:hover:not(:disabled){transform:scale(1.05)}.pager button:active:not(:disabled){transform:scale(.95)}details summary{transition:background .14s ease,color .14s ease}details[open]>summary{color:var(--text)}.list-row{transition:background .12s ease,transform .1s ease}.list-row:hover{background:color-mix(in srgb,var(--group) 50%,transparent)}.channel-card,.model-card{animation:slide-up .25s ease-out backwards}.channel-card:nth-child(1),.model-card:nth-child(1){animation-delay:0ms}.channel-card:nth-child(2),.model-card:nth-child(2){animation-delay:30ms}.channel-card:nth-child(3),.model-card:nth-child(3){animation-delay:60ms}.channel-card:nth-child(4),.model-card:nth-child(4){animation-delay:90ms}.channel-card:nth-child(5),.model-card:nth-child(5){animation-delay:.12s}.channel-card:nth-child(6),.model-card:nth-child(6){animation-delay:.15s}.channel-card:nth-child(7),.model-card:nth-child(7){animation-delay:.18s}.channel-card:nth-child(8),.model-card:nth-child(8){animation-delay:.21s}.users-layout .table-row.selected{animation:pop .2s ease-out}.user-filter-row button,.model-filter-actions button,.log-status-filter button,.model-provider-filter button{transition:transform .1s ease,color .12s ease,background .12s ease,box-shadow .12s ease}.user-filter-row button:active,.model-filter-actions button:active,.log-status-filter button:active,.model-provider-filter button:active{transform:scale(.96)}.bulk-action-bar{animation:slide-up .2s ease-out}.secret-dialog code{animation:fade-in .3s ease-out .15s backwards}.gateway-terminal{animation:scale-in .5s cubic-bezier(.16,1,.3,1) .2s backwards}.home-kicker{animation:slide-up .35s ease-out backwards}.home-cta{animation:slide-up .4s ease-out .15s backwards}.integration-row>div span{animation:slide-up .3s ease-out backwards}.integration-row>div span:nth-child(1){animation-delay:.25s}.integration-row>div span:nth-child(2){animation-delay:.3s}.integration-row>div span:nth-child(3){animation-delay:.35s}.topbar{animation:slide-down .3s ease-out}.nav-item{animation:fade-in .25s ease-out backwards}nav .nav-item:nth-child(1){animation-delay:0ms}nav .nav-item:nth-child(2){animation-delay:30ms}nav .nav-item:nth-child(3){animation-delay:60ms}nav .nav-item:nth-child(4){animation-delay:90ms}nav .nav-item:nth-child(5){animation-delay:.12s}nav .nav-item:nth-child(6){animation-delay:.15s}nav .nav-item:nth-child(7){animation-delay:.18s}nav .nav-item:nth-child(8){animation-delay:.21s}.sidebar-footer{animation:fade-in .4s ease-out .2s backwards}input:focus,select:focus,textarea:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 15%,transparent)}.provider-icon{transition:transform .15s ease}.channel-card:hover .provider-icon,.model-card:hover .provider-icon{transform:scale(1.1)}input[type=checkbox],input[type=radio]{transition:transform .1s ease,box-shadow .1s ease}input[type=checkbox]:active,input[type=radio]:active{transform:scale(.9)}.log-inspector{animation:slide-up .25s ease-out}.model-hero{animation:slide-up .35s ease-out backwards}.flow-step{animation:slide-up .3s ease-out backwards}.flow-step:nth-child(1){animation-delay:0ms}.flow-step:nth-child(2){animation-delay:60ms}.flow-step:nth-child(3){animation-delay:.12s}.flow-step:nth-child(4){animation-delay:.18s}.hero-strip{animation:fade-in .35s ease-out backwards}.empty{animation:fade-in .3s ease-out}.account-model-grid article{animation:slide-up .25s ease-out backwards;transition:transform .15s ease,box-shadow .15s ease}.account-model-grid article:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014}.account-model-grid article:nth-child(1){animation-delay:0ms}.account-model-grid article:nth-child(2){animation-delay:25ms}.account-model-grid article:nth-child(3){animation-delay:50ms}.account-model-grid article:nth-child(4){animation-delay:75ms}.account-model-grid article:nth-child(5){animation-delay:.1s}.account-model-grid article:nth-child(6){animation-delay:125ms}.account-key-list>div{animation:slide-up .25s ease-out backwards}.account-key-list>div:nth-child(1){animation-delay:0ms}.account-key-list>div:nth-child(2){animation-delay:40ms}.account-key-list>div:nth-child(3){animation-delay:80ms}.one-time-secret{animation:scale-in .3s cubic-bezier(.34,1.25,.64,1)}.account-balance{animation:fade-in .4s ease-out .1s backwards}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.pulse-dot{animation:none}}.app-shell{--glass: linear-gradient(158deg, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, .64) 100%);--glass-border: rgba(255, 255, 255, .72);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .6), 0 1px 2px rgba(17, 24, 39, .04), 0 12px 34px rgba(17, 24, 39, .08);background:radial-gradient(1120px 620px at 6% -8%,rgba(0,122,255,.1),transparent 58%),radial-gradient(960px 560px at 102% 2%,rgba(48,176,199,.1),transparent 56%),radial-gradient(900px 760px at 50% 118%,rgba(255,149,0,.06),transparent 60%),var(--bg)}.app-shell[data-theme=dark]{--glass: linear-gradient(158deg, rgba(58, 58, 66, .72) 0%, rgba(28, 28, 34, .6) 100%);--glass-border: rgba(255, 255, 255, .1);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 2px 6px rgba(0, 0, 0, .3), 0 18px 44px rgba(0, 0, 0, .48);background:radial-gradient(1120px 620px at 6% -8%,rgba(10,132,255,.18),transparent 58%),radial-gradient(960px 560px at 102% 2%,rgba(48,176,199,.15),transparent 56%),radial-gradient(900px 760px at 50% 120%,rgba(120,88,255,.14),transparent 60%),var(--bg)}.account-page,.auth-page{--glass: linear-gradient(158deg, rgba(255, 255, 255, .94) 0%, rgba(255, 255, 255, .66) 100%);--glass-border: rgba(255, 255, 255, .75);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .65), 0 1px 2px rgba(17, 24, 39, .04), 0 16px 40px rgba(17, 24, 39, .09);background:radial-gradient(1080px 640px at 4% -10%,rgba(0,122,255,.12),transparent 56%),radial-gradient(940px 560px at 104% 4%,rgba(48,176,199,.1),transparent 54%),radial-gradient(880px 720px at 52% 120%,rgba(175,82,222,.07),transparent 60%),var(--bg)}.account-page[data-theme=dark],.auth-page[data-theme=dark]{--glass: linear-gradient(158deg, rgba(58, 58, 66, .7) 0%, rgba(24, 24, 30, .58) 100%);--glass-border: rgba(255, 255, 255, .12);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 2px 6px rgba(0, 0, 0, .35), 0 22px 52px rgba(0, 0, 0, .5);background:radial-gradient(1080px 640px at 4% -10%,rgba(10,132,255,.22),transparent 56%),radial-gradient(940px 560px at 104% 4%,rgba(48,176,199,.16),transparent 54%),radial-gradient(880px 720px at 52% 122%,rgba(175,82,222,.16),transparent 60%),var(--bg)}.metric,.panel,.account-section:not(.check-in-section),.settings-group,.model-card,.channel-card,.flow-panel,.hero-strip,.model-hero,.log-inspector,.source-guide-item{background:var(--glass);border:1px solid var(--glass-border);box-shadow:var(--glass-shadow);-webkit-backdrop-filter:blur(26px) saturate(185%);backdrop-filter:blur(26px) saturate(185%)}.app-shell[data-theme=dark] .metric,.app-shell[data-theme=dark] .panel,.app-shell[data-theme=dark] .settings-group,.app-shell[data-theme=dark] .model-card,.app-shell[data-theme=dark] .channel-card,.app-shell[data-theme=dark] .flow-panel,.app-shell[data-theme=dark] .hero-strip,.app-shell[data-theme=dark] .model-hero,.app-shell[data-theme=dark] .log-inspector,.app-shell[data-theme=dark] .source-guide-item{background:var(--glass);border-color:var(--glass-border);box-shadow:var(--glass-shadow)}.group-assign-row{display:grid;gap:6px;margin-top:4px;padding:12px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.group-assign-row label{display:grid;gap:6px;color:var(--muted);font-size:12px}.group-assign-row select{height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.group-assign-row select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.group-assign-row small{color:var(--muted);font-size:12px;line-height:1.5}.channel-group-field{display:grid;gap:8px;padding:12px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.channel-group-empty{color:var(--muted);font-size:13px;line-height:1.5}.channel-group-options{display:flex;flex-wrap:wrap;gap:8px}.channel-group-options button{display:grid;gap:2px;min-width:0;padding:8px 12px;color:var(--text);text-align:left;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;cursor:pointer}.channel-group-options button small{color:var(--muted)}.channel-group-options button.selected{border-color:color-mix(in srgb,var(--blue) 46%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 28%,transparent)}.app-shell[data-theme=dark] .group-assign-row select,.app-shell[data-theme=dark] .channel-group-options button,.app-shell[data-theme=dark] .group-edit-fields input{background:#7676801f;border-color:transparent}.group-edit-fields{display:grid;gap:8px}.group-edit-fields input{height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.group-edit-fields input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)} +:root{color:#1d1d1f;background:#f2f2f7;font-family:-apple-system,BlinkMacSystemFont,SF Pro Display,Segoe UI,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh}button,input,select,textarea{font:inherit}button{border:0}.app-shell select:not([multiple]){appearance:none;padding-right:38px!important;background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%)!important;background-position:calc(100% - 17px) 50%,calc(100% - 12px) 50%!important;background-size:5px 5px,5px 5px!important;background-repeat:no-repeat!important;cursor:pointer}.app-shell[data-theme=dark] select{color-scheme:dark}.app-shell[data-theme=dark] select option{color:#f5f5f7;background:#2c2c2e}.app-shell input[type=datetime-local],.app-shell input[type=date],.app-shell input[type=time]{color-scheme:dark}.app-shell input[type=datetime-local]::-webkit-calendar-picker-indicator,.app-shell input[type=date]::-webkit-calendar-picker-indicator,.app-shell input[type=time]::-webkit-calendar-picker-indicator{opacity:.72;cursor:pointer}.app-shell input[type=number]{appearance:textfield}.app-shell input[type=number]::-webkit-inner-spin-button,.app-shell input[type=number]::-webkit-outer-spin-button{margin:0;appearance:none}.app-shell{--bg: #f2f2f7;--surface: rgba(255, 255, 255, .78);--surface-solid: #ffffff;--group: #f4f5f7;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .12);--hairline-strong: rgba(60, 60, 67, .2);--blue: #007aff;--green: #34c759;--red: #ff3b30;--orange: #ff9500;--teal: #30b0c7;--shadow: 0 2px 8px rgba(0, 0, 0, .04), 0 12px 32px rgba(0, 0, 0, .06);--shadow-lg: 0 4px 12px rgba(0, 0, 0, .05), 0 20px 48px rgba(0, 0, 0, .1);--row-height: 58px;display:grid;grid-template-columns:264px 1fr;min-height:100vh;color:var(--text);background:var(--bg)}.app-shell[data-theme=dark]{--bg: #0a0a0c;--surface: rgba(22, 22, 26, .8);--surface-solid: #161618;--group: rgba(255, 255, 255, .04);--text: #f5f5f7;--muted: #8e8e93;--hairline: rgba(255, 255, 255, .06);--hairline-strong: rgba(255, 255, 255, .1);--shadow: 0 2px 8px rgba(0, 0, 0, .2), 0 12px 32px rgba(0, 0, 0, .25);--shadow-lg: 0 4px 12px rgba(0, 0, 0, .3), 0 24px 56px rgba(0, 0, 0, .4);background:var(--bg);color-scheme:dark}.app-shell[data-density=compact]{--row-height: 48px}.sidebar{position:sticky;top:0;height:100vh;padding:16px 14px;background:var(--surface-solid);border-right:1px solid var(--hairline);box-shadow:2px 0 12px #00000008}.app-shell[data-theme=dark] .sidebar{background:#111113;border-right-color:#ffffff0d;box-shadow:2px 0 16px #00000040}.ios-window-dots{display:flex;gap:7px;padding:4px 10px 18px;cursor:default}.ios-window-dots span{width:12px;height:12px;border-radius:50%;opacity:.85;transition:opacity .16s ease,transform .16s ease}.ios-window-dots:hover span{opacity:1}.ios-window-dots span:hover{transform:scale(1.18)}.ios-window-dots span:nth-child(1){background:#ff5f57}.ios-window-dots span:nth-child(2){background:#ffbd2e}.ios-window-dots span:nth-child(3){background:#28c840}.brand{display:flex;align-items:center;gap:12px;padding:0 10px 24px}.brand-mark{display:grid;place-items:center;width:42px;height:42px;color:#fff;background:#1d1d1f;border-radius:13px;font-weight:800;box-shadow:inset 0 1px #ffffff2e}.app-shell[data-theme=dark] .brand-mark{color:#fff;background:#76768033;border:0}.brand strong,.brand span{display:block}.brand span{margin-top:2px;color:var(--muted);font-size:13px}nav{display:grid;gap:6px}.nav-item{position:relative;display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:0 12px;color:var(--muted);background:transparent;border-radius:12px;cursor:pointer;text-align:left}.nav-item:hover{color:var(--text);background:var(--group)}.nav-item.active{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000000f,inset 0 0 0 1px var(--hairline)}.app-shell[data-theme=dark] .nav-item:hover{background:#ffffff0d}.app-shell[data-theme=dark] .nav-item.active{color:#fff;background:#ffffff14;box-shadow:0 1px 6px #0003,inset 0 0 0 1px #ffffff0f}.sidebar-footer{position:absolute;left:14px;right:14px;bottom:16px;display:flex;justify-content:space-between;align-items:center;min-height:44px;padding:0 12px;color:var(--muted);background:var(--group);border-radius:14px;font-size:13px}.sidebar-footer strong{display:inline-flex;align-items:center;gap:7px;color:var(--green)}.sidebar-footer .pulse-dot{width:7px;height:7px}.icon{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}.content{width:calc(100vw - 264px);padding:28px 30px 44px;background:var(--bg)}.topbar{position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;gap:18px;margin:-28px -30px 24px;padding:24px 30px 18px;background:color-mix(in srgb,var(--bg) 82%,transparent);border-bottom:1px solid var(--hairline);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.app-shell[data-theme=dark] .topbar{background:#000000d1;border-bottom-color:#ffffff14}.topbar-actions,.panel-toolbar,.setting-value{display:flex;align-items:center;gap:10px}.eyebrow{margin:0 0 5px;color:var(--muted);font-size:13px}h1,h2,h3,p{margin:0}h1{font-size:34px;line-height:1.08;letter-spacing:0}h2{font-size:18px;letter-spacing:0}h3{margin:6px 0 10px;font-size:14px;color:var(--muted)}.primary-button,.secondary-button,.danger-button,.icon-button,.theme-toggle{display:inline-flex;align-items:center;justify-content:center;min-height:38px;border-radius:999px;cursor:pointer;text-decoration:none}.primary-button{padding:0 18px;color:#fff;background:var(--blue);font-weight:700;box-shadow:0 2px 6px #007aff40;box-shadow:0 5px 14px color-mix(in srgb,var(--blue) 24%,transparent)}.secondary-button{padding:0 16px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline-strong);font-weight:650;box-shadow:0 1px 3px #0000000a}.danger-button{padding:0 16px;color:#d70015;background:color-mix(in srgb,var(--red) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--red) 28%,var(--hairline));font-weight:700}.compact-button{min-height:32px;padding:0 12px;font-size:13px}.icon-button{width:38px;color:var(--text);background:var(--group);border:1px solid var(--hairline)}.theme-toggle{gap:8px;padding:0 14px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline)}.app-shell[data-theme=dark] .secondary-button,.app-shell[data-theme=dark] .icon-button,.app-shell[data-theme=dark] .theme-toggle,.app-shell[data-theme=dark] .compact-button{background:#ffffff14;border-color:#ffffff1a;box-shadow:0 1px 4px #00000026}.primary-button:disabled,.secondary-button:disabled,.danger-button:disabled,.icon-button:disabled,.theme-toggle:disabled{cursor:not-allowed;opacity:.55}.muted-inline{color:var(--muted);font-size:13px}.status-button{display:inline-flex;justify-content:flex-start;padding:0;background:transparent;border:0;cursor:pointer}.segmented-control{display:inline-grid;grid-auto-flow:column;gap:2px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.app-shell[data-theme=dark] .segmented-control,.app-shell[data-theme=dark] .user-filter-row,.app-shell[data-theme=dark] .model-filter-actions,.app-shell[data-theme=dark] .log-status-filter,.app-shell[data-theme=dark] .settings-tabs,.app-shell[data-theme=dark] .registration-mode-control{background:#7676801f;border-color:transparent}.segmented-control button{min-width:54px;height:30px;padding:0 12px;color:var(--muted);background:transparent;border-radius:999px;cursor:pointer}.segmented-control button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.app-shell[data-theme=dark] .segmented-control button.selected,.app-shell[data-theme=dark] .user-filter-row button.selected,.app-shell[data-theme=dark] .model-filter-actions button.selected,.app-shell[data-theme=dark] .log-status-filter button.selected,.app-shell[data-theme=dark] .settings-tabs button.selected,.app-shell[data-theme=dark] .registration-mode-control button.selected{background:#ffffff1f;box-shadow:none}.page-stack{display:grid;gap:18px}.hero-strip{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:128px;padding:24px;background:var(--surface);border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.hero-strip span,.metric span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.hero-strip strong{display:block;font-size:22px;letter-spacing:0}.hero-strip p{max-width:620px;margin-top:8px;color:var(--muted);line-height:1.55}.live-island{display:inline-flex;align-items:center;gap:8px;min-width:92px;height:34px;padding:0 14px;color:#fff;background:#1d1d1f;border:1px solid var(--hairline);border-radius:999px;font-weight:700;box-shadow:inset 0 1px #ffffff29}.app-shell[data-theme=dark] .live-island{color:var(--muted);background:var(--group)}.hero-strip .live-island{margin-right:4px}.pulse-dot{width:9px;height:9px;background:var(--green);border-radius:50%;box-shadow:0 0 0 5px color-mix(in srgb,var(--green) 20%,transparent);animation:status-pulse 1.8s ease-out infinite}.quick-actions{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.quick-action{display:flex;align-items:center;justify-content:center;gap:9px;min-height:48px;padding:0 14px;color:var(--text);background:var(--surface);border:1px solid var(--hairline);border-radius:999px;cursor:pointer;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.quick-action:nth-child(1){color:var(--blue)}.quick-action:nth-child(2){color:var(--teal)}.quick-action:nth-child(3){color:var(--green)}.quick-action:nth-child(4){color:var(--orange)}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}.metric,.panel{background:var(--surface-solid);border:1px solid var(--hairline);box-shadow:var(--shadow)}.app-shell[data-theme=dark] .quick-action,.app-shell[data-theme=dark] .metric,.app-shell[data-theme=dark] .panel,.app-shell[data-theme=dark] .hero-strip,.app-shell[data-theme=dark] .flow-panel,.app-shell[data-theme=dark] .model-hero{background:var(--surface-solid);border-color:var(--hairline);box-shadow:var(--shadow)}.metric{min-height:118px;padding:18px;border-radius:22px}.metric strong{display:block;overflow:hidden;font-size:31px;letter-spacing:0;text-overflow:ellipsis;white-space:nowrap}.split-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}.flow-panel{display:grid;grid-template-columns:minmax(190px,.7fr) minmax(0,1.3fr);gap:18px;align-items:center;padding:18px;background:var(--surface);border:1px solid var(--hairline);border-radius:24px;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.flow-copy span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.flow-copy strong{display:block;font-size:20px;line-height:1.3}.flow-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.flow-step{position:relative;min-height:104px;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.flow-step:not(:last-child):after{content:"";position:absolute;top:50%;right:-10px;width:10px;height:1px;background:var(--hairline-strong)}.flow-index{display:grid;place-items:center;width:28px;height:28px;margin-bottom:12px;color:#fff;background:var(--blue);border-radius:50%;font-size:13px;font-weight:800}.flow-step strong,.flow-step span{display:block}.flow-step span{margin-top:4px;color:var(--muted);font-size:13px}.panel{padding:20px;border-radius:20px;min-width:0}.app-shell[data-theme=dark] .panel{border-radius:18px}.panel-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding:0 2px}.panel-title h2{font-size:17px;font-weight:700}.app-shell[data-theme=dark] .panel-title{padding-bottom:14px;border-bottom:1px solid rgba(255,255,255,.06)}.list-row,.setting{display:flex;align-items:center;justify-content:space-between;gap:14px;min-height:var(--row-height);padding:10px 2px;border-top:1px solid var(--hairline)}.list-row:first-of-type,.setting:first-child{border-top:0}.list-row>div,.setting>div{min-width:0}.row-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:8px;flex-shrink:0}.list-row strong,.list-row span,.setting span,.setting strong,.table-row span,.table-row strong,.table-row small{min-width:0}.list-row strong,.list-row span{display:block}.list-row span,.table-row small{margin-top:3px;color:var(--muted);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overview-channel-row>div{flex:1 1 auto;overflow:hidden}.overview-channel-row>.badge{flex:0 0 auto;min-width:54px;overflow:visible}.badge{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:54px;height:27px;padding:0 11px;color:var(--muted);background:var(--group);border-radius:999px;font-size:12px;font-weight:650;letter-spacing:.01em;white-space:nowrap}.app-shell[data-theme=dark] .badge{background:#76768024;border:0}.badge.tone-active:before,.badge.tone-healthy:before,.badge.tone-available:before,.badge.tone-success:before,.badge.tone-disabled:before,.badge.tone-failed:before,.badge.tone-limited:before,.badge.tone-overdue:before,.badge.tone-standby:before{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;background:currentColor;flex:0 0 auto}.tone-active,.tone-healthy,.tone-available,.tone-success{color:#118446;background:color-mix(in srgb,var(--green) 16%,transparent)}.tone-disabled,.tone-failed{color:#d70015;background:color-mix(in srgb,var(--red) 14%,transparent)}.tone-limited,.tone-overdue,.tone-standby{color:#a05a00;background:color-mix(in srgb,var(--orange) 15%,transparent)}.users-layout{display:grid;grid-template-columns:minmax(780px,1.55fr) minmax(380px,.7fr);gap:18px;align-items:start}.users-layout .panel:first-child{padding:14px}.users-layout .panel:first-child .table{background:transparent;border:0;border-radius:0;gap:8px}.users-layout .panel:first-child .table-head{min-height:34px;padding:0 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-head{background:#7676801a;border-color:transparent}.users-layout .panel:first-child .table-row{min-height:56px;padding:0 14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:16px}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row{background:#1c1c1ec7;border-color:#ffffff0d}.users-layout .panel:first-child .table-row:hover{background:var(--group)}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row:hover{background:#2c2c2ee0}.users-layout .panel:first-child .table-row.selected{border-color:color-mix(in srgb,var(--blue) 45%,var(--hairline));box-shadow:inset 3px 0 0 var(--blue)}.app-shell[data-theme=dark] .users-layout .panel:first-child .table-row.selected{background:#76768029;border-color:transparent;box-shadow:none}.user-summary-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:12px}.user-summary-strip span{min-height:50px;padding:10px 12px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:14px;font-size:13px}.user-summary-strip strong{display:block;color:var(--text);font-size:20px}.user-filter-row{display:flex;gap:4px;width:fit-content;margin-bottom:12px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.user-filter-row button{min-height:30px;padding:0 13px;color:var(--muted);background:transparent;border-radius:999px;cursor:pointer;font-weight:700}.user-filter-row button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.mobile-bulk-select{display:none;margin-bottom:12px}.bulk-action-bar{display:grid;grid-template-columns:auto 100px minmax(160px,1fr) auto auto auto minmax(130px,auto) auto;align-items:center;gap:8px;margin-bottom:12px;padding:10px;background:color-mix(in srgb,var(--blue) 8%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 25%,var(--hairline));border-radius:12px}.bulk-group-select{min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.bulk-group-select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.app-shell[data-theme=dark] .bulk-group-select{background:#7676801f;border-color:transparent}.auth-default-balance select{min-width:0;width:180px;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.auth-default-balance select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.app-shell[data-theme=dark] .auth-default-balance select{background:#7676801f;border-color:transparent}.bulk-action-bar input,.auth-default-balance input{min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.bulk-action-bar input:focus,.auth-default-balance input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.pagination-bar{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:12px;color:var(--muted);font-weight:700}.models-page{display:grid;gap:18px;width:100%}.model-hero{padding:18px 22px;background:var(--surface);border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.model-hero span{display:block;margin-bottom:8px;color:var(--muted);font-size:13px}.model-hero strong{display:block;font-size:24px;line-height:1.3}.model-hero p{margin-top:8px;color:var(--muted)}.model-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.model-list{display:grid;gap:10px}.model-list-toolbar{justify-content:space-between;align-items:center}.model-list-toolbar input{flex:1 1 460px;width:auto;max-width:720px;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-list-toolbar input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-filter-actions{display:inline-flex;gap:6px;padding:4px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.model-filter-actions button{height:32px;padding:0 12px;color:var(--muted);background:transparent;border:0;border-radius:999px}.model-filter-actions button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.model-provider-filter{display:flex;gap:8px;margin:14px 0;padding-bottom:2px;overflow-x:auto;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 45%,transparent) transparent}.model-provider-filter button{display:grid;grid-template-columns:34px minmax(0,1fr) auto;align-items:center;gap:10px;flex:0 0 240px;min-height:58px;padding:10px;color:var(--text);text-align:left;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.model-provider-filter button.selected{background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 46%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 28%,transparent)}.app-shell[data-theme=dark] .model-provider-filter button.selected,.app-shell[data-theme=dark] .provider-chip-grid button.selected,.app-shell[data-theme=dark] .stream-mode-grid button.selected{background:#ffffff1f;border-color:transparent;box-shadow:none}.model-provider-filter strong,.model-provider-filter small{display:block;min-width:0}.model-provider-filter strong{overflow-wrap:anywhere}.model-provider-filter small{color:var(--muted);font-weight:800}.provider-icon-all{display:grid;place-items:center;flex:0 0 38px;width:38px;height:38px;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.02em;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 26%,var(--hairline));border-radius:10px}.model-list-summary{display:inline-flex;align-items:baseline;gap:6px;margin-bottom:10px;color:var(--muted);font-size:13px}.model-list-summary strong{color:var(--text);font-size:20px}.model-provider-groups{display:grid;gap:14px}.model-provider-group{overflow:hidden;border:1px solid var(--hairline);border-radius:14px}.model-provider-group>header{display:flex;align-items:center;gap:10px;min-height:58px;padding:9px 12px;background:var(--group);border-bottom:1px solid var(--hairline)}.model-provider-group>header div{display:grid;gap:2px}.model-provider-group>header span{color:var(--muted);font-size:12px}.provider-icon,.provider-icon svg{display:block;width:38px;height:38px;flex:0 0 38px}.provider-icon svg rect{fill:var(--surface-solid);stroke:var(--hairline)}.provider-icon svg text{fill:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:17px;font-weight:800}.provider-icon svg path{fill:currentColor}.provider-icon-google svg text{fill:#4285f4}.provider-icon-openai{color:var(--text)}.provider-icon-deepseek,.provider-icon-deepseek svg,.provider-icon-deepseek svg path{color:#4d6bfe;fill:#4d6bfe}.provider-icon-openrouter svg text{fill:#ef4444}.provider-icon-groq svg text{fill:#f55036}.provider-icon-moonshot svg text{fill:#16a34a}.model-compact-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr))}.model-compact-row{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;gap:9px;min-width:0;min-height:78px;padding:12px;border-bottom:1px solid var(--hairline)}.model-compact-row:last-child{border-bottom:0}.model-compact-main{min-width:0}.model-compact-main strong,.model-compact-main small{display:block;min-width:0;overflow-wrap:anywhere}.model-compact-main small{margin-top:3px;color:var(--muted);font-size:12px;line-height:1.35}.model-compact-main span{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}.model-compact-main em{max-width:120px;overflow:hidden;padding:3px 7px;color:var(--muted);font-size:11px;font-style:normal;text-overflow:ellipsis;white-space:nowrap;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:999px}.model-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:0;flex-wrap:wrap}.model-row-actions .compact-button{min-height:32px;padding-inline:11px}.model-row-actions{gap:6px}.model-row-actions .icon-button{width:32px;min-height:32px;color:var(--muted);background:transparent;border-color:transparent}.model-recommended-mark{padding:4px 8px;color:var(--orange);background:color-mix(in srgb,var(--orange) 10%,transparent);border-radius:999px;font-size:11px;font-weight:700}.model-row-menu{position:relative}.model-row-menu>summary{width:32px;min-height:32px;color:var(--muted);line-height:27px;text-align:center;letter-spacing:1px;list-style:none;background:transparent;border:1px solid transparent;border-radius:10px;cursor:pointer}.model-row-menu>summary::-webkit-details-marker{display:none}.model-row-menu>summary:hover{color:var(--text);background:var(--group)}.model-row-menu>div{position:absolute;right:0;bottom:calc(100% + 6px);z-index:8;display:grid;width:max-content;gap:2px;padding:6px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:var(--shadow)}.model-row-menu button{min-height:34px;padding:0 10px;color:var(--text);text-align:left;background:transparent;border:0;border-radius:8px;cursor:pointer;font-size:13px}.model-row-menu button:hover{background:var(--group)}.model-row-menu button.is-danger{color:var(--red)}.model-row-menu button.is-danger:hover{background:color-mix(in srgb,var(--red) 10%,var(--surface-solid))}.settings-tabs{display:flex;flex-wrap:wrap;width:fit-content;max-width:100%;padding:4px;gap:2px;overflow-x:auto;background:var(--group);border-radius:14px}.settings-tabs button{display:inline-flex;flex:0 0 auto;align-items:center;min-height:34px;padding:0 12px;border-radius:10px}.settings-tabs button small{display:none}.settings-tab-note{display:flex;align-items:baseline;gap:8px;min-height:18px;color:var(--muted);font-size:13px}.settings-tab-note strong{color:var(--text);font-size:14px}.logs-table{grid-template-columns:minmax(280px,1.55fr) minmax(220px,1fr) minmax(180px,.9fr) 82px}.logs-layout{display:block}.log-entry .table-row{min-height:58px}.log-entry .table-row>span:nth-child(2),.log-entry .table-row>span:nth-child(3){overflow:hidden;color:var(--muted);text-overflow:ellipsis;white-space:nowrap}.log-inspector{position:relative;top:auto;grid-template-columns:minmax(220px,.8fr) minmax(0,1.6fr) auto;align-items:start;margin-top:14px;padding:16px;border-radius:16px}.log-inspector header{padding:6px 14px 6px 0;border-right:1px solid var(--hairline);border-bottom:0}.log-detail{grid-template-columns:repeat(4,minmax(0,1fr))}.log-detail>div{padding:9px 10px;border-radius:10px}.log-actions{align-self:center;justify-content:flex-end}@media(max-width:980px){.log-inspector{grid-template-columns:1fr}.log-inspector header{padding:0 0 12px;border-right:0;border-bottom:1px solid var(--hairline)}.log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}}.logs-layout.has-detail{display:grid;grid-template-columns:minmax(0,1.65fr) minmax(360px,.75fr);gap:14px;align-items:start}.logs-layout.has-detail .log-inspector{position:sticky;top:92px;display:grid;grid-template-columns:1fr;margin-top:0;padding:16px}.logs-layout.has-detail .log-inspector header{padding:0 0 12px;border-right:0;border-bottom:1px solid var(--hairline)}.logs-layout.has-detail .log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}@media(max-width:980px){.logs-layout.has-detail{grid-template-columns:1fr}.logs-layout.has-detail .log-inspector{position:static}}@media(max-width:720px){.settings-tabs{flex-wrap:nowrap;width:100%}.settings-tab-note{align-items:flex-start;flex-direction:column;gap:2px}}.pager{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:12px}.pager span{color:var(--muted);font-size:13px;font-weight:700}.model-create-form{display:grid;grid-template-columns:repeat(3,minmax(0,1fr)) auto;gap:10px;align-items:center}.model-create-form input,.model-create-form select{width:100%;min-width:0;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-create-form select{appearance:none}.model-create-form input:focus,.model-create-form select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-create-wide{grid-column:span 2}.model-create-message{grid-column:1 / -1;min-height:18px;color:#ff3b30;font-size:13px}.drawing-channel-models{display:flex;flex-wrap:wrap;gap:8px}.drawing-channel-models span{max-width:100%;padding:7px 10px;color:var(--muted);font-size:12px;font-weight:750;background:var(--group);border:1px solid var(--hairline);border-radius:999px;overflow-wrap:anywhere}.model-card{display:grid;gap:12px;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.model-card.featured{min-height:210px}.model-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.model-card-head strong,.model-card-head span{display:block}.model-card-head span{margin-top:4px;color:var(--muted);font-size:13px}.model-card p{color:var(--muted);line-height:1.55}.model-card-actions{display:flex;justify-content:flex-end;gap:8px}.alias-row,.model-meta{display:flex;flex-wrap:wrap;gap:8px}.alias-row span,.model-meta span{display:inline-flex;align-items:center;min-height:28px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px;font-weight:700}.model-meta span{color:var(--muted);font-weight:650}.model-id{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;padding:0 0 0 12px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.model-id code{overflow:hidden;color:var(--text);text-overflow:ellipsis;white-space:nowrap}.panel-toolbar{margin-bottom:12px}.search-box{display:flex;align-items:center;gap:8px;width:100%;height:42px;padding:0 13px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px}.app-shell[data-theme=dark] .search-box,.app-shell[data-theme=dark] .model-list-toolbar input,.app-shell[data-theme=dark] .model-create-form input,.app-shell[data-theme=dark] .model-create-form select,.app-shell[data-theme=dark] .channel-form-grid input,.app-shell[data-theme=dark] .channel-form-grid textarea,.app-shell[data-theme=dark] .channel-editor input,.app-shell[data-theme=dark] .provider-picker-trigger,.app-shell[data-theme=dark] .key-editor-grid input,.app-shell[data-theme=dark] .settings-form-grid input,.app-shell[data-theme=dark] .settings-form-grid textarea,.app-shell[data-theme=dark] .maintenance-control input,.app-shell[data-theme=dark] .bulk-action-bar input,.app-shell[data-theme=dark] .auth-default-balance input{background:#7676801f;border-color:transparent}.search-box input{width:100%;border:0;outline:0;background:transparent;color:var(--text)}.search-box input::placeholder{color:var(--muted)}.table{display:grid;overflow:hidden;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .table{background:#1c1c1eb8;border-color:#ffffff0d}.table:has(.channel-editor){overflow:visible}.table-head,.table-row{display:grid;gap:12px;align-items:center;min-height:var(--row-height);padding:0 14px;text-align:left}.table-head{color:var(--muted);font-size:12px;font-weight:700;background:var(--group);border-bottom:1px solid var(--hairline)}.app-shell[data-theme=dark] .table-head{background:#7676801a;border-bottom-color:#ffffff0d}.table-row{width:100%;color:var(--text);background:transparent;border-bottom:1px solid var(--hairline)}.app-shell[data-theme=dark] .table-row{border-bottom-color:#ffffff0d}.table-row small{display:block}.table-row:last-child{border-bottom:0}button.table-row{cursor:pointer}button.table-row:hover{background:var(--group)}.app-shell[data-theme=dark] button.table-row:hover,.app-shell[data-theme=dark] .log-entry .table-row:hover,.app-shell[data-theme=dark] .log-entry .table-row.selected{background:#7676801f}.users-table{grid-template-columns:22px minmax(220px,1fr) 86px minmax(120px,.45fr) 68px}.users-table>span:nth-child(4),.users-table>span:nth-child(5){justify-self:end;text-align:right}.users-table.table-row>span:nth-child(4){max-width:100%;overflow:hidden;font-variant-numeric:tabular-nums;text-overflow:ellipsis}.users-table>input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--blue);cursor:pointer}.channels-table{grid-template-columns:minmax(220px,1.4fr) 90px 64px minmax(150px,.8fr) minmax(240px,1fr)}.channels-stack{display:grid;gap:14px}.channel-create-form{margin-bottom:14px}.channel-create-form .channel-form-grid{grid-template-columns:1fr 1fr;gap:14px}.channel-create-form .channel-form-wide{grid-column:1 / -1}.channel-card{display:grid;gap:14px;padding:16px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .channel-card,.app-shell[data-theme=dark] .model-card,.app-shell[data-theme=dark] .log-inspector,.app-shell[data-theme=dark] .settings-group,.app-shell[data-theme=dark] .provider-picker-menu{background:#1c1c1eb8;border-color:#ffffff0f}.channel-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.channel-card-head>div:first-child{min-width:0}.channel-card-head-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;flex-shrink:0}.channel-card-head strong,.channel-card-head span{display:block}.channel-card-head span{margin-top:4px;color:var(--muted);font-size:13px}.channel-card-head small{display:block;max-width:100%;margin-top:6px;color:var(--muted);font-size:12px;line-height:1.45;overflow-wrap:anywhere}.provider-chip-grid{display:flex;flex-wrap:wrap;gap:8px}.provider-chip-grid button{min-height:34px;padding:0 12px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;cursor:pointer;font-weight:750}.provider-chip-grid button.selected{color:var(--text);background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 42%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 30%,transparent)}.stream-mode-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}.stream-mode-grid button{display:grid;gap:3px;min-height:58px;padding:9px 11px;color:var(--muted);text-align:left;background:var(--group);border:1px solid var(--hairline);border-radius:14px;cursor:pointer}.stream-mode-grid button strong{color:var(--text);font-size:14px}.stream-mode-grid button span{overflow:hidden;font-size:12px;text-overflow:ellipsis;white-space:nowrap}.stream-mode-grid button.selected{background:var(--surface-solid);border-color:color-mix(in srgb,var(--blue) 42%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 30%,transparent)}.app-shell[data-theme=dark] .provider-chip-grid button.selected,.app-shell[data-theme=dark] .stream-mode-grid button.selected{background:#ffffff1f;border-color:transparent;box-shadow:none}.channel-form-grid{display:grid;grid-template-columns:1.4fr .5fr .7fr;gap:12px}.channel-form-grid label{display:grid;min-width:0;gap:7px;color:var(--muted);font-size:13px;font-weight:700}.channel-model-field{display:grid;min-width:0;gap:7px}.field-label-row{display:flex;align-items:center;justify-content:space-between;gap:10px;color:var(--muted);font-size:13px;font-weight:700}.field-label-row small{font-size:12px;font-weight:700}.field-label-row .model-pull-button{min-height:28px;padding:0 12px;color:var(--blue);background:color-mix(in srgb,var(--blue) 10%,transparent);border:1px solid color-mix(in srgb,var(--blue) 26%,transparent);border-radius:999px;font-size:12.5px;font-weight:650;white-space:nowrap;cursor:pointer;transition:background .12s ease,transform .1s ease}.field-label-row .model-pull-button:hover{background:color-mix(in srgb,var(--blue) 16%,transparent)}.field-label-row .model-pull-button:active{transform:scale(.97)}.channel-form-wide{grid-column:span 2}.channel-billing-note{grid-column:1 / -1;color:var(--muted);font-size:12px}.channel-form-grid input,.channel-form-grid textarea{width:100%;min-width:0;min-height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.channel-form-grid textarea{min-height:72px;padding:10px 12px;resize:vertical;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.channel-form-grid input:focus,.channel-form-grid textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.channel-model-actions{display:flex;flex-wrap:wrap;gap:8px}.channel-card-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:10px}.channel-card-actions .model-create-message{flex:1;min-width:180px}.channel-editor{align-items:start;padding-block:12px}.channel-editor input,.provider-picker-trigger{width:100%;min-width:0;height:36px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.provider-picker{position:relative;z-index:2}.provider-picker-trigger{display:grid;grid-template-columns:minmax(0,1fr) 12px;align-items:center;gap:8px;text-align:left;cursor:pointer}.provider-picker-trigger span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.provider-picker-trigger i{width:7px;height:7px;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:translateY(-2px) rotate(45deg)}.provider-picker-menu{position:absolute;top:calc(100% + 6px);left:0;display:grid;width:min(240px,70vw);max-height:280px;padding:6px;overflow:auto;background:color-mix(in srgb,var(--surface-solid) 94%,transparent);border:1px solid var(--hairline);border-radius:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.provider-picker-menu button{min-height:34px;padding:0 10px;color:var(--text);background:transparent;border-radius:9px;text-align:left;cursor:pointer}.provider-picker-menu button:hover,.provider-picker-menu button.selected{background:var(--group)}.provider-picker-menu button.selected{color:var(--blue);font-weight:800}.channel-editor strong{display:block;margin-bottom:8px}.channel-actions{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;align-items:center}.logs-table{grid-template-columns:minmax(210px,1.35fr) minmax(170px,1fr) minmax(150px,.9fr) 78px 78px 86px 80px}.logs-layout{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(420px,.75fr);gap:14px;align-items:start}.logs-toolbar{display:grid;grid-template-columns:minmax(260px,1fr) auto auto;align-items:center;gap:12px;margin-bottom:14px}.log-status-filter{display:flex;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:10px}.log-status-filter button{min-height:32px;padding:0 12px;color:var(--muted);background:transparent;border-radius:7px;cursor:pointer}.log-status-filter button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 3px #0000001f}.log-entry+.log-entry{border-top:1px solid var(--hairline)}.log-entry .table-row{border:0;cursor:pointer}.log-entry .table-row:hover,.log-entry .table-row.selected{background:var(--group)}.log-inspector{position:sticky;top:92px;display:grid;gap:14px;min-width:0;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.app-shell[data-theme=dark] .flow-step{background:#7676801a;border-color:transparent}.log-inspector header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid var(--hairline)}.log-inspector header div{display:grid;gap:4px;min-width:0}.log-inspector header span,.empty-inspector{color:var(--muted);font-size:13px}.app-shell[data-theme=dark] .sidebar-footer{background:#7676801f;border:0}.log-inspector header strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.empty-inspector{min-height:180px;place-items:center}.log-detail{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.log-detail>div{display:grid;gap:5px;min-width:0;padding:12px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.app-shell[data-theme=dark] .log-detail>div,.app-shell[data-theme=dark] .user-summary-strip span,.app-shell[data-theme=dark] .model-provider-group,.app-shell[data-theme=dark] .model-provider-filter button,.app-shell[data-theme=dark] .model-id,.app-shell[data-theme=dark] .alias-row span,.app-shell[data-theme=dark] .model-meta span{background:#7676801a;border-color:transparent}.log-detail span{color:var(--muted);font-size:12px}.log-detail strong{overflow:hidden;font-size:13px;text-overflow:ellipsis;white-space:nowrap}.log-actions{display:flex;justify-content:flex-end;gap:8px}.detail-stack{display:grid;gap:14px}.user-hero{display:grid;grid-template-columns:52px 1fr auto;align-items:center;gap:12px;padding:4px 2px 16px;border-bottom:1px solid var(--hairline)}.user-hero h2{margin-bottom:3px;font-size:21px}.user-hero p{color:var(--muted);font-size:13px}.avatar{display:grid;place-items:center;width:52px;height:52px;color:#fff;background:var(--blue);border-radius:50%;font-weight:800;box-shadow:inset 0 1px #ffffff4d}.settings-group{overflow:hidden;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:16px;padding:4px 16px;box-shadow:0 1px 3px #0000000a}.app-shell[data-theme=dark] .settings-group{box-shadow:0 1px 2px #0003}.registration-mode-control{display:inline-grid;grid-auto-flow:column;gap:3px;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.registration-mode-control button{min-width:74px;height:30px;padding:0 10px;color:var(--muted);background:transparent;border-radius:999px;font-weight:700;cursor:pointer}.registration-mode-control button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.settings-layout{display:grid;gap:20px}.settings-tabs{display:flex;flex-wrap:wrap;gap:6px;width:fit-content;max-width:100%;padding:5px;overflow-x:auto;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.settings-tabs button{display:flex;align-items:center;gap:6px;min-width:0;min-height:40px;padding:0 14px;color:var(--muted);text-align:left;background:transparent;border-radius:11px;cursor:pointer;transition:color .14s ease,background .14s ease,box-shadow .14s ease}.settings-tabs button:hover:not(.selected){color:var(--text);background:color-mix(in srgb,var(--surface-solid) 50%,transparent)}.settings-tabs button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f}.settings-tabs strong,.settings-tabs small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.settings-tabs strong{font-size:13px;font-weight:700}.settings-tabs small,.settings-tab-note{display:none}.discord-settings{display:grid;gap:18px}.discord-toggle-row,.settings-save-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.discord-toggle-row{min-height:56px;padding:0 2px 16px;border-bottom:1px solid var(--hairline)}.discord-toggle-row strong,.discord-toggle-row span{display:block}.discord-toggle-row span,.settings-save-row span{margin-top:3px;color:var(--muted);font-size:13px}.backup-actions label{display:inline-flex;align-items:center;cursor:pointer}.backup-actions input{display:none}.channel-import-actions{display:flex;align-items:center;flex-wrap:wrap;gap:10px}.channel-import-actions label{cursor:pointer}.channel-import-actions input,.channel-card-actions input[type=file]{display:none}.account-pool-list{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));margin-top:14px}.account-filter-bar{display:flex;flex-wrap:wrap;gap:7px;margin:10px 0 2px}.account-filter-bar button{padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--muted);cursor:pointer;font:inherit;font-size:12px}.account-filter-bar input{min-width:180px;flex:1 1 220px;padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--text);font:inherit;font-size:12px}.account-filter-bar select{padding:5px 9px;border:1px solid var(--hairline);border-radius:999px;background:var(--control, var(--group));color:var(--text);font:inherit;font-size:12px}.app-shell[data-theme=dark] .account-filter-bar select,.app-shell[data-theme=dark] .account-filter-bar input{background:#7676802e;border-color:#ffffff1a;color:#f5f5f7}.account-filter-bar button.selected{border-color:var(--accent);color:var(--accent)}.channel-capability-tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:5px}.channel-capability-tags span{padding:2px 7px;border:1px solid var(--hairline);border-radius:999px;color:var(--muted);font-size:11px}.account-pool-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:12px;padding:10px 12px;border:1px solid var(--hairline);border-radius:12px;background:var(--control)}.account-pool-main{display:grid;gap:8px;min-width:0}.account-pool-main>div{display:grid;gap:3px;min-width:0}.account-pool-title{display:flex;align-items:center;gap:8px;min-width:0}.account-pool-title strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.account-pool-main>div>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:12px}.account-pool-meta{display:flex;flex-shrink:0;align-items:center;gap:8px;justify-content:flex-end}.account-pool-more{display:flex;align-items:center;justify-content:space-between;gap:12px;grid-column:1 / -1;padding:6px 2px 0}.account-pool-more-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.account-pool-more-actions .secondary-button{flex-shrink:0}.quota-bars{display:grid;gap:6px}.quota-bar{display:grid;gap:4px}.quota-bar-label{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px}.quota-bar-label strong{color:var(--text)}.quota-bar-track{height:5px;overflow:hidden;border-radius:999px;background:var(--hairline)}.quota-bar-track span{display:block;height:100%;border-radius:inherit;background:var(--green)}.key-editor{display:grid;gap:14px;padding:16px;border:1px solid var(--hairline);border-radius:22px;background:var(--surface-solid)}.app-shell[data-theme=dark] .key-editor{background:#1c1c1eb8;border-color:#ffffff0f}.key-editor+.key-editor{margin-top:12px}.key-editor-collapsible{gap:0;padding:0;overflow:hidden;border-radius:16px}.key-editor-collapsible[open]{gap:0}.key-editor-collapsible>summary{min-height:74px;padding:14px 16px;cursor:pointer;list-style:none}.key-editor-collapsible>summary::-webkit-details-marker{display:none}.key-editor-collapsible[open]>summary{border-bottom:1px solid var(--hairline)}.key-editor-body{display:grid;gap:14px;padding:16px}.key-expand-hint{padding:5px 10px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px}.key-editor-collapsible[open] .key-expand-hint:after{content:"中"}.key-editor-head{display:flex;align-items:center;justify-content:space-between;gap:16px}.key-editor-head strong,.key-editor-head span{display:block}.key-editor-head span{margin-top:4px;color:var(--muted);font-size:13px}.key-editor-grid{display:grid;grid-template-columns:minmax(160px,.8fr) minmax(240px,1.4fr) minmax(180px,1fr) minmax(140px,.8fr);gap:12px}.key-editor-grid label{display:grid;gap:7px;color:var(--muted);font-size:13px}.key-editor-grid input{width:100%;min-width:0;height:40px;padding:0 12px;color:var(--text);color-scheme:dark;background:var(--group);border:1px solid var(--hairline);border-radius:14px;outline:none}.key-editor-grid input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.key-editor-grid input::placeholder{color:var(--muted);opacity:.72}.key-editor-actions{display:flex;gap:8px;justify-content:flex-end}.settings-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.settings-form-grid label{display:grid;min-width:0;gap:7px;color:var(--muted);font-size:13px}.settings-form-grid input{width:100%;min-width:0;height:44px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.settings-form-grid input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-form-grid textarea{width:100%;min-width:0;min-height:88px;padding:10px 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none;resize:vertical;font:inherit;line-height:1.5;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.settings-form-grid textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-form-grid small{color:var(--muted);font-size:12px;line-height:1.45}.settings-form-grid input::placeholder{color:var(--muted);opacity:.72}.settings-form-wide{grid-column:1 / -1}.settings-save-row{min-height:44px}.settings-save-row .primary-button:disabled{cursor:wait;opacity:.58}.setting{min-height:52px}.setting span{color:var(--muted);font-size:14px}.setting-value{display:flex;align-items:center;gap:10px}.setting-value strong{color:var(--text);font-size:14px;font-weight:600}.setting>span small{display:block;margin-top:3px;color:var(--muted);font-size:12px}.auth-default-balance input{width:130px}.check-in-settings-row{align-items:center}.check-in-reward-inputs{display:grid;grid-template-columns:repeat(2,120px);gap:10px}.check-in-reward-inputs label{display:grid;gap:5px;color:var(--muted);font-size:12px}.check-in-reward-inputs input{width:100%;height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.check-in-reward-inputs input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.maintenance-control input{width:150px;height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.maintenance-control input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.settings-save-row{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:12px;border-top:1px solid var(--hairline)}.settings-save-row span{margin-right:auto;color:var(--muted);font-size:13px}.ios-switch{position:relative;flex:0 0 auto;width:49px;height:30px;padding:2px;background:#d1d1d6;border-radius:999px;cursor:pointer;transition:background .16s ease}.ios-switch span{display:block;width:26px;height:26px;margin:0;background:#fff;border-radius:50%;box-shadow:0 2px 5px #0000003d;transition:transform .16s ease}.ios-switch.is-on{background:var(--green)}.ios-switch.is-on span{transform:translate(19px)}.action-row{display:flex;flex-wrap:wrap;gap:10px}.balance-adjuster{display:grid;gap:12px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.balance-adjuster-title,.balance-adjuster-actions{display:flex;align-items:center;gap:10px}.balance-adjuster-title{justify-content:space-between}.balance-adjuster-title span,.balance-adjuster-actions span,.balance-adjuster-fields label>span{color:var(--muted);font-size:12px}.balance-adjuster-fields{display:grid;grid-template-columns:110px minmax(0,1fr);gap:10px}.balance-adjuster-fields label{display:grid;gap:6px}.balance-adjuster-fields input{width:100%;min-width:0;height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.balance-adjuster-fields input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.balance-adjuster-actions span{min-width:0;overflow-wrap:anywhere}.empty{display:grid;place-items:center;min-height:160px;color:var(--muted);background:var(--group);border:1px dashed var(--hairline-strong);border-radius:18px}.toast{position:fixed;left:50%;bottom:28px;transform:translate(-50%);padding:10px 14px;color:#fff;background:#1d1d1feb;border-radius:999px;font-size:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.secret-dialog-backdrop{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:20px;background:#0000006b;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.secret-dialog{display:grid;gap:18px;width:min(520px,100%);padding:22px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px;box-shadow:var(--shadow)}.secret-dialog>p{color:var(--muted);line-height:1.55}.secret-dialog code{overflow-x:auto;padding:13px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;white-space:nowrap}.secret-dialog-actions{display:flex;justify-content:flex-end;gap:10px}.auth-page,.account-page{--bg: #f2f2f7;--surface-solid: #ffffff;--group: #f9f9fb;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .16);--blue: #007aff;--green: #34c759;--shadow: 0 18px 45px rgba(0, 0, 0, .08);min-height:100vh;color:var(--text);background:var(--bg)}.auth-page[data-theme=dark],.account-page[data-theme=dark]{--bg: #000000;--surface-solid: #1c1c1e;--group: #2c2c2e;--text: #f5f5f7;--muted: #a1a1aa;--hairline: rgba(255, 255, 255, .12);--shadow: 0 24px 60px rgba(0, 0, 0, .36)}.auth-topbar,.account-topbar{display:flex;align-items:center;justify-content:space-between;width:min(1120px,calc(100% - 40px));min-height:76px;margin:0 auto;border-bottom:1px solid var(--hairline)}.auth-brand{display:inline-flex;align-items:center;gap:10px;padding:0;color:var(--text);background:transparent;cursor:pointer}.auth-brand .brand-mark{width:36px;height:36px;border-radius:10px}.auth-stage{display:grid;grid-template-columns:minmax(0,.9fr) minmax(360px,1fr);align-items:start;width:min(920px,calc(100% - 40px));gap:72px;margin:0 auto;padding:72px 0}.auth-intro{padding-top:24px}.auth-intro>span{color:var(--blue);font-size:13px;font-weight:700}.auth-intro h1{margin:10px 0 14px;font-size:42px}.auth-intro p{max-width:390px;color:var(--muted);line-height:1.65}.auth-form{display:grid;gap:15px;padding:24px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px;box-shadow:var(--shadow)}.auth-form label{display:grid;gap:7px;color:var(--muted);font-size:13px}.auth-form input,.auth-form select{width:100%;height:46px;padding:0 12px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:14px;outline:none}[data-theme=dark] .auth-form input,[data-theme=dark] .auth-form select{color-scheme:dark;background:var(--group)}.auth-form input:focus,.auth-form select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.setup-options{display:grid;gap:12px;padding:14px;border:1px solid var(--hairline);border-radius:18px;background:var(--group)}.setup-options .setting{padding:0;border:0}.setup-options label{gap:7px}.auth-message{min-height:18px;color:#ff3b30;font-size:13px}.auth-submit,.discord-login-button{min-height:44px;width:100%}.auth-submit:disabled{cursor:wait;opacity:.58}.discord-login-button{display:grid;place-items:center;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-weight:700;text-decoration:none}.auth-discord-register{display:grid;gap:10px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.auth-discord-register span{color:var(--muted);font-size:13px;line-height:1.5}.auth-switch{display:flex;justify-content:center}.auth-switch button{padding:6px 10px;color:var(--blue);background:transparent;cursor:pointer}.account-actions,.account-section-title,.account-heading{display:flex;align-items:center;justify-content:space-between;gap:14px}.account-section-title>div{display:grid;gap:3px}.account-content{display:grid;width:min(1120px,calc(100% - 40px));gap:18px;margin:0 auto;padding:42px 0 72px}.account-heading{padding-bottom:18px;border-bottom:1px solid var(--hairline)}.account-balance{text-align:right}.account-balance span,.account-balance strong{display:block}.account-balance span{color:var(--muted);font-size:13px}.account-balance strong{margin-top:4px;font-size:26px}.account-section{display:grid;gap:16px;padding:20px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.check-in-section{overflow:hidden;background:radial-gradient(circle at 100% 0,color-mix(in srgb,var(--blue) 22%,transparent),transparent 48%),var(--glass);border:1px solid var(--glass-border);box-shadow:var(--glass-shadow);-webkit-backdrop-filter:blur(26px) saturate(180%);backdrop-filter:blur(26px) saturate(180%)}.check-in-section .account-section-title>div{display:grid;gap:4px}.check-in-section .eyebrow,.check-in-section h2{margin:0}.check-in-section .primary-button:disabled{cursor:default;opacity:.62}.check-in-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.check-in-summary>div{display:grid;gap:6px;padding:14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.check-in-summary span,.check-in-note{color:var(--muted);font-size:13px}.check-in-summary strong{font-size:15px}.check-in-note{margin:0;line-height:1.5}.check-in-message{color:var(--blue)}.one-time-secret{overflow-x:auto;padding:13px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px}.account-message{color:var(--muted);font-size:13px}.account-key-list{display:grid}.account-key-list>div{display:flex;align-items:center;gap:13px;min-height:66px;padding:13px 6px;border-top:1px solid var(--hairline)}.account-key-list>div:first-child{border-top:0}.account-key-list .empty{justify-content:center}.account-key-mark{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:40px;height:40px;color:var(--blue);background:color-mix(in srgb,var(--blue) 13%,transparent);border-radius:12px}.account-key-mark .icon{width:19px;height:19px}.account-key-info{display:flex;flex-direction:column;gap:3px;flex:1 1 auto;min-width:0}.account-key-info strong{font-size:15px;font-weight:650;line-height:1.25}.account-key-info code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;letter-spacing:.01em;color:var(--muted);overflow-wrap:anywhere}.account-key-list .badge{flex:0 0 auto;align-self:center}.usage-section{--usage-mark: var(--blue);--usage-plot-height: 150px;--usage-tick-band: 18px;--usage-axis-gutter: 46px}.usage-body{display:grid;gap:16px;transition:opacity .16s ease}.usage-body.is-refreshing{opacity:.55}.usage-placeholder{margin:0;color:var(--muted);font-size:13px}.usage-kpi{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.usage-tile{display:grid;gap:3px;min-width:0;padding:12px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.usage-tile>span{color:var(--muted);font-size:12px}.usage-tile>strong{font-size:22px;font-weight:650;line-height:1.15;overflow-wrap:anywhere}.usage-tile>small{color:var(--muted);font-size:12px}.usage-range{display:inline-flex;gap:4px;width:fit-content;padding:3px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.usage-range button{min-height:28px;padding:0 12px;color:var(--muted);background:transparent;border:0;border-radius:999px;cursor:pointer;font-size:13px;font-weight:700}.usage-range button.selected{color:var(--text);background:var(--surface-solid);box-shadow:0 1px 4px #0000001f}.account-page[data-theme=dark] .usage-range button.selected{background:#ffffff29;box-shadow:none}.usage-block{display:grid;gap:10px}.usage-block-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.usage-block-head>strong{font-size:14px}.usage-block-head>span{color:var(--muted);font-size:12px}.usage-plot{position:relative;padding-left:var(--usage-axis-gutter)}.usage-grid{position:absolute;top:0;left:var(--usage-axis-gutter);right:0;height:var(--usage-plot-height);pointer-events:none}.usage-gridline{position:absolute;left:0;right:0;border-top:1px solid var(--hairline)}.usage-gridline>span{position:absolute;right:100%;margin-right:8px;transform:translateY(-50%);color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}.usage-columns{position:relative;display:flex;align-items:flex-end;gap:2px}.usage-column{display:flex;flex:1 1 0;flex-direction:column;align-items:center;min-width:0}.usage-column-hit{position:relative;display:flex;align-items:flex-end;justify-content:center;width:100%;height:var(--usage-plot-height);padding:0;background:none;border:0;cursor:pointer}.usage-column-bar{display:block;width:min(24px,100%);min-height:2px;background:var(--usage-mark);border-radius:4px 4px 0 0;transition:opacity .16s ease}.usage-column-hit.is-hovered .usage-column-bar{opacity:.72}.usage-column-peak{position:absolute;left:50%;transform:translate(-50%);color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none}.usage-column-tick{height:var(--usage-tick-band);color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}.usage-tooltip{position:absolute;bottom:calc(var(--usage-tick-band) + 8px);z-index:2;display:grid;gap:1px;transform:translate(-50%);padding:7px 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:10px;box-shadow:var(--shadow);pointer-events:none;white-space:nowrap}.usage-tooltip>strong{font-size:14px;font-variant-numeric:tabular-nums}.usage-tooltip>span{color:var(--muted);font-size:11px}.usage-table-toggle>summary{width:fit-content;color:var(--muted);cursor:pointer;font-size:12px}.usage-table{display:grid;margin-top:8px;overflow:hidden;border:1px solid var(--hairline);border-radius:12px}.usage-table-head,.usage-table-row{display:grid;grid-template-columns:minmax(0,1fr) 72px 88px;gap:10px;align-items:center;min-height:32px;padding:0 12px}.usage-table-head{color:var(--muted);background:var(--group);font-size:11px;font-weight:700}.usage-table-head>span:not(:first-child),.usage-table-row>span:not(:first-child){justify-self:end;font-variant-numeric:tabular-nums}.usage-table-row{border-top:1px solid var(--hairline);font-size:12px}.usage-models{display:grid;gap:8px}.usage-model-row{display:grid;grid-template-columns:minmax(90px,160px) minmax(0,1fr) 72px;gap:10px;align-items:center}.usage-model-name{overflow:hidden;color:var(--text);font-size:13px;text-overflow:ellipsis;white-space:nowrap}.usage-model-track{display:block;height:10px;background:var(--group);border-radius:999px}.usage-model-bar{display:block;height:100%;min-width:2px;background:var(--usage-mark);border-radius:999px}.usage-model-value{justify-self:end;font-size:13px;font-variant-numeric:tabular-nums}@media(max-width:720px){.usage-kpi{grid-template-columns:repeat(2,minmax(0,1fr))}.usage-model-row{grid-template-columns:minmax(0,1fr) 64px}.usage-model-track{display:none}}.account-model-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.account-model-empty{grid-column:1 / -1;padding:26px 18px;color:var(--muted);text-align:center;font-size:13px;background:color-mix(in srgb,var(--group) 60%,transparent);border:1px dashed var(--hairline);border-radius:14px}.account-model-grid article{display:grid;gap:9px;min-width:0;padding:16px;background:var(--group);border:1px solid var(--hairline);border-radius:8px}.account-model-grid article>span,.account-model-grid article p{color:var(--muted);font-size:13px}.account-model-grid article p{line-height:1.5}.account-model-grid code{overflow:hidden;text-overflow:ellipsis}.public-home{--bg: #f4f5f8;--surface: rgba(255, 255, 255, .86);--surface-solid: #ffffff;--group: #eef1f6;--text: #1d1d1f;--muted: #6e6e73;--hairline: rgba(60, 60, 67, .16);--hairline-strong: rgba(60, 60, 67, .24);--blue: #007aff;--violet: #8b5cf6;--green: #34c759;--orange: #ff9500;--shadow: 0 28px 80px rgba(16, 24, 40, .16);--glow: rgba(0, 122, 255, .15);position:relative;min-height:100vh;padding:22px;color:var(--text);background:var(--bg);overflow:hidden}.public-home:before,.public-home:after{content:"";position:absolute;border-radius:50%;filter:blur(120px);opacity:.5;pointer-events:none;z-index:0}.public-home:before{top:-10%;right:5%;width:600px;height:600px;background:var(--glow)}.public-home:after{bottom:-15%;left:-5%;width:500px;height:500px;background:#8b5cf61f}.public-home>*{position:relative;z-index:1}.public-home[data-theme=dark]{--bg: #050508;--surface: rgba(12, 17, 24, .84);--surface-solid: #0d1117;--group: #0b1017;--text: #f5f5f7;--muted: #8f969f;--hairline: rgba(255, 255, 255, .08);--hairline-strong: rgba(255, 255, 255, .16);--shadow: 0 38px 90px rgba(0, 0, 0, .5);--glow: rgba(0, 122, 255, .25);background:var(--bg)}.public-home[data-theme=dark]:before{opacity:.35}.public-home[data-theme=dark]:after{background:#8b5cf62e;opacity:.4}.home-topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;max-width:1180px;margin:0 auto}.home-brand,.home-actions,.home-cta{display:flex;align-items:center;gap:12px}.home-brand span{display:block;margin-top:2px;color:var(--muted);font-size:13px}.home-hero{display:grid;grid-template-columns:minmax(0,.88fr) minmax(460px,.92fr);gap:clamp(38px,7vw,86px);align-items:center;max-width:1180px;min-height:calc(100vh - 250px);margin:0 auto;padding:clamp(72px,10vw,128px) 0 68px}.home-copy{display:grid;gap:22px;align-content:center}.home-kicker{width:fit-content;padding:8px 13px;color:var(--blue);background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 28%,var(--hairline));border-radius:999px;font-size:13px;font-weight:700}.home-copy h1{max-width:680px;font-size:clamp(42px,4.8vw,58px);line-height:1.08;letter-spacing:0}.home-copy h1 span{display:block;width:fit-content;color:var(--blue);white-space:nowrap}.home-copy p{max-width:620px;color:var(--muted);font-size:17px;font-weight:600;line-height:1.8}.public-home .home-cta .primary-button{gap:8px;min-height:54px;padding:0 28px;color:#fff;background:var(--blue);border-radius:16px;box-shadow:0 4px 14px #007aff59,inset 0 1px #fff3;font-size:15px;font-weight:700}.public-home .home-cta .primary-button:hover{box-shadow:0 6px 20px #007aff73,inset 0 1px #fff3}.public-home[data-theme=dark] .home-cta .primary-button{color:#111318;background:#fff;box-shadow:0 4px 16px #ffffff26,inset 0 1px #ffffff80}.public-home[data-theme=dark] .home-cta .primary-button:hover{box-shadow:0 6px 24px #ffffff38,inset 0 1px #ffffff80}.public-home .home-cta .secondary-button{min-height:54px;padding:0 24px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline-strong);border-radius:16px;box-shadow:0 2px 8px #0000000f;font-size:15px;font-weight:700}.public-home[data-theme=dark] .home-cta .secondary-button{background:#ffffff14;border-color:#ffffff1f;box-shadow:0 2px 10px #0003}.integration-row{display:grid;gap:12px;margin-top:18px;color:var(--muted);font-size:13px;font-weight:700}.integration-row>div{display:flex;flex-wrap:wrap;gap:10px}.integration-row>div span{min-height:40px;padding:11px 18px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:0 2px 6px #0000000a,inset 0 1px #fff9;transition:transform .18s ease,box-shadow .18s ease}.integration-row>div span:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014,inset 0 1px #fff9}.public-home[data-theme=dark] .integration-row>div span{background:#ffffff0f;border-color:#ffffff1a;box-shadow:0 2px 8px #0003,inset 0 1px #ffffff0d}.public-home[data-theme=dark] .integration-row>div span:hover{background:#ffffff1a;box-shadow:0 4px 16px #0000004d,inset 0 1px #ffffff14}.gateway-terminal{position:relative;overflow:hidden;min-height:500px;color:#d7dde7;background:#0a0e14;border:1px solid rgba(255,255,255,.08);border-radius:24px;box-shadow:0 0 0 1px #ffffff0d,0 25px 60px -12px #0006,0 0 40px #007aff14}.gateway-terminal:before{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(255,255,255,.03) 0%,transparent 30%);pointer-events:none}.terminal-titlebar{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;min-height:54px;padding:0 18px;color:#9aa5b4;background:#111821;border-bottom:1px solid rgba(255,255,255,.08);font-size:13px}.terminal-dots{display:flex;gap:6px}.terminal-dots span{width:9px;height:9px;background:#445061;border-radius:50%}.terminal-status{display:inline-flex;align-items:center;gap:8px;color:#d7dde7}.terminal-status .pulse-dot{width:8px;height:8px}.terminal-endpoint{display:flex;align-items:center;gap:12px;min-height:56px;padding:0 22px;background:#0c1118;border-bottom:1px solid rgba(255,255,255,.08)}.terminal-endpoint span{padding:4px 8px;color:var(--green);background:#34c7591f;border-radius:8px;font-size:11px;font-weight:900}.terminal-endpoint strong{overflow:hidden;color:#f2f5f9;font-size:16px;text-overflow:ellipsis;white-space:nowrap}.terminal-body{display:grid;gap:18px;padding:22px}.terminal-block{display:grid;gap:10px}.terminal-block>span{color:#758194;font-size:12px;font-weight:900;letter-spacing:.14em}.terminal-block pre{overflow-x:auto;margin:0;padding:0;color:#8fd5ff;background:transparent;border:0;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:13px;font-weight:700;line-height:1.75}.terminal-block.response pre{color:#76e4a6}.terminal-route{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.terminal-route div{min-width:0;padding:12px;background:#111821;border:1px solid rgba(255,255,255,.08);border-radius:14px}.terminal-route span{display:block;margin-bottom:6px;color:#758194;font-size:11px;font-weight:800}.terminal-route strong{overflow:hidden;display:block;color:#f2f5f9;font-size:13px;text-overflow:ellipsis;white-space:nowrap}@keyframes status-pulse{0%{box-shadow:0 0 color-mix(in srgb,var(--green) 42%,transparent)}70%{box-shadow:0 0 0 9px color-mix(in srgb,var(--green) 0%,transparent)}to{box-shadow:0 0 color-mix(in srgb,var(--green) 0%,transparent)}}@media(prefers-reduced-motion:reduce){.pulse-dot{animation:none}}.home-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;max-width:1120px;margin:0 auto;padding-bottom:34px}.home-feature{display:grid;gap:9px;min-height:150px;padding:18px;background:var(--surface);border:1px solid var(--hairline);border-radius:24px;-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.home-feature .icon{color:var(--blue)}.home-feature span{color:var(--muted);line-height:1.5}@media(max-width:1280px){.users-layout{grid-template-columns:1fr}}@media(max-width:980px){.app-shell{grid-template-columns:1fr}.sidebar{position:fixed;inset:auto 12px 12px;z-index:30;height:auto;padding:8px;border:1px solid var(--hairline);border-radius:26px;box-shadow:var(--shadow)}.ios-window-dots,.brand,.sidebar-footer{display:none}nav{grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}.nav-item{flex-direction:column;justify-content:center;gap:4px;min-height:54px;padding:0 4px;border-radius:18px;font-size:11px}.content{width:100%;padding:20px 14px calc(108px + env(safe-area-inset-bottom))}.topbar{margin:-20px -14px 20px;padding:18px 14px 14px}.metrics-grid,.split-grid,.users-layout,.flow-panel,.user-summary-strip,.channel-form-grid{grid-template-columns:1fr}.stream-mode-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.bulk-action-bar{grid-template-columns:auto 100px minmax(160px,1fr)}.bulk-group-select,.auth-default-balance select{width:100%}.channel-form-wide{grid-column:auto}.model-grid{grid-template-columns:1fr}.model-list-toolbar{align-items:stretch;flex-direction:column}.model-list-toolbar input{width:100%}.model-compact-grid{grid-template-columns:1fr}.model-compact-row,.model-compact-row:nth-child(odd),.model-compact-row:nth-last-child(-n+2){border-right:0;border-bottom:1px solid var(--hairline)}.model-compact-row:last-child{border-bottom:0}.flow-steps{grid-template-columns:repeat(4,minmax(136px,1fr));overflow-x:auto;padding-bottom:2px;scroll-snap-type:x mandatory}.flow-step{scroll-snap-align:start}.channels-table,.logs-table{grid-template-columns:minmax(140px,1.3fr) 90px 70px}.logs-toolbar{grid-template-columns:1fr auto}.logs-toolbar .search-box{grid-column:1 / -1}.logs-layout{grid-template-columns:1fr}.log-inspector{position:static}.log-detail{grid-template-columns:repeat(2,minmax(0,1fr))}.channels-table span:nth-child(4),.channels-table span:nth-child(5),.logs-table span:nth-child(3),.logs-table span:nth-child(4),.logs-table span:nth-child(5),.logs-table span:nth-child(6){display:none}}@media(max-width:900px){.home-hero,.home-grid{grid-template-columns:1fr}.home-hero{min-height:0}.model-create-form{grid-template-columns:1fr}.model-create-wide{grid-column:auto}.model-compact-grid{grid-template-columns:1fr}.model-compact-row{grid-template-columns:1fr;align-items:stretch}.model-row-actions{justify-content:flex-start;flex-wrap:wrap}.auth-stage{grid-template-columns:1fr;gap:28px;max-width:560px;padding:38px 0 64px}.auth-intro{padding-top:0}.account-model-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:680px){.app-shell{display:block;min-height:100dvh}.topbar{position:sticky;top:0;align-items:flex-start;flex-direction:column;gap:12px}.topbar-actions{width:100%;display:grid;grid-template-columns:1fr auto auto auto}.segmented-control{flex:1}.segmented-control button{min-width:0}.theme-toggle span{display:none}.theme-toggle{width:40px;padding:0}.topbar-actions .home-link{display:none}.quick-actions{display:flex;overflow-x:auto;padding-bottom:2px;scroll-snap-type:x mandatory}.bulk-action-bar{grid-template-columns:1fr 1fr}.bulk-action-bar strong,.bulk-action-bar input[aria-label=调整原因]{grid-column:1 / -1}.balance-adjuster-fields{grid-template-columns:1fr}.user-filter-row{width:100%;overflow-x:auto}.user-filter-row button{flex:1 0 auto}.auth-default-balance{width:100%}.auth-default-balance input{flex:1;width:auto}.quick-action{min-width:132px;scroll-snap-align:start}.settings-form-grid{grid-template-columns:1fr}.settings-form-wide{grid-column:auto}.settings-save-row{align-items:stretch;flex-direction:column}.settings-save-row .primary-button{width:100%}.auth-topbar,.account-topbar,.auth-stage,.account-content{width:min(100% - 28px,560px)}.auth-intro h1{font-size:34px}.auth-form{padding:18px}.account-model-grid,.check-in-summary{grid-template-columns:1fr}.check-in-section .account-section-title{align-items:stretch;flex-direction:column}.check-in-section .primary-button{width:100%}.check-in-reward-inputs{width:100%;grid-template-columns:repeat(2,minmax(0,1fr))}.account-heading{align-items:flex-start}.public-home{padding:14px}.home-topbar{align-items:flex-start;flex-direction:column}.home-actions{width:100%}.home-actions .primary-button{flex:1}.home-hero{gap:20px;padding:34px 0 20px}.home-copy p{font-size:16px}.home-cta{align-items:stretch;flex-direction:column}.gateway-terminal{min-height:0;border-radius:24px}.terminal-titlebar{grid-template-columns:auto 1fr}.terminal-status{grid-column:1 / -1;justify-content:center;padding:8px 12px;background:#0c1118;border:1px solid rgba(255,255,255,.08);border-radius:999px}.terminal-body,.terminal-endpoint{padding-right:18px;padding-left:18px}.terminal-block pre{font-size:12px}.terminal-route{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:560px){nav{grid-template-columns:repeat(7,minmax(0,1fr))}h1{font-size:30px}.home-copy h1 span{white-space:normal}.metrics-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.setting{align-items:flex-start;flex-direction:column}.registration-mode-control{width:100%}.registration-mode-control button{min-width:0}.hero-strip{align-items:stretch;flex-direction:column;min-height:0;padding:18px}.hero-strip strong{font-size:20px}.live-island{justify-content:center;width:100%}.flow-panel{padding:14px}.flow-steps{display:flex;overflow-x:auto}.flow-step{min-width:136px}.flow-step:not(:last-child):after{display:none}.table{gap:10px;overflow:visible;background:transparent;border:0;border-radius:0}.table-head{display:none}.table-row,.users-table,.channels-table,.logs-table{display:grid;grid-template-columns:1fr auto;gap:8px 12px;min-height:0;padding:14px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:18px}.table-row span:nth-child(n+3){display:none}.users-table.table-row{grid-template-columns:22px minmax(0,1fr) auto}.users-table.table-row>:nth-child(3){display:inline-flex}.mobile-bulk-select{display:inline-flex;width:100%}.channel-editor.channels-table{grid-template-columns:1fr}.channel-editor span:nth-child(n+3),.channel-actions{display:grid}.channel-actions{grid-template-columns:1fr}.table-head,.table-head.users-table,.table-head.channels-table,.table-head.logs-table{display:none}.panel{padding:14px;border-radius:22px}.user-hero{grid-template-columns:48px 1fr}.user-hero .badge{grid-column:1 / -1;justify-self:start}}.modal-backdrop{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;padding:20px;background:#00000073;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.modal-card{width:100%;max-width:520px;max-height:88vh;overflow-y:auto;padding:22px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:20px;box-shadow:0 20px 60px #00000059}.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.modal-head strong{font-size:18px}.modal-head>div{display:grid;gap:4px}.modal-head>div>span{color:var(--muted);font-size:13px}.account-add-modal{max-width:680px}.account-add-options{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:20px}.account-add-option{position:relative;display:grid;justify-items:start;gap:7px;min-width:0;padding:18px;color:var(--text);text-align:left;cursor:pointer;background:var(--group);border:1px solid var(--hairline);border-radius:16px;transition:border-color .16s ease,background .16s ease,transform .16s ease}.account-add-option:hover:not(:disabled):not(.disabled){transform:translateY(-2px);background:color-mix(in srgb,var(--blue) 7%,var(--group));border-color:color-mix(in srgb,var(--blue) 36%,var(--hairline))}.account-add-option.recommended:after{content:"推荐";position:absolute;top:12px;right:12px;padding:3px 8px;color:var(--blue);font-size:11px;font-weight:700;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border-radius:999px}.account-add-option small{color:var(--muted);line-height:1.45}.account-add-option input{display:none}.account-add-option.disabled{cursor:not-allowed;opacity:.55}.account-add-icon{display:grid;width:34px;height:34px;place-items:center;color:var(--blue);font-size:13px;font-weight:800;background:color-mix(in srgb,var(--blue) 12%,var(--surface-solid));border-radius:11px}.account-add-modal .modal-actions{margin-top:18px}@media(max-width:760px){.channel-card-head{flex-direction:column}.channel-card-head-actions{width:100%;justify-content:flex-start}.account-add-options{grid-template-columns:1fr}}.oauth-steps{margin:16px 0 0;padding-left:18px;display:flex;flex-direction:column;gap:18px}.oauth-steps li{line-height:1.6}.oauth-steps label{display:block;margin-bottom:8px;font-weight:600}.oauth-steps input{width:100%;box-sizing:border-box;height:40px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:10px;font-size:14px}.oauth-link{margin-top:10px;display:flex;flex-direction:column;gap:6px}.modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}.model-picker-modal{max-width:560px}.model-picker-toolbar{display:flex;align-items:center;gap:8px}.model-picker-search{flex:1 1 auto;min-width:0;height:38px;padding:0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.model-picker-search:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.model-picker-count{margin:10px 2px 8px;color:var(--muted);font-size:12.5px;font-weight:600}.model-picker-list{display:grid;gap:4px;max-height:46vh;overflow-y:auto;padding:4px;border:1px solid var(--hairline);border-radius:14px;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--muted) 55%,transparent) transparent}.model-picker-row{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:10px;cursor:pointer}.model-picker-row:hover{background:var(--group)}.model-picker-row.checked{background:color-mix(in srgb,var(--blue) 10%,var(--group))}.model-picker-row input[type=checkbox]{flex:0 0 auto;width:17px;height:17px;accent-color:var(--blue);cursor:pointer}.model-picker-name{flex:1 1 auto;min-width:0;font-size:13.5px;color:var(--text);overflow-wrap:anywhere}.model-picker-tag{flex:0 0 auto;padding:2px 8px;color:var(--blue);background:color-mix(in srgb,var(--blue) 14%,transparent);border-radius:999px;font-size:11px;font-weight:650}.model-picker-status{padding:26px 12px;color:var(--muted);text-align:center;font-size:13px}.model-picker-error{color:#d70015}.form-error{margin-top:14px;padding:10px 12px;color:#d70015;background:color-mix(in srgb,var(--red) 12%,var(--surface-solid));border:1px solid color-mix(in srgb,var(--red) 28%,var(--hairline));border-radius:10px;font-size:13px}.source-guide{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px}.source-guide-item{padding:14px 16px;background:var(--group);border:1px solid var(--hairline);border-radius:16px}.source-guide-item strong{display:block;margin-bottom:4px;font-size:14px}.source-guide-item span{color:var(--muted);font-size:13px;line-height:1.5}.channel-card-collapsible>summary{cursor:pointer;list-style:none}.channel-card-collapsible>summary::-webkit-details-marker{display:none}.channel-card-collapsible>summary:after{content:"展开";align-self:center;margin-left:10px;padding:4px 10px;color:var(--muted);font-size:12px;background:var(--group);border:1px solid var(--hairline);border-radius:999px}.channel-card-collapsible[open]>summary:after{content:"收起"}.manual-add{display:inline-block}.manual-add>summary{cursor:pointer;list-style:none}.manual-add>summary::-webkit-details-marker{display:none}.manual-add-body{margin-top:10px;padding:12px;display:flex;flex-direction:column;gap:10px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.manual-add-actions{display:flex;flex-wrap:wrap;gap:8px}.source-tag{flex:0 0 auto;padding:1px 8px;font-size:11px;font-weight:700;border-radius:999px;vertical-align:middle}.source-tag-web{color:#0a7d28;background:color-mix(in srgb,#34c759 16%,var(--surface-solid));border:1px solid color-mix(in srgb,#34c759 32%,var(--hairline))}.source-tag-manual{color:var(--muted);background:var(--group);border:1px solid var(--hairline)}@media(max-width:720px){.source-guide{grid-template-columns:1fr}.account-pool-list{grid-template-columns:minmax(0,1fr)}}.form-success{color:var(--success);font-size:13px}.authsession-field{display:grid;gap:8px;margin-top:18px;color:var(--muted);font-size:13px;font-weight:700}.authsession-field textarea{width:100%;min-height:120px;padding:12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;resize:vertical;outline:none}.authsession-field textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.primary-button,.secondary-button,.danger-button,.icon-button,.theme-toggle{transition:transform .16s ease,background .16s ease,border-color .16s ease,box-shadow .16s ease}.primary-button:hover:not(:disabled){box-shadow:0 8px 20px color-mix(in srgb,var(--blue) 32%,transparent);transform:translateY(-1px)}.secondary-button:hover:not(:disabled),.icon-button:hover:not(:disabled){background:color-mix(in srgb,var(--blue) 9%,var(--surface-solid));border-color:color-mix(in srgb,var(--blue) 18%,var(--hairline))}.channel-page-intro{display:flex;align-items:center;justify-content:space-between;gap:24px;margin:-2px 0 20px;padding:18px 20px;background:linear-gradient(120deg,color-mix(in srgb,var(--blue) 10%,var(--surface-solid)),var(--surface-solid));border:1px solid color-mix(in srgb,var(--blue) 18%,var(--hairline));border-radius:16px}.channel-page-intro strong,.channel-page-intro span{display:block}.channel-page-intro strong{margin-bottom:5px;font-size:16px}.channel-page-intro>div>span{color:var(--muted);font-size:13px}.channel-page-summary{display:flex;flex:0 0 auto;gap:20px}.channel-page-summary span{color:var(--muted);font-size:12px;white-space:nowrap}.channel-page-summary b{margin-right:4px;color:var(--text);font-size:18px}.channel-toolbar{padding-bottom:14px;border-bottom:1px solid var(--hairline)}.channels-stack{gap:10px}.channel-card-collapsible{gap:0;padding:0;overflow:hidden;border-radius:16px}.channel-card-collapsible[open]{gap:18px;padding:18px}.channel-list-row{display:grid;grid-template-columns:minmax(240px,1.4fr) minmax(130px,.55fr) minmax(150px,.75fr) auto;align-items:center;gap:20px;min-height:86px;padding:14px 18px}.channel-card-collapsible[open] .channel-list-row{min-height:0;padding:0 0 18px;border-bottom:1px solid var(--hairline)}.channel-card-collapsible>.channel-list-row:after{content:none}.channel-identity strong{font-size:15px}.channel-identity span,.channel-identity small{overflow:hidden;max-width:100%;text-overflow:ellipsis;white-space:nowrap}.channel-identity span{margin-top:4px;color:var(--text);font-size:12px;font-weight:650}.channel-identity small{margin-top:4px}.channel-list-meta{display:flex;flex-wrap:wrap;gap:6px 12px;color:var(--muted);font-size:12px}.channel-list-meta b{color:var(--text)}.channel-check-result{display:grid;gap:4px;min-width:0}.channel-check-result>span{margin:0;color:var(--muted);font-size:11px}.channel-check-result b{overflow:hidden;color:var(--muted);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.channel-check-result b.is-ok{color:var(--green)}.channel-check-result b.is-error{color:var(--red)}.channel-list-status{display:flex;align-items:center;justify-content:flex-end;gap:10px}.channel-expand-hint{padding:5px 10px;color:var(--muted);background:var(--group);border:1px solid var(--hairline);border-radius:999px;font-size:12px}.channel-card-collapsible[open] .channel-expand-hint:after{content:"中"}.channel-editor-controls{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.channel-select-field{display:grid;gap:7px;color:var(--muted);font-size:13px;font-weight:700}.channel-select-field select{width:100%;min-height:40px;padding:0 34px 0 12px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:12px;outline:none}.channel-select-field select:focus{border-color:var(--blue)}.channel-choice-menu{position:relative}.channel-choice-menu>summary{display:flex;align-items:center;justify-content:space-between;min-height:40px;padding:0 12px;color:var(--text);list-style:none;background:var(--group);border:1px solid var(--hairline);border-radius:12px;cursor:pointer}.channel-choice-menu>summary::-webkit-details-marker{display:none}.channel-choice-menu>summary:after{content:"⌄";margin-left:12px;color:var(--muted)}.channel-choice-menu>summary>span{font-weight:650}.channel-choice-menu>summary>small{color:var(--muted);font-size:12px;font-weight:500}.channel-choice-menu>div{position:absolute;top:calc(100% + 7px);right:0;left:0;z-index:20;display:grid;gap:2px;padding:6px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:14px;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%)}.app-shell[data-theme=dark] .channel-choice-menu>div{background:#2c2c2e;border-color:#ffffff1f}.channel-choice-menu button{display:grid;gap:3px;width:100%;padding:9px 10px;color:var(--text);text-align:left;background:transparent;border:0;border-radius:9px;cursor:pointer}.channel-choice-menu button strong{font-size:13px}.channel-choice-menu button span{color:var(--muted);font-size:12px}.channel-choice-menu button:hover,.channel-choice-menu button.selected{background:color-mix(in srgb,var(--blue) 10%,var(--group))}.channel-choice-menu button.selected strong{color:var(--blue)}.channel-more-actions{position:relative}.channel-more-actions>summary{min-height:36px;padding:0 12px;color:var(--muted);line-height:36px;list-style:none;background:var(--group);border:1px solid var(--hairline);border-radius:10px;cursor:pointer;font-size:13px;font-weight:700}.channel-more-actions>summary::-webkit-details-marker{display:none}.channel-more-actions>summary:after{content:"⌄";margin-left:7px}.channel-more-actions>div{position:absolute;right:0;bottom:calc(100% + 8px);z-index:4;display:grid;width:max-content;gap:6px;padding:8px;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;box-shadow:var(--shadow)}.channel-more-actions label{cursor:pointer}.channel-more-actions input{display:none}.channel-card-actions{gap:4px}.channel-card-actions>.secondary-button,.channel-card-actions .channel-more-actions>summary,.channel-model-actions .secondary-button{min-height:34px;padding-inline:10px;color:var(--muted);background:transparent;border-color:transparent;box-shadow:none}.channel-card-actions>.secondary-button:hover:not(:disabled),.channel-card-actions .channel-more-actions>summary:hover,.channel-model-actions .secondary-button:hover:not(:disabled){color:var(--text);background:color-mix(in srgb,var(--blue) 9%,var(--group));border-color:transparent}.channel-card-actions>.primary-button{min-height:36px;padding-inline:15px}.channel-more-actions>summary{line-height:34px}.channel-more-actions>div{padding:6px;border-radius:14px}.channel-more-actions>div .secondary-button,.channel-more-actions>div .danger-button{justify-content:flex-start;min-height:34px;padding-inline:10px;background:transparent;border-color:transparent;border-radius:9px}.channel-more-actions>div .secondary-button:hover:not(:disabled){background:var(--group);border-color:transparent}.channel-more-actions>div .danger-button:hover:not(:disabled){background:color-mix(in srgb,var(--red) 10%,var(--surface-solid));border-color:transparent}@media(max-width:780px){.channel-page-intro{align-items:flex-start;flex-direction:column;gap:14px}.channel-list-row{grid-template-columns:minmax(0,1fr) auto;gap:12px}.channel-list-meta,.channel-check-result{grid-column:1 / -1}.channel-list-meta{order:3}.channel-check-result{order:4}.channel-list-status{grid-column:2;grid-row:1}.channel-editor-controls{grid-template-columns:1fr}}.gateway-terminal .terminal-block{opacity:0;animation:terminal-rise .5s ease-out forwards}.gateway-terminal .terminal-block.response{animation-delay:.45s}.gateway-terminal .terminal-route div{opacity:0;animation:terminal-rise .4s ease-out forwards}.gateway-terminal .terminal-route div:nth-child(1){animation-delay:.18s}.gateway-terminal .terminal-route div:nth-child(2){animation-delay:.28s}.gateway-terminal .terminal-route div:nth-child(3){animation-delay:.38s}.gateway-terminal .terminal-route div:nth-child(4){animation-delay:.48s}.terminal-caret{display:inline-block;width:7px;height:15px;margin-left:2px;vertical-align:text-bottom;background:#76e4a6;border-radius:1px;animation:terminal-caret-blink 1.1s step-end infinite}@keyframes terminal-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes terminal-caret-blink{0%,50%{opacity:1}50.01%,to{opacity:0}}@media(prefers-reduced-motion:reduce){.gateway-terminal .terminal-block,.gateway-terminal .terminal-route div{opacity:1;animation:none}.terminal-caret{animation:none}}.panel,.metric,.hero-strip,.flow-panel,.model-hero,.channel-card,.model-card,.settings-group,.account-pool-row,.model-provider-group,.model-provider-filter button,.table-row,.list-row,.channel-choice-menu button,.provider-picker-menu button,.model-row-menu button{transition:background .16s ease,border-color .16s ease,box-shadow .16s ease}button.table-row:hover,.log-entry .table-row:hover{box-shadow:inset 0 0 0 1px var(--hairline)}.metric:hover{border-color:var(--hairline-strong)}.cli-intro{margin:0 0 16px;color:var(--muted);font-size:14px;line-height:1.6}.cli-credentials{display:grid;gap:8px;margin-bottom:20px}.cli-credential{display:flex;align-items:center;gap:12px;min-height:48px;padding:10px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:12px}.cli-credential span{min-width:72px;color:var(--muted);font-size:13px;font-weight:600}.cli-credential code{flex:1;overflow:hidden;padding:0;color:var(--text);background:transparent;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:13px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.cli-credential .copy-button{display:grid;place-items:center;flex-shrink:0;width:32px;height:32px;color:var(--muted);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;cursor:pointer;transition:color .14s ease,border-color .14s ease}.cli-credential .copy-button:hover{color:var(--text);border-color:var(--hairline-strong)}.cli-credential .copy-button .icon{width:15px;height:15px}.cli-tools{display:grid;gap:10px}.cli-tool{overflow:hidden;background:var(--group);border:1px solid var(--hairline);border-radius:14px;transition:border-color .16s ease}.cli-tool[open]{border-color:var(--hairline-strong)}.cli-tool summary{display:flex;align-items:center;gap:12px;min-height:52px;padding:12px 16px;cursor:pointer;list-style:none}.cli-tool summary::-webkit-details-marker{display:none}.cli-tool summary:before{content:"";display:block;width:6px;height:6px;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:rotate(-45deg);transition:transform .16s ease}.cli-tool[open] summary:before{transform:rotate(45deg)}.cli-tool summary strong{flex:1;color:var(--text);font-size:14px;font-weight:700}.cli-tool summary span{color:var(--muted);font-size:12px}.cli-tool>p,.cli-tool>pre{margin:0 16px 14px}.cli-tool>p{color:var(--muted);font-size:13px;line-height:1.55}.cli-tool>p code{padding:2px 6px;color:var(--text);background:var(--surface-solid);border-radius:5px;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:12px}.cli-tool>pre{overflow-x:auto;padding:14px 16px;color:#8fd5ff;background:#0d1117;border-radius:10px;font-family:SFMono-Regular,Consolas,Liberation Mono,monospace;font-size:12px;font-weight:600;line-height:1.7;white-space:pre-wrap;word-break:break-all}.app-shell[data-theme=dark] .cli-tool>pre{background:#0006}.cli-tool>pre+pre{margin-top:-4px}.cli-message{margin:16px 0 0;padding:10px 14px;color:var(--green);background:color-mix(in srgb,var(--green) 8%,transparent);border-radius:10px;font-size:13px;font-weight:600}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes slide-down{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}@keyframes pop{0%{transform:scale(1)}50%{transform:scale(.95)}to{transform:scale(1)}}@keyframes toast-in{0%{opacity:0;transform:translateY(16px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.content{animation:fade-in .25s ease-out}.panel,.settings-group,.flow-panel,.hero-strip{animation:slide-up .3s ease-out backwards}.panel:nth-child(1),.settings-group:nth-child(1){animation-delay:0ms}.panel:nth-child(2),.settings-group:nth-child(2){animation-delay:50ms}.panel:nth-child(3),.settings-group:nth-child(3){animation-delay:.1s}.panel:nth-child(4),.settings-group:nth-child(4){animation-delay:.15s}.metric,.channel-card,.model-card,.cli-tool,.cli-credential{animation:slide-up .28s ease-out backwards}.metric:nth-child(1),.channel-card:nth-child(1),.model-card:nth-child(1){animation-delay:0ms}.metric:nth-child(2),.channel-card:nth-child(2),.model-card:nth-child(2){animation-delay:40ms}.metric:nth-child(3),.channel-card:nth-child(3),.model-card:nth-child(3){animation-delay:80ms}.metric:nth-child(4),.channel-card:nth-child(4),.model-card:nth-child(4){animation-delay:.12s}.metric:nth-child(5),.channel-card:nth-child(5),.model-card:nth-child(5){animation-delay:.16s}.metric:nth-child(6),.channel-card:nth-child(6),.model-card:nth-child(6){animation-delay:.2s}.table-row,.list-row{animation:fade-in .2s ease-out backwards}.primary-button,.secondary-button,.danger-button{transition:transform .12s ease,box-shadow .12s ease,background .14s ease,border-color .14s ease}.primary-button:hover,.secondary-button:hover,.danger-button:hover{transform:translateY(-1px)}.primary-button:active,.secondary-button:active,.danger-button:active{transform:translateY(0) scale(.98)}.ios-switch{transition:background .18s ease}.ios-switch span{transition:transform .2s cubic-bezier(.34,1.56,.64,1)}.metric:hover,.channel-card:hover,.model-card:hover{transform:translateY(-2px);box-shadow:0 6px 20px #00000014}.app-shell[data-theme=dark] .metric:hover,.app-shell[data-theme=dark] .channel-card:hover,.app-shell[data-theme=dark] .model-card:hover{box-shadow:0 6px 24px #00000047}.metric,.channel-card,.model-card{transition:transform .18s ease,box-shadow .18s ease,border-color .16s ease}.nav-item{transition:background .14s ease,color .14s ease,transform .1s ease}.nav-item:hover{transform:translate(2px)}.nav-item:active{transform:translate(0) scale(.98)}.settings-tabs button{transition:transform .12s ease,color .14s ease,background .14s ease,box-shadow .14s ease}.settings-tabs button:active{transform:scale(.97)}.toast{animation:toast-in .28s cubic-bezier(.34,1.25,.64,1)}.secret-dialog-backdrop{animation:fade-in .2s ease-out}.secret-dialog{animation:scale-in .25s cubic-bezier(.34,1.25,.64,1)}.copy-button,.cli-credential .copy-button{transition:transform .1s ease,color .14s ease,border-color .14s ease,background .14s ease}.copy-button:active,.cli-credential .copy-button:active{transform:scale(.9)}.channel-choice-menu>div,.provider-picker-menu>div,.model-row-menu{animation:slide-down .18s ease-out}@keyframes pulse-subtle{0%,to{opacity:1}50%{opacity:.7}}.pulse-dot{animation:pulse-subtle 2s ease-in-out infinite}.cli-tool summary{transition:background .14s ease}.cli-tool summary:hover{background:color-mix(in srgb,var(--surface-solid) 50%,transparent)}.cli-tool summary:before{transition:transform .2s cubic-bezier(.34,1.25,.64,1)}.icon{transition:transform .14s ease}button:hover .icon{transform:scale(1.08)}button:active .icon{transform:scale(.95)}.segmented-control button{transition:color .14s ease,background .14s ease,box-shadow .14s ease,transform .1s ease}.segmented-control button:active{transform:scale(.96)}.theme-toggle{transition:transform .12s ease,background .14s ease,border-color .14s ease}.theme-toggle:hover{transform:scale(1.03)}.theme-toggle:active{transform:scale(.97)}input,select,textarea{transition:border-color .14s ease,box-shadow .14s ease}.auth-form{animation:scale-in .3s cubic-bezier(.34,1.15,.64,1)}.account-section{animation:slide-up .3s ease-out backwards}.account-section:nth-child(1){animation-delay:0ms}.account-section:nth-child(2){animation-delay:80ms}.account-section:nth-child(3){animation-delay:.16s}.home-hero{animation:fade-in .4s ease-out}.home-copy{animation:slide-up .4s ease-out .1s backwards}.brand{transition:transform .14s ease}.brand:hover{transform:scale(1.02)}.quick-action{transition:transform .14s ease,background .14s ease,border-color .14s ease,box-shadow .14s ease}.quick-action:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014}.quick-action:active{transform:translateY(0) scale(.98)}.table-row{transition:background .12s ease,box-shadow .12s ease,transform .1s ease}button.table-row:active{transform:scale(.995)}.badge:before{transition:transform .2s ease,opacity .2s ease}.badge:hover:before{transform:scale(1.3)}.model-list-toolbar input,.user-filter-row input,.search-input{transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}.model-list-toolbar input:focus,.user-filter-row input:focus,.search-input:focus{background:var(--surface-solid)}.pager button{transition:transform .1s ease,background .12s ease,border-color .12s ease}.pager button:hover:not(:disabled){transform:scale(1.05)}.pager button:active:not(:disabled){transform:scale(.95)}details summary{transition:background .14s ease,color .14s ease}details[open]>summary{color:var(--text)}.list-row{transition:background .12s ease,transform .1s ease}.list-row:hover{background:color-mix(in srgb,var(--group) 50%,transparent)}.channel-card,.model-card{animation:slide-up .25s ease-out backwards}.channel-card:nth-child(1),.model-card:nth-child(1){animation-delay:0ms}.channel-card:nth-child(2),.model-card:nth-child(2){animation-delay:30ms}.channel-card:nth-child(3),.model-card:nth-child(3){animation-delay:60ms}.channel-card:nth-child(4),.model-card:nth-child(4){animation-delay:90ms}.channel-card:nth-child(5),.model-card:nth-child(5){animation-delay:.12s}.channel-card:nth-child(6),.model-card:nth-child(6){animation-delay:.15s}.channel-card:nth-child(7),.model-card:nth-child(7){animation-delay:.18s}.channel-card:nth-child(8),.model-card:nth-child(8){animation-delay:.21s}.users-layout .table-row.selected{animation:pop .2s ease-out}.user-filter-row button,.model-filter-actions button,.log-status-filter button,.model-provider-filter button{transition:transform .1s ease,color .12s ease,background .12s ease,box-shadow .12s ease}.user-filter-row button:active,.model-filter-actions button:active,.log-status-filter button:active,.model-provider-filter button:active{transform:scale(.96)}.bulk-action-bar{animation:slide-up .2s ease-out}.secret-dialog code{animation:fade-in .3s ease-out .15s backwards}.gateway-terminal{animation:scale-in .5s cubic-bezier(.16,1,.3,1) .2s backwards}.home-kicker{animation:slide-up .35s ease-out backwards}.home-cta{animation:slide-up .4s ease-out .15s backwards}.integration-row>div span{animation:slide-up .3s ease-out backwards}.integration-row>div span:nth-child(1){animation-delay:.25s}.integration-row>div span:nth-child(2){animation-delay:.3s}.integration-row>div span:nth-child(3){animation-delay:.35s}.topbar{animation:slide-down .3s ease-out}.nav-item{animation:fade-in .25s ease-out backwards}nav .nav-item:nth-child(1){animation-delay:0ms}nav .nav-item:nth-child(2){animation-delay:30ms}nav .nav-item:nth-child(3){animation-delay:60ms}nav .nav-item:nth-child(4){animation-delay:90ms}nav .nav-item:nth-child(5){animation-delay:.12s}nav .nav-item:nth-child(6){animation-delay:.15s}nav .nav-item:nth-child(7){animation-delay:.18s}nav .nav-item:nth-child(8){animation-delay:.21s}.sidebar-footer{animation:fade-in .4s ease-out .2s backwards}input:focus,select:focus,textarea:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 15%,transparent)}.provider-icon{transition:transform .15s ease}.channel-card:hover .provider-icon,.model-card:hover .provider-icon{transform:scale(1.1)}input[type=checkbox],input[type=radio]{transition:transform .1s ease,box-shadow .1s ease}input[type=checkbox]:active,input[type=radio]:active{transform:scale(.9)}.log-inspector{animation:slide-up .25s ease-out}.model-hero{animation:slide-up .35s ease-out backwards}.flow-step{animation:slide-up .3s ease-out backwards}.flow-step:nth-child(1){animation-delay:0ms}.flow-step:nth-child(2){animation-delay:60ms}.flow-step:nth-child(3){animation-delay:.12s}.flow-step:nth-child(4){animation-delay:.18s}.hero-strip{animation:fade-in .35s ease-out backwards}.empty{animation:fade-in .3s ease-out}.account-model-grid article{animation:slide-up .25s ease-out backwards;transition:transform .15s ease,box-shadow .15s ease}.account-model-grid article:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000014}.account-model-grid article:nth-child(1){animation-delay:0ms}.account-model-grid article:nth-child(2){animation-delay:25ms}.account-model-grid article:nth-child(3){animation-delay:50ms}.account-model-grid article:nth-child(4){animation-delay:75ms}.account-model-grid article:nth-child(5){animation-delay:.1s}.account-model-grid article:nth-child(6){animation-delay:125ms}.account-key-list>div{animation:slide-up .25s ease-out backwards}.account-key-list>div:nth-child(1){animation-delay:0ms}.account-key-list>div:nth-child(2){animation-delay:40ms}.account-key-list>div:nth-child(3){animation-delay:80ms}.one-time-secret{animation:scale-in .3s cubic-bezier(.34,1.25,.64,1)}.account-balance{animation:fade-in .4s ease-out .1s backwards}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.pulse-dot{animation:none}}.app-shell{--glass: linear-gradient(158deg, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, .64) 100%);--glass-border: rgba(255, 255, 255, .72);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .6), 0 1px 2px rgba(17, 24, 39, .04), 0 12px 34px rgba(17, 24, 39, .08);background:radial-gradient(1120px 620px at 6% -8%,rgba(0,122,255,.1),transparent 58%),radial-gradient(960px 560px at 102% 2%,rgba(48,176,199,.1),transparent 56%),radial-gradient(900px 760px at 50% 118%,rgba(255,149,0,.06),transparent 60%),var(--bg)}.app-shell[data-theme=dark]{--glass: linear-gradient(158deg, rgba(58, 58, 66, .72) 0%, rgba(28, 28, 34, .6) 100%);--glass-border: rgba(255, 255, 255, .1);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 2px 6px rgba(0, 0, 0, .3), 0 18px 44px rgba(0, 0, 0, .48);background:radial-gradient(1120px 620px at 6% -8%,rgba(10,132,255,.18),transparent 58%),radial-gradient(960px 560px at 102% 2%,rgba(48,176,199,.15),transparent 56%),radial-gradient(900px 760px at 50% 120%,rgba(120,88,255,.14),transparent 60%),var(--bg)}.account-page,.auth-page{--glass: linear-gradient(158deg, rgba(255, 255, 255, .94) 0%, rgba(255, 255, 255, .66) 100%);--glass-border: rgba(255, 255, 255, .75);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .65), 0 1px 2px rgba(17, 24, 39, .04), 0 16px 40px rgba(17, 24, 39, .09);background:radial-gradient(1080px 640px at 4% -10%,rgba(0,122,255,.12),transparent 56%),radial-gradient(940px 560px at 104% 4%,rgba(48,176,199,.1),transparent 54%),radial-gradient(880px 720px at 52% 120%,rgba(175,82,222,.07),transparent 60%),var(--bg)}.account-page[data-theme=dark],.auth-page[data-theme=dark]{--glass: linear-gradient(158deg, rgba(58, 58, 66, .7) 0%, rgba(24, 24, 30, .58) 100%);--glass-border: rgba(255, 255, 255, .12);--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 2px 6px rgba(0, 0, 0, .35), 0 22px 52px rgba(0, 0, 0, .5);background:radial-gradient(1080px 640px at 4% -10%,rgba(10,132,255,.22),transparent 56%),radial-gradient(940px 560px at 104% 4%,rgba(48,176,199,.16),transparent 54%),radial-gradient(880px 720px at 52% 122%,rgba(175,82,222,.16),transparent 60%),var(--bg)}.metric,.panel,.account-section:not(.check-in-section),.settings-group,.model-card,.channel-card,.flow-panel,.hero-strip,.model-hero,.log-inspector,.source-guide-item{background:var(--glass);border:1px solid var(--glass-border);box-shadow:var(--glass-shadow);-webkit-backdrop-filter:blur(26px) saturate(185%);backdrop-filter:blur(26px) saturate(185%)}.app-shell[data-theme=dark] .metric,.app-shell[data-theme=dark] .panel,.app-shell[data-theme=dark] .settings-group,.app-shell[data-theme=dark] .model-card,.app-shell[data-theme=dark] .channel-card,.app-shell[data-theme=dark] .flow-panel,.app-shell[data-theme=dark] .hero-strip,.app-shell[data-theme=dark] .model-hero,.app-shell[data-theme=dark] .log-inspector,.app-shell[data-theme=dark] .source-guide-item{background:var(--glass);border-color:var(--glass-border);box-shadow:var(--glass-shadow)}.group-assign-row{display:grid;gap:6px;margin-top:4px;padding:12px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.group-assign-row label{display:grid;gap:6px;color:var(--muted);font-size:12px}.group-assign-row select{height:38px;padding:0 10px;color:var(--text);background:var(--surface-solid);border:1px solid var(--hairline);border-radius:8px;outline:none}.group-assign-row select:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}.group-assign-row small{color:var(--muted);font-size:12px;line-height:1.5}.channel-group-field{display:grid;gap:8px;padding:12px 14px;background:var(--group);border:1px solid var(--hairline);border-radius:14px}.channel-group-empty{color:var(--muted);font-size:13px;line-height:1.5}.channel-group-options{display:flex;flex-wrap:wrap;gap:8px}.channel-group-options button{display:grid;gap:2px;min-width:0;padding:8px 12px;color:var(--text);text-align:left;background:var(--surface-solid);border:1px solid var(--hairline);border-radius:12px;cursor:pointer}.channel-group-options button small{color:var(--muted)}.channel-group-options button.selected{border-color:color-mix(in srgb,var(--blue) 46%,var(--hairline));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--blue) 28%,transparent)}.app-shell[data-theme=dark] .group-assign-row select,.app-shell[data-theme=dark] .channel-group-options button,.app-shell[data-theme=dark] .group-edit-fields input{background:#7676801f;border-color:transparent}.group-edit-fields{display:grid;gap:8px}.group-edit-fields input{height:38px;padding:0 10px;color:var(--text);background:var(--group);border:1px solid var(--hairline);border-radius:8px;outline:none}.group-edit-fields input:focus{border-color:var(--blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)} diff --git a/dist/assets/index-BW0kmUgI.js b/dist/assets/index-BW0kmUgI.js deleted file mode 100644 index 31ccc72..0000000 --- a/dist/assets/index-BW0kmUgI.js +++ /dev/null @@ -1,43 +0,0 @@ -(function(){const m=document.createElement("link").relList;if(m&&m.supports&&m.supports("modulepreload"))return;for(const E of document.querySelectorAll('link[rel="modulepreload"]'))r(E);new MutationObserver(E=>{for(const O of E)if(O.type==="childList")for(const K of O.addedNodes)K.tagName==="LINK"&&K.rel==="modulepreload"&&r(K)}).observe(document,{childList:!0,subtree:!0});function y(E){const O={};return E.integrity&&(O.integrity=E.integrity),E.referrerPolicy&&(O.referrerPolicy=E.referrerPolicy),E.crossOrigin==="use-credentials"?O.credentials="include":E.crossOrigin==="anonymous"?O.credentials="omit":O.credentials="same-origin",O}function r(E){if(E.ep)return;E.ep=!0;const O=y(E);fetch(E.href,O)}})();function H0(c){return c&&c.__esModule&&Object.prototype.hasOwnProperty.call(c,"default")?c.default:c}var Xc={exports:{}},ii={};var em;function w0(){if(em)return ii;em=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.fragment");function y(r,E,O){var K=null;if(O!==void 0&&(K=""+O),E.key!==void 0&&(K=""+E.key),"key"in E){O={};for(var P in E)P!=="key"&&(O[P]=E[P])}else O=E;return E=O.ref,{$$typeof:c,type:r,key:K,ref:E!==void 0?E:null,props:O}}return ii.Fragment=m,ii.jsx=y,ii.jsxs=y,ii}var tm;function B0(){return tm||(tm=1,Xc.exports=w0()),Xc.exports}var n=B0(),Kc={exports:{}},Ae={};var lm;function q0(){if(lm)return Ae;lm=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.portal"),y=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),O=Symbol.for("react.consumer"),K=Symbol.for("react.context"),P=Symbol.for("react.forward_ref"),T=Symbol.for("react.suspense"),b=Symbol.for("react.memo"),G=Symbol.for("react.lazy"),_=Symbol.for("react.activity"),ae=Symbol.iterator;function te(f){return f===null||typeof f!="object"?null:(f=ae&&f[ae]||f["@@iterator"],typeof f=="function"?f:null)}var de={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},le=Object.assign,ne={};function ie(f,N,q){this.props=f,this.context=N,this.refs=ne,this.updater=q||de}ie.prototype.isReactComponent={},ie.prototype.setState=function(f,N){if(typeof f!="object"&&typeof f!="function"&&f!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,f,N,"setState")},ie.prototype.forceUpdate=function(f){this.updater.enqueueForceUpdate(this,f,"forceUpdate")};function ge(){}ge.prototype=ie.prototype;function me(f,N,q){this.props=f,this.context=N,this.refs=ne,this.updater=q||de}var Ce=me.prototype=new ge;Ce.constructor=me,le(Ce,ie.prototype),Ce.isPureReactComponent=!0;var F=Array.isArray;function ve(){}var D={H:null,A:null,T:null,S:null},ee=Object.prototype.hasOwnProperty;function oe(f,N,q){var L=q.ref;return{$$typeof:c,type:f,key:N,ref:L!==void 0?L:null,props:q}}function Ne(f,N){return oe(f.type,N,f.props)}function Me(f){return typeof f=="object"&&f!==null&&f.$$typeof===c}function ue(f){var N={"=":"=0",":":"=2"};return"$"+f.replace(/[=:]/g,function(q){return N[q]})}var Q=/\/+/g;function re(f,N){return typeof f=="object"&&f!==null&&f.key!=null?ue(""+f.key):N.toString(36)}function V(f){switch(f.status){case"fulfilled":return f.value;case"rejected":throw f.reason;default:switch(typeof f.status=="string"?f.then(ve,ve):(f.status="pending",f.then(function(N){f.status==="pending"&&(f.status="fulfilled",f.value=N)},function(N){f.status==="pending"&&(f.status="rejected",f.reason=N)})),f.status){case"fulfilled":return f.value;case"rejected":throw f.reason}}throw f}function A(f,N,q,L,Z){var xe=typeof f;(xe==="undefined"||xe==="boolean")&&(f=null);var M=!1;if(f===null)M=!0;else switch(xe){case"bigint":case"string":case"number":M=!0;break;case"object":switch(f.$$typeof){case c:case m:M=!0;break;case G:return M=f._init,A(M(f._payload),N,q,L,Z)}}if(M)return Z=Z(f),M=L===""?"."+re(f,0):L,F(Z)?(q="",M!=null&&(q=M.replace(Q,"$&/")+"/"),A(Z,N,q,"",function(ot){return ot})):Z!=null&&(Me(Z)&&(Z=Ne(Z,q+(Z.key==null||f&&f.key===Z.key?"":(""+Z.key).replace(Q,"$&/")+"/")+M)),N.push(Z)),1;M=0;var je=L===""?".":L+":";if(F(f))for(var Se=0;Se>>1,$=A[z];if(0>>1;zE(q,p))L<$&&0>E(Z,q)?(A[z]=Z,A[L]=p,z=L):(A[z]=q,A[N]=p,z=N);else if(L<$&&0>E(Z,p))A[z]=Z,A[L]=p,z=L;else break e}}return Y}function E(A,Y){var p=A.sortIndex-Y.sortIndex;return p!==0?p:A.id-Y.id}if(c.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var O=performance;c.unstable_now=function(){return O.now()}}else{var K=Date,P=K.now();c.unstable_now=function(){return K.now()-P}}var T=[],b=[],G=1,_=null,ae=3,te=!1,de=!1,le=!1,ne=!1,ie=typeof setTimeout=="function"?setTimeout:null,ge=typeof clearTimeout=="function"?clearTimeout:null,me=typeof setImmediate<"u"?setImmediate:null;function Ce(A){for(var Y=y(b);Y!==null;){if(Y.callback===null)r(b);else if(Y.startTime<=A)r(b),Y.sortIndex=Y.expirationTime,m(T,Y);else break;Y=y(b)}}function F(A){if(le=!1,Ce(A),!de)if(y(T)!==null)de=!0,ve||(ve=!0,ue());else{var Y=y(b);Y!==null&&V(F,Y.startTime-A)}}var ve=!1,D=-1,ee=5,oe=-1;function Ne(){return ne?!0:!(c.unstable_now()-oeA&&Ne());){var z=_.callback;if(typeof z=="function"){_.callback=null,ae=_.priorityLevel;var $=z(_.expirationTime<=A);if(A=c.unstable_now(),typeof $=="function"){_.callback=$,Ce(A),Y=!0;break t}_===y(T)&&r(T),Ce(A)}else r(T);_=y(T)}if(_!==null)Y=!0;else{var f=y(b);f!==null&&V(F,f.startTime-A),Y=!1}}break e}finally{_=null,ae=p,te=!1}Y=void 0}}finally{Y?ue():ve=!1}}}var ue;if(typeof me=="function")ue=function(){me(Me)};else if(typeof MessageChannel<"u"){var Q=new MessageChannel,re=Q.port2;Q.port1.onmessage=Me,ue=function(){re.postMessage(null)}}else ue=function(){ie(Me,0)};function V(A,Y){D=ie(function(){A(c.unstable_now())},Y)}c.unstable_IdlePriority=5,c.unstable_ImmediatePriority=1,c.unstable_LowPriority=4,c.unstable_NormalPriority=3,c.unstable_Profiling=null,c.unstable_UserBlockingPriority=2,c.unstable_cancelCallback=function(A){A.callback=null},c.unstable_forceFrameRate=function(A){0>A||125z?(A.sortIndex=p,m(b,A),y(T)===null&&A===y(b)&&(le?(ge(D),D=-1):le=!0,V(F,p-z))):(A.sortIndex=$,m(T,A),de||te||(de=!0,ve||(ve=!0,ue()))),A},c.unstable_shouldYield=Ne,c.unstable_wrapCallback=function(A){var Y=ae;return function(){var p=ae;ae=Y;try{return A.apply(this,arguments)}finally{ae=p}}}})(Vc)),Vc}var im;function L0(){return im||(im=1,kc.exports=Y0()),kc.exports}var Jc={exports:{}},xt={};var sm;function Q0(){if(sm)return xt;sm=1;var c=Pc();function m(T){var b="https://react.dev/errors/"+T;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Jc.exports=Q0(),Jc.exports}var cm;function K0(){if(cm)return si;cm=1;var c=L0(),m=Pc(),y=X0();function r(e){var t="https://react.dev/errors/"+e;if(1$||(e.current=z[$],z[$]=null,$--)}function q(e,t){$++,z[$]=e.current,e.current=t}var L=f(null),Z=f(null),xe=f(null),M=f(null);function je(e,t){switch(q(xe,t),q(Z,e),q(L,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Nf(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Nf(t),e=Af(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}N(L),q(L,e)}function Se(){N(L),N(Z),N(xe)}function ot(e){e.memoizedState!==null&&q(M,e);var t=L.current,l=Af(t,e.type);t!==l&&(q(Z,e),q(L,l))}function J(e){Z.current===e&&(N(L),N(Z)),M.current===e&&(N(M),ti._currentValue=p)}var Je,ut;function Ie(e){if(Je===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);Je=t&&t[1]||"",ut=-1)":-1i||d[a]!==j[i]){var U=` -`+d[a].replace(" at new "," at ");return e.displayName&&U.includes("")&&(U=U.replace("",e.displayName)),U}while(1<=a&&0<=i);break}}}finally{tl=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Ie(l):""}function mt(e,t){switch(e.tag){case 26:case 27:case 5:return Ie(e.type);case 16:return Ie("Lazy");case 13:return e.child!==t&&t!==null?Ie("Suspense Fallback"):Ie("Suspense");case 19:return Ie("SuspenseList");case 0:case 15:return k(e.type,!1);case 11:return k(e.type.render,!1);case 1:return k(e.type,!0);case 31:return Ie("Activity");default:return""}}function Ut(e){try{var t="",l=null;do t+=mt(e,l),l=e,e=e.return;while(e);return t}catch(a){return` -Error generating stack: `+a.message+` -`+a.stack}}var R=Object.prototype.hasOwnProperty,Ue=c.unstable_scheduleCallback,rt=c.unstable_cancelCallback,jt=c.unstable_shouldYield,ht=c.unstable_requestPaint,Pe=c.unstable_now,zs=c.unstable_getCurrentPriorityLevel,mn=c.unstable_ImmediatePriority,na=c.unstable_UserBlockingPriority,ia=c.unstable_NormalPriority,Os=c.unstable_LowPriority,H=c.unstable_IdlePriority,X=c.log,I=c.unstable_setDisableYieldValue,W=null,he=null;function qe(e){if(typeof X=="function"&&I(e),he&&typeof he.setStrictMode=="function")try{he.setStrictMode(W,e)}catch{}}var Ze=Math.clz32?Math.clz32:sa,Rt=Math.log,Dl=Math.LN2;function sa(e){return e>>>=0,e===0?32:31-(Rt(e)/Dl|0)|0}var Ta=256,Ea=262144,Ul=4194304;function fl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function oi(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var i=0,s=e.suspendedLanes,u=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~s,a!==0?i=fl(a):(u&=o,u!==0?i=fl(u):l||(l=o&~e,l!==0&&(i=fl(l))))):(o=a&~s,o!==0?i=fl(o):u!==0?i=fl(u):l||(l=a&~e,l!==0&&(i=fl(l)))),i===0?0:t!==0&&t!==i&&(t&s)===0&&(s=i&-i,l=t&-t,s>=l||s===32&&(l&4194048)!==0)?t:i}function hn(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Sm(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function lo(){var e=Ul;return Ul<<=1,(Ul&62914560)===0&&(Ul=4194304),e}function _s(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function pn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Nm(e,t,l,a,i,s){var u=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,d=e.expirationTimes,j=e.hiddenUpdates;for(l=u&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var zm=/[\n"\\]/g;function Kt(e){return e.replace(zm,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bs(e,t,l,a,i,s,u,o){e.name="",u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"?e.type=u:e.removeAttribute("type"),t!=null?u==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Xt(t)):e.value!==""+Xt(t)&&(e.value=""+Xt(t)):u!=="submit"&&u!=="reset"||e.removeAttribute("value"),t!=null?qs(e,u,Xt(t)):l!=null?qs(e,u,Xt(l)):a!=null&&e.removeAttribute("value"),i==null&&s!=null&&(e.defaultChecked=!!s),i!=null&&(e.checked=i&&typeof i!="function"&&typeof i!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+Xt(o):e.removeAttribute("name")}function vo(e,t,l,a,i,s,u,o){if(s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"&&(e.type=s),t!=null||l!=null){if(!(s!=="submit"&&s!=="reset"||t!=null)){ws(e);return}l=l!=null?""+Xt(l):"",t=t!=null?""+Xt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??i,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.name=u),ws(e)}function qs(e,t,l){t==="number"&&fi(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ua(e,t,l,a){if(e=e.options,t){t={};for(var i=0;i"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Xs=!1;if(pl)try{var gn={};Object.defineProperty(gn,"passive",{get:function(){Xs=!0}}),window.addEventListener("test",gn,gn),window.removeEventListener("test",gn,gn)}catch{Xs=!1}var Hl=null,Ks=null,hi=null;function No(){if(hi)return hi;var e,t=Ks,l=t.length,a,i="value"in Hl?Hl.value:Hl.textContent,s=i.length;for(e=0;e=Sn),zo=" ",Oo=!1;function _o(e,t){switch(e){case"keyup":return ah.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Do(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ba=!1;function ih(e,t){switch(e){case"compositionend":return Do(t);case"keypress":return t.which!==32?null:(Oo=!0,zo);case"textInput":return e=t.data,e===zo&&Oo?null:e;default:return null}}function sh(e,t){if(Ba)return e==="compositionend"||!$s&&_o(e,t)?(e=No(),hi=Ks=Hl=null,Ba=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Yo(l)}}function Qo(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Qo(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Xo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fi(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fi(e.document)}return t}function Is(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var hh=pl&&"documentMode"in document&&11>=document.documentMode,qa=null,Ps=null,Tn=null,eu=!1;function Ko(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||qa==null||qa!==fi(a)||(a=qa,"selectionStart"in a&&Is(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Tn&&Cn(Tn,a)||(Tn=a,a=us(Ps,"onSelect"),0>=u,i-=u,cl=1<<32-Ze(t)+i|l<Ee?(De=ce,ce=null):De=ce.sibling;var we=S(v,ce,x[Ee],w);if(we===null){ce===null&&(ce=De);break}e&&ce&&we.alternate===null&&t(v,ce),h=s(we,h,Ee),He===null?fe=we:He.sibling=we,He=we,ce=De}if(Ee===x.length)return l(v,ce),Re&&yl(v,Ee),fe;if(ce===null){for(;EeEe?(De=ce,ce=null):De=ce.sibling;var aa=S(v,ce,we.value,w);if(aa===null){ce===null&&(ce=De);break}e&&ce&&aa.alternate===null&&t(v,ce),h=s(aa,h,Ee),He===null?fe=aa:He.sibling=aa,He=aa,ce=De}if(we.done)return l(v,ce),Re&&yl(v,Ee),fe;if(ce===null){for(;!we.done;Ee++,we=x.next())we=B(v,we.value,w),we!==null&&(h=s(we,h,Ee),He===null?fe=we:He.sibling=we,He=we);return Re&&yl(v,Ee),fe}for(ce=a(ce);!we.done;Ee++,we=x.next())we=C(ce,v,Ee,we.value,w),we!==null&&(e&&we.alternate!==null&&ce.delete(we.key===null?Ee:we.key),h=s(we,h,Ee),He===null?fe=we:He.sibling=we,He=we);return e&&ce.forEach(function(R0){return t(v,R0)}),Re&&yl(v,Ee),fe}function Xe(v,h,x,w){if(typeof x=="object"&&x!==null&&x.type===le&&x.key===null&&(x=x.props.children),typeof x=="object"&&x!==null){switch(x.$$typeof){case te:e:{for(var fe=x.key;h!==null;){if(h.key===fe){if(fe=x.type,fe===le){if(h.tag===7){l(v,h.sibling),w=i(h,x.props.children),w.return=v,v=w;break e}}else if(h.elementType===fe||typeof fe=="object"&&fe!==null&&fe.$$typeof===ee&&ya(fe)===h.type){l(v,h.sibling),w=i(h,x.props),Dn(w,x),w.return=v,v=w;break e}l(v,h);break}else t(v,h);h=h.sibling}x.type===le?(w=fa(x.props.children,v.mode,w,x.key),w.return=v,v=w):(w=Ai(x.type,x.key,x.props,null,v.mode,w),Dn(w,x),w.return=v,v=w)}return u(v);case de:e:{for(fe=x.key;h!==null;){if(h.key===fe)if(h.tag===4&&h.stateNode.containerInfo===x.containerInfo&&h.stateNode.implementation===x.implementation){l(v,h.sibling),w=i(h,x.children||[]),w.return=v,v=w;break e}else{l(v,h);break}else t(v,h);h=h.sibling}w=uu(x,v.mode,w),w.return=v,v=w}return u(v);case ee:return x=ya(x),Xe(v,h,x,w)}if(V(x))return se(v,h,x,w);if(ue(x)){if(fe=ue(x),typeof fe!="function")throw Error(r(150));return x=fe.call(x),ye(v,h,x,w)}if(typeof x.then=="function")return Xe(v,h,_i(x),w);if(x.$$typeof===me)return Xe(v,h,Ei(v,x),w);Di(v,x)}return typeof x=="string"&&x!==""||typeof x=="number"||typeof x=="bigint"?(x=""+x,h!==null&&h.tag===6?(l(v,h.sibling),w=i(h,x),w.return=v,v=w):(l(v,h),w=su(x,v.mode,w),w.return=v,v=w),u(v)):l(v,h)}return function(v,h,x,w){try{_n=0;var fe=Xe(v,h,x,w);return $a=null,fe}catch(ce){if(ce===Ja||ce===zi)throw ce;var He=wt(29,ce,null,v.mode);return He.lanes=w,He.return=v,He}}}var ga=mr(!0),hr=mr(!1),Yl=!1;function gu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ll(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ql(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Be&2)!==0){var i=a.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),a.pending=t,t=Ni(e),Fo(e,null,l),t}return Si(e,a,t,l),Ni(e)}function Un(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var i=null,s=null;if(l=l.firstBaseUpdate,l!==null){do{var u={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};s===null?i=s=u:s=s.next=u,l=l.next}while(l!==null);s===null?i=s=t:s=s.next=t}else i=s=t;l={baseState:a.baseState,firstBaseUpdate:i,lastBaseUpdate:s,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function Rn(){if(Su){var e=Va;if(e!==null)throw e}}function Hn(e,t,l,a){Su=!1;var i=e.updateQueue;Yl=!1;var s=i.firstBaseUpdate,u=i.lastBaseUpdate,o=i.shared.pending;if(o!==null){i.shared.pending=null;var d=o,j=d.next;d.next=null,u===null?s=j:u.next=j,u=d;var U=e.alternate;U!==null&&(U=U.updateQueue,o=U.lastBaseUpdate,o!==u&&(o===null?U.firstBaseUpdate=j:o.next=j,U.lastBaseUpdate=d))}if(s!==null){var B=i.baseState;u=0,U=j=d=null,o=s;do{var S=o.lane&-536870913,C=S!==o.lane;if(C?(_e&S)===S:(a&S)===S){S!==0&&S===ka&&(Su=!0),U!==null&&(U=U.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var se=e,ye=o;S=t;var Xe=l;switch(ye.tag){case 1:if(se=ye.payload,typeof se=="function"){B=se.call(Xe,B,S);break e}B=se;break e;case 3:se.flags=se.flags&-65537|128;case 0:if(se=ye.payload,S=typeof se=="function"?se.call(Xe,B,S):se,S==null)break e;B=_({},B,S);break e;case 2:Yl=!0}}S=o.callback,S!==null&&(e.flags|=64,C&&(e.flags|=8192),C=i.callbacks,C===null?i.callbacks=[S]:C.push(S))}else C={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},U===null?(j=U=C,d=B):U=U.next=C,u|=S;if(o=o.next,o===null){if(o=i.shared.pending,o===null)break;C=o,o=C.next,C.next=null,i.lastBaseUpdate=C,i.shared.pending=null}}while(!0);U===null&&(d=B),i.baseState=d,i.firstBaseUpdate=j,i.lastBaseUpdate=U,s===null&&(i.shared.lanes=0),Vl|=u,e.lanes=u,e.memoizedState=B}}function pr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function vr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;es?s:8;var u=A.T,o={};A.T=o,Lu(e,!1,t,l);try{var d=i(),j=A.S;if(j!==null&&j(o,d),d!==null&&typeof d=="object"&&typeof d.then=="function"){var U=Nh(d,a);qn(e,t,U,Lt(e))}else qn(e,t,a,Lt(e))}catch(B){qn(e,t,{then:function(){},status:"rejected",reason:B},Lt())}finally{Y.p=s,u!==null&&o.types!==null&&(u.types=o.types),A.T=u}}function zh(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var i=Jr(e).queue;Vr(e,i,t,p,l===null?zh:function(){return $r(e),l(a)})}function Jr(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:p,baseState:p,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:jl,lastRenderedState:p},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:jl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function $r(e){var t=Jr(e);t.next===null&&(t=e.alternate.memoizedState),qn(e,t.next.queue,{},Lt())}function Yu(){return yt(ti)}function Wr(){return tt().memoizedState}function Fr(){return tt().memoizedState}function Oh(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Lt();e=Ll(l);var a=Ql(t,e,l);a!==null&&(zt(a,t,l),Un(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function _h(e,t,l){var a=Lt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Qi(e)?Pr(t,l):(l=nu(e,t,l,a),l!==null&&(zt(l,e,a),ed(l,t,a)))}function Ir(e,t,l){var a=Lt();qn(e,t,l,a)}function qn(e,t,l,a){var i={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Qi(e))Pr(t,i);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var u=t.lastRenderedState,o=s(u,l);if(i.hasEagerState=!0,i.eagerState=o,Ht(o,u))return Si(e,t,i,0),Ke===null&&ji(),!1}catch{}if(l=nu(e,t,i,a),l!==null)return zt(l,e,a),ed(l,t,a),!0}return!1}function Lu(e,t,l,a){if(a={lane:2,revertLane:gc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Qi(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&zt(t,e,2)}function Qi(e){var t=e.alternate;return e===Te||t!==null&&t===Te}function Pr(e,t){Fa=Hi=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ed(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}var Gn={readContext:yt,use:qi,useCallback:We,useContext:We,useEffect:We,useImperativeHandle:We,useLayoutEffect:We,useInsertionEffect:We,useMemo:We,useReducer:We,useRef:We,useState:We,useDebugValue:We,useDeferredValue:We,useTransition:We,useSyncExternalStore:We,useId:We,useHostTransitionStatus:We,useFormState:We,useActionState:We,useOptimistic:We,useMemoCache:We,useCacheRefresh:We};Gn.useEffectEvent=We;var td={readContext:yt,use:qi,useCallback:function(e,t){return St().memoizedState=[e,t===void 0?null:t],e},useContext:yt,useEffect:qr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Yi(4194308,4,Qr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Yi(4194308,4,e,t)},useInsertionEffect:function(e,t){Yi(4,2,e,t)},useMemo:function(e,t){var l=St();t=t===void 0?null:t;var a=e();if(xa){qe(!0);try{e()}finally{qe(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=St();if(l!==void 0){var i=l(t);if(xa){qe(!0);try{l(t)}finally{qe(!1)}}}else i=t;return a.memoizedState=a.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},a.queue=e,e=e.dispatch=_h.bind(null,Te,e),[a.memoizedState,e]},useRef:function(e){var t=St();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Ir.bind(null,Te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=St();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Vr.bind(null,Te,e.queue,!0,!1),St().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Te,i=St();if(Re){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Ke===null)throw Error(r(349));(_e&127)!==0||Sr(a,t,l)}i.memoizedState=l;var s={value:l,getSnapshot:t};return i.queue=s,qr(Ar.bind(null,a,s,e),[e]),a.flags|=2048,Pa(9,{destroy:void 0},Nr.bind(null,a,s,l,t),null),l},useId:function(){var e=St(),t=Ke.identifierPrefix;if(Re){var l=ol,a=cl;l=(a&~(1<<32-Ze(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=wi++,0<\/script>",s=s.removeChild(s.firstChild);break;case"select":s=typeof a.is=="string"?u.createElement("select",{is:a.is}):u.createElement("select"),a.multiple?s.multiple=!0:a.size&&(s.size=a.size);break;default:s=typeof a.is=="string"?u.createElement(i,{is:a.is}):u.createElement(i)}}s[pt]=t,s[Nt]=a;e:for(u=t.child;u!==null;){if(u.tag===5||u.tag===6)s.appendChild(u.stateNode);else if(u.tag!==4&&u.tag!==27&&u.child!==null){u.child.return=u,u=u.child;continue}if(u===t)break e;for(;u.sibling===null;){if(u.return===null||u.return===t)break e;u=u.return}u.sibling.return=u.return,u=u.sibling}t.stateNode=s;e:switch(gt(s,i,a),i){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Nl(t)}}return Ve(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&Nl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=xe.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,i=vt,i!==null)switch(i.tag){case 27:case 5:a=i.memoizedProps}e[pt]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||jf(e.nodeValue,l)),e||ql(t,!0)}else e=cs(e).createTextNode(a),e[pt]=t,t.stateNode=e}return Ve(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[pt]=t}else ma(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(qt(t),t):(qt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Ve(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(i=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!i)throw Error(r(318));if(i=t.memoizedState,i=i!==null?i.dehydrated:null,!i)throw Error(r(317));i[pt]=t}else ma(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),i=!1}else i=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=i),i=!0;if(!i)return t.flags&256?(qt(t),t):(qt(t),null)}return qt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,i=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(i=a.alternate.memoizedState.cachePool.pool),s=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(s=a.memoizedState.cachePool.pool),s!==i&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vi(t,t.updateQueue),Ve(t),null);case 4:return Se(),e===null&&Nc(t.stateNode.containerInfo),Ve(t),null;case 10:return gl(t.type),Ve(t),null;case 19:if(N(et),a=t.memoizedState,a===null)return Ve(t),null;if(i=(t.flags&128)!==0,s=a.rendering,s===null)if(i)Ln(a,!1);else{if(Fe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(s=Ri(e),s!==null){for(t.flags|=128,Ln(a,!1),e=s.updateQueue,t.updateQueue=e,Vi(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Io(l,e),l=l.sibling;return q(et,et.current&1|2),Re&&yl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&Pe()>Ii&&(t.flags|=128,i=!0,Ln(a,!1),t.lanes=4194304)}else{if(!i)if(e=Ri(s),e!==null){if(t.flags|=128,i=!0,e=e.updateQueue,t.updateQueue=e,Vi(t,e),Ln(a,!0),a.tail===null&&a.tailMode==="hidden"&&!s.alternate&&!Re)return Ve(t),null}else 2*Pe()-a.renderingStartTime>Ii&&l!==536870912&&(t.flags|=128,i=!0,Ln(a,!1),t.lanes=4194304);a.isBackwards?(s.sibling=t.child,t.child=s):(e=a.last,e!==null?e.sibling=s:t.child=s,a.last=s)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=Pe(),e.sibling=null,l=et.current,q(et,i?l&1|2:l&1),Re&&yl(t,a.treeForkCount),e):(Ve(t),null);case 22:case 23:return qt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Ve(t),t.subtreeFlags&6&&(t.flags|=8192)):Ve(t),l=t.updateQueue,l!==null&&Vi(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&N(va),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),gl(at),Ve(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function wh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return gl(at),Se(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return J(t),null;case 31:if(t.memoizedState!==null){if(qt(t),t.alternate===null)throw Error(r(340));ma()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(qt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));ma()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return N(et),null;case 4:return Se(),null;case 10:return gl(t.type),null;case 22:case 23:return qt(t),Au(),e!==null&&N(va),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return gl(at),null;case 25:return null;default:return null}}function Cd(e,t){switch(ou(t),t.tag){case 3:gl(at),Se();break;case 26:case 27:case 5:J(t);break;case 4:Se();break;case 31:t.memoizedState!==null&&qt(t);break;case 13:qt(t);break;case 19:N(et);break;case 10:gl(t.type);break;case 22:case 23:qt(t),Au(),e!==null&&N(va);break;case 24:gl(at)}}function Qn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var i=a.next;l=i;do{if((l.tag&e)===e){a=void 0;var s=l.create,u=l.inst;a=s(),u.destroy=a}l=l.next}while(l!==i)}}catch(o){Ye(t,t.return,o)}}function Zl(e,t,l){try{var a=t.updateQueue,i=a!==null?a.lastEffect:null;if(i!==null){var s=i.next;a=s;do{if((a.tag&e)===e){var u=a.inst,o=u.destroy;if(o!==void 0){u.destroy=void 0,i=t;var d=l,j=o;try{j()}catch(U){Ye(i,d,U)}}}a=a.next}while(a!==s)}}catch(U){Ye(t,t.return,U)}}function Td(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{vr(t,l)}catch(a){Ye(e,e.return,a)}}}function Ed(e,t,l){l.props=ja(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ye(e,t,a)}}function Xn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(i){Ye(e,t,i)}}function rl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(i){Ye(e,t,i)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(i){Ye(e,t,i)}else l.current=null}function Md(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(i){Ye(e,e.return,i)}}function lc(e,t,l){try{var a=e.stateNode;n0(a,e.type,l,t),a[Nt]=t}catch(i){Ye(e,e.return,i)}}function zd(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Il(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||zd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Il(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=hl));else if(a!==4&&(a===27&&Il(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Ji(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&Il(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Ji(e,t,l),e=e.sibling;e!==null;)Ji(e,t,l),e=e.sibling}function Od(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);gt(t,a,l),t[pt]=e,t[Nt]=l}catch(s){Ye(e,e.return,s)}}var Al=!1,st=!1,ic=!1,_d=typeof WeakSet=="function"?WeakSet:Set,ft=null;function Bh(e,t){if(e=e.containerInfo,Tc=ps,e=Xo(e),Is(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var i=a.anchorOffset,s=a.focusNode;a=a.focusOffset;try{l.nodeType,s.nodeType}catch{l=null;break e}var u=0,o=-1,d=-1,j=0,U=0,B=e,S=null;t:for(;;){for(var C;B!==l||i!==0&&B.nodeType!==3||(o=u+i),B!==s||a!==0&&B.nodeType!==3||(d=u+a),B.nodeType===3&&(u+=B.nodeValue.length),(C=B.firstChild)!==null;)S=B,B=C;for(;;){if(B===e)break t;if(S===l&&++j===i&&(o=u),S===s&&++U===a&&(d=u),(C=B.nextSibling)!==null)break;B=S,S=B.parentNode}B=C}l=o===-1||d===-1?null:{start:o,end:d}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},ps=!1,ft=t;ft!==null;)if(t=ft,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,ft=e;else for(;ft!==null;){switch(t=ft,s=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),gt(s,a,l),s[pt]=e,dt(s),a=s;break e;case"link":var u=qf("link","href",i).get(a+(l.href||""));if(u){for(var o=0;oXe&&(u=Xe,Xe=ye,ye=u);var v=Lo(o,ye),h=Lo(o,Xe);if(v&&h&&(C.rangeCount!==1||C.anchorNode!==v.node||C.anchorOffset!==v.offset||C.focusNode!==h.node||C.focusOffset!==h.offset)){var x=B.createRange();x.setStart(v.node,v.offset),C.removeAllRanges(),ye>Xe?(C.addRange(x),C.extend(h.node,h.offset)):(x.setEnd(h.node,h.offset),C.addRange(x))}}}}for(B=[],C=o;C=C.parentNode;)C.nodeType===1&&B.push({element:C,left:C.scrollLeft,top:C.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,A.T=null,l=fc,fc=null;var s=$l,u=zl;if(ct=0,nn=$l=null,zl=0,(Be&6)!==0)throw Error(r(331));var o=Be;if(Be|=4,Qd(s.current),Gd(s,s.current,u,l),Be=o,$n(0,!1),he&&typeof he.onPostCommitFiberRoot=="function")try{he.onPostCommitFiberRoot(W,s)}catch{}return!0}finally{Y.p=i,A.T=a,uf(e,t)}}function of(e,t,l){t=kt(l,t),t=Zu(e.stateNode,t,2),e=Ql(e,t,2),e!==null&&(pn(e,2),dl(e))}function Ye(e,t,l){if(e.tag===3)of(e,e,l);else for(;t!==null;){if(t.tag===3){of(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Jl===null||!Jl.has(a))){e=kt(l,e),l=od(2),a=Ql(t,l,2),a!==null&&(rd(l,a,t,e),pn(a,2),dl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Yh;var i=new Set;a.set(t,i)}else i=a.get(t),i===void 0&&(i=new Set,a.set(t,i));i.has(l)||(cc=!0,i.add(l),e=Zh.bind(null,e,t,l),t.then(e,e))}function Zh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Ke===e&&(_e&l)===l&&(Fe===4||Fe===3&&(_e&62914560)===_e&&300>Pe()-Fi?(Be&2)===0&&sn(e,0):oc|=l,an===_e&&(an=0)),dl(e)}function rf(e,t){t===0&&(t=lo()),e=da(e,t),e!==null&&(pn(e,t),dl(e))}function kh(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),rf(e,l)}function Vh(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,i=e.memoizedState;i!==null&&(l=i.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),rf(e,l)}function Jh(e,t){return Ue(e,t)}var ns=null,cn=null,yc=!1,is=!1,bc=!1,Fl=0;function dl(e){e!==cn&&e.next===null&&(cn===null?ns=cn=e:cn=cn.next=e),is=!0,yc||(yc=!0,Wh())}function $n(e,t){if(!bc&&is){bc=!0;do for(var l=!1,a=ns;a!==null;){if(e!==0){var i=a.pendingLanes;if(i===0)var s=0;else{var u=a.suspendedLanes,o=a.pingedLanes;s=(1<<31-Ze(42|e)+1)-1,s&=i&~(u&~o),s=s&201326741?s&201326741|1:s?s|2:0}s!==0&&(l=!0,hf(a,s))}else s=_e,s=oi(a,a===Ke?s:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(s&3)===0||hn(a,s)||(l=!0,hf(a,s));a=a.next}while(l);bc=!1}}function $h(){df()}function df(){is=yc=!1;var e=0;Fl!==0&&s0()&&(e=Fl);for(var t=Pe(),l=null,a=ns;a!==null;){var i=a.next,s=ff(a,t);s===0?(a.next=null,l===null?ns=i:l.next=i,i===null&&(cn=l)):(l=a,(e!==0||(s&3)!==0)&&(is=!0)),a=i}ct!==0&&ct!==5||$n(e),Fl!==0&&(Fl=0)}function ff(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,i=e.expirationTimes,s=e.pendingLanes&-62914561;0o)break;var U=d.transferSize,B=d.initiatorType;U&&Sf(B)&&(d=d.responseEnd,u+=U*(d"u"?null:document;function Rf(e,t,l){var a=on;if(a&&typeof t=="string"&&t){var i=Kt(t);i='link[rel="'+e+'"][href="'+i+'"]',typeof l=="string"&&(i+='[crossorigin="'+l+'"]'),Uf.has(i)||(Uf.add(i),e={rel:e,crossOrigin:l,href:t},a.querySelector(i)===null&&(t=a.createElement("link"),gt(t,"link",e),dt(t),a.head.appendChild(t)))}}function p0(e){Ol.D(e),Rf("dns-prefetch",e,null)}function v0(e,t){Ol.C(e,t),Rf("preconnect",e,t)}function y0(e,t,l){Ol.L(e,t,l);var a=on;if(a&&e&&t){var i='link[rel="preload"][as="'+Kt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(i+='[imagesrcset="'+Kt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(i+='[imagesizes="'+Kt(l.imageSizes)+'"]')):i+='[href="'+Kt(e)+'"]';var s=i;switch(t){case"style":s=rn(e);break;case"script":s=dn(e)}It.has(s)||(e=_({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),It.set(s,e),a.querySelector(i)!==null||t==="style"&&a.querySelector(Pn(s))||t==="script"&&a.querySelector(ei(s))||(t=a.createElement("link"),gt(t,"link",e),dt(t),a.head.appendChild(t)))}}function b0(e,t){Ol.m(e,t);var l=on;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",i='link[rel="modulepreload"][as="'+Kt(a)+'"][href="'+Kt(e)+'"]',s=i;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":s=dn(e)}if(!It.has(s)&&(e=_({rel:"modulepreload",href:e},t),It.set(s,e),l.querySelector(i)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ei(s)))return}a=l.createElement("link"),gt(a,"link",e),dt(a),l.head.appendChild(a)}}}function g0(e,t,l){Ol.S(e,t,l);var a=on;if(a&&e){var i=_a(a).hoistableStyles,s=rn(e);t=t||"default";var u=i.get(s);if(!u){var o={loading:0,preload:null};if(u=a.querySelector(Pn(s)))o.loading=5;else{e=_({rel:"stylesheet",href:e,"data-precedence":t},l),(l=It.get(s))&&Rc(e,l);var d=u=a.createElement("link");dt(d),gt(d,"link",e),d._p=new Promise(function(j,U){d.onload=j,d.onerror=U}),d.addEventListener("load",function(){o.loading|=1}),d.addEventListener("error",function(){o.loading|=2}),o.loading|=4,rs(u,t,a)}u={type:"stylesheet",instance:u,count:1,state:o},i.set(s,u)}}}function x0(e,t){Ol.X(e,t);var l=on;if(l&&e){var a=_a(l).hoistableScripts,i=dn(e),s=a.get(i);s||(s=l.querySelector(ei(i)),s||(e=_({src:e,async:!0},t),(t=It.get(i))&&Hc(e,t),s=l.createElement("script"),dt(s),gt(s,"link",e),l.head.appendChild(s)),s={type:"script",instance:s,count:1,state:null},a.set(i,s))}}function j0(e,t){Ol.M(e,t);var l=on;if(l&&e){var a=_a(l).hoistableScripts,i=dn(e),s=a.get(i);s||(s=l.querySelector(ei(i)),s||(e=_({src:e,async:!0,type:"module"},t),(t=It.get(i))&&Hc(e,t),s=l.createElement("script"),dt(s),gt(s,"link",e),l.head.appendChild(s)),s={type:"script",instance:s,count:1,state:null},a.set(i,s))}}function Hf(e,t,l,a){var i=(i=xe.current)?os(i):null;if(!i)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=rn(l.href),l=_a(i).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=rn(l.href);var s=_a(i).hoistableStyles,u=s.get(e);if(u||(i=i.ownerDocument||i,u={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},s.set(e,u),(s=i.querySelector(Pn(e)))&&!s._p&&(u.instance=s,u.state.loading=5),It.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},It.set(e,l),s||S0(i,e,l,u.state))),t&&a===null)throw Error(r(528,""));return u}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=dn(l),l=_a(i).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function rn(e){return'href="'+Kt(e)+'"'}function Pn(e){return'link[rel="stylesheet"]['+e+"]"}function wf(e){return _({},e,{"data-precedence":e.precedence,precedence:null})}function S0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),gt(t,"link",l),dt(t),e.head.appendChild(t))}function dn(e){return'[src="'+Kt(e)+'"]'}function ei(e){return"script[async]"+e}function Bf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Kt(l.href)+'"]');if(a)return t.instance=a,dt(a),a;var i=_({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),dt(a),gt(a,"style",i),rs(a,l.precedence,e),t.instance=a;case"stylesheet":i=rn(l.href);var s=e.querySelector(Pn(i));if(s)return t.state.loading|=4,t.instance=s,dt(s),s;a=wf(l),(i=It.get(i))&&Rc(a,i),s=(e.ownerDocument||e).createElement("link"),dt(s);var u=s;return u._p=new Promise(function(o,d){u.onload=o,u.onerror=d}),gt(s,"link",a),t.state.loading|=4,rs(s,l.precedence,e),t.instance=s;case"script":return s=dn(l.src),(i=e.querySelector(ei(s)))?(t.instance=i,dt(i),i):(a=l,(i=It.get(s))&&(a=_({},l),Hc(a,i)),e=e.ownerDocument||e,i=e.createElement("script"),dt(i),gt(i,"link",a),e.head.appendChild(i),t.instance=i);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,rs(a,l.precedence,e));return t.instance}function rs(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),i=a.length?a[a.length-1]:null,s=i,u=0;u title"):null)}function N0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Yf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function A0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var i=rn(a.href),s=t.querySelector(Pn(i));if(s){t=s._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fs.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=s,dt(s);return}s=t.ownerDocument||t,a=wf(a),(i=It.get(i))&&Rc(a,i),s=s.createElement("link"),dt(s);var u=s;u._p=new Promise(function(o,d){u.onload=o,u.onerror=d}),gt(s,"link",a),l.instance=s}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fs.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var wc=0;function C0(e,t){return e.stylesheets&&e.count===0&&hs(e,e.stylesheets),0wc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(i)}}:null}function fs(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hs(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var ms=null;function hs(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,ms=new Map,t.forEach(T0,e),ms=null,fs.call(e))}function T0(e,t){if(!(t.state.loading&4)){var l=ms.get(e);if(l)var a=l.get(null);else{l=new Map,ms.set(e,l);for(var i=e.querySelectorAll("link[data-precedence],style[data-precedence]"),s=0;s"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Zc.exports=K0(),Zc.exports}var k0=Z0();function be(c){return Array.isArray(c)?c:[]}function hm(c){const m=new Set;return c.map(y=>y.trim()).filter(y=>{const r=y.toLowerCase();return!y||m.has(r)?!1:(m.add(r),!0)})}function il(c){const m=Ns.some(y=>y.value===c.streamMode)?c.streamMode:"auto";return{...c,streamMode:m,models:be(c.models),allowedGroupIds:be(c.allowedGroupIds),openaiAccounts:be(c.openaiAccounts),kiroAccounts:be(c.kiroAccounts)}}function ui(c){return{...c,aliases:be(c.aliases)}}function V0(c){return{...c,apiKeys:be(c.apiKeys),logs:be(c.logs)}}class Cs extends Error{status;payload;constructor(m,y,r){super(y),this.status=m,this.payload=r}}const J0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function Ot({name:c}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:J0[c]})})}async function pe(c,m){const y=new Headers(m?.headers);y.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&y.set("Authorization",`Bearer ${r}`);const E=await fetch(c,{credentials:"include",...m,headers:y});if(!E.ok){const O=await E.json().catch(()=>null);throw new Cs(E.status,O?.error?.message||`Request failed: ${E.status}`,O)}return E.json()}async function $0(c,m){const y=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&y.set("Authorization",`Bearer ${r}`);const E=await fetch(c,{credentials:"include",method:"POST",headers:y,body:m});if(!E.ok){const O=await E.json().catch(()=>null);throw new Cs(E.status,O?.error?.message||`Request failed: ${E.status}`,O)}return E.json()}const rm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],eo=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],pm="https://api.openai.com/v1",Ts="https://chatgpt.com/backend-api",vm="http://localhost:8317/v1",ym="https://codewhisperer.us-east-1.amazonaws.com",bm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",W0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",F0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",I0="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:ym,models:I0.split(",").map(c=>c.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:pm,models:W0.split(",").map(c=>c.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ts,models:bm.split(",").map(c=>c.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:vm,models:F0.split(",").map(c=>c.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Aa(c){return Fc.find(m=>m.provider===c)||Fc[2]}function gm(c){const m=Aa(c);return{name:m.name,provider:m.provider,baseUrl:m.baseUrl,models:[...m.models],streamMode:"auto"}}function P0(c){const m=c?.trim().toLowerCase();return m&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[m]||c)||"套餐未知"}function dm(c){return c?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[c]||c:""}function Es(c){return c==="openai"?pm:c==="codex"?Ts:c==="cpa"||c==="cliproxyapi"?vm:c==="kiro"?ym:""}function Ic(c){return hm(c.split(/[\s,;,;]+/))}function ep(c){return hm(c.split(/[\n,;,;]+/).map(m=>m.trim()))}function xm(c){const m=ep(c);return m.length===0?{}:m.length===1?{upstreamApiKey:m[0]}:{upstreamApiKeys:m}}const Ns=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function el(c){if(!c)return"未使用";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(m)}function fm(c){if(!c)return"";const m=new Date(c);if(Number.isNaN(m.getTime()))return"";const y=m.getTimezoneOffset()*6e4;return new Date(m.getTime()-y).toISOString().slice(0,16)}function tp(c){if(!c)return"";const m=new Date(c);return Number.isNaN(m.getTime())?"":m.toISOString()}function lp(c){if(!c)return"-";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(m)}function _t(c){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[c]||c}function ci(c,m=2){const y=Number(c||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:m,maximumFractionDigits:m}).format(y)}function Ca(c){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(c||0))))}function to(c){return c.model?c.model:c.errorCode==="invalid_api_key"?"密钥无效":c.errorCode==="model_not_available"?"模型不可用":c.errorCode==="insufficient_quota"?"额度不足":c.errorCode==="rate_limit_exceeded"?"请求过快":c.errorCode||"请求失败"}function ap(c){return c.model||(c.errorCode?`错误:${c.errorCode}`:"-")}function np(c){return c.channel||(c.apiKeyPrefix?`Key ${c.apiKeyPrefix}`:"-")}function ip(c){const m=be(c);if(m.length===0)return"未绑定模型";const y=m.slice(0,2).join(", ");return m.length>2?`${y} · 其余 ${m.length-2} 个`:y}function sl(c){return c==="cliproxyapi"||c==="cli-proxy-api"?"CPA / CLIProxyAPI":eo.find(m=>m.value===c)?.label||c||"Custom"}function $c(c){const m=`${c.vendor} ${c.id} ${c.name}`.toLowerCase();return m.includes("cliproxyapi")||/\bcpa\b/.test(m)?"cpa":m.includes("openai")||/\bgpt[-_/]/.test(m)||m.includes("o1-")||m.includes("o3-")?"openai":m.includes("anthropic")||m.includes("claude")?"anthropic":m.includes("google")||m.includes("gemini")||m.includes("gcli-")?"google":m.includes("deepseek")?"deepseek":m.includes("openrouter")?"openrouter":m.includes("groq")?"groq":m.includes("siliconflow")?"siliconflow":m.includes("moonshot")||m.includes("kimi")?"moonshot":c.vendor&&c.vendor.toLowerCase()!=="custom"?c.vendor.toLowerCase():"compatible"}function mm({provider:c}){if(c==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(c==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const m=c==="codex"?"C":c==="cpa"||c==="cliproxyapi"?"CPA":c==="anthropic"?"A":c==="google"?"✦":c==="openrouter"?"↗":c==="groq"?"G":c==="siliconflow"?"S":c==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${c}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:m})]})})}async function As(c){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(c);return}const m=document.createElement("textarea");m.value=c,m.setAttribute("readonly","true"),m.style.position="fixed",m.style.opacity="0",document.body.appendChild(m),m.select(),document.execCommand("copy"),document.body.removeChild(m)}function _l(){return window.location.origin}function sp(){return`${_l()}/api/auth/discord/callback`}function up(){return`${_l()}/`}function Wc(c){return{...c,redirectUri:c.redirectUri&&!c.redirectUri.includes("localhost")?c.redirectUri:sp(),authSuccessUrl:c.authSuccessUrl&&!c.authSuccessUrl.includes("localhost")?c.authSuccessUrl:up(),blockedGuildIds:be(c.blockedGuildIds),sessionTtlHours:c.sessionTtlHours||168}}function Ms(c){return c==="email"||c==="discord"?c:"username"}function cp(c){const y=(c.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(y.length>=3?y:"user").slice(0,24)}function op(){const[c,m]=g.useState("home"),[y,r]=g.useState("login"),[E,O]=g.useState(null),[K,P]=g.useState("overview"),[T,b]=g.useState(()=>{const H=window.localStorage.getItem("capi-theme");return H==="light"||H==="dark"?H:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[G,_]=g.useState("comfortable"),[ae,te]=g.useState(null),[de,le]=g.useState([]),[ne,ie]=g.useState([]),[ge,me]=g.useState([]),[Ce,F]=g.useState([]),[ve,D]=g.useState([]),[ee,oe]=g.useState(""),[Ne,Me]=g.useState(""),[ue,Q]=g.useState(null),[re,V]=g.useState(""),[A,Y]=g.useState(""),[p,z]=g.useState(!1),$=g.useMemo(()=>{const H=ee.trim().toLowerCase();return H?de.filter(X=>`${X.id} ${X.name} ${X.email}`.toLowerCase().includes(H)):de},[ee,de]);async function f(){const H=new Date().getTimezoneOffset(),[X,I,W,he,qe,Ze]=await Promise.all([pe(`/api/overview?timezoneOffset=${H}`),pe("/api/users"),pe("/api/channels"),pe("/api/models"),pe("/api/logs"),pe("/api/groups")]),Rt=be(I.users),Dl=be(W.channels).map(il),sa=be(he.models).map(ui),Ta=be(qe.logs),Ea=be(Ze.groups);te(X),le(Rt),ie(Dl),me(Ea),F(sa),D(Ta),Me(Ul=>Ul&&Rt.some(fl=>fl.id===Ul)?Ul:Rt[0]?.id||""),Rt.length===0&&Q(null),z(!0)}async function N(H){const X=await pe(`/api/users/${H}`);Q(V0(X))}async function q(H,X){const I=await pe(`/api/users/${H}`,{method:"PATCH",body:JSON.stringify(X)});le(W=>W.map(he=>he.id===H?I.user:he)),Q(W=>W?.user.id===H?{...W,user:I.user}:W),V("已更新用户"),window.setTimeout(()=>V(""),1800)}async function L(H,X,I={}){const W=await pe("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:H,action:X,...I})}),he=new Map(be(W.users).map(qe=>[qe.id,qe]));le(qe=>qe.map(Ze=>he.get(Ze.id)||Ze)),Q(qe=>{if(!qe)return qe;const Ze=he.get(qe.user.id);return Ze?{...qe,user:Ze}:qe}),V(`已处理 ${W.updated} 个用户`),window.setTimeout(()=>V(""),1800)}async function Z(H){const X=await pe(`/api/users/${H}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ue?.user.id===H&&Q({...ue,apiKeys:[...ue.apiKeys,X.apiKey]}),Y(X.secret),await As(X.secret),V("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>V(""),2400)}async function xe(H){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await pe(`/api/api-keys/${H}`,{method:"DELETE"}),Q(X=>X&&{...X,apiKeys:X.apiKeys.filter(I=>I.id!==H)}),V("Key 已删除"),window.setTimeout(()=>V(""),1800))}async function M(H,X){const I=await pe(`/api/api-keys/${H}`,{method:"PATCH",body:JSON.stringify(X)});Q(W=>W&&{...W,apiKeys:W.apiKeys.map(he=>he.id===H?I.apiKey:he)}),V("Key 已更新"),window.setTimeout(()=>V(""),1800)}async function je(H,X){const I=await pe(`/api/channels/${H}`,{method:"PATCH",body:JSON.stringify(X)});ie(W=>W.map(he=>he.id===H?il(I.channel):he)),Ie(I.removedModels),V("渠道已更新"),window.setTimeout(()=>V(""),1800)}async function Se(H){const X=ne.find(W=>W.id===H);if(!window.confirm(`删除渠道「${X?.name||H}」?`))return;const I=await pe(`/api/channels/${H}`,{method:"DELETE"});ie(W=>W.filter(he=>he.id!==H)),Ie(I.removedModels),V("渠道已删除"),window.setTimeout(()=>V(""),1800)}async function ot(H){const X=await pe("/api/groups",{method:"POST",body:JSON.stringify(H)});me(I=>[...I,X.group]),V("分组已创建"),window.setTimeout(()=>V(""),1800)}async function J(H,X){const I=await pe(`/api/groups/${H}`,{method:"PATCH",body:JSON.stringify(X)});me(W=>W.map(he=>he.id===H?I.group:he)),V("分组已更新"),window.setTimeout(()=>V(""),1800)}async function Je(H){const X=ge.find(I=>I.id===H);window.confirm(`删除分组「${X?.name||H}」?删除后渠道的可见范围会移除该分组。`)&&(await pe(`/api/groups/${H}`,{method:"DELETE"}),me(I=>I.filter(W=>W.id!==H)),ie(I=>I.map(W=>({...W,allowedGroupIds:W.allowedGroupIds.filter(he=>he!==H)}))),V("分组已删除"),window.setTimeout(()=>V(""),1800))}async function ut(H,X){const I=be(X).map(Rt=>Rt.trim()).filter(Boolean),W=await pe(`/api/channels/${H}/sync-models`,{method:"POST",body:JSON.stringify(I.length?{models:I}:{})}),he=il(W.channel),qe=be(W.addedModels).map(ui),Ze=be(W.models);ie(Rt=>Rt.map(Dl=>Dl.id===H?he:Dl)),qe.length>0&&F(Rt=>{const Dl=new Set(Rt.map(sa=>sa.id.toLowerCase()));return[...Rt,...qe.filter(sa=>!Dl.has(sa.id.toLowerCase()))]}),Ie(W.removedModels),V(I.length?`已保存 ${Ze.length} 个模型`:Ze.length?`已拉取 ${Ze.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>V(""),2200)}function Ie(H){const X=new Set(be(H).map(I=>I.toLowerCase()));X.size!==0&&(F(I=>I.filter(W=>!X.has(W.id.toLowerCase()))),Q(I=>I&&{...I,apiKeys:I.apiKeys.map(W=>({...W,allowedModels:W.allowedModels.filter(he=>!X.has(he.toLowerCase()))}))}))}async function tl(H){try{const X=await pe(`/api/channels/${H}/check`,{method:"POST",body:JSON.stringify({})});ie(I=>I.map(W=>W.id===H?il(X.channel):W)),V(X.ok?`渠道可用,检测到 ${be(X.models).length} 个模型`:"渠道检测失败")}catch(X){const I=X instanceof Cs?X.payload?.channel:null;I&&ie(W=>W.map(he=>he.id===H?il(I):he)),V(X instanceof Error?X.message:"渠道检测失败")}window.setTimeout(()=>V(""),2400)}async function k(H=gm("codex")){const X=await pe("/api/channels",{method:"POST",body:JSON.stringify(H)});ie(I=>[...I,il(X.channel)]),V("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>V(""),2400)}async function mt(H,X){const I=new FormData;I.append("file",X);const W=await $0(`/api/channels/${encodeURIComponent(H)}/import-openai-accounts`,I);ie(he=>he.map(qe=>qe.id===W.channel.id?il(W.channel):qe)),V(`新增 ${W.created??W.imported} 个账号${W.updated?`,更新 ${W.updated} 个已有账号`:""}${W.skipped?`,跳过 ${W.skipped} 个`:""}`),window.setTimeout(()=>V(""),2600)}async function Ut(H,X=!1,I=""){const W=await pe(`/api/channels/${encodeURIComponent(H)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:X,accountId:I})});ie(he=>he.map(qe=>qe.id===W.channel.id?il(W.channel):qe)),V(`${X?"无效账号复检":"账号测活"}完成:${W.healthy}/${W.checked} 可用${W.failed?`,无效 ${W.failed}`:""}`),window.setTimeout(()=>V(""),3e3)}async function R(H){const X=await pe(`/api/channels/${encodeURIComponent(H)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ie(I=>I.map(W=>W.id===X.channel.id?il(X.channel):W)),V(X.removed?`已合并 ${X.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>V(""),2600)}async function Ue(H,X){const I=await pe(`/api/channels/${encodeURIComponent(H)}/openai-accounts/${encodeURIComponent(X)}`,{method:"DELETE"});ie(W=>W.map(he=>he.id===I.channel.id?il(I.channel):he)),V("账号已删除"),window.setTimeout(()=>V(""),1800)}async function rt(H){return pe(`/api/channels/${encodeURIComponent(H)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function jt(H,X){const I=await pe(`/api/channels/${encodeURIComponent(H)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(X)});return ie(W=>W.map(he=>he.id===I.channel.id?il(I.channel):he)),V("已通过 OAuth 添加账号"),window.setTimeout(()=>V(""),2400),I}async function ht(H){const X=await pe("/api/models",{method:"POST",body:JSON.stringify(H)});F(I=>[...I,ui(X.model)]),V("模型已添加"),window.setTimeout(()=>V(""),1800)}async function Pe(H,X){const I=await pe(`/api/models/${encodeURIComponent(H)}`,{method:"PATCH",body:JSON.stringify(X)});F(W=>W.map(he=>he.id===H?ui(I.model):he)),V("模型已更新"),window.setTimeout(()=>V(""),1600)}async function zs(H){window.confirm(`删除模型 ${H}?渠道和 Key 中的引用也会一起清理。`)&&(await pe(`/api/models/${encodeURIComponent(H)}`,{method:"DELETE"}),F(X=>X.filter(I=>I.id!==H)),ie(X=>X.map(I=>({...I,models:I.models.filter(W=>W!==H)}))),Q(X=>X&&{...X,apiKeys:X.apiKeys.map(I=>({...I,allowedModels:I.allowedModels.filter(W=>W!==H)}))}),V("模型已删除"),window.setTimeout(()=>V(""),1800))}async function mn(H,X="已复制"){await As(H),V(X),window.setTimeout(()=>V(""),1600)}function na(H,X){if(H instanceof Cs&&H.status===401){z(!1),r("login"),m("auth");return}V(X)}async function ia(){try{const H=await pe("/api/auth/status");if(O(H),!H.initialized){r("setup"),m("auth");return}if(!H.authenticated){r("login"),m("auth");return}m(H.session?.role==="admin"?"console":"account")}catch(H){na(H,"认证状态加载失败")}}async function Os(){await pe("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),O(null),m("home")}return g.useEffect(()=>{let H=!1;return pe("/api/auth/status").then(X=>{H||(O(X),X.authenticated&&X.session&&m(X.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{H=!0}},[]),g.useEffect(()=>{c==="console"&&(z(!1),f().catch(H=>na(H,"加载数据失败")))},[c]),g.useEffect(()=>{c!=="console"||!p||N(Ne).catch(H=>na(H,"加载用户详情失败"))},[Ne,c,p]),g.useEffect(()=>{window.localStorage.setItem("capi-theme",T)},[T]),g.useEffect(()=>{window.scrollTo({top:0,left:0})},[c,K]),c==="home"?n.jsx(fp,{theme:T,setTheme:b,enterConsole:ia}):c==="auth"?n.jsx(rp,{theme:T,mode:y,status:E,setTheme:b,setMode:r,goHome:()=>m("home"),onAuthenticated:H=>{O(X=>X?{...X,authenticated:!0,initialized:!0,session:H}:null),m(H.role==="admin"?"console":"account")}}):c==="account"?n.jsx(dp,{theme:T,setTheme:b,goHome:()=>m("home"),openLogin:ia}):n.jsxs("div",{className:"app-shell","data-theme":T,"data-density":G,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:rm.map(H=>n.jsxs("button",{className:K===H.id?"nav-item active":"nav-item",onClick:()=>P(H.id),children:[n.jsx(Ot,{name:H.icon}),n.jsx("span",{className:"nav-label",children:H.label})]},H.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:rm.find(H=>H.id===K)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(qp,{value:G,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:H=>_(H)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>b(T==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:T==="dark"?"sun":"moon"}),n.jsx("span",{children:T==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>f().catch(H=>na(H,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>m("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Os,children:"退出"})]})]}),K==="overview"&&n.jsx(mp,{overview:ae,channels:ne,logs:ve,onNavigate:H=>{P(H),H==="channels"&&ne.length===0&&V("渠道页可以创建第一个上游"),H==="logs"&&ve.length===0&&V("暂无异常日志"),window.setTimeout(()=>V(""),1800)}}),K==="users"&&n.jsx(pp,{users:$,query:ee,selectedUser:ue,onQuery:oe,onSelect:Me,onUpdate:q,onBulkUpdate:L,onCreateKey:Z,groups:ge,onOpenRegistration:()=>{P("settings"),V("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>V(""),2400)}}),K==="groups"&&n.jsx(wp,{groups:ge,onCreate:ot,onUpdate:J,onDelete:Je}),K==="keys"&&n.jsx(vp,{selectedUser:ue,onCreateKey:Z,onUpdateKey:M,onDeleteKey:xe}),K==="models"&&n.jsx(bp,{models:Ce,onCopy:mn,onCreate:ht,onUpdate:Pe,onDelete:zs}),K==="drawing"&&n.jsx(jp,{channels:ne,onCreate:k,onImport:mt,onCheckAccounts:Ut,onDeduplicateAccounts:R,onDeleteAccount:Ue,onUpdate:je,onStartOAuth:rt,onCompleteOAuth:jt}),K==="channels"&&n.jsx(_p,{channels:ne,groups:ge,onUpdate:je,onCreate:k,onImport:mt,onDelete:Se,onSyncModels:ut,onCheck:tl}),K==="logs"&&n.jsx(Up,{logs:ve,onCopy:mn}),K==="settings"&&n.jsx(Hp,{models:Ce,channels:ne,groups:ge})]}),A&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:A}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{As(A),V("完整 Key 已复制"),window.setTimeout(()=>V(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>Y(""),children:"完成"})]})]})}),re&&n.jsx("div",{className:"toast",children:re})]})}function rp({theme:c,mode:m,status:y,setTheme:r,setMode:E,goHome:O,onAuthenticated:K}){const[P,T]=g.useState(""),[b,G]=g.useState(""),[_,ae]=g.useState(""),[te,de]=g.useState(""),[le,ne]=g.useState(""),[ie,ge]=g.useState(""),[me,Ce]=g.useState(!1),[F,ve]=g.useState("username"),[D,ee]=g.useState("0"),[oe,Ne]=g.useState(""),[Me,ue]=g.useState(!1),Q=m==="setup",re=m==="register",V=Ms(y?.registrationMode),A=re&&V==="email",Y=re&&V==="discord";async function p(){if(!Y){if((Q||re)&&le!==ie){Ne("两次输入的密码不一致");return}ue(!0),Ne("");try{const z=Q?"/api/auth/setup":re?"/api/auth/register":"/api/auth/login",$=A?cp(_):P,f=m==="login"?{identifier:P,password:le}:{username:$,password:le,displayName:b,email:_,discordUserId:Q?te:"",registrationEnabled:Q?me:void 0,registrationMode:Q?F:void 0,defaultBalance:Q?Number(D||0):void 0},N=await pe(z,{method:"POST",body:JSON.stringify(f)});K(N.session)}catch(z){Ne(z instanceof Error?z.message:"操作失败")}finally{ue(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":c,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:O,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(c==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:Q?"First Run":"Welcome Back"}),n.jsx("h1",{children:Q?"初始化 CAPI":re?"创建账号":"登录"}),n.jsx("p",{children:Q?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:z=>{z.preventDefault(),p()},children:[Y?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),y?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:b,onChange:z=>G(z.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!A&&n.jsxs("label",{children:[n.jsx("span",{children:m==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:P,onChange:z=>T(z.target.value),autoComplete:"username",placeholder:m==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(Q||A)&&n.jsxs("label",{children:[n.jsx("span",{children:A?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:_,onChange:z=>ae(z.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),Q&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:te,onChange:z=>de(z.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:me?"ios-switch is-on":"ios-switch","aria-pressed":me,onClick:()=>Ce(z=>!z),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:F,onChange:z=>ve(Ms(z.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:D,onChange:z=>ee(z.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:le,onChange:z=>ne(z.target.value),autoComplete:m==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ie,onChange:z=>ge(z.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:oe}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Me,children:Me?"请稍候":Q?"创建管理员":re?"注册":"登录"})]}),!Q&&!Y&&y?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!Q&&n.jsx("div",{className:"auth-switch",children:m==="login"&&y?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>E("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>E("login"),children:"返回登录"})})]})]})]})}function dp({theme:c,setTheme:m,goHome:y,openLogin:r}){const[E,O]=g.useState(null),[K,P]=g.useState([]),[T,b]=g.useState(null),[G,_]=g.useState(!1),[ae,te]=g.useState(""),[de,le]=g.useState(""),[ne,ie]=g.useState("");async function ge(){try{const[D,ee,oe]=await Promise.all([pe("/api/account/me"),pe("/api/catalog/models"),pe("/api/account/check-in")]);O({...D,apiKeys:be(D.apiKeys)}),P(be(ee.models).map(ui)),b(oe.checkIn)}catch{r()}}g.useEffect(()=>{ge()},[]);async function me(){if(!(!T?.enabled||T.claimed||G)){_(!0),te("");try{const D=await pe("/api/account/check-in",{method:"POST",body:JSON.stringify({})});O(ee=>ee&&{...ee,user:D.user}),b(D.checkIn),te(`签到成功,获得 ${D.reward.toFixed(2)} 额度`)}catch(D){te(D instanceof Error?D.message:"签到失败,请稍后重试")}finally{_(!1)}}}async function Ce(){try{const D=await pe("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});le(D.secret),ie("新密钥只显示这一次"),await ge()}catch(D){ie(D instanceof Error?D.message:"创建密钥失败")}}async function F(D){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await pe(`/api/account/api-keys/${D}`,{method:"DELETE"}),O(ee=>ee&&{...ee,apiKeys:ee.apiKeys.filter(oe=>oe.id!==D)}),ie("密钥已删除")}catch(ee){ie(ee instanceof Error?ee.message:"删除密钥失败")}}async function ve(){await pe("/api/auth/logout",{method:"POST"}),y()}return n.jsxs("main",{className:"account-page","data-theme":c,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:y,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:n.jsx(Ot,{name:c==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:ve,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:E?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:E?E.user.balance.toFixed(2):"-"})]})]}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!T?.enabled||!!T?.claimed||G,onClick:me,children:G?"领取中":T?.claimed?"今日已签到":T?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:T?.claimed?`已领取 ${T.reward.toFixed(2)}`:T?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:T?`${T.minReward.toFixed(2)} - ${T.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:T?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),ae&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:ae})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:Ce,children:"创建密钥"})]}),de&&n.jsx("code",{className:"one-time-secret",children:de}),ne&&n.jsx("p",{className:"account-message",children:ne}),n.jsxs("div",{className:"account-key-list",children:[E?.apiKeys?.map(D=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(Ot,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:D.name}),n.jsxs("code",{children:[D.prefix,"…"]})]}),n.jsx(Dt,{tone:D.status,children:_t(D.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${D.name}`,title:"删除密钥",onClick:()=>F(D.id),children:n.jsx(Ot,{name:"ban"})})]},D.id)),be(E?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[K.map(D=>n.jsxs("article",{children:[n.jsx("span",{children:D.vendor}),n.jsx("strong",{children:D.name}),n.jsx("p",{children:D.description}),n.jsx("code",{children:D.id})]},D.id)),K.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function fp({theme:c,setTheme:m,enterConsole:y}){return n.jsxs("main",{className:"public-home","data-theme":c,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:y,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:y,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ - -H "Authorization: Bearer cat_..." \\ - -d '{ - "model": "capi-fast", - "messages": [{ "role": "user", "content": "ping" }] - }'`})]}),n.jsxs("div",{className:"terminal-route",children:[n.jsxs("div",{children:[n.jsx("span",{children:"auth"}),n.jsx("strong",{children:"pass"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"quota"}),n.jsx("strong",{children:"ok"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"route"}),n.jsx("strong",{children:"capi-fast"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"latency"}),n.jsx("strong",{children:"186ms"})]})]}),n.jsxs("div",{className:"terminal-block response",children:[n.jsx("span",{children:"RESPONSE"}),n.jsxs("pre",{children:[`{ - "status": 200, - "model": "capi-fast", - "usage": { "total_tokens": 27 }, - "message": "request routed" -}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function mp({overview:c,channels:m,logs:y,onNavigate:r}){const E=y.filter(O=>O.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",c?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Ss,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Ss,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Ss,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Ss,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"活跃用户",value:c?Ca(c.activeUsers):"-"}),n.jsx(ul,{label:"今日请求",value:c?Ca(c.requestsToday):"-"}),n.jsx(ul,{label:"今日输入",value:c?Ca(c.todayInputTokens):"-"}),n.jsx(ul,{label:"今日输出",value:c?Ca(c.todayOutputTokens):"-"}),n.jsx(ul,{label:"今日扣费",value:c?ci(c.todayCost,4):"-"}),n.jsx(ul,{label:"账户余额",value:c?ci(c.totalBalance):"-"}),n.jsx(ul,{label:"成功率",value:c?`${c.successRate}%`:"-"})]}),n.jsx(hp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(lt,{title:"渠道状态",children:m.length?m.map(O=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:O.name}),n.jsx("span",{title:be(O.models).join(", "),children:ip(O.models)})]}),n.jsx(Dt,{tone:O.status,children:_t(O.status)})]},O.id)):n.jsx(Qt,{text:"暂无渠道"})}),n.jsx(lt,{title:"最近请求",children:y.length?y.slice(0,4).map(O=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:to(O)}),n.jsxs("span",{children:[O.id," · ",O.errorCode||el(O.createdAt)]})]}),n.jsx(Dt,{tone:O.status,children:_t(O.status)})]},O.id)):n.jsx(Qt,{text:E.length?"暂无最近请求":"暂无请求"})})]})]})}function Ss({icon:c,label:m,onClick:y}){return n.jsxs("button",{className:"quick-action",onClick:y,children:[n.jsx(Ot,{name:c}),n.jsx("span",{children:m})]})}function hp(){const c=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:c.map((m,y)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:y+1}),n.jsx("strong",{children:m.label}),n.jsx("span",{children:m.detail})]},m.label))})]})}function pp({users:c,query:m,selectedUser:y,onQuery:r,onSelect:E,onUpdate:O,onBulkUpdate:K,onCreateKey:P,groups:T,onOpenRegistration:b}){const[_,ae]=g.useState(1),[te,de]=g.useState("all"),[le,ne]=g.useState(new Set),[ie,ge]=g.useState("10"),[me,Ce]=g.useState(""),[F,ve]=g.useState(""),[D,ee]=g.useState(!1),[oe,Ne]=g.useState("10"),[Me,ue]=g.useState(""),[Q,re]=g.useState(""),[V,A]=g.useState(!1),Y=te==="all"?c:c.filter(M=>M.status===te),p=Y.filter(M=>M.role!=="admin"),z=Math.max(1,Math.ceil(Y.length/25)),$=Math.min(_,z),f=Y.slice(($-1)*25,$*25),N=p.length>0&&p.every(M=>le.has(M.id));g.useEffect(()=>{ae(1)},[m,te]),g.useEffect(()=>{const M=new Set(c.map(je=>je.id));ne(je=>new Set([...je].filter(Se=>M.has(Se))))},[c]),g.useEffect(()=>{Ne("10"),ue(""),re("")},[y?.user.id]);function q(M){ne(je=>{const Se=new Set(je);return Se.has(M)?Se.delete(M):Se.add(M),Se})}function L(){ne(M=>{const je=new Set(M);return N?p.forEach(Se=>je.delete(Se.id)):p.forEach(Se=>je.add(Se.id)),je})}async function Z(M,je){if(le.size!==0){ee(!0);try{await K([...le],M,je),ne(new Set),Ce("")}finally{ee(!1)}}}async function xe(M){if(!y)return;const je=Math.abs(Number(oe));if(!Number.isFinite(je)||je<=0){re("请输入大于 0 的金额");return}A(!0),re("");try{await K([y.user.id],"adjust_balance",{amount:Number((je*M).toFixed(4)),reason:Me.trim()||(M>0?"管理员增加额度":"管理员扣减额度")}),re(M>0?"额度已增加":"额度已扣减"),ue("")}catch(Se){re(Se instanceof Error?Se.message:"额度调整失败")}finally{A(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(lt,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:m,onChange:M=>r(M.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:b,children:n.jsx(Ot,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:c.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(M=>M.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(M=>M.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.reduce((M,je)=>M+je.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(M=>n.jsx("button",{type:"button",className:te===M.value?"selected":"",onClick:()=>de(M.value),children:M.label},M.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:L,children:N?"取消全选":`全选结果(${p.length})`}),le.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",le.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ie,onChange:M=>ge(M.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:me,onChange:M=>Ce(M.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D||!Number(ie),onClick:()=>Z("adjust_balance",{amount:Number(ie),reason:me}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>Z("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:D,onClick:()=>Z("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:F,disabled:D,"aria-label":"批量设置分组",onChange:M=>ve(M.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),T.map(M=>n.jsx("option",{value:M.id,children:M.name},M.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>Z("set_group",{value:F}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:N,onChange:L,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),f.map(M=>n.jsxs("div",{className:y?.user.id===M.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>E(M.id),onKeyDown:je=>{(je.key==="Enter"||je.key===" ")&&E(M.id)},children:[n.jsx("input",{type:"checkbox",checked:le.has(M.id),disabled:M.role==="admin",onChange:()=>q(M.id),onClick:je=>je.stopPropagation(),"aria-label":M.role==="admin"?`${M.name} 是管理员,不参与批量操作`:`选择 ${M.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:M.name}),n.jsxs("small",{children:[M.id," · ",M.email||"未绑定邮箱"]})]}),n.jsx(Dt,{tone:M.status,children:_t(M.status)}),n.jsx("span",{children:ci(M.balance)}),n.jsx("span",{children:M.requestsToday})]},M.id)),Y.length===0&&n.jsx(Qt,{text:"暂无匹配用户"})]}),Y.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:$<=1,onClick:()=>ae(M=>Math.max(1,M-1)),children:"上一页"}),n.jsxs("span",{children:[$," / ",z]}),n.jsx("button",{className:"secondary-button",disabled:$>=z,onClick:()=>ae(M=>Math.min(z,M+1)),children:"下一页"})]})]}),n.jsx(lt,{title:"用户详情",children:y?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:y.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:y.user.name}),n.jsx("p",{children:y.user.email})]}),n.jsx(Dt,{tone:y.user.status,children:_t(y.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"角色",value:y.user.role==="admin"?"管理员":"用户"}),n.jsx(Pt,{label:"余额",value:ci(y.user.balance)}),n.jsx(Pt,{label:"总请求",value:String(y.user.totalRequests)}),n.jsx(Pt,{label:"最后登录",value:el(y.user.lastLoginAt)}),n.jsx(Pt,{label:"API 调用",value:y.user.status==="disabled"?"关闭":"允许",switchOn:y.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:y.user.groupId||"",onChange:M=>O(y.user.id,{groupId:M.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),T.map(M=>n.jsx("option",{value:M.id,children:M.name},M.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",ci(y.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:oe,onChange:M=>Ne(M.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Me,onChange:M=>ue(M.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:V,onClick:()=>xe(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:V,onClick:()=>xe(-1),children:"扣减"}),n.jsx("span",{role:"status",children:Q})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>P(y.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:y.user.role==="admin",onClick:()=>O(y.user.id,{status:y.user.status==="disabled"?"active":"disabled"}),children:y.user.role==="admin"?"管理员保护":y.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),y.apiKeys.map(M=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:M.name}),n.jsxs("span",{children:[M.prefix,"*** · ",M.requestCount," 次"]})]}),n.jsx(Dt,{tone:M.status,children:_t(M.status)})]},M.id)),y.apiKeys.length===0&&n.jsx(Qt,{text:"暂无 API Key"})]})]}):n.jsx(Qt,{text:"请选择一个用户"})})]})}function vp({selectedUser:c,onCreateKey:m,onUpdateKey:y,onDeleteKey:r}){return n.jsx(lt,{title:"密钥管理",children:c?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[c.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>m(c.user.id),children:"创建 Key"})]}),c.apiKeys.length?c.apiKeys.map(E=>n.jsx(yp,{apiKey:E,onSave:y,onDelete:r},E.id)):n.jsx(Qt,{text:"暂无密钥"})]}):n.jsx(Qt,{text:"请选择一个用户"})})}function yp({apiKey:c,onSave:m,onDelete:y}){const[r,E]=g.useState(c.name),[O,K]=g.useState(be(c.allowedModels).join(", ")),[P,T]=g.useState(fm(c.expiresAt||"")),[b,G]=g.useState(String(c.rateLimitPerMinute||"")),[_,ae]=g.useState(!1),te=be(c.allowedModels).length?be(c.allowedModels).join(", "):"全部模型";g.useEffect(()=>{E(c.name),K(be(c.allowedModels).join(", ")),T(fm(c.expiresAt||"")),G(String(c.rateLimitPerMinute||""))},[c]);async function de(){ae(!0);try{await m(c.id,{name:r.trim()||"API Key",allowedModels:Ic(O),expiresAt:tp(P),rateLimitPerMinute:Number(b||0)})}finally{ae(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.prefix,"*** · ",te," · 最后使用 ",el(c.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(Dt,{tone:c.status,children:_t(c.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:le=>E(le.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:O,onChange:le=>K(le.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:P,onChange:le=>T(le.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:b,onChange:le=>G(le.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>m(c.id,{status:c.status==="active"?"disabled":"active"}),children:c.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>y(c.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:_,onClick:de,children:_?"保存中":"保存设置"})]})]})]})}function bp({models:c,onCopy:m,onCreate:y,onUpdate:r,onDelete:E}){const O=c.filter(p=>p.recommended),[K,P]=g.useState(""),[T,b]=g.useState("all"),[G,_]=g.useState("all"),[ae,te]=g.useState(1),[de,le]=g.useState(""),[ne,ie]=g.useState(""),[ge,me]=g.useState(""),[Ce,F]=g.useState(""),[ve,D]=g.useState(""),[ee,oe]=g.useState(""),Ne=60,Me=g.useMemo(()=>{const p=new Map;return c.forEach(z=>{const $=$c(z);p.set($,(p.get($)||0)+1)}),Array.from(p.entries()).sort((z,$)=>$[1]-z[1]||sl(z[0]).localeCompare(sl($[0]))).map(([z,$])=>({provider:z,count:$}))},[c]),ue=g.useMemo(()=>{const p=K.trim().toLowerCase();return c.filter(z=>T!=="all"&&$c(z)!==T||G!=="all"&&z.status!==G?!1:p?[z.id,z.name,z.vendor,z.category,z.description,...be(z.aliases)].join(" ").toLowerCase().includes(p):!0)},[c,K,T,G]),Q=g.useMemo(()=>{const p=new Map;ue.forEach(q=>{const L=$c(q);p.set(L,[...p.get(L)||[],q])});const z=[];let $=[],f=0;const N=Array.from(p.entries()).sort((q,L)=>sl(q[0]).localeCompare(sl(L[0])));for(const q of N)$.length>0&&f+q[1].length>Ne&&(z.push($),$=[],f=0),$.push(q),f+=q[1].length;return $.length>0&&z.push($),z},[ue]),re=Math.max(1,Q.length),V=Math.min(ae,re),A=Q[V-1]||[];g.useEffect(()=>{te(1)},[K,T,G,c.length]);async function Y(p){p.preventDefault();const z=de.trim();if(z){oe("");try{await y({id:z,name:ne.trim()||z,vendor:ge.trim()||"Custom",aliases:Ce.split(",").map($=>$.trim()).filter(Boolean),category:"通用",description:ve.trim(),price:"自定义",context:"未配置上下文"}),le(""),ie(""),me(""),F(""),D("")}catch($){oe($ instanceof Error?$.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(lt,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:Y,children:[n.jsx("input",{value:de,onChange:p=>le(p.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:ne,onChange:p=>ie(p.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:ge,onChange:p=>me(p.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:Ce,onChange:p=>F(p.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:ve,onChange:p=>D(p.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:ee})]})}),O.length>0&&n.jsx(lt,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:O.map(p=>n.jsx(xp,{model:p,featured:!0,onCopy:m,onUpdate:r},p.id))})}),n.jsxs(lt,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:K,onChange:p=>P(p.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(p=>n.jsx("button",{type:"button",className:G===p.value?"selected":"",onClick:()=>_(p.value),children:p.label},p.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:T==="all"?"selected":"",onClick:()=>b("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:c.length})]}),Me.map(p=>n.jsxs("button",{type:"button",className:T===p.provider?"selected":"",onClick:()=>b(p.provider),children:[n.jsx(mm,{provider:p.provider}),n.jsx("strong",{children:sl(p.provider)}),n.jsx("small",{children:p.count})]},p.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:T==="all"?"全部供应商":sl(T)}),n.jsx("strong",{children:ue.length}),n.jsx("span",{children:"个模型"})]}),ue.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:A.map(([p,z])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(mm,{provider:p}),n.jsxs("div",{children:[n.jsx("strong",{children:sl(p)}),n.jsxs("span",{children:[z.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:z.map($=>n.jsx(gp,{model:$,onCopy:m,onUpdate:r,onDelete:E},$.id))})]},p))}),re>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>te(p=>Math.max(1,p-1)),disabled:V<=1,children:"上一页"}),n.jsxs("span",{children:[V," / ",re]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>te(p=>Math.min(re,p+1)),disabled:V>=re,children:"下一页"})]})]}):n.jsx(Qt,{text:c.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function gp({model:c,onCopy:m,onUpdate:y,onDelete:r}){const E=be(c.aliases).slice(0,3),O=c.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:c.name}),n.jsx("small",{children:c.id}),E.length>0&&n.jsx("span",{children:E.map(K=>n.jsx("em",{children:K},K))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(Dt,{tone:c.status,children:_t(c.status)}),c.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>m(c.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>y(c.id,{recommended:!c.recommended}),children:c.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>y(c.id,{status:O?"available":"disabled"}),children:O?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(c.id),children:"删除模型"})]})]})]})]})}function xp({model:c,featured:m=!1,onCopy:y,onUpdate:r}){return n.jsxs("article",{className:m?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.vendor," · ",c.category]})]}),n.jsx(Dt,{tone:c.status,children:_t(c.status)})]}),n.jsx("p",{children:c.description}),n.jsx("div",{className:"alias-row",children:be(c.aliases).map(E=>n.jsx("span",{children:E},E))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",c.price]}),n.jsx("span",{children:c.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:c.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>y(c.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{status:c.status==="disabled"?"available":"disabled"}),children:c.status==="disabled"?"启用":"停用"})]})]})}function jp({channels:c,onCreate:m,onImport:y,onCheckAccounts:r,onDeduplicateAccounts:E,onDeleteAccount:O,onUpdate:K,onStartOAuth:P,onCompleteOAuth:T}){const b=c.filter(p=>p.provider==="codex"||p.provider==="openai"||be(p.models).some(z=>z.includes("image"))),[G,_]=g.useState(""),[ae,te]=g.useState({}),[de,le]=g.useState({}),[ne,ie]=g.useState({}),[ge,me]=g.useState({}),[Ce,F]=g.useState(""),[ve,D]=g.useState(""),[ee,oe]=g.useState(""),Ne=24,Me=48;async function ue(p,z){_(`import:${p}`);try{await y(p,z)}finally{_("")}}async function Q(p,z=!1,$=""){_($?`check-account:${$}`:`${z?"retry":"check"}:${p}`);try{await r(p,z,$)}finally{_("")}}async function re(p){_(`dedupe:${p}`);try{await E(p)}finally{_("")}}function V(p){const z=be(p.openaiAccounts).map(Z=>[Z.email||Z.name||Z.accountId||Z.id,Z.accountId||"",Z.status||"unchecked",Z.credentialMode||"access-token",Z.planType||"",Z.expiresAt||"",Z.lastCheckedAt||"",Z.lastUsedAt||"",String(Z.requestCount||0),Z.lastErrorCode||"",Z.lastError||""]),$=Z=>`"${Z.replace(/"/g,'""')}"`,f=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...z].map(Z=>Z.map($).join(",")).join(`\r -`),N=new Blob(["\uFEFF"+f],{type:"text/csv;charset=utf-8"}),q=URL.createObjectURL(N),L=document.createElement("a");L.href=q,L.download=`${p.name||"account-pool"}-health-report.csv`,L.click(),URL.revokeObjectURL(q)}async function A(p){_(`status:${p.id}`);try{await K(p.id,{status:p.status==="disabled"?"healthy":"disabled",baseUrl:p.baseUrl||Es(p.provider)||Ts,provider:p.provider||"codex",models:be(p.models).length?p.models:bm.split(",").map(z=>z.trim())})}finally{_("")}}async function Y(p,z){const $=z.email||z.name||z.accountId||z.id;if(window.confirm(`删除账号「${$}」?`)){_(`delete-account:${z.id}`);try{await O(p.id,z.id)}finally{_("")}}}return n.jsxs(lt,{title:"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"账号有两种来源,任选其一即可。"}),n.jsx("button",{className:"primary-button",onClick:()=>m(gm("codex")),children:"新增账号池渠道"})]}),n.jsxs("div",{className:"source-guide",children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]}),n.jsxs("div",{className:"channels-stack",children:[b.map(p=>{const z=be(p.openaiAccounts),$=z.filter(k=>k.status==="healthy").length,f=z.filter(k=>k.status==="invalid").length,N=z.filter(k=>!!k.lastErrorCode).length,q=Math.max(0,z.length-$-f),L=z.filter(k=>k.credentialMode==="refreshable").length,Z=z.filter(k=>k.credentialMode==="browser-session").length,xe=Math.max(0,z.length-L-Z),M=de[p.id]||"all",je=(ne[p.id]||"").trim().toLowerCase(),Se=z.filter(k=>{const mt=M==="all"||M==="attention"&&Op(k)||M==="invalid"&&k.status==="invalid"||M==="error"&&!!k.lastErrorCode||M==="refreshable"&&k.credentialMode==="refreshable",Ut=`${k.email||""} ${k.name||""} ${k.accountId||""} ${k.userId||""} ${k.lastError||""}`.toLowerCase();return mt&&(!je||Ut.includes(je))}),ot=ge[p.id]||"pool",J=[...Se].sort((k,mt)=>{if(ot==="pool")return 0;const Ut=ot==="expiry"?k.expiresAt||"9999-12-31":k.lastUsedAt||"",R=ot==="expiry"?mt.expiresAt||"9999-12-31":mt.lastUsedAt||"";return ot==="recent"?R.localeCompare(Ut):Ut.localeCompare(R)}),Je=Math.min(J.length,ae[p.id]||Ne),ut=J.slice(0,Je),Ie=Math.max(0,J.length-ut.length),tl=Ie===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:p.name}),n.jsx("span",{children:p.baseUrl||Es(p.provider)||Ts}),n.jsxs("small",{children:["账号 ",z.length," 个,可用 ",$,",无效 ",f,",未验证 ",q]}),n.jsxs("small",{children:["可续期 ",L," · 网页会话 ",Z," · 仅 Token ",xe]}),n.jsxs("small",{children:["自动检测 ",p.lastCheckedAt?el(p.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(Dt,{tone:p.status,children:_t(p.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>oe(p.id),disabled:G!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>Q(p.id),disabled:G!==""||z.length===0,children:G===`check:${p.id}`?"检测中":"批量检测"}),f>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>Q(p.id,!0),disabled:G!=="",children:G===`retry:${p.id}`?"复检中":`复检无效 ${f}`}),z.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>re(p.id),disabled:G!=="",children:G===`dedupe:${p.id}`?"去重中":"账号去重"}),z.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>V(p),disabled:G!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>A(p),disabled:G!=="",children:p.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:ne[p.id]||"",onChange:k=>ie(mt=>({...mt,[p.id]:k.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:ot,onChange:k=>me(mt=>({...mt,[p.id]:k.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${z.length}`],["attention","需关注"],["invalid",`无效 ${f}`],["error",`有错误 ${N}`],["refreshable",`可续期 ${L}`]].map(([k,mt])=>n.jsx("button",{type:"button",className:M===k?"selected":"",onClick:()=>le(Ut=>({...Ut,[p.id]:k})),children:mt},k))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"账号总数",value:z.length}),n.jsx(ul,{label:"可用账号",value:$}),n.jsx(ul,{label:"无效账号",value:f}),n.jsx(ul,{label:"未验证账号",value:q})]}),n.jsx("div",{className:"drawing-channel-models",children:be(p.models).length?be(p.models).map(k=>n.jsx("span",{children:k},k)):n.jsx("span",{children:"未绑定绘图模型"})}),z.length>0&&n.jsxs("div",{className:"account-pool-list",children:[ut.map(k=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:k.email||k.name||k.accountId||k.id,children:k.email||k.name||k.accountId||k.id}),n.jsx("span",{className:`source-tag source-tag-${k.source==="web-login"?"web":"manual"}`,children:k.source==="web-login"?"网页登录":k.source==="web-oauth"?"网页 OAuth":k.source==="oauth"?"Codex OAuth":"导入"})]}),n.jsx("span",{children:k.lastError?`${dm(k.lastErrorCode)}${dm(k.lastErrorCode)?" · ":""}${k.lastError}`:k.lastCheckedAt?`上次检测 ${el(k.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[k.credentialMode==="refreshable"?"可自动续期":k.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",k.expiresAt?` · 到期 ${el(k.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",P0(k.planType)]}),k.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",el(k.lastUsedAt)," · ",k.requestCount||0," 次"]})]}),n.jsx(Tp,{limits:k.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(Dt,{tone:k.status==="healthy"?"healthy":k.status==="invalid"?"disabled":"standby",children:k.status==="healthy"?"可用":k.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:G!=="",onClick:()=>Q(p.id,!1,k.id),children:G===`check-account:${k.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:G!=="",onClick:()=>Y(p,k),children:G===`delete-account:${k.id}`?"删除中":"删除"})]})]},k.id)),Se.length===0&&n.jsx(Qt,{text:"没有匹配的账号"}),J.length>Ne&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:tl?`已显示全部 ${J.length} 个账号`:`已显示 ${ut.length} 个,还有 ${Ie} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!tl&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(k=>({...k,[p.id]:Math.min(J.length,Je+Me)})),children:["再显示 ",Math.min(Me,Ie)," 个"]}),!tl&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(k=>({...k,[p.id]:J.length})),children:"全部显示"}),Je>Ne&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(k=>({...k,[p.id]:Ne})),children:"收起"})]})]})]})]},p.id)}),b.length===0&&n.jsx(Qt,{text:"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),Ce&&n.jsx(Cp,{channelId:Ce,onStart:P,onComplete:T,onClose:()=>F("")}),ee&&n.jsx(Sp,{busy:G!=="",onAuthSession:()=>{D(ee),oe("")},onImport:async p=>{await ue(ee,p),oe("")},onClose:()=>oe("")}),ve&&n.jsx(Ap,{onImport:async p=>{await ue(ve,new File([JSON.stringify(Np(p))],"authsession.json",{type:"application/json"}))},onClose:()=>D("")})]})}function Sp({busy:c,onAuthSession:m,onImport:y,onClose:r}){return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:E=>E.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:m,disabled:c,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("label",{className:`account-add-option${c?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:c?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:c,onChange:E=>{const O=E.target.files?.[0];O&&y(O),E.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:r,children:"取消"})})]})})}function Np(c){const m=c.trim(),y=m.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(y)return{sessionToken:y[2],source:"web-login"};try{const r=JSON.parse(m),E=r.tokens&&typeof r.tokens=="object"?r.tokens:{},O=G=>typeof r[G]=="string"?r[G]:typeof E[G]=="string"?E[G]:"",K=O("accessToken")||O("access_token"),P=O("refreshToken")||O("refresh_token"),T=O("sessionToken")||O("session_token"),b=r.user&&typeof r.user=="object"?r.user:{};if(K||P||T)return{accessToken:K||void 0,refreshToken:P||void 0,sessionToken:T||void 0,email:typeof b.email=="string"?b.email:void 0,name:typeof b.name=="string"?b.name:void 0,source:"web-login"}}catch{}return{sessionToken:m,source:"web-login"}}function Ap({onImport:c,onClose:m}){const[y,r]=g.useState(""),[E,O]=g.useState(!1),[K,P]=g.useState(""),[T,b]=g.useState("");async function G(){if(!y.trim()){P("请粘贴 authsession");return}O(!0),P(""),b("");try{await c(y.trim()),r(""),b("已导入,继续粘贴下一条即可")}catch(_){P(_ instanceof Error?_.message:"导入失败")}finally{O(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:_=>_.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:y,onChange:_=>r(_.target.value),placeholder:"eyJhbGci..."})]}),K&&n.jsx("div",{className:"form-error",children:K}),T&&n.jsx("div",{className:"form-success",children:T}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:E,onClick:G,children:E?"导入中":"导入账号"})]})]})})}function Cp({channelId:c,onStart:m,onComplete:y,onClose:r}){const[E,O]=g.useState(""),[K,P]=g.useState(""),[T,b]=g.useState(""),[G,_]=g.useState(!1),[ae,te]=g.useState("");async function de(){_(!0),te("");try{const ne=await m(c);O(ne.authorizeUrl),P(ne.state),window.open(ne.authorizeUrl,"_blank","noopener")}catch(ne){te(ne instanceof Error?ne.message:"发起授权失败")}finally{_(!1)}}async function le(){if(!T.trim()){te("请粘贴授权完成后浏览器跳转的回调地址");return}_(!0),te("");try{await y(c,{callbackUrl:T.trim(),state:K}),r()}catch(ne){te(ne instanceof Error?ne.message:"完成授权失败")}finally{_(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card",onClick:ne=>ne.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:de,disabled:G,children:E?"重新生成授权链接":"① 生成授权链接并打开"}),E&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:E,onFocus:ne=>ne.target.select()}),n.jsx("span",{className:"muted-inline",children:"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:T,placeholder:"https://platform.openai.com/auth/callback?code=...&state=...",onChange:ne=>b(ne.target.value),disabled:!E||G})]})]}),ae&&n.jsx("p",{className:"form-error",children:ae}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:r,disabled:G,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:le,disabled:!E||G,children:G?"处理中":"完成授权"})]})]})})}function Tp({limits:c}){const m=be(c).filter(y=>y.label||y.name).slice(0,3);return m.length?n.jsx("div",{className:"quota-bars",children:m.map(y=>{const r=Ep(y);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:y.label||y.name}),n.jsx("span",{children:Mp(y,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${y.label||y.name}-${y.resetAt||""}`)})}):null}function Ep(c){return typeof c.percentRemaining=="number"&&Number.isFinite(c.percentRemaining)?Math.max(0,Math.min(100,c.percentRemaining)):typeof c.remaining=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,c.remaining/c.limit*100)):typeof c.used=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,(c.limit-c.used)/c.limit*100)):0}function Mp(c,m){const y=c.resetAt?` · ${el(c.resetAt)}`:"";return typeof c.remaining=="number"?`${Math.round(m)}% 剩余${y}`:`${Math.round(m)}%${y}`}function zp(c){const m=be(c.models).join(" ").toLowerCase(),y=["对话"];c.streamMode!=="disabled"&&y.push("流式"),/(image|dall-e|gpt-image)/.test(m)&&y.push("图片"),(c.openaiAccountCount??c.openaiAccounts?.length??0)>0&&y.push("账号池");const r=c.upstreamKeyCount??0;return r>1&&y.push(`${r} Key 轮询`),y}function Op(c){if(c.status==="invalid"||c.credentialMode==="browser-session")return!0;if(!c.expiresAt)return!1;const m=new Date(c.expiresAt).getTime();return Number.isFinite(m)&&m-Date.now()<=1440*60*1e3}function _p({channels:c,groups:m,onUpdate:y,onCreate:r,onImport:E,onDelete:O,onSyncModels:K,onCheck:P}){const T=Aa("openai"),[b,G]=g.useState(!1),[_,ae]=g.useState(T.provider),[te,de]=g.useState(T.name),[le,ne]=g.useState(T.baseUrl),[ie,ge]=g.useState(T.models.join(", ")),[me,Ce]=g.useState(""),[F,ve]=g.useState(""),[D,ee]=g.useState(!1),[oe,Ne]=g.useState(!1);function Me(Q){const re=Aa(Q);ae(re.provider),de(re.name),ne(re.baseUrl),ge(re.models.join(", ")),ve("")}async function ue(Q){Q.preventDefault(),ee(!0),ve("");try{await r({name:te.trim()||Aa(_).name,provider:_,baseUrl:le.trim(),...xm(me),models:Ic(ie),streamMode:"auto"}),G(!1),Ce(""),Me(_)}catch(re){ve(re instanceof Error?re.message:"渠道创建失败")}finally{ee(!1)}}return n.jsxs(lt,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:c.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:c.filter(Q=>Q.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>G(Q=>!Q),children:b?"取消新增":"+ 新增渠道"})]}),b&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ue,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Aa(_).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(Q=>n.jsxs("button",{type:"button",className:_===Q.provider?"selected":"",onClick:re=>{Me(Q.provider),re.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:Q.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},Q.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:te,onChange:Q=>de(Q.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:sl(_),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:le,onChange:Q=>ne(Q.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:me,onChange:Q=>Ce(Q.target.value),placeholder:_==="codex"?"账号池导入后使用":_==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(_!=="codex"&&!le.trim()){ve("请先填写 Base URL 再获取模型");return}ve(""),Ne(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ie,onChange:Q=>ge(Q.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:F}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Me(_),disabled:D,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:D,children:D?"创建中":"创建渠道"})]})]}),b&&oe&&n.jsx(jm,{subtitle:`${te.trim()||Aa(_).name} · 勾选需要接入的模型`,current:Ic(ie),loadModels:async()=>{const Q=await pe("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:_,baseUrl:le.trim(),upstreamApiKey:me})});return be(Q.models)},onConfirm:async Q=>{ge(Q.join(", "))},onClose:()=>Ne(!1)}),n.jsxs("div",{className:"channels-stack",children:[c.map(Q=>n.jsx(Dp,{channel:Q,groups:m,onUpdate:y,onImport:E,onDelete:O,onSyncModels:K,onCheck:P},Q.id)),c.length===0&&n.jsx(Qt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Dp({channel:c,groups:m,onUpdate:y,onImport:r,onDelete:E,onSyncModels:O,onCheck:K}){const[P,T]=g.useState(c.name),[b,G]=g.useState(c.provider),[_,ae]=g.useState(c.streamMode||"auto"),[te,de]=g.useState(c.baseUrl),[le,ne]=g.useState(be(c.allowedGroupIds)),[ie,ge]=g.useState(be(c.models).join(", ")),[me,Ce]=g.useState("saved"),[F,ve]=g.useState(String(c.inputPricePer1K||0)),[D,ee]=g.useState(String(c.outputPricePer1K||0)),[oe,Ne]=g.useState(!!c.webEndpoint),[Me,ue]=g.useState(""),[Q,re]=g.useState(""),[V,A]=g.useState(!1),Y=c.openaiAccountCount??c.openaiAccounts?.length??0,p=be(c.models).length,z=zp(c),$=c.status==="disabled",f={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[me],N=Ns.find(J=>J.value===_)||Ns[0],q={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};g.useEffect(()=>{T(c.name),G(c.provider),ae(c.streamMode||"auto"),de(c.baseUrl),ne(be(c.allowedGroupIds)),ge(be(c.models).join(", ")),Ce("saved"),ve(String(c.inputPricePer1K||0)),ee(String(c.outputPricePer1K||0)),Ne(!!c.webEndpoint),ue("")},[c.id,c.name,c.provider,c.streamMode,c.baseUrl,c.models,c.inputPricePer1K,c.outputPricePer1K,c.webEndpoint]);async function L(){const J=Z();re("save");try{await y(c.id,J),ue("")}finally{re("")}}function Z(){const J=Es(b),Je=!/^https?:\/\//i.test(te.trim())&&J?J:te,ut={name:P.trim()||c.name,provider:b,streamMode:_,baseUrl:Je,inputPricePer1K:Number(F)||0,outputPricePer1K:Number(D)||0,webEndpoint:oe,models:ie.split(",").map(Ie=>Ie.trim()).filter(Boolean),allowedGroupIds:le};return Object.assign(ut,xm(Me)),ut}async function xe(){const J=c.status==="disabled"?"healthy":"disabled";re("status");try{await y(c.id,{...Z(),status:J}),ue("")}finally{re("")}}async function M(){re("sync");try{await y(c.id,Z()),ue(""),A(!0)}finally{re("")}}function je(){const J=Aa(b);ge(J.models.join(", ")),Ce("template"),J.baseUrl&&!/^https?:\/\//i.test(te.trim())&&de(J.baseUrl)}async function Se(){re("check");try{await L(),await K(c.id)}finally{re("")}}async function ot(J){re("import");try{await r(c.id,J)}finally{re("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:c.name}),n.jsx("span",{children:sl(b)}),n.jsx("small",{children:c.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:z.map(J=>n.jsx("span",{children:J},J))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:p})," 个模型"]}),Y>0&&n.jsxs("span",{children:[n.jsx("b",{children:Y})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:c.lastError?"is-error":c.lastCheckedAt?"is-ok":"",children:c.lastError?"检测失败":c.lastCheckedAt?`已检测 ${el(c.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(Dt,{tone:c.status,children:$?"已停用":_t(c.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:sl(b)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:eo.map(J=>n.jsxs("button",{type:"button",className:b===J.value?"selected":"",onClick:Je=>{G(J.value);const ut=Es(J.value);ut&&!/^https?:\/\//i.test(te.trim())&&de(ut),Je.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:J.label}),n.jsx("span",{children:J.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},J.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:q[N.value]}),n.jsx("small",{children:N.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ns.map(J=>n.jsxs("button",{type:"button",className:_===J.value?"selected":"",onClick:Je=>{ae(J.value),Je.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:q[J.value]}),n.jsx("span",{children:J.description})]},J.value))})]})]})]}),(b==="codex"||Y>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:oe?"ios-switch is-on":"ios-switch","aria-label":oe?"关闭网页对话接口":"开启网页对话接口","aria-pressed":oe,onClick:()=>Ne(J=>!J),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:P,onChange:J=>T(J.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:sl(b),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:te,onChange:J=>de(J.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:c.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",f]})]}),n.jsx("textarea",{value:ie,onChange:J=>{ge(J.target.value),Ce("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:je,disabled:Q!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:M,disabled:Q!=="",children:Q==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(c.upstreamKeyCount??0)>0?` (已配置 ${c.upstreamKeyCount} 个)`:c.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Me,onChange:J=>ue(J.target.value),placeholder:b==="codex"?"Codex 账号池不需要上游 Key":b==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:F,onChange:J=>ve(J.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:D,onChange:J=>ee(J.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:le.length?`已选择 ${le.length} 个分组`:"全部用户可用"})]}),m.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:m.map(J=>{const Je=le.includes(J.id);return n.jsxs("button",{type:"button",className:Je?"selected":"","aria-pressed":Je,onClick:()=>ne(ut=>Je?ut.filter(Ie=>Ie!==J.id):[...ut,J.id]),children:[n.jsx("span",{children:J.name}),J.description&&n.jsx("small",{children:J.description})]},J.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:Se,disabled:Q!=="",children:Q==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:L,disabled:Q!=="",children:Q==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[Q==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:Q!=="",onChange:J=>{const Je=J.target.files?.[0];Je&&ot(Je),J.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:xe,disabled:Q!=="",children:c.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>E(c.id),disabled:Q!=="",children:"删除渠道"})]})]})]})]}),V&&n.jsx(jm,{subtitle:`${c.name} · 勾选需要接入的模型`,current:ie.split(",").map(J=>J.trim()).filter(Boolean),loadModels:async()=>{const J=await pe(`/api/channels/${c.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return be(J.models)},onConfirm:async J=>{await O(c.id,J)},onClose:()=>A(!1)})]})}function jm({subtitle:c,current:m,loadModels:y,onConfirm:r,onClose:E}){const[O,K]=g.useState(!0),[P,T]=g.useState(""),[b,G]=g.useState([]),[_,ae]=g.useState(new Set),[te,de]=g.useState(""),[le,ne]=g.useState(!1);g.useEffect(()=>{let D=!1;return(async()=>{K(!0),T("");try{const ee=await y();if(D)return;const oe=new Set,Ne=be(ee).map(ue=>ue.trim()).filter(ue=>{if(!ue)return!1;const Q=ue.toLowerCase();return oe.has(Q)?!1:(oe.add(Q),!0)}),Me=new Set(m.map(ue=>ue.toLowerCase()));G(Ne),ae(new Set(Ne.filter(ue=>Me.has(ue.toLowerCase()))))}catch(ee){D||T(ee instanceof Error?ee.message:"获取上游模型失败")}finally{D||K(!1)}})(),()=>{D=!0}},[]);const ie=te.trim().toLowerCase(),ge=ie?b.filter(D=>D.toLowerCase().includes(ie)):b,me=ge.length>0&&ge.every(D=>_.has(D));function Ce(D){ae(ee=>{const oe=new Set(ee);return oe.has(D)?oe.delete(D):oe.add(D),oe})}function F(){ae(D=>{const ee=new Set(D);return me?ge.forEach(oe=>ee.delete(oe)):ge.forEach(oe=>ee.add(oe)),ee})}async function ve(){const D=new Set(b.map(ue=>ue.toLowerCase())),ee=m.filter(ue=>!D.has(ue.toLowerCase())),oe=b.filter(ue=>_.has(ue)),Ne=new Set,Me=[...ee,...oe].filter(ue=>{const Q=ue.toLowerCase();return Ne.has(Q)?!1:(Ne.add(Q),!0)});ne(!0);try{await r(Me),E()}catch{ne(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:E,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:D=>D.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:c})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:E,children:"×"})]}),O?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):P?n.jsx("div",{className:"model-picker-status model-picker-error",children:P}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:te,onChange:D=>de(D.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:F,disabled:ge.length===0,children:me?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",b.length," 个 · 已选 ",_.size," 个",ie?` · 匹配 ${ge.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[ge.map(D=>{const ee=_.has(D),oe=m.some(Ne=>Ne.toLowerCase()===D.toLowerCase());return n.jsxs("label",{className:`model-picker-row${ee?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:ee,onChange:()=>Ce(D)}),n.jsx("span",{className:"model-picker-name",children:D}),oe&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},D)}),ge.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:E,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:O||!!P||le,onClick:ve,children:le?"保存中":`导入所选 (${_.size})`})]})]})})}function Up({logs:c,onCopy:m}){const[y,r]=g.useState(c),[E,O]=g.useState(c.length),[K,P]=g.useState(1),[T,b]=g.useState(""),[G,_]=g.useState("all"),[ae,te]=g.useState(null),[de,le]=g.useState(!1),[ne,ie]=g.useState(!1),ge=25,me=Math.max(1,Math.ceil(E/ge));g.useEffect(()=>{P(1)},[T,G]),g.useEffect(()=>{K>me&&P(me)},[K,me]),g.useEffect(()=>{const F=new AbortController,ve=window.setTimeout(async()=>{le(!0);try{const D=new URLSearchParams({page:String(K),pageSize:String(ge),status:G,q:T.trim()}),ee=await pe(`/api/logs?${D}`,{signal:F.signal}),oe=be(ee.logs);r(oe),O(ee.total||0),te(Ne=>Ne&&oe.some(Me=>Me.id===Ne.id)?Ne:null)}catch(D){D instanceof DOMException&&D.name==="AbortError"||(r([]),O(0))}finally{F.signal.aborted||le(!1)}},T?250:0);return()=>{window.clearTimeout(ve),F.abort()}},[K,T,G]);async function Ce(F){if(ae?.id===F.id){te(null);return}te(F),ie(!0);try{const ve=await pe(`/api/logs/${encodeURIComponent(F.id)}`);te(ve.log)}catch{te(F)}finally{ie(!1)}}return n.jsxs(lt,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:T,onChange:F=>b(F.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(F=>n.jsx("button",{type:"button",className:G===F.value?"selected":"",onClick:()=>_(F.value),children:F.label},F.value))}),n.jsx("span",{className:"muted-inline",children:de?"加载中":`共 ${E} 条`})]}),n.jsxs("div",{className:ae?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),y.map(F=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:ae?.id===F.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>Ce(F),onKeyDown:ve=>{(ve.key==="Enter"||ve.key===" ")&&Ce(F)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:to(F)}),n.jsxs("small",{children:[F.id," · ",el(F.createdAt)," · ",F.latencyMs,"ms"]})]}),n.jsx("span",{children:ap(F)}),n.jsx("span",{children:np(F)}),n.jsx(Dt,{tone:F.status,children:_t(F.status)})]})},F.id)),!de&&y.length===0&&n.jsx(Qt,{text:T||G!=="all"?"没有匹配的日志":"暂无调用日志"})]}),ae&&n.jsx(Rp,{log:ae,loading:ne,onCopy:m})]}),me>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:K<=1||de,onClick:()=>P(F=>Math.max(1,F-1)),children:"上一页"}),n.jsxs("span",{children:[K," / ",me]}),n.jsx("button",{className:"secondary-button",disabled:K>=me||de,onClick:()=>P(F=>Math.min(me,F+1)),children:"下一页"})]})]})}function Rp({log:c,loading:m,onCopy:y}){if(!c)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(c.inputTokens||0),E=Number(c.outputTokens||0),O=typeof c.attempts=="number"?Math.max(0,c.attempts):null,K=[["请求 ID",c.id],["状态",_t(c.status)],["时间",lp(c.createdAt)],["用户 ID",c.userId||"未识别"],["API Key",c.apiKeyPrefix?`${c.apiKeyPrefix}***`:"未识别"],["模型",c.model||"未提供"],["渠道",c.channel||"未选择"],["实际账号",c.account||"未记录"],["响应耗时",`${c.latencyMs} ms`],["尝试次数",O===null?"未记录":String(O)],["是否重试",O===null?"未记录":O>1?"是":"否"],["输入 Tokens",Ca(r)],["输出 Tokens",Ca(E)],["总 Tokens",Ca(r+E)],["扣费",c.cost.toFixed(4)],["错误码",c.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:m?"加载中":"日志详情"}),n.jsx("strong",{children:to(c)})]}),n.jsx(Dt,{tone:c.status,children:_t(c.status)})]}),n.jsx("div",{className:"log-detail",children:K.map(([P,T])=>n.jsxs("div",{children:[n.jsx("span",{children:P}),n.jsx("strong",{title:T,children:T})]},P))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>y(c.id,"请求 ID 已复制"),children:"复制请求 ID"}),c.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>y(c.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function Hp({models:c,channels:m,groups:y}){const[r,E]=g.useState(null),[O,K]=g.useState(null),[P,T]=g.useState("username"),[b,G]=g.useState("0"),[_,ae]=g.useState(""),[te,de]=g.useState({enabled:!0,minReward:.1,maxReward:1}),[le,ne]=g.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ie,ge]=g.useState(null),[me,Ce]=g.useState(null),[F,ve]=g.useState(""),[D,ee]=g.useState(""),[oe,Ne]=g.useState(""),[Me,ue]=g.useState(""),[Q,re]=g.useState(""),[V,A]=g.useState(""),[Y,p]=g.useState(""),[z,$]=g.useState(""),[f,N]=g.useState(""),[q,L]=g.useState(!1),[Z,xe]=g.useState("system"),M=c.find(R=>R.recommended&&R.status==="available")?.id||c.find(R=>R.status==="available")?.id||"未配置",je=m.filter(R=>R.status!=="disabled").length,Se=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],ot=Se.find(R=>R.value===Z)||Se[0];g.useEffect(()=>{Promise.all([pe("/api/settings/discord"),pe("/api/settings/auth"),pe("/api/settings/check-in"),pe("/api/account/me"),pe("/api/settings/maintenance"),pe("/api/health")]).then(([R,Ue,rt,jt,ht,Pe])=>{E(Wc(R.discord)),$(be(R.discord.blockedGuildIds).join(` -`)),K(Ue.auth.registrationEnabled),T(Ms(Ue.auth.registrationMode)),G(String(Ue.auth.defaultBalance||0)),ae(Ue.auth.defaultGroupId||""),de(rt.checkIn),Ce(jt.account),ve(jt.account?.username||""),ee(jt.user.name||""),Ne(jt.account?.email||""),ue(jt.account?.discordUserId||""),ne(ht.maintenance),ge(Pe)}).catch(()=>N("设置加载失败"))},[]);async function J(R=O,Ue=P,rt=Number(b),jt=_){if(R!==null)try{const ht=await pe("/api/settings/auth",{method:"PATCH",body:JSON.stringify({registrationEnabled:R,registrationMode:Ue,defaultBalance:rt,defaultGroupId:jt})});K(ht.auth.registrationEnabled),T(Ms(ht.auth.registrationMode)),G(String(ht.auth.defaultBalance||0)),ae(ht.auth.defaultGroupId||""),N(ht.auth.registrationEnabled?"注册设置已保存":"已关闭用户注册")}catch(ht){N(ht instanceof Error?ht.message:"注册设置保存失败")}}async function Je(){O!==null&&J(!O,P)}async function ut(){L(!0),N("");try{const R=await pe("/api/settings/check-in",{method:"PATCH",body:JSON.stringify(te)});de(R.checkIn),N(R.checkIn.enabled?"签到奖励设置已保存":"已关闭每日签到")}catch(R){N(R instanceof Error?R.message:"签到设置保存失败")}finally{L(!1)}}async function Ie(){if(r){L(!0),N("");try{const R=Wc(r),Ue=z.split(/[\s,]+/).map(jt=>jt.trim()).filter(Boolean),rt=await pe("/api/settings/discord",{method:"PATCH",body:JSON.stringify({...R,blockedGuildIds:Ue,clientSecret:Y})});E(Wc(rt.discord)),$(be(rt.discord.blockedGuildIds).join(` -`)),p(""),N("Discord 配置已保存")}catch(R){N(R instanceof Error?R.message:"保存失败,请检查填写内容")}finally{L(!1)}}}async function tl(){try{const R=await pe("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:F,displayName:D,email:oe,discordUserId:Me,currentPassword:Q,newPassword:V})});Ce(R.account),ve(R.account.username),Ne(R.account.email||""),ue(R.account.discordUserId||""),re(""),A(""),N("管理员账号已保存")}catch(R){N(R instanceof Error?R.message:"账号设置保存失败")}}async function k(){L(!0),N("");try{const R=await pe("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(le)});ne(R.maintenance),N("维护设置已保存,历史数据已按新规则清理")}catch(R){N(R instanceof Error?R.message:"维护设置保存失败")}finally{L(!1)}}async function mt(){L(!0),N("");try{const R=await fetch("/api/backup",{credentials:"include"});if(!R.ok)throw new Error("备份导出失败");const Ue=await R.blob(),jt=(R.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",ht=URL.createObjectURL(Ue),Pe=document.createElement("a");Pe.href=ht,Pe.download=jt,Pe.click(),URL.revokeObjectURL(ht),N("备份已导出,请妥善保管")}catch(R){N(R instanceof Error?R.message:"备份导出失败")}finally{L(!1)}}async function Ut(R){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){L(!0),N("");try{const Ue=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:R}),rt=await Ue.json().catch(()=>null);if(!Ue.ok)throw new Error(rt?.error?.message||"备份恢复失败");N(`已恢复 ${rt.users} 个用户、${rt.channels} 条渠道和 ${rt.models} 个模型,请重新登录`)}catch(Ue){N(Ue instanceof Error?Ue.message:"备份恢复失败")}finally{L(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:Se.map(R=>n.jsxs("button",{type:"button",className:Z===R.value?"selected":"",onClick:()=>xe(R.value),children:[n.jsx("strong",{children:R.label}),n.jsx("small",{children:R.description})]},R.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:ot.label}),n.jsx("span",{children:ot.description})]}),Z==="system"&&n.jsx(lt,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"接口兼容",value:"OpenAI API"}),n.jsx(Pt,{label:"当前默认模型",value:M}),n.jsx(Pt,{label:"已配置渠道",value:`${m.length} 个,${je} 个启用`}),n.jsx(Pt,{label:"可选供应商",value:`${eo.length} 种`}),n.jsx(Pt,{label:"运行版本",value:`${ie?.version||"未知"} · ${ie?.commit||"未知"}`}),n.jsx(Pt,{label:"构建时间",value:ie?.buildTime?el(ie.buildTime):"本地构建"}),n.jsx(Pt,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),Z==="cli"&&n.jsxs(lt,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:_l()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{As(_l()),N("已复制 Base URL")},children:n.jsx(Ot,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${_l()}" -export ANTHROPIC_AUTH_TOKEN="cat_你的_api_key" -export ANTHROPIC_MODEL="${M}" -claude`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Codex CLI"}),n.jsx("span",{children:"OpenAI Chat 协议"})]}),n.jsxs("p",{children:["编辑 ",n.jsx("code",{children:"~/.codex/config.toml"}),":"]}),n.jsx("pre",{children:`model = "${M}" -model_provider = "capi" - -[model_providers.capi] -name = "CAPI" -base_url = "${_l()}/v1" -env_key = "CAPI_KEY" -wire_api = "chat"`}),n.jsx("p",{children:"然后设置环境变量并运行:"}),n.jsx("pre",{children:`export CAPI_KEY="cat_你的_api_key" -codex`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Aider"}),n.jsx("span",{children:"OpenAI 兼容"})]}),n.jsx("pre",{children:`export OPENAI_API_BASE="${_l()}" -export OPENAI_API_KEY="cat_你的_api_key" -aider --model openai/${M}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Cline / Roo Code / Kilo Code"}),n.jsx("span",{children:"VS Code 插件"})]}),n.jsxs("p",{children:["在插件设置中选择 ",n.jsx("strong",{children:"OpenAI Compatible"}),":"]}),n.jsx("pre",{children:`Base URL: ${_l()}/v1 -API Key: cat_你的_api_key -Model ID: ${M}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"通用 OpenAI SDK"}),n.jsx("span",{children:"Python / Node.js"})]}),n.jsx("pre",{children:`export OPENAI_BASE_URL="${_l()}" -export OPENAI_API_KEY="cat_你的_api_key"`}),n.jsx("pre",{children:`from openai import OpenAI -client = OpenAI() -response = client.chat.completions.create( - model="${M}", - messages=[{"role": "user", "content": "hello"}] -)`})]})]}),f&&n.jsx("p",{className:"cli-message",role:"status",children:f})]}),Z==="maintenance"&&n.jsx(lt,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:le.logRetentionDays,onChange:R=>ne(Ue=>({...Ue,logRetentionDays:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:le.maxLogs,onChange:R=>ne(Ue=>({...Ue,maxLogs:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:le.maxQuotaEntries,onChange:R=>ne(Ue=>({...Ue,maxQuotaEntries:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{type:"button",className:"primary-button",disabled:q,onClick:k,children:q?"保存中":"保存维护设置"})]})]})}),Z==="backup"&&n.jsx(lt,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:q,onClick:mt,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:q,onChange:R=>{const Ue=R.target.files?.[0];Ue&&Ut(Ue),R.target.value=""}})]})]})]})})}),Z==="auth"&&n.jsx(lt,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:O?"启用":"关闭"}),n.jsx("button",{type:"button",className:O?"ios-switch is-on":"ios-switch","aria-label":O?"关闭用户注册":"开放用户注册","aria-pressed":!!O,onClick:Je,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(R=>n.jsx("button",{type:"button",className:P===R.value?"selected":"",onClick:()=>J(O??!0,R.value),children:R.label},R.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:b,onChange:R=>G(R.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>J(O,P,Number(b)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:_,onChange:R=>ae(R.target.value),"aria-label":"默认注册分组",children:[y.map(R=>n.jsx("option",{value:R.id,children:R.name},R.id)),y.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:y.length===0,onClick:()=>J(O,P,Number(b),_),children:"保存"})]})]})]})}),Z==="check-in"&&n.jsx(lt,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:te.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:te.enabled?"ios-switch is-on":"ios-switch","aria-label":te.enabled?"关闭每日签到":"开放每日签到","aria-pressed":te.enabled,onClick:()=>de(R=>({...R,enabled:!R.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:te.minReward,onChange:R=>de(Ue=>({...Ue,minReward:Number(R.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:te.maxReward,onChange:R=>de(Ue=>({...Ue,maxReward:Number(R.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{type:"button",className:"primary-button",disabled:q,onClick:ut,children:q?"保存中":"保存签到设置"})]})]})}),Z==="admin"&&n.jsx(lt,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:R=>{R.preventDefault(),tl()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:F,onChange:R=>ve(R.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:D,onChange:R=>ee(R.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:oe,onChange:R=>Ne(R.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Me,onChange:R=>ue(R.target.value),placeholder:me?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:Q,onChange:R=>re(R.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:V,onChange:R=>A(R.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),Z==="discord"&&n.jsx(lt,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:R=>{R.preventDefault(),Ie()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>E({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:R=>E({...r,clientId:R.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:Y,onChange:R=>p(R.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:R=>E({...r,redirectUri:R.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:R=>E({...r,allowedGuildId:R.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:R=>E({...r,allowedRoleId:R.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:z,onChange:R=>$(R.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:R=>E({...r,authSuccessUrl:R.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:R=>E({...r,sessionTtlHours:Number(R.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{className:"primary-button",type:"submit",disabled:q,children:q?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function ul({label:c,value:m}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:c}),n.jsx("strong",{children:m})]})}function wp({groups:c,onCreate:m,onUpdate:y,onDelete:r}){const[E,O]=g.useState(""),[K,P]=g.useState(""),[T,b]=g.useState(!1);async function G(_){if(_.preventDefault(),!!E.trim()){b(!0);try{await m({name:E.trim(),description:K.trim()}),O(""),P("")}finally{b(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(lt,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:G,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:E,onChange:_=>O(_.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:K,onChange:_=>P(_.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:T||!E.trim(),children:T?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(lt,{title:"全部分组",children:c.length===0?n.jsx(Qt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:c.map(_=>n.jsx(Bp,{group:_,onUpdate:y,onDelete:r},_.id))})})]})}function Bp({group:c,onUpdate:m,onDelete:y}){const[r,E]=g.useState(!1),[O,K]=g.useState(c.name),[P,T]=g.useState(c.description),[b,G]=g.useState(!1);async function _(){G(!0);try{await m(c.id,{name:O.trim(),description:P.trim()}),E(!1)}finally{G(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:O,onChange:ae=>K(ae.target.value),placeholder:"分组名称"}),n.jsx("input",{value:P,onChange:ae=>T(ae.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:c.name}),c.description&&n.jsx("span",{children:c.description}),n.jsxs("small",{children:["创建于 ",el(c.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:_,disabled:b||!O.trim(),children:b?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{K(c.name),T(c.description),E(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>E(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>y(c.id),children:"删除"})]})})]})})}function lt({title:c,children:m}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:c})}),m]})}function Dt({tone:c,children:m}){return n.jsx("span",{className:`badge tone-${c}`,children:m})}function Pt({label:c,value:m,switchOn:y}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:c}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:m}),typeof y=="boolean"&&n.jsx("div",{className:y?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function qp({value:c,options:m,onChange:y}){return n.jsx("div",{className:"segmented-control",children:m.map(r=>n.jsx("button",{className:c===r.value?"selected":"",onClick:()=>y(r.value),children:r.label},r.value))})}function Qt({text:c}){return n.jsx("div",{className:"empty",children:c})}k0.createRoot(document.getElementById("root")).render(n.jsx(G0.StrictMode,{children:n.jsx(op,{})})); diff --git a/dist/assets/index-Cv9ZCWeR.js b/dist/assets/index-Cv9ZCWeR.js new file mode 100644 index 0000000..5ee0c5b --- /dev/null +++ b/dist/assets/index-Cv9ZCWeR.js @@ -0,0 +1,43 @@ +(function(){const m=document.createElement("link").relList;if(m&&m.supports&&m.supports("modulepreload"))return;for(const E of document.querySelectorAll('link[rel="modulepreload"]'))r(E);new MutationObserver(E=>{for(const M of E)if(M.type==="childList")for(const X of M.addedNodes)X.tagName==="LINK"&&X.rel==="modulepreload"&&r(X)}).observe(document,{childList:!0,subtree:!0});function p(E){const M={};return E.integrity&&(M.integrity=E.integrity),E.referrerPolicy&&(M.referrerPolicy=E.referrerPolicy),E.crossOrigin==="use-credentials"?M.credentials="include":E.crossOrigin==="anonymous"?M.credentials="omit":M.credentials="same-origin",M}function r(E){if(E.ep)return;E.ep=!0;const M=p(E);fetch(E.href,M)}})();function H0(c){return c&&c.__esModule&&Object.prototype.hasOwnProperty.call(c,"default")?c.default:c}var Xc={exports:{}},is={};var em;function B0(){if(em)return is;em=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.fragment");function p(r,E,M){var X=null;if(M!==void 0&&(X=""+M),E.key!==void 0&&(X=""+E.key),"key"in E){M={};for(var P in E)P!=="key"&&(M[P]=E[P])}else M=E;return E=M.ref,{$$typeof:c,type:r,key:X,ref:E!==void 0?E:null,props:M}}return is.Fragment=m,is.jsx=p,is.jsxs=p,is}var tm;function q0(){return tm||(tm=1,Xc.exports=B0()),Xc.exports}var n=q0(),kc={exports:{}},Ce={};var lm;function G0(){if(lm)return Ce;lm=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),M=Symbol.for("react.consumer"),X=Symbol.for("react.context"),P=Symbol.for("react.forward_ref"),T=Symbol.for("react.suspense"),b=Symbol.for("react.memo"),q=Symbol.for("react.lazy"),z=Symbol.for("react.activity"),ee=Symbol.iterator;function te(f){return f===null||typeof f!="object"?null:(f=ee&&f[ee]||f["@@iterator"],typeof f=="function"?f:null)}var re={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},se=Object.assign,ne={};function ie(f,N,G){this.props=f,this.context=N,this.refs=ne,this.updater=G||re}ie.prototype.isReactComponent={},ie.prototype.setState=function(f,N){if(typeof f!="object"&&typeof f!="function"&&f!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,f,N,"setState")},ie.prototype.forceUpdate=function(f){this.updater.enqueueForceUpdate(this,f,"forceUpdate")};function ge(){}ge.prototype=ie.prototype;function Y(f,N,G){this.props=f,this.context=N,this.refs=ne,this.updater=G||re}var ye=Y.prototype=new ge;ye.constructor=Y,se(ye,ie.prototype),ye.isPureReactComponent=!0;var I=Array.isArray;function me(){}var _={H:null,A:null,T:null,S:null},le=Object.prototype.hasOwnProperty;function de(f,N,G){var Q=G.ref;return{$$typeof:c,type:f,key:N,ref:Q!==void 0?Q:null,props:G}}function Ae(f,N){return de(f.type,N,f.props)}function Me(f){return typeof f=="object"&&f!==null&&f.$$typeof===c}function ce(f){var N={"=":"=0",":":"=2"};return"$"+f.replace(/[=:]/g,function(G){return N[G]})}var k=/\/+/g;function fe(f,N){return typeof f=="object"&&f!==null&&f.key!=null?ce(""+f.key):N.toString(36)}function J(f){switch(f.status){case"fulfilled":return f.value;case"rejected":throw f.reason;default:switch(typeof f.status=="string"?f.then(me,me):(f.status="pending",f.then(function(N){f.status==="pending"&&(f.status="fulfilled",f.value=N)},function(N){f.status==="pending"&&(f.status="rejected",f.reason=N)})),f.status){case"fulfilled":return f.value;case"rejected":throw f.reason}}throw f}function A(f,N,G,Q,Z){var je=typeof f;(je==="undefined"||je==="boolean")&&(f=null);var O=!1;if(f===null)O=!0;else switch(je){case"bigint":case"string":case"number":O=!0;break;case"object":switch(f.$$typeof){case c:case m:O=!0;break;case q:return O=f._init,A(O(f._payload),N,G,Q,Z)}}if(O)return Z=Z(f),O=Q===""?"."+fe(f,0):Q,I(Z)?(G="",O!=null&&(G=O.replace(k,"$&/")+"/"),A(Z,N,G,"",function(ot){return ot})):Z!=null&&(Me(Z)&&(Z=Ae(Z,G+(Z.key==null||f&&f.key===Z.key?"":(""+Z.key).replace(k,"$&/")+"/")+O)),N.push(Z)),1;O=0;var Se=Q===""?".":Q+":";if(I(f))for(var Ne=0;Ne>>1,W=A[D];if(0>>1;DE(G,v))QE(Z,G)?(A[D]=Z,A[Q]=v,D=Q):(A[D]=G,A[N]=v,D=N);else if(QE(Z,v))A[D]=Z,A[Q]=v,D=Q;else break e}}return L}function E(A,L){var v=A.sortIndex-L.sortIndex;return v!==0?v:A.id-L.id}if(c.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var M=performance;c.unstable_now=function(){return M.now()}}else{var X=Date,P=X.now();c.unstable_now=function(){return X.now()-P}}var T=[],b=[],q=1,z=null,ee=3,te=!1,re=!1,se=!1,ne=!1,ie=typeof setTimeout=="function"?setTimeout:null,ge=typeof clearTimeout=="function"?clearTimeout:null,Y=typeof setImmediate<"u"?setImmediate:null;function ye(A){for(var L=p(b);L!==null;){if(L.callback===null)r(b);else if(L.startTime<=A)r(b),L.sortIndex=L.expirationTime,m(T,L);else break;L=p(b)}}function I(A){if(se=!1,ye(A),!re)if(p(T)!==null)re=!0,me||(me=!0,ce());else{var L=p(b);L!==null&&J(I,L.startTime-A)}}var me=!1,_=-1,le=5,de=-1;function Ae(){return ne?!0:!(c.unstable_now()-deA&&Ae());){var D=z.callback;if(typeof D=="function"){z.callback=null,ee=z.priorityLevel;var W=D(z.expirationTime<=A);if(A=c.unstable_now(),typeof W=="function"){z.callback=W,ye(A),L=!0;break t}z===p(T)&&r(T),ye(A)}else r(T);z=p(T)}if(z!==null)L=!0;else{var f=p(b);f!==null&&J(I,f.startTime-A),L=!1}}break e}finally{z=null,ee=v,te=!1}L=void 0}}finally{L?ce():me=!1}}}var ce;if(typeof Y=="function")ce=function(){Y(Me)};else if(typeof MessageChannel<"u"){var k=new MessageChannel,fe=k.port2;k.port1.onmessage=Me,ce=function(){fe.postMessage(null)}}else ce=function(){ie(Me,0)};function J(A,L){_=ie(function(){A(c.unstable_now())},L)}c.unstable_IdlePriority=5,c.unstable_ImmediatePriority=1,c.unstable_LowPriority=4,c.unstable_NormalPriority=3,c.unstable_Profiling=null,c.unstable_UserBlockingPriority=2,c.unstable_cancelCallback=function(A){A.callback=null},c.unstable_forceFrameRate=function(A){0>A||125D?(A.sortIndex=v,m(b,A),p(T)===null&&A===p(b)&&(se?(ge(_),_=-1):se=!0,J(I,v-D))):(A.sortIndex=W,m(T,A),re||te||(re=!0,me||(me=!0,ce()))),A},c.unstable_shouldYield=Ae,c.unstable_wrapCallback=function(A){var L=ee;return function(){var v=ee;ee=L;try{return A.apply(this,arguments)}finally{ee=v}}}})(Vc)),Vc}var sm;function Q0(){return sm||(sm=1,Zc.exports=L0()),Zc.exports}var Jc={exports:{}},xt={};var im;function X0(){if(im)return xt;im=1;var c=Pc();function m(T){var b="https://react.dev/errors/"+T;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Jc.exports=X0(),Jc.exports}var cm;function K0(){if(cm)return us;cm=1;var c=Q0(),m=Pc(),p=k0();function r(e){var t="https://react.dev/errors/"+e;if(1W||(e.current=D[W],D[W]=null,W--)}function G(e,t){W++,D[W]=e.current,e.current=t}var Q=f(null),Z=f(null),je=f(null),O=f(null);function Se(e,t){switch(G(je,t),G(Z,e),G(Q,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Nf(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Nf(t),e=Af(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}N(Q),G(Q,e)}function Ne(){N(Q),N(Z),N(je)}function ot(e){e.memoizedState!==null&&G(O,e);var t=Q.current,l=Af(t,e.type);t!==l&&(G(Z,e),G(Q,l))}function $(e){Z.current===e&&(N(Q),N(Z)),O.current===e&&(N(O),ls._currentValue=v)}var Je,ut;function Ie(e){if(Je===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);Je=t&&t[1]||"",ut=-1)":-1s||d[a]!==j[s]){var U=` +`+d[a].replace(" at new "," at ");return e.displayName&&U.includes("")&&(U=U.replace("",e.displayName)),U}while(1<=a&&0<=s);break}}}finally{ll=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Ie(l):""}function mt(e,t){switch(e.tag){case 26:case 27:case 5:return Ie(e.type);case 16:return Ie("Lazy");case 13:return e.child!==t&&t!==null?Ie("Suspense Fallback"):Ie("Suspense");case 19:return Ie("SuspenseList");case 0:case 15:return V(e.type,!1);case 11:return V(e.type.render,!1);case 1:return V(e.type,!0);case 31:return Ie("Activity");default:return""}}function Rt(e){try{var t="",l=null;do t+=mt(e,l),l=e,e=e.return;while(e);return t}catch(a){return` +Error generating stack: `+a.message+` +`+a.stack}}var R=Object.prototype.hasOwnProperty,Ue=c.unstable_scheduleCallback,rt=c.unstable_cancelCallback,jt=c.unstable_shouldYield,ht=c.unstable_requestPaint,Pe=c.unstable_now,zi=c.unstable_getCurrentPriorityLevel,hn=c.unstable_ImmediatePriority,ia=c.unstable_UserBlockingPriority,ua=c.unstable_NormalPriority,Oi=c.unstable_LowPriority,w=c.unstable_IdlePriority,K=c.log,ae=c.unstable_setDisableYieldValue,F=null,ve=null;function qe(e){if(typeof K=="function"&&ae(e),ve&&typeof ve.setStrictMode=="function")try{ve.setStrictMode(F,e)}catch{}}var Ke=Math.clz32?Math.clz32:ca,wt=Math.log,Rl=Math.LN2;function ca(e){return e>>>=0,e===0?32:31-(wt(e)/Rl|0)|0}var Ea=256,Ma=262144,wl=4194304;function hl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function os(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var s=0,i=e.suspendedLanes,u=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~i,a!==0?s=hl(a):(u&=o,u!==0?s=hl(u):l||(l=o&~e,l!==0&&(s=hl(l))))):(o=a&~i,o!==0?s=hl(o):u!==0?s=hl(u):l||(l=a&~e,l!==0&&(s=hl(l)))),s===0?0:t!==0&&t!==s&&(t&i)===0&&(i=s&-s,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:s}function pn(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Nm(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function lo(){var e=wl;return wl<<=1,(wl&62914560)===0&&(wl=4194304),e}function _i(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function vn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Am(e,t,l,a,s,i){var u=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,d=e.expirationTimes,j=e.hiddenUpdates;for(l=u&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Om=/[\n"\\]/g;function Kt(e){return e.replace(Om,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bi(e,t,l,a,s,i,u,o){e.name="",u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"?e.type=u:e.removeAttribute("type"),t!=null?u==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+kt(t)):e.value!==""+kt(t)&&(e.value=""+kt(t)):u!=="submit"&&u!=="reset"||e.removeAttribute("value"),t!=null?qi(e,u,kt(t)):l!=null?qi(e,u,kt(l)):a!=null&&e.removeAttribute("value"),s==null&&i!=null&&(e.defaultChecked=!!i),s!=null&&(e.checked=s&&typeof s!="function"&&typeof s!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+kt(o):e.removeAttribute("name")}function vo(e,t,l,a,s,i,u,o){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Hi(e);return}l=l!=null?""+kt(l):"",t=t!=null?""+kt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??s,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.name=u),Hi(e)}function qi(e,t,l){t==="number"&&fs(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ra(e,t,l,a){if(e=e.options,t){t={};for(var s=0;s"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Xi=!1;if(yl)try{var xn={};Object.defineProperty(xn,"passive",{get:function(){Xi=!0}}),window.addEventListener("test",xn,xn),window.removeEventListener("test",xn,xn)}catch{Xi=!1}var Bl=null,ki=null,hs=null;function No(){if(hs)return hs;var e,t=ki,l=t.length,a,s="value"in Bl?Bl.value:Bl.textContent,i=s.length;for(e=0;e=Nn),zo=" ",Oo=!1;function _o(e,t){switch(e){case"keyup":return nh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Do(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var qa=!1;function ih(e,t){switch(e){case"compositionend":return Do(t);case"keypress":return t.which!==32?null:(Oo=!0,zo);case"textInput":return e=t.data,e===zo&&Oo?null:e;default:return null}}function uh(e,t){if(qa)return e==="compositionend"||!$i&&_o(e,t)?(e=No(),hs=ki=Bl=null,qa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Yo(l)}}function Qo(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Qo(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Xo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fs(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fs(e.document)}return t}function Ii(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var ph=yl&&"documentMode"in document&&11>=document.documentMode,Ga=null,Pi=null,En=null,eu=!1;function ko(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||Ga==null||Ga!==fs(a)||(a=Ga,"selectionStart"in a&&Ii(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),En&&Tn(En,a)||(En=a,a=ui(Pi,"onSelect"),0>=u,s-=u,ol=1<<32-Ke(t)+s|l<Ee?(De=oe,oe=null):De=oe.sibling;var He=S(y,oe,x[Ee],H);if(He===null){oe===null&&(oe=De);break}e&&oe&&He.alternate===null&&t(y,oe),h=i(He,h,Ee),we===null?he=He:we.sibling=He,we=He,oe=De}if(Ee===x.length)return l(y,oe),Re&&gl(y,Ee),he;if(oe===null){for(;EeEe?(De=oe,oe=null):De=oe.sibling;var sa=S(y,oe,He.value,H);if(sa===null){oe===null&&(oe=De);break}e&&oe&&sa.alternate===null&&t(y,oe),h=i(sa,h,Ee),we===null?he=sa:we.sibling=sa,we=sa,oe=De}if(He.done)return l(y,oe),Re&&gl(y,Ee),he;if(oe===null){for(;!He.done;Ee++,He=x.next())He=B(y,He.value,H),He!==null&&(h=i(He,h,Ee),we===null?he=He:we.sibling=He,we=He);return Re&&gl(y,Ee),he}for(oe=a(oe);!He.done;Ee++,He=x.next())He=C(oe,y,Ee,He.value,H),He!==null&&(e&&He.alternate!==null&&oe.delete(He.key===null?Ee:He.key),h=i(He,h,Ee),we===null?he=He:we.sibling=He,we=He);return e&&oe.forEach(function(w0){return t(y,w0)}),Re&&gl(y,Ee),he}function Xe(y,h,x,H){if(typeof x=="object"&&x!==null&&x.type===se&&x.key===null&&(x=x.props.children),typeof x=="object"&&x!==null){switch(x.$$typeof){case te:e:{for(var he=x.key;h!==null;){if(h.key===he){if(he=x.type,he===se){if(h.tag===7){l(y,h.sibling),H=s(h,x.props.children),H.return=y,y=H;break e}}else if(h.elementType===he||typeof he=="object"&&he!==null&&he.$$typeof===le&&ga(he)===h.type){l(y,h.sibling),H=s(h,x.props),Un(H,x),H.return=y,y=H;break e}l(y,h);break}else t(y,h);h=h.sibling}x.type===se?(H=ha(x.props.children,y.mode,H,x.key),H.return=y,y=H):(H=As(x.type,x.key,x.props,null,y.mode,H),Un(H,x),H.return=y,y=H)}return u(y);case re:e:{for(he=x.key;h!==null;){if(h.key===he)if(h.tag===4&&h.stateNode.containerInfo===x.containerInfo&&h.stateNode.implementation===x.implementation){l(y,h.sibling),H=s(h,x.children||[]),H.return=y,y=H;break e}else{l(y,h);break}else t(y,h);h=h.sibling}H=uu(x,y.mode,H),H.return=y,y=H}return u(y);case le:return x=ga(x),Xe(y,h,x,H)}if(J(x))return ue(y,h,x,H);if(ce(x)){if(he=ce(x),typeof he!="function")throw Error(r(150));return x=he.call(x),xe(y,h,x,H)}if(typeof x.then=="function")return Xe(y,h,_s(x),H);if(x.$$typeof===Y)return Xe(y,h,Es(y,x),H);Ds(y,x)}return typeof x=="string"&&x!==""||typeof x=="number"||typeof x=="bigint"?(x=""+x,h!==null&&h.tag===6?(l(y,h.sibling),H=s(h,x),H.return=y,y=H):(l(y,h),H=iu(x,y.mode,H),H.return=y,y=H),u(y)):l(y,h)}return function(y,h,x,H){try{Dn=0;var he=Xe(y,h,x,H);return Wa=null,he}catch(oe){if(oe===$a||oe===zs)throw oe;var we=Bt(29,oe,null,y.mode);return we.lanes=H,we.return=y,we}}}var ja=mr(!0),hr=mr(!1),Ql=!1;function gu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Xl(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function kl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Be&2)!==0){var s=a.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),a.pending=t,t=Ns(e),Fo(e,null,l),t}return Ss(e,a,t,l),Ns(e)}function Rn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var s=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var u={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?s=i=u:i=i.next=u,l=l.next}while(l!==null);i===null?s=i=t:i=i.next=t}else s=i=t;l={baseState:a.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function wn(){if(Su){var e=Ja;if(e!==null)throw e}}function Hn(e,t,l,a){Su=!1;var s=e.updateQueue;Ql=!1;var i=s.firstBaseUpdate,u=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var d=o,j=d.next;d.next=null,u===null?i=j:u.next=j,u=d;var U=e.alternate;U!==null&&(U=U.updateQueue,o=U.lastBaseUpdate,o!==u&&(o===null?U.firstBaseUpdate=j:o.next=j,U.lastBaseUpdate=d))}if(i!==null){var B=s.baseState;u=0,U=j=d=null,o=i;do{var S=o.lane&-536870913,C=S!==o.lane;if(C?(_e&S)===S:(a&S)===S){S!==0&&S===Va&&(Su=!0),U!==null&&(U=U.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var ue=e,xe=o;S=t;var Xe=l;switch(xe.tag){case 1:if(ue=xe.payload,typeof ue=="function"){B=ue.call(Xe,B,S);break e}B=ue;break e;case 3:ue.flags=ue.flags&-65537|128;case 0:if(ue=xe.payload,S=typeof ue=="function"?ue.call(Xe,B,S):ue,S==null)break e;B=z({},B,S);break e;case 2:Ql=!0}}S=o.callback,S!==null&&(e.flags|=64,C&&(e.flags|=8192),C=s.callbacks,C===null?s.callbacks=[S]:C.push(S))}else C={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},U===null?(j=U=C,d=B):U=U.next=C,u|=S;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;C=o,o=C.next,C.next=null,s.lastBaseUpdate=C,s.shared.pending=null}}while(!0);U===null&&(d=B),s.baseState=d,s.firstBaseUpdate=j,s.lastBaseUpdate=U,i===null&&(s.shared.lanes=0),$l|=u,e.lanes=u,e.memoizedState=B}}function pr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function vr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var u=A.T,o={};A.T=o,Lu(e,!1,t,l);try{var d=s(),j=A.S;if(j!==null&&j(o,d),d!==null&&typeof d=="object"&&typeof d.then=="function"){var U=Ah(d,a);Gn(e,t,U,Qt(e))}else Gn(e,t,a,Qt(e))}catch(B){Gn(e,t,{then:function(){},status:"rejected",reason:B},Qt())}finally{L.p=i,u!==null&&o.types!==null&&(u.types=o.types),A.T=u}}function Oh(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var s=Jr(e).queue;Vr(e,s,t,v,l===null?Oh:function(){return $r(e),l(a)})}function Jr(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:v,baseState:v,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:v},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function $r(e){var t=Jr(e);t.next===null&&(t=e.alternate.memoizedState),Gn(e,t.next.queue,{},Qt())}function Yu(){return yt(ls)}function Wr(){return tt().memoizedState}function Fr(){return tt().memoizedState}function _h(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Qt();e=Xl(l);var a=kl(t,e,l);a!==null&&(Ot(a,t,l),Rn(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function Dh(e,t,l){var a=Qt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Qs(e)?Pr(t,l):(l=nu(e,t,l,a),l!==null&&(Ot(l,e,a),ed(l,t,a)))}function Ir(e,t,l){var a=Qt();Gn(e,t,l,a)}function Gn(e,t,l,a){var s={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Qs(e))Pr(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var u=t.lastRenderedState,o=i(u,l);if(s.hasEagerState=!0,s.eagerState=o,Ht(o,u))return Ss(e,t,s,0),ke===null&&js(),!1}catch{}if(l=nu(e,t,s,a),l!==null)return Ot(l,e,a),ed(l,t,a),!0}return!1}function Lu(e,t,l,a){if(a={lane:2,revertLane:gc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Qs(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&Ot(t,e,2)}function Qs(e){var t=e.alternate;return e===Te||t!==null&&t===Te}function Pr(e,t){Ia=ws=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ed(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}var Yn={readContext:yt,use:qs,useCallback:We,useContext:We,useEffect:We,useImperativeHandle:We,useLayoutEffect:We,useInsertionEffect:We,useMemo:We,useReducer:We,useRef:We,useState:We,useDebugValue:We,useDeferredValue:We,useTransition:We,useSyncExternalStore:We,useId:We,useHostTransitionStatus:We,useFormState:We,useActionState:We,useOptimistic:We,useMemoCache:We,useCacheRefresh:We};Yn.useEffectEvent=We;var td={readContext:yt,use:qs,useCallback:function(e,t){return St().memoizedState=[e,t===void 0?null:t],e},useContext:yt,useEffect:qr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Ys(4194308,4,Qr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Ys(4194308,4,e,t)},useInsertionEffect:function(e,t){Ys(4,2,e,t)},useMemo:function(e,t){var l=St();t=t===void 0?null:t;var a=e();if(Sa){qe(!0);try{e()}finally{qe(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=St();if(l!==void 0){var s=l(t);if(Sa){qe(!0);try{l(t)}finally{qe(!1)}}}else s=t;return a.memoizedState=a.baseState=s,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:s},a.queue=e,e=e.dispatch=Dh.bind(null,Te,e),[a.memoizedState,e]},useRef:function(e){var t=St();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Ir.bind(null,Te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=St();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Vr.bind(null,Te,e.queue,!0,!1),St().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Te,s=St();if(Re){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),ke===null)throw Error(r(349));(_e&127)!==0||Sr(a,t,l)}s.memoizedState=l;var i={value:l,getSnapshot:t};return s.queue=i,qr(Ar.bind(null,a,i,e),[e]),a.flags|=2048,en(9,{destroy:void 0},Nr.bind(null,a,i,l,t),null),l},useId:function(){var e=St(),t=ke.identifierPrefix;if(Re){var l=rl,a=ol;l=(a&~(1<<32-Ke(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Hs++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?u.createElement("select",{is:a.is}):u.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?u.createElement(s,{is:a.is}):u.createElement(s)}}i[pt]=t,i[At]=a;e:for(u=t.child;u!==null;){if(u.tag===5||u.tag===6)i.appendChild(u.stateNode);else if(u.tag!==4&&u.tag!==27&&u.child!==null){u.child.return=u,u=u.child;continue}if(u===t)break e;for(;u.sibling===null;){if(u.return===null||u.return===t)break e;u=u.return}u.sibling.return=u.return,u=u.sibling}t.stateNode=i;e:switch(gt(i,s,a),s){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Cl(t)}}return Ve(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&Cl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=je.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,s=vt,s!==null)switch(s.tag){case 27:case 5:a=s.memoizedProps}e[pt]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||jf(e.nodeValue,l)),e||Yl(t,!0)}else e=ci(e).createTextNode(a),e[pt]=t,t.stateNode=e}return Ve(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[pt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(Gt(t),t):(Gt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Ve(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(s=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!s)throw Error(r(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(r(317));s[pt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),s=!1}else s=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),s=!0;if(!s)return t.flags&256?(Gt(t),t):(Gt(t),null)}return Gt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,s=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(s=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==s&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vs(t,t.updateQueue),Ve(t),null);case 4:return Ne(),e===null&&Nc(t.stateNode.containerInfo),Ve(t),null;case 10:return jl(t.type),Ve(t),null;case 19:if(N(et),a=t.memoizedState,a===null)return Ve(t),null;if(s=(t.flags&128)!==0,i=a.rendering,i===null)if(s)Qn(a,!1);else{if(Fe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Rs(e),i!==null){for(t.flags|=128,Qn(a,!1),e=i.updateQueue,t.updateQueue=e,Vs(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Io(l,e),l=l.sibling;return G(et,et.current&1|2),Re&&gl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&Pe()>Is&&(t.flags|=128,s=!0,Qn(a,!1),t.lanes=4194304)}else{if(!s)if(e=Rs(i),e!==null){if(t.flags|=128,s=!0,e=e.updateQueue,t.updateQueue=e,Vs(t,e),Qn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!Re)return Ve(t),null}else 2*Pe()-a.renderingStartTime>Is&&l!==536870912&&(t.flags|=128,s=!0,Qn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=Pe(),e.sibling=null,l=et.current,G(et,s?l&1|2:l&1),Re&&gl(t,a.treeForkCount),e):(Ve(t),null);case 22:case 23:return Gt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Ve(t),t.subtreeFlags&6&&(t.flags|=8192)):Ve(t),l=t.updateQueue,l!==null&&Vs(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&N(ba),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),jl(at),Ve(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function Bh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return jl(at),Ne(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return $(t),null;case 31:if(t.memoizedState!==null){if(Gt(t),t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Gt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return N(et),null;case 4:return Ne(),null;case 10:return jl(t.type),null;case 22:case 23:return Gt(t),Au(),e!==null&&N(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return jl(at),null;case 25:return null;default:return null}}function Cd(e,t){switch(ou(t),t.tag){case 3:jl(at),Ne();break;case 26:case 27:case 5:$(t);break;case 4:Ne();break;case 31:t.memoizedState!==null&&Gt(t);break;case 13:Gt(t);break;case 19:N(et);break;case 10:jl(t.type);break;case 22:case 23:Gt(t),Au(),e!==null&&N(ba);break;case 24:jl(at)}}function Xn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var s=a.next;l=s;do{if((l.tag&e)===e){a=void 0;var i=l.create,u=l.inst;a=i(),u.destroy=a}l=l.next}while(l!==s)}}catch(o){Ye(t,t.return,o)}}function Vl(e,t,l){try{var a=t.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var i=s.next;a=i;do{if((a.tag&e)===e){var u=a.inst,o=u.destroy;if(o!==void 0){u.destroy=void 0,s=t;var d=l,j=o;try{j()}catch(U){Ye(s,d,U)}}}a=a.next}while(a!==i)}}catch(U){Ye(t,t.return,U)}}function Td(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{vr(t,l)}catch(a){Ye(e,e.return,a)}}}function Ed(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ye(e,t,a)}}function kn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(s){Ye(e,t,s)}}function dl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(s){Ye(e,t,s)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(s){Ye(e,t,s)}else l.current=null}function Md(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(s){Ye(e,e.return,s)}}function lc(e,t,l){try{var a=e.stateNode;s0(a,e.type,l,t),a[At]=t}catch(s){Ye(e,e.return,s)}}function zd(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ea(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||zd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ea(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=vl));else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Js(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Js(e,t,l),e=e.sibling;e!==null;)Js(e,t,l),e=e.sibling}function Od(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,s=t.attributes;s.length;)t.removeAttributeNode(s[0]);gt(t,a,l),t[pt]=e,t[At]=l}catch(i){Ye(e,e.return,i)}}var Tl=!1,it=!1,sc=!1,_d=typeof WeakSet=="function"?WeakSet:Set,ft=null;function qh(e,t){if(e=e.containerInfo,Tc=pi,e=Xo(e),Ii(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var s=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var u=0,o=-1,d=-1,j=0,U=0,B=e,S=null;t:for(;;){for(var C;B!==l||s!==0&&B.nodeType!==3||(o=u+s),B!==i||a!==0&&B.nodeType!==3||(d=u+a),B.nodeType===3&&(u+=B.nodeValue.length),(C=B.firstChild)!==null;)S=B,B=C;for(;;){if(B===e)break t;if(S===l&&++j===s&&(o=u),S===i&&++U===a&&(d=u),(C=B.nextSibling)!==null)break;B=S,S=B.parentNode}B=C}l=o===-1||d===-1?null:{start:o,end:d}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},pi=!1,ft=t;ft!==null;)if(t=ft,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,ft=e;else for(;ft!==null;){switch(t=ft,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),gt(i,a,l),i[pt]=e,dt(i),a=i;break e;case"link":var u=qf("link","href",s).get(a+(l.href||""));if(u){for(var o=0;oXe&&(u=Xe,Xe=xe,xe=u);var y=Lo(o,xe),h=Lo(o,Xe);if(y&&h&&(C.rangeCount!==1||C.anchorNode!==y.node||C.anchorOffset!==y.offset||C.focusNode!==h.node||C.focusOffset!==h.offset)){var x=B.createRange();x.setStart(y.node,y.offset),C.removeAllRanges(),xe>Xe?(C.addRange(x),C.extend(h.node,h.offset)):(x.setEnd(h.node,h.offset),C.addRange(x))}}}}for(B=[],C=o;C=C.parentNode;)C.nodeType===1&&B.push({element:C,left:C.scrollLeft,top:C.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,A.T=null,l=fc,fc=null;var i=Fl,u=_l;if(ct=0,sn=Fl=null,_l=0,(Be&6)!==0)throw Error(r(331));var o=Be;if(Be|=4,Qd(i.current),Gd(i,i.current,u,l),Be=o,Wn(0,!1),ve&&typeof ve.onPostCommitFiberRoot=="function")try{ve.onPostCommitFiberRoot(F,i)}catch{}return!0}finally{L.p=s,A.T=a,uf(e,t)}}function of(e,t,l){t=Vt(l,t),t=Ku(e.stateNode,t,2),e=kl(e,t,2),e!==null&&(vn(e,2),fl(e))}function Ye(e,t,l){if(e.tag===3)of(e,e,l);else for(;t!==null;){if(t.tag===3){of(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Wl===null||!Wl.has(a))){e=Vt(l,e),l=od(2),a=kl(t,l,2),a!==null&&(rd(l,a,t,e),vn(a,2),fl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Lh;var s=new Set;a.set(t,s)}else s=a.get(t),s===void 0&&(s=new Set,a.set(t,s));s.has(l)||(cc=!0,s.add(l),e=Zh.bind(null,e,t,l),t.then(e,e))}function Zh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,ke===e&&(_e&l)===l&&(Fe===4||Fe===3&&(_e&62914560)===_e&&300>Pe()-Fs?(Be&2)===0&&un(e,0):oc|=l,nn===_e&&(nn=0)),fl(e)}function rf(e,t){t===0&&(t=lo()),e=ma(e,t),e!==null&&(vn(e,t),fl(e))}function Vh(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),rf(e,l)}function Jh(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,s=e.memoizedState;s!==null&&(l=s.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),rf(e,l)}function $h(e,t){return Ue(e,t)}var ni=null,on=null,yc=!1,si=!1,bc=!1,Pl=0;function fl(e){e!==on&&e.next===null&&(on===null?ni=on=e:on=on.next=e),si=!0,yc||(yc=!0,Fh())}function Wn(e,t){if(!bc&&si){bc=!0;do for(var l=!1,a=ni;a!==null;){if(e!==0){var s=a.pendingLanes;if(s===0)var i=0;else{var u=a.suspendedLanes,o=a.pingedLanes;i=(1<<31-Ke(42|e)+1)-1,i&=s&~(u&~o),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,hf(a,i))}else i=_e,i=os(a,a===ke?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||pn(a,i)||(l=!0,hf(a,i));a=a.next}while(l);bc=!1}}function Wh(){df()}function df(){si=yc=!1;var e=0;Pl!==0&&u0()&&(e=Pl);for(var t=Pe(),l=null,a=ni;a!==null;){var s=a.next,i=ff(a,t);i===0?(a.next=null,l===null?ni=s:l.next=s,s===null&&(on=l)):(l=a,(e!==0||(i&3)!==0)&&(si=!0)),a=s}ct!==0&&ct!==5||Wn(e),Pl!==0&&(Pl=0)}function ff(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,s=e.expirationTimes,i=e.pendingLanes&-62914561;0o)break;var U=d.transferSize,B=d.initiatorType;U&&Sf(B)&&(d=d.responseEnd,u+=U*(d"u"?null:document;function Rf(e,t,l){var a=rn;if(a&&typeof t=="string"&&t){var s=Kt(t);s='link[rel="'+e+'"][href="'+s+'"]',typeof l=="string"&&(s+='[crossorigin="'+l+'"]'),Uf.has(s)||(Uf.add(s),e={rel:e,crossOrigin:l,href:t},a.querySelector(s)===null&&(t=a.createElement("link"),gt(t,"link",e),dt(t),a.head.appendChild(t)))}}function v0(e){Dl.D(e),Rf("dns-prefetch",e,null)}function y0(e,t){Dl.C(e,t),Rf("preconnect",e,t)}function b0(e,t,l){Dl.L(e,t,l);var a=rn;if(a&&e&&t){var s='link[rel="preload"][as="'+Kt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(s+='[imagesrcset="'+Kt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(s+='[imagesizes="'+Kt(l.imageSizes)+'"]')):s+='[href="'+Kt(e)+'"]';var i=s;switch(t){case"style":i=dn(e);break;case"script":i=fn(e)}Pt.has(i)||(e=z({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),Pt.set(i,e),a.querySelector(s)!==null||t==="style"&&a.querySelector(es(i))||t==="script"&&a.querySelector(ts(i))||(t=a.createElement("link"),gt(t,"link",e),dt(t),a.head.appendChild(t)))}}function g0(e,t){Dl.m(e,t);var l=rn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",s='link[rel="modulepreload"][as="'+Kt(a)+'"][href="'+Kt(e)+'"]',i=s;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=fn(e)}if(!Pt.has(i)&&(e=z({rel:"modulepreload",href:e},t),Pt.set(i,e),l.querySelector(s)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ts(i)))return}a=l.createElement("link"),gt(a,"link",e),dt(a),l.head.appendChild(a)}}}function x0(e,t,l){Dl.S(e,t,l);var a=rn;if(a&&e){var s=Da(a).hoistableStyles,i=dn(e);t=t||"default";var u=s.get(i);if(!u){var o={loading:0,preload:null};if(u=a.querySelector(es(i)))o.loading=5;else{e=z({rel:"stylesheet",href:e,"data-precedence":t},l),(l=Pt.get(i))&&Rc(e,l);var d=u=a.createElement("link");dt(d),gt(d,"link",e),d._p=new Promise(function(j,U){d.onload=j,d.onerror=U}),d.addEventListener("load",function(){o.loading|=1}),d.addEventListener("error",function(){o.loading|=2}),o.loading|=4,ri(u,t,a)}u={type:"stylesheet",instance:u,count:1,state:o},s.set(i,u)}}}function j0(e,t){Dl.X(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0},t),(t=Pt.get(s))&&wc(e,t),i=l.createElement("script"),dt(i),gt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function S0(e,t){Dl.M(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0,type:"module"},t),(t=Pt.get(s))&&wc(e,t),i=l.createElement("script"),dt(i),gt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function wf(e,t,l,a){var s=(s=je.current)?oi(s):null;if(!s)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=dn(l.href),l=Da(s).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=dn(l.href);var i=Da(s).hoistableStyles,u=i.get(e);if(u||(s=s.ownerDocument||s,u={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,u),(i=s.querySelector(es(e)))&&!i._p&&(u.instance=i,u.state.loading=5),Pt.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},Pt.set(e,l),i||N0(s,e,l,u.state))),t&&a===null)throw Error(r(528,""));return u}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=fn(l),l=Da(s).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function dn(e){return'href="'+Kt(e)+'"'}function es(e){return'link[rel="stylesheet"]['+e+"]"}function Hf(e){return z({},e,{"data-precedence":e.precedence,precedence:null})}function N0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),gt(t,"link",l),dt(t),e.head.appendChild(t))}function fn(e){return'[src="'+Kt(e)+'"]'}function ts(e){return"script[async]"+e}function Bf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Kt(l.href)+'"]');if(a)return t.instance=a,dt(a),a;var s=z({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),dt(a),gt(a,"style",s),ri(a,l.precedence,e),t.instance=a;case"stylesheet":s=dn(l.href);var i=e.querySelector(es(s));if(i)return t.state.loading|=4,t.instance=i,dt(i),i;a=Hf(l),(s=Pt.get(s))&&Rc(a,s),i=(e.ownerDocument||e).createElement("link"),dt(i);var u=i;return u._p=new Promise(function(o,d){u.onload=o,u.onerror=d}),gt(i,"link",a),t.state.loading|=4,ri(i,l.precedence,e),t.instance=i;case"script":return i=fn(l.src),(s=e.querySelector(ts(i)))?(t.instance=s,dt(s),s):(a=l,(s=Pt.get(i))&&(a=z({},l),wc(a,s)),e=e.ownerDocument||e,s=e.createElement("script"),dt(s),gt(s,"link",a),e.head.appendChild(s),t.instance=s);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ri(a,l.precedence,e));return t.instance}function ri(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),s=a.length?a[a.length-1]:null,i=s,u=0;u title"):null)}function A0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Yf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function C0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var s=dn(a.href),i=t.querySelector(es(s));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fi.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,dt(i);return}i=t.ownerDocument||t,a=Hf(a),(s=Pt.get(s))&&Rc(a,s),i=i.createElement("link"),dt(i);var u=i;u._p=new Promise(function(o,d){u.onload=o,u.onerror=d}),gt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fi.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Hc=0;function T0(e,t){return e.stylesheets&&e.count===0&&hi(e,e.stylesheets),0Hc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(s)}}:null}function fi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hi(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var mi=null;function hi(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,mi=new Map,t.forEach(E0,e),mi=null,fi.call(e))}function E0(e,t){if(!(t.state.loading&4)){var l=mi.get(e);if(l)var a=l.get(null);else{l=new Map,mi.set(e,l);for(var s=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Kc.exports=K0(),Kc.exports}var V0=Z0();function be(c){return Array.isArray(c)?c:[]}function pm(c){const m=new Set;return c.map(p=>p.trim()).filter(p=>{const r=p.toLowerCase();return!p||m.has(r)?!1:(m.add(r),!0)})}function il(c){const m=Ni.some(p=>p.value===c.streamMode)?c.streamMode:"auto";return{...c,streamMode:m,models:be(c.models),allowedGroupIds:be(c.allowedGroupIds),openaiAccounts:be(c.openaiAccounts),kiroAccounts:be(c.kiroAccounts)}}function cs(c){return{...c,aliases:be(c.aliases)}}function J0(c){return{...c,apiKeys:be(c.apiKeys),logs:be(c.logs)}}class Ci extends Error{status;payload;constructor(m,p,r){super(p),this.status=m,this.payload=r}}const $0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function _t({name:c}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:$0[c]})})}async function pe(c,m){const p=new Headers(m?.headers);p.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const E=await fetch(c,{credentials:"include",...m,headers:p});if(!E.ok){const M=await E.json().catch(()=>null);throw new Ci(E.status,M?.error?.message||`Request failed: ${E.status}`,M)}return E.json()}async function W0(c,m){const p=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const E=await fetch(c,{credentials:"include",method:"POST",headers:p,body:m});if(!E.ok){const M=await E.json().catch(()=>null);throw new Ci(E.status,M?.error?.message||`Request failed: ${E.status}`,M)}return E.json()}const rm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],eo=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],vm="https://api.openai.com/v1",Ti="https://chatgpt.com/backend-api",ym="http://localhost:8317/v1",bm="https://codewhisperer.us-east-1.amazonaws.com",gm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",F0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",I0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",P0="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:bm,models:P0.split(",").map(c=>c.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:vm,models:F0.split(",").map(c=>c.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ti,models:gm.split(",").map(c=>c.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:ym,models:I0.split(",").map(c=>c.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Ta(c){return Fc.find(m=>m.provider===c)||Fc[2]}function xm(c){const m=Ta(c);return{name:m.name,provider:m.provider,baseUrl:m.baseUrl,models:[...m.models],streamMode:"auto"}}function ep(c){const m=c?.trim().toLowerCase();return m&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[m]||c)||"套餐未知"}function dm(c){return c?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[c]||c:""}function Ei(c){return c==="openai"?vm:c==="codex"?Ti:c==="cpa"||c==="cliproxyapi"?ym:c==="kiro"?bm:""}function Ic(c){return pm(c.split(/[\s,;,;]+/))}function tp(c){return pm(c.split(/[\n,;,;]+/).map(m=>m.trim()))}function jm(c){const m=tp(c);return m.length===0?{}:m.length===1?{upstreamApiKey:m[0]}:{upstreamApiKeys:m}}const Ni=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function tl(c){if(!c)return"未使用";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(m)}function fm(c){if(!c)return"";const m=new Date(c);if(Number.isNaN(m.getTime()))return"";const p=m.getTimezoneOffset()*6e4;return new Date(m.getTime()-p).toISOString().slice(0,16)}function lp(c){if(!c)return"";const m=new Date(c);return Number.isNaN(m.getTime())?"":m.toISOString()}function ap(c){if(!c)return"-";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(m)}function Dt(c){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[c]||c}function Nt(c,m=2){const p=Number(c||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:m,maximumFractionDigits:m}).format(p)}function ml(c){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(c||0))))}function to(c){return c.model?c.model:c.errorCode==="invalid_api_key"?"密钥无效":c.errorCode==="model_not_available"?"模型不可用":c.errorCode==="insufficient_quota"?"额度不足":c.errorCode==="rate_limit_exceeded"?"请求过快":c.errorCode||"请求失败"}function np(c){return c.model||(c.errorCode?`错误:${c.errorCode}`:"-")}function sp(c){return c.channel||(c.apiKeyPrefix?`Key ${c.apiKeyPrefix}`:"-")}function ip(c){const m=be(c);if(m.length===0)return"未绑定模型";const p=m.slice(0,2).join(", ");return m.length>2?`${p} · 其余 ${m.length-2} 个`:p}function ul(c){return c==="cliproxyapi"||c==="cli-proxy-api"?"CPA / CLIProxyAPI":eo.find(m=>m.value===c)?.label||c||"Custom"}function $c(c){const m=`${c.vendor} ${c.id} ${c.name}`.toLowerCase();return m.includes("cliproxyapi")||/\bcpa\b/.test(m)?"cpa":m.includes("openai")||/\bgpt[-_/]/.test(m)||m.includes("o1-")||m.includes("o3-")?"openai":m.includes("anthropic")||m.includes("claude")?"anthropic":m.includes("google")||m.includes("gemini")||m.includes("gcli-")?"google":m.includes("deepseek")?"deepseek":m.includes("openrouter")?"openrouter":m.includes("groq")?"groq":m.includes("siliconflow")?"siliconflow":m.includes("moonshot")||m.includes("kimi")?"moonshot":c.vendor&&c.vendor.toLowerCase()!=="custom"?c.vendor.toLowerCase():"compatible"}function mm({provider:c}){if(c==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(c==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const m=c==="codex"?"C":c==="cpa"||c==="cliproxyapi"?"CPA":c==="anthropic"?"A":c==="google"?"✦":c==="openrouter"?"↗":c==="groq"?"G":c==="siliconflow"?"S":c==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${c}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:m})]})})}async function Ai(c){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(c);return}const m=document.createElement("textarea");m.value=c,m.setAttribute("readonly","true"),m.style.position="fixed",m.style.opacity="0",document.body.appendChild(m),m.select(),document.execCommand("copy"),document.body.removeChild(m)}function Ul(){return window.location.origin}function up(){return`${Ul()}/api/auth/discord/callback`}function cp(){return`${Ul()}/`}function Wc(c){return{...c,redirectUri:c.redirectUri&&!c.redirectUri.includes("localhost")?c.redirectUri:up(),authSuccessUrl:c.authSuccessUrl&&!c.authSuccessUrl.includes("localhost")?c.authSuccessUrl:cp(),blockedGuildIds:be(c.blockedGuildIds),sessionTtlHours:c.sessionTtlHours||168}}function Mi(c){return c==="email"||c==="discord"?c:"username"}function op(c){const p=(c.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(p.length>=3?p:"user").slice(0,24)}function rp(){const[c,m]=g.useState("home"),[p,r]=g.useState("login"),[E,M]=g.useState(null),[X,P]=g.useState("overview"),[T,b]=g.useState(()=>{const w=window.localStorage.getItem("capi-theme");return w==="light"||w==="dark"?w:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[q,z]=g.useState("comfortable"),[ee,te]=g.useState(null),[re,se]=g.useState([]),[ne,ie]=g.useState([]),[ge,Y]=g.useState([]),[ye,I]=g.useState([]),[me,_]=g.useState([]),[le,de]=g.useState(""),[Ae,Me]=g.useState(""),[ce,k]=g.useState(null),[fe,J]=g.useState(""),[A,L]=g.useState(""),[v,D]=g.useState(!1),W=g.useMemo(()=>{const w=le.trim().toLowerCase();return w?re.filter(K=>`${K.id} ${K.name} ${K.email}`.toLowerCase().includes(w)):re},[le,re]);async function f(){const w=new Date().getTimezoneOffset(),[K,ae,F,ve,qe,Ke]=await Promise.all([pe(`/api/overview?timezoneOffset=${w}`),pe("/api/users"),pe("/api/channels"),pe("/api/models"),pe("/api/logs"),pe("/api/groups")]),wt=be(ae.users),Rl=be(F.channels).map(il),ca=be(ve.models).map(cs),Ea=be(qe.logs),Ma=be(Ke.groups);te(K),se(wt),ie(Rl),Y(Ma),I(ca),_(Ea),Me(wl=>wl&&wt.some(hl=>hl.id===wl)?wl:wt[0]?.id||""),wt.length===0&&k(null),D(!0)}async function N(w){const K=await pe(`/api/users/${w}`);k(J0(K))}async function G(w,K){const ae=await pe(`/api/users/${w}`,{method:"PATCH",body:JSON.stringify(K)});se(F=>F.map(ve=>ve.id===w?ae.user:ve)),k(F=>F?.user.id===w?{...F,user:ae.user}:F),J("已更新用户"),window.setTimeout(()=>J(""),1800)}async function Q(w,K,ae={}){const F=await pe("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:w,action:K,...ae})}),ve=new Map(be(F.users).map(qe=>[qe.id,qe]));se(qe=>qe.map(Ke=>ve.get(Ke.id)||Ke)),k(qe=>{if(!qe)return qe;const Ke=ve.get(qe.user.id);return Ke?{...qe,user:Ke}:qe}),J(`已处理 ${F.updated} 个用户`),window.setTimeout(()=>J(""),1800)}async function Z(w){const K=await pe(`/api/users/${w}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ce?.user.id===w&&k({...ce,apiKeys:[...ce.apiKeys,K.apiKey]}),L(K.secret),await Ai(K.secret),J("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>J(""),2400)}async function je(w){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await pe(`/api/api-keys/${w}`,{method:"DELETE"}),k(K=>K&&{...K,apiKeys:K.apiKeys.filter(ae=>ae.id!==w)}),J("Key 已删除"),window.setTimeout(()=>J(""),1800))}async function O(w,K){const ae=await pe(`/api/api-keys/${w}`,{method:"PATCH",body:JSON.stringify(K)});k(F=>F&&{...F,apiKeys:F.apiKeys.map(ve=>ve.id===w?ae.apiKey:ve)}),J("Key 已更新"),window.setTimeout(()=>J(""),1800)}async function Se(w,K){const ae=await pe(`/api/channels/${w}`,{method:"PATCH",body:JSON.stringify(K)});ie(F=>F.map(ve=>ve.id===w?il(ae.channel):ve)),Ie(ae.removedModels),J("渠道已更新"),window.setTimeout(()=>J(""),1800)}async function Ne(w){const K=ne.find(F=>F.id===w);if(!window.confirm(`删除渠道「${K?.name||w}」?`))return;const ae=await pe(`/api/channels/${w}`,{method:"DELETE"});ie(F=>F.filter(ve=>ve.id!==w)),Ie(ae.removedModels),J("渠道已删除"),window.setTimeout(()=>J(""),1800)}async function ot(w){const K=await pe("/api/groups",{method:"POST",body:JSON.stringify(w)});Y(ae=>[...ae,K.group]),J("分组已创建"),window.setTimeout(()=>J(""),1800)}async function $(w,K){const ae=await pe(`/api/groups/${w}`,{method:"PATCH",body:JSON.stringify(K)});Y(F=>F.map(ve=>ve.id===w?ae.group:ve)),J("分组已更新"),window.setTimeout(()=>J(""),1800)}async function Je(w){const K=ge.find(ae=>ae.id===w);window.confirm(`删除分组「${K?.name||w}」?删除后渠道的可见范围会移除该分组。`)&&(await pe(`/api/groups/${w}`,{method:"DELETE"}),Y(ae=>ae.filter(F=>F.id!==w)),ie(ae=>ae.map(F=>({...F,allowedGroupIds:F.allowedGroupIds.filter(ve=>ve!==w)}))),J("分组已删除"),window.setTimeout(()=>J(""),1800))}async function ut(w,K){const ae=be(K).map(wt=>wt.trim()).filter(Boolean),F=await pe(`/api/channels/${w}/sync-models`,{method:"POST",body:JSON.stringify(ae.length?{models:ae}:{})}),ve=il(F.channel),qe=be(F.addedModels).map(cs),Ke=be(F.models);ie(wt=>wt.map(Rl=>Rl.id===w?ve:Rl)),qe.length>0&&I(wt=>{const Rl=new Set(wt.map(ca=>ca.id.toLowerCase()));return[...wt,...qe.filter(ca=>!Rl.has(ca.id.toLowerCase()))]}),Ie(F.removedModels),J(ae.length?`已保存 ${Ke.length} 个模型`:Ke.length?`已拉取 ${Ke.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>J(""),2200)}function Ie(w){const K=new Set(be(w).map(ae=>ae.toLowerCase()));K.size!==0&&(I(ae=>ae.filter(F=>!K.has(F.id.toLowerCase()))),k(ae=>ae&&{...ae,apiKeys:ae.apiKeys.map(F=>({...F,allowedModels:F.allowedModels.filter(ve=>!K.has(ve.toLowerCase()))}))}))}async function ll(w){try{const K=await pe(`/api/channels/${w}/check`,{method:"POST",body:JSON.stringify({})});ie(ae=>ae.map(F=>F.id===w?il(K.channel):F)),J(K.ok?`渠道可用,检测到 ${be(K.models).length} 个模型`:"渠道检测失败")}catch(K){const ae=K instanceof Ci?K.payload?.channel:null;ae&&ie(F=>F.map(ve=>ve.id===w?il(ae):ve)),J(K instanceof Error?K.message:"渠道检测失败")}window.setTimeout(()=>J(""),2400)}async function V(w=xm("codex")){const K=await pe("/api/channels",{method:"POST",body:JSON.stringify(w)});ie(ae=>[...ae,il(K.channel)]),J("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>J(""),2400)}async function mt(w,K){const ae=new FormData;ae.append("file",K);const F=await W0(`/api/channels/${encodeURIComponent(w)}/import-openai-accounts`,ae);ie(ve=>ve.map(qe=>qe.id===F.channel.id?il(F.channel):qe)),J(`新增 ${F.created??F.imported} 个账号${F.updated?`,更新 ${F.updated} 个已有账号`:""}${F.skipped?`,跳过 ${F.skipped} 个`:""}`),window.setTimeout(()=>J(""),2600)}async function Rt(w,K=!1,ae=""){const F=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:K,accountId:ae})});ie(ve=>ve.map(qe=>qe.id===F.channel.id?il(F.channel):qe)),J(`${K?"无效账号复检":"账号测活"}完成:${F.healthy}/${F.checked} 可用${F.failed?`,无效 ${F.failed}`:""}`),window.setTimeout(()=>J(""),3e3)}async function R(w){const K=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ie(ae=>ae.map(F=>F.id===K.channel.id?il(K.channel):F)),J(K.removed?`已合并 ${K.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>J(""),2600)}async function Ue(w,K){const ae=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/${encodeURIComponent(K)}`,{method:"DELETE"});ie(F=>F.map(ve=>ve.id===ae.channel.id?il(ae.channel):ve)),J("账号已删除"),window.setTimeout(()=>J(""),1800)}async function rt(w){return pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function jt(w,K){const ae=await pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(K)});return ie(F=>F.map(ve=>ve.id===ae.channel.id?il(ae.channel):ve)),J("已通过 OAuth 添加账号"),window.setTimeout(()=>J(""),2400),ae}async function ht(w){const K=await pe("/api/models",{method:"POST",body:JSON.stringify(w)});I(ae=>[...ae,cs(K.model)]),J("模型已添加"),window.setTimeout(()=>J(""),1800)}async function Pe(w,K){const ae=await pe(`/api/models/${encodeURIComponent(w)}`,{method:"PATCH",body:JSON.stringify(K)});I(F=>F.map(ve=>ve.id===w?cs(ae.model):ve)),J("模型已更新"),window.setTimeout(()=>J(""),1600)}async function zi(w){window.confirm(`删除模型 ${w}?渠道和 Key 中的引用也会一起清理。`)&&(await pe(`/api/models/${encodeURIComponent(w)}`,{method:"DELETE"}),I(K=>K.filter(ae=>ae.id!==w)),ie(K=>K.map(ae=>({...ae,models:ae.models.filter(F=>F!==w)}))),k(K=>K&&{...K,apiKeys:K.apiKeys.map(ae=>({...ae,allowedModels:ae.allowedModels.filter(F=>F!==w)}))}),J("模型已删除"),window.setTimeout(()=>J(""),1800))}async function hn(w,K="已复制"){await Ai(w),J(K),window.setTimeout(()=>J(""),1600)}function ia(w,K){if(w instanceof Ci&&w.status===401){D(!1),r("login"),m("auth");return}J(K)}async function ua(){try{const w=await pe("/api/auth/status");if(M(w),!w.initialized){r("setup"),m("auth");return}if(!w.authenticated){r("login"),m("auth");return}m(w.session?.role==="admin"?"console":"account")}catch(w){ia(w,"认证状态加载失败")}}async function Oi(){await pe("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),M(null),m("home")}return g.useEffect(()=>{let w=!1;return pe("/api/auth/status").then(K=>{w||(M(K),K.authenticated&&K.session&&m(K.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{w=!0}},[]),g.useEffect(()=>{c==="console"&&(D(!1),f().catch(w=>ia(w,"加载数据失败")))},[c]),g.useEffect(()=>{c!=="console"||!v||N(Ae).catch(w=>ia(w,"加载用户详情失败"))},[Ae,c,v]),g.useEffect(()=>{window.localStorage.setItem("capi-theme",T)},[T]),g.useEffect(()=>{window.scrollTo({top:0,left:0})},[c,X]),c==="home"?n.jsx(yp,{theme:T,setTheme:b,enterConsole:ua}):c==="auth"?n.jsx(dp,{theme:T,mode:p,status:E,setTheme:b,setMode:r,goHome:()=>m("home"),onAuthenticated:w=>{M(K=>K?{...K,authenticated:!0,initialized:!0,session:w}:null),m(w.role==="admin"?"console":"account")}}):c==="account"?n.jsx(vp,{theme:T,setTheme:b,goHome:()=>m("home"),openLogin:ua}):n.jsxs("div",{className:"app-shell","data-theme":T,"data-density":q,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:rm.map(w=>n.jsxs("button",{className:X===w.id?"nav-item active":"nav-item",onClick:()=>P(w.id),children:[n.jsx(_t,{name:w.icon}),n.jsx("span",{className:"nav-label",children:w.label})]},w.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:rm.find(w=>w.id===X)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(Xp,{value:q,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:w=>z(w)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>b(T==="dark"?"light":"dark"),children:[n.jsx(_t,{name:T==="dark"?"sun":"moon"}),n.jsx("span",{children:T==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>f().catch(w=>ia(w,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>m("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Oi,children:"退出"})]})]}),X==="overview"&&n.jsx(bp,{overview:ee,channels:ne,logs:me,onNavigate:w=>{P(w),w==="channels"&&ne.length===0&&J("渠道页可以创建第一个上游"),w==="logs"&&me.length===0&&J("暂无异常日志"),window.setTimeout(()=>J(""),1800)}}),X==="users"&&n.jsx(xp,{users:W,query:le,selectedUser:ce,onQuery:de,onSelect:Me,onUpdate:G,onBulkUpdate:Q,onCreateKey:Z,groups:ge,onOpenRegistration:()=>{P("settings"),J("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>J(""),2400)}}),X==="groups"&&n.jsx(Lp,{groups:ge,onCreate:ot,onUpdate:$,onDelete:Je}),X==="keys"&&n.jsx(jp,{selectedUser:ce,onCreateKey:Z,onUpdateKey:O,onDeleteKey:je}),X==="models"&&n.jsx(Np,{models:ye,onCopy:hn,onCreate:ht,onUpdate:Pe,onDelete:zi}),X==="drawing"&&n.jsx(Tp,{channels:ne,onCreate:V,onImport:mt,onCheckAccounts:Rt,onDeduplicateAccounts:R,onDeleteAccount:Ue,onUpdate:Se,onStartOAuth:rt,onCompleteOAuth:jt}),X==="channels"&&n.jsx(Hp,{channels:ne,groups:ge,onUpdate:Se,onCreate:V,onImport:mt,onDelete:Ne,onSyncModels:ut,onCheck:ll}),X==="logs"&&n.jsx(qp,{logs:me,onCopy:hn}),X==="settings"&&n.jsx(Yp,{models:ye,channels:ne,groups:ge})]}),A&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:A}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{Ai(A),J("完整 Key 已复制"),window.setTimeout(()=>J(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>L(""),children:"完成"})]})]})}),fe&&n.jsx("div",{className:"toast",children:fe})]})}function dp({theme:c,mode:m,status:p,setTheme:r,setMode:E,goHome:M,onAuthenticated:X}){const[P,T]=g.useState(""),[b,q]=g.useState(""),[z,ee]=g.useState(""),[te,re]=g.useState(""),[se,ne]=g.useState(""),[ie,ge]=g.useState(""),[Y,ye]=g.useState(!1),[I,me]=g.useState("username"),[_,le]=g.useState("0"),[de,Ae]=g.useState(""),[Me,ce]=g.useState(!1),k=m==="setup",fe=m==="register",J=Mi(p?.registrationMode),A=fe&&J==="email",L=fe&&J==="discord";async function v(){if(!L){if((k||fe)&&se!==ie){Ae("两次输入的密码不一致");return}ce(!0),Ae("");try{const D=k?"/api/auth/setup":fe?"/api/auth/register":"/api/auth/login",W=A?op(z):P,f=m==="login"?{identifier:P,password:se}:{username:W,password:se,displayName:b,email:z,discordUserId:k?te:"",registrationEnabled:k?Y:void 0,registrationMode:k?I:void 0,defaultBalance:k?Number(_||0):void 0},N=await pe(D,{method:"POST",body:JSON.stringify(f)});X(N.session)}catch(D){Ae(D instanceof Error?D.message:"操作失败")}finally{ce(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":c,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:M,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(c==="dark"?"light":"dark"),children:[n.jsx(_t,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:k?"First Run":"Welcome Back"}),n.jsx("h1",{children:k?"初始化 CAPI":fe?"创建账号":"登录"}),n.jsx("p",{children:k?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:D=>{D.preventDefault(),v()},children:[L?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),p?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:b,onChange:D=>q(D.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!A&&n.jsxs("label",{children:[n.jsx("span",{children:m==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:P,onChange:D=>T(D.target.value),autoComplete:"username",placeholder:m==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(k||A)&&n.jsxs("label",{children:[n.jsx("span",{children:A?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:z,onChange:D=>ee(D.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),k&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:te,onChange:D=>re(D.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:Y?"ios-switch is-on":"ios-switch","aria-pressed":Y,onClick:()=>ye(D=>!D),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:I,onChange:D=>me(Mi(D.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:_,onChange:D=>le(D.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:se,onChange:D=>ne(D.target.value),autoComplete:m==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ie,onChange:D=>ge(D.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:de}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Me,children:Me?"请稍候":k?"创建管理员":fe?"注册":"登录"})]}),!k&&!L&&p?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!k&&n.jsx("div",{className:"auth-switch",children:m==="login"&&p?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>E("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>E("login"),children:"返回登录"})})]})]})]})}const fp=[1,1.5,2,2.5,3,4,5,6,8,10];function mp(c){if(!(c>0))return 1;const m=Math.floor(Math.log10(c)),p=Math.pow(10,m),r=c/p;return(fp.find(M=>r<=M)??10)*p}const hm=88;function hp(c){const m=c.split("-");return m.length===3?`${m[1]}/${m[2]}`:c}function pp(){const[c,m]=g.useState(14),[p,r]=g.useState(null),[E,M]=g.useState(!0),[X,P]=g.useState(!1),[T,b]=g.useState("");g.useEffect(()=>{let Y=!1;return M(!0),pe(`/api/account/usage?days=${c}&timezoneOffset=${new Date().getTimezoneOffset()}`).then(ye=>{Y||(r({...ye.usage,daily:be(ye.usage?.daily),models:be(ye.usage?.models)}),P(!1))}).catch(()=>{Y||P(!0)}).finally(()=>{Y||M(!1)}),()=>{Y=!0}},[c]);const q=p?.daily??[],z=p?.models??[],ee=mp(Math.max(0,...q.map(Y=>Y.cost))),te=Math.max(0,...z.map(Y=>Y.cost)),re=q.reduce((Y,ye)=>!Y||ye.cost>Y.cost?ye:Y,null),se=Math.max(1,Math.ceil(q.length/5)),ne=q.find(Y=>Y.day===T)||null,ie=ne?q.indexOf(ne):-1,ge=p?p.today.cost-p.yesterday.cost:0;return n.jsxs("section",{className:"account-section usage-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Usage"}),n.jsx("h2",{children:"用量概览"})]})}),!p&&E&&n.jsx("p",{className:"usage-placeholder",children:"正在统计用量…"}),!p&&!E&&X&&n.jsx("p",{className:"usage-placeholder",children:"用量加载失败,请稍后重试"}),p&&n.jsxs("div",{className:E?"usage-body is-refreshing":"usage-body",children:[n.jsxs("div",{className:"usage-kpi",children:[n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日消费"}),n.jsx("strong",{children:Nt(p.today.cost)}),n.jsxs("small",{children:["较昨日 ",ge>=0?"+":"−",Nt(Math.abs(ge))]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"本月消费"}),n.jsx("strong",{children:Nt(p.month.cost)}),n.jsxs("small",{children:[ml(p.month.requests)," 次请求"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日请求"}),n.jsx("strong",{children:ml(p.today.requests)}),n.jsxs("small",{children:["成功率 ",p.today.successRate,"%"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"累计消费"}),n.jsx("strong",{children:Nt(p.total.cost)}),n.jsxs("small",{children:[ml(p.total.requests)," 次请求"]})]})]}),n.jsx("div",{className:"usage-range",role:"group","aria-label":"统计范围",children:[7,14,30].map(Y=>n.jsxs("button",{type:"button",className:c===Y?"selected":"","aria-pressed":c===Y,onClick:()=>m(Y),children:["近 ",Y," 天"]},Y))}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"每日消费"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天"]})]}),q.length===0||ee<=0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有消费记录"}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"usage-plot",children:[n.jsx("div",{className:"usage-grid","aria-hidden":"true",children:[1,.5,0].map(Y=>n.jsx("div",{className:"usage-gridline",style:{bottom:`${Y*hm}%`},children:n.jsx("span",{children:Nt(ee*Y)})},Y))}),n.jsxs("div",{className:"usage-columns",children:[q.map((Y,ye)=>{const I=ee>0?Y.cost/ee*hm:0,me=Y.cost>0,_=me&&re!==null&&Y.day===re.day,le=ye%se===0||ye===q.length-1;return n.jsxs("div",{className:"usage-column",children:[n.jsxs("button",{type:"button",className:T===Y.day?"usage-column-hit is-hovered":"usage-column-hit",onMouseEnter:()=>b(Y.day),onMouseLeave:()=>b(""),onFocus:()=>b(Y.day),onBlur:()=>b(""),"aria-label":`${Y.day} 消费 ${Nt(Y.cost)},${Y.requests} 次请求`,children:[me&&n.jsx("span",{className:"usage-column-bar",style:{height:`${I}%`}}),_&&n.jsx("span",{className:"usage-column-peak",style:{bottom:`calc(${I}% + 6px)`},children:Nt(Y.cost)})]}),n.jsx("span",{className:"usage-column-tick",children:le?hp(Y.day):""})]},Y.day)}),ne&&n.jsxs("div",{className:"usage-tooltip",style:{left:`${(ie+.5)/q.length*100}%`},role:"status",children:[n.jsx("strong",{children:Nt(ne.cost)}),n.jsx("span",{children:ne.day}),n.jsxs("span",{children:[ne.requests," 次请求"]})]})]})]}),n.jsxs("details",{className:"usage-table-toggle",children:[n.jsx("summary",{children:"查看数据表"}),n.jsxs("div",{className:"usage-table",children:[n.jsxs("div",{className:"usage-table-head",children:[n.jsx("span",{children:"日期"}),n.jsx("span",{children:"请求"}),n.jsx("span",{children:"消费"})]}),q.slice().reverse().map(Y=>n.jsxs("div",{className:"usage-table-row",children:[n.jsx("span",{children:Y.day}),n.jsx("span",{children:Y.requests}),n.jsx("span",{children:Nt(Y.cost)})]},Y.day))]})]})]})]}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"按模型拆分"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天消费"]})]}),z.length===0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有调用记录"}):n.jsx("div",{className:"usage-models",children:z.map(Y=>n.jsxs("div",{className:"usage-model-row",children:[n.jsx("span",{className:"usage-model-name",title:Y.model,children:Y.model}),n.jsx("span",{className:"usage-model-track",children:n.jsx("span",{className:"usage-model-bar",style:{width:`${te>0?Y.cost/te*100:0}%`}})}),n.jsx("span",{className:"usage-model-value",children:Nt(Y.cost)})]},Y.model))})]})]})]})}function vp({theme:c,setTheme:m,goHome:p,openLogin:r}){const[E,M]=g.useState(null),[X,P]=g.useState([]),[T,b]=g.useState(null),[q,z]=g.useState(!1),[ee,te]=g.useState(""),[re,se]=g.useState(""),[ne,ie]=g.useState("");async function ge(){try{const[_,le,de]=await Promise.all([pe("/api/account/me"),pe("/api/catalog/models"),pe("/api/account/check-in")]);M({..._,apiKeys:be(_.apiKeys)}),P(be(le.models).map(cs)),b(de.checkIn)}catch{r()}}g.useEffect(()=>{ge()},[]);async function Y(){if(!(!T?.enabled||T.claimed||q)){z(!0),te("");try{const _=await pe("/api/account/check-in",{method:"POST",body:JSON.stringify({})});M(le=>le&&{...le,user:_.user}),b(_.checkIn),te(`签到成功,获得 ${_.reward.toFixed(2)} 额度`)}catch(_){te(_ instanceof Error?_.message:"签到失败,请稍后重试")}finally{z(!1)}}}async function ye(){try{const _=await pe("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});se(_.secret),ie("新密钥只显示这一次"),await ge()}catch(_){ie(_ instanceof Error?_.message:"创建密钥失败")}}async function I(_){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await pe(`/api/account/api-keys/${_}`,{method:"DELETE"}),M(le=>le&&{...le,apiKeys:le.apiKeys.filter(de=>de.id!==_)}),ie("密钥已删除")}catch(le){ie(le instanceof Error?le.message:"删除密钥失败")}}async function me(){await pe("/api/auth/logout",{method:"POST"}),p()}return n.jsxs("main",{className:"account-page","data-theme":c,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:p,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:n.jsx(_t,{name:c==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:me,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:E?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:E?E.user.balance.toFixed(2):"-"})]})]}),n.jsx(pp,{}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!T?.enabled||!!T?.claimed||q,onClick:Y,children:q?"领取中":T?.claimed?"今日已签到":T?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:T?.claimed?`已领取 ${T.reward.toFixed(2)}`:T?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:T?`${T.minReward.toFixed(2)} - ${T.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:T?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),ee&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:ee})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:ye,children:"创建密钥"})]}),re&&n.jsx("code",{className:"one-time-secret",children:re}),ne&&n.jsx("p",{className:"account-message",children:ne}),n.jsxs("div",{className:"account-key-list",children:[E?.apiKeys?.map(_=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(_t,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:_.name}),n.jsxs("code",{children:[_.prefix,"…"]})]}),n.jsx(Ut,{tone:_.status,children:Dt(_.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${_.name}`,title:"删除密钥",onClick:()=>I(_.id),children:n.jsx(_t,{name:"ban"})})]},_.id)),be(E?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[X.map(_=>n.jsxs("article",{children:[n.jsx("span",{children:_.vendor}),n.jsx("strong",{children:_.name}),n.jsx("p",{children:_.description}),n.jsx("code",{children:_.id})]},_.id)),X.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function yp({theme:c,setTheme:m,enterConsole:p}){return n.jsxs("main",{className:"public-home","data-theme":c,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:[n.jsx(_t,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:p,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:p,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ + -H "Authorization: Bearer cat_..." \\ + -d '{ + "model": "capi-fast", + "messages": [{ "role": "user", "content": "ping" }] + }'`})]}),n.jsxs("div",{className:"terminal-route",children:[n.jsxs("div",{children:[n.jsx("span",{children:"auth"}),n.jsx("strong",{children:"pass"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"quota"}),n.jsx("strong",{children:"ok"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"route"}),n.jsx("strong",{children:"capi-fast"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"latency"}),n.jsx("strong",{children:"186ms"})]})]}),n.jsxs("div",{className:"terminal-block response",children:[n.jsx("span",{children:"RESPONSE"}),n.jsxs("pre",{children:[`{ + "status": 200, + "model": "capi-fast", + "usage": { "total_tokens": 27 }, + "message": "request routed" +}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function bp({overview:c,channels:m,logs:p,onNavigate:r}){const E=p.filter(M=>M.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",c?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Si,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Si,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Si,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Si,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(cl,{label:"活跃用户",value:c?ml(c.activeUsers):"-"}),n.jsx(cl,{label:"今日请求",value:c?ml(c.requestsToday):"-"}),n.jsx(cl,{label:"今日输入",value:c?ml(c.todayInputTokens):"-"}),n.jsx(cl,{label:"今日输出",value:c?ml(c.todayOutputTokens):"-"}),n.jsx(cl,{label:"今日扣费",value:c?Nt(c.todayCost,4):"-"}),n.jsx(cl,{label:"账户余额",value:c?Nt(c.totalBalance):"-"}),n.jsx(cl,{label:"成功率",value:c?`${c.successRate}%`:"-"})]}),n.jsx(gp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(lt,{title:"渠道状态",children:m.length?m.map(M=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:M.name}),n.jsx("span",{title:be(M.models).join(", "),children:ip(M.models)})]}),n.jsx(Ut,{tone:M.status,children:Dt(M.status)})]},M.id)):n.jsx(Xt,{text:"暂无渠道"})}),n.jsx(lt,{title:"最近请求",children:p.length?p.slice(0,4).map(M=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:to(M)}),n.jsxs("span",{children:[M.id," · ",M.errorCode||tl(M.createdAt)]})]}),n.jsx(Ut,{tone:M.status,children:Dt(M.status)})]},M.id)):n.jsx(Xt,{text:E.length?"暂无最近请求":"暂无请求"})})]})]})}function Si({icon:c,label:m,onClick:p}){return n.jsxs("button",{className:"quick-action",onClick:p,children:[n.jsx(_t,{name:c}),n.jsx("span",{children:m})]})}function gp(){const c=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:c.map((m,p)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:p+1}),n.jsx("strong",{children:m.label}),n.jsx("span",{children:m.detail})]},m.label))})]})}function xp({users:c,query:m,selectedUser:p,onQuery:r,onSelect:E,onUpdate:M,onBulkUpdate:X,onCreateKey:P,groups:T,onOpenRegistration:b}){const[z,ee]=g.useState(1),[te,re]=g.useState("all"),[se,ne]=g.useState(new Set),[ie,ge]=g.useState("10"),[Y,ye]=g.useState(""),[I,me]=g.useState(""),[_,le]=g.useState(!1),[de,Ae]=g.useState("10"),[Me,ce]=g.useState(""),[k,fe]=g.useState(""),[J,A]=g.useState(!1),L=te==="all"?c:c.filter(O=>O.status===te),v=L.filter(O=>O.role!=="admin"),D=Math.max(1,Math.ceil(L.length/25)),W=Math.min(z,D),f=L.slice((W-1)*25,W*25),N=v.length>0&&v.every(O=>se.has(O.id));g.useEffect(()=>{ee(1)},[m,te]),g.useEffect(()=>{const O=new Set(c.map(Se=>Se.id));ne(Se=>new Set([...Se].filter(Ne=>O.has(Ne))))},[c]),g.useEffect(()=>{Ae("10"),ce(""),fe("")},[p?.user.id]);function G(O){ne(Se=>{const Ne=new Set(Se);return Ne.has(O)?Ne.delete(O):Ne.add(O),Ne})}function Q(){ne(O=>{const Se=new Set(O);return N?v.forEach(Ne=>Se.delete(Ne.id)):v.forEach(Ne=>Se.add(Ne.id)),Se})}async function Z(O,Se){if(se.size!==0){le(!0);try{await X([...se],O,Se),ne(new Set),ye("")}finally{le(!1)}}}async function je(O){if(!p)return;const Se=Math.abs(Number(de));if(!Number.isFinite(Se)||Se<=0){fe("请输入大于 0 的金额");return}A(!0),fe("");try{await X([p.user.id],"adjust_balance",{amount:Number((Se*O).toFixed(4)),reason:Me.trim()||(O>0?"管理员增加额度":"管理员扣减额度")}),fe(O>0?"额度已增加":"额度已扣减"),ce("")}catch(Ne){fe(Ne instanceof Error?Ne.message:"额度调整失败")}finally{A(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(lt,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(_t,{name:"search"}),n.jsx("input",{value:m,onChange:O=>r(O.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:b,children:n.jsx(_t,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:c.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(O=>O.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(O=>O.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.reduce((O,Se)=>O+Se.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(O=>n.jsx("button",{type:"button",className:te===O.value?"selected":"",onClick:()=>re(O.value),children:O.label},O.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:Q,children:N?"取消全选":`全选结果(${v.length})`}),se.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",se.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ie,onChange:O=>ge(O.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:Y,onChange:O=>ye(O.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_||!Number(ie),onClick:()=>Z("adjust_balance",{amount:Number(ie),reason:Y}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_,onClick:()=>Z("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:_,onClick:()=>Z("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:I,disabled:_,"aria-label":"批量设置分组",onChange:O=>me(O.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),T.map(O=>n.jsx("option",{value:O.id,children:O.name},O.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_,onClick:()=>Z("set_group",{value:I}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:N,onChange:Q,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),f.map(O=>n.jsxs("div",{className:p?.user.id===O.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>E(O.id),onKeyDown:Se=>{(Se.key==="Enter"||Se.key===" ")&&E(O.id)},children:[n.jsx("input",{type:"checkbox",checked:se.has(O.id),disabled:O.role==="admin",onChange:()=>G(O.id),onClick:Se=>Se.stopPropagation(),"aria-label":O.role==="admin"?`${O.name} 是管理员,不参与批量操作`:`选择 ${O.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:O.name}),n.jsxs("small",{children:[O.id," · ",O.email||"未绑定邮箱"]})]}),n.jsx(Ut,{tone:O.status,children:Dt(O.status)}),n.jsx("span",{children:Nt(O.balance)}),n.jsx("span",{children:O.requestsToday})]},O.id)),L.length===0&&n.jsx(Xt,{text:"暂无匹配用户"})]}),L.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:W<=1,onClick:()=>ee(O=>Math.max(1,O-1)),children:"上一页"}),n.jsxs("span",{children:[W," / ",D]}),n.jsx("button",{className:"secondary-button",disabled:W>=D,onClick:()=>ee(O=>Math.min(D,O+1)),children:"下一页"})]})]}),n.jsx(lt,{title:"用户详情",children:p?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:p.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:p.user.name}),n.jsx("p",{children:p.user.email})]}),n.jsx(Ut,{tone:p.user.status,children:Dt(p.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(el,{label:"角色",value:p.user.role==="admin"?"管理员":"用户"}),n.jsx(el,{label:"余额",value:Nt(p.user.balance)}),n.jsx(el,{label:"总请求",value:String(p.user.totalRequests)}),n.jsx(el,{label:"最后登录",value:tl(p.user.lastLoginAt)}),n.jsx(el,{label:"API 调用",value:p.user.status==="disabled"?"关闭":"允许",switchOn:p.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:p.user.groupId||"",onChange:O=>M(p.user.id,{groupId:O.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),T.map(O=>n.jsx("option",{value:O.id,children:O.name},O.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",Nt(p.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:de,onChange:O=>Ae(O.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Me,onChange:O=>ce(O.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:J,onClick:()=>je(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:J,onClick:()=>je(-1),children:"扣减"}),n.jsx("span",{role:"status",children:k})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>P(p.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:p.user.role==="admin",onClick:()=>M(p.user.id,{status:p.user.status==="disabled"?"active":"disabled"}),children:p.user.role==="admin"?"管理员保护":p.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),p.apiKeys.map(O=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:O.name}),n.jsxs("span",{children:[O.prefix,"*** · ",O.requestCount," 次"]})]}),n.jsx(Ut,{tone:O.status,children:Dt(O.status)})]},O.id)),p.apiKeys.length===0&&n.jsx(Xt,{text:"暂无 API Key"})]})]}):n.jsx(Xt,{text:"请选择一个用户"})})]})}function jp({selectedUser:c,onCreateKey:m,onUpdateKey:p,onDeleteKey:r}){return n.jsx(lt,{title:"密钥管理",children:c?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[c.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>m(c.user.id),children:"创建 Key"})]}),c.apiKeys.length?c.apiKeys.map(E=>n.jsx(Sp,{apiKey:E,onSave:p,onDelete:r},E.id)):n.jsx(Xt,{text:"暂无密钥"})]}):n.jsx(Xt,{text:"请选择一个用户"})})}function Sp({apiKey:c,onSave:m,onDelete:p}){const[r,E]=g.useState(c.name),[M,X]=g.useState(be(c.allowedModels).join(", ")),[P,T]=g.useState(fm(c.expiresAt||"")),[b,q]=g.useState(String(c.rateLimitPerMinute||"")),[z,ee]=g.useState(!1),te=be(c.allowedModels).length?be(c.allowedModels).join(", "):"全部模型";g.useEffect(()=>{E(c.name),X(be(c.allowedModels).join(", ")),T(fm(c.expiresAt||"")),q(String(c.rateLimitPerMinute||""))},[c]);async function re(){ee(!0);try{await m(c.id,{name:r.trim()||"API Key",allowedModels:Ic(M),expiresAt:lp(P),rateLimitPerMinute:Number(b||0)})}finally{ee(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.prefix,"*** · ",te," · 最后使用 ",tl(c.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(Ut,{tone:c.status,children:Dt(c.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:se=>E(se.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:M,onChange:se=>X(se.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:P,onChange:se=>T(se.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:b,onChange:se=>q(se.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>m(c.id,{status:c.status==="active"?"disabled":"active"}),children:c.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>p(c.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:z,onClick:re,children:z?"保存中":"保存设置"})]})]})]})}function Np({models:c,onCopy:m,onCreate:p,onUpdate:r,onDelete:E}){const M=c.filter(v=>v.recommended),[X,P]=g.useState(""),[T,b]=g.useState("all"),[q,z]=g.useState("all"),[ee,te]=g.useState(1),[re,se]=g.useState(""),[ne,ie]=g.useState(""),[ge,Y]=g.useState(""),[ye,I]=g.useState(""),[me,_]=g.useState(""),[le,de]=g.useState(""),Ae=60,Me=g.useMemo(()=>{const v=new Map;return c.forEach(D=>{const W=$c(D);v.set(W,(v.get(W)||0)+1)}),Array.from(v.entries()).sort((D,W)=>W[1]-D[1]||ul(D[0]).localeCompare(ul(W[0]))).map(([D,W])=>({provider:D,count:W}))},[c]),ce=g.useMemo(()=>{const v=X.trim().toLowerCase();return c.filter(D=>T!=="all"&&$c(D)!==T||q!=="all"&&D.status!==q?!1:v?[D.id,D.name,D.vendor,D.category,D.description,...be(D.aliases)].join(" ").toLowerCase().includes(v):!0)},[c,X,T,q]),k=g.useMemo(()=>{const v=new Map;ce.forEach(G=>{const Q=$c(G);v.set(Q,[...v.get(Q)||[],G])});const D=[];let W=[],f=0;const N=Array.from(v.entries()).sort((G,Q)=>ul(G[0]).localeCompare(ul(Q[0])));for(const G of N)W.length>0&&f+G[1].length>Ae&&(D.push(W),W=[],f=0),W.push(G),f+=G[1].length;return W.length>0&&D.push(W),D},[ce]),fe=Math.max(1,k.length),J=Math.min(ee,fe),A=k[J-1]||[];g.useEffect(()=>{te(1)},[X,T,q,c.length]);async function L(v){v.preventDefault();const D=re.trim();if(D){de("");try{await p({id:D,name:ne.trim()||D,vendor:ge.trim()||"Custom",aliases:ye.split(",").map(W=>W.trim()).filter(Boolean),category:"通用",description:me.trim(),price:"自定义",context:"未配置上下文"}),se(""),ie(""),Y(""),I(""),_("")}catch(W){de(W instanceof Error?W.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(lt,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:L,children:[n.jsx("input",{value:re,onChange:v=>se(v.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:ne,onChange:v=>ie(v.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:ge,onChange:v=>Y(v.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:ye,onChange:v=>I(v.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:me,onChange:v=>_(v.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:le})]})}),M.length>0&&n.jsx(lt,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:M.map(v=>n.jsx(Cp,{model:v,featured:!0,onCopy:m,onUpdate:r},v.id))})}),n.jsxs(lt,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:X,onChange:v=>P(v.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(v=>n.jsx("button",{type:"button",className:q===v.value?"selected":"",onClick:()=>z(v.value),children:v.label},v.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:T==="all"?"selected":"",onClick:()=>b("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:c.length})]}),Me.map(v=>n.jsxs("button",{type:"button",className:T===v.provider?"selected":"",onClick:()=>b(v.provider),children:[n.jsx(mm,{provider:v.provider}),n.jsx("strong",{children:ul(v.provider)}),n.jsx("small",{children:v.count})]},v.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:T==="all"?"全部供应商":ul(T)}),n.jsx("strong",{children:ce.length}),n.jsx("span",{children:"个模型"})]}),ce.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:A.map(([v,D])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(mm,{provider:v}),n.jsxs("div",{children:[n.jsx("strong",{children:ul(v)}),n.jsxs("span",{children:[D.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:D.map(W=>n.jsx(Ap,{model:W,onCopy:m,onUpdate:r,onDelete:E},W.id))})]},v))}),fe>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>te(v=>Math.max(1,v-1)),disabled:J<=1,children:"上一页"}),n.jsxs("span",{children:[J," / ",fe]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>te(v=>Math.min(fe,v+1)),disabled:J>=fe,children:"下一页"})]})]}):n.jsx(Xt,{text:c.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function Ap({model:c,onCopy:m,onUpdate:p,onDelete:r}){const E=be(c.aliases).slice(0,3),M=c.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:c.name}),n.jsx("small",{children:c.id}),E.length>0&&n.jsx("span",{children:E.map(X=>n.jsx("em",{children:X},X))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(Ut,{tone:c.status,children:Dt(c.status)}),c.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>m(c.id,"模型 ID 已复制"),children:n.jsx(_t,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>p(c.id,{recommended:!c.recommended}),children:c.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>p(c.id,{status:M?"available":"disabled"}),children:M?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(c.id),children:"删除模型"})]})]})]})]})}function Cp({model:c,featured:m=!1,onCopy:p,onUpdate:r}){return n.jsxs("article",{className:m?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.vendor," · ",c.category]})]}),n.jsx(Ut,{tone:c.status,children:Dt(c.status)})]}),n.jsx("p",{children:c.description}),n.jsx("div",{className:"alias-row",children:be(c.aliases).map(E=>n.jsx("span",{children:E},E))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",c.price]}),n.jsx("span",{children:c.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:c.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>p(c.id,"模型 ID 已复制"),children:n.jsx(_t,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{status:c.status==="disabled"?"available":"disabled"}),children:c.status==="disabled"?"启用":"停用"})]})]})}function Tp({channels:c,onCreate:m,onImport:p,onCheckAccounts:r,onDeduplicateAccounts:E,onDeleteAccount:M,onUpdate:X,onStartOAuth:P,onCompleteOAuth:T}){const b=c.filter(v=>v.provider==="codex"||v.provider==="openai"||be(v.models).some(D=>D.includes("image"))),[q,z]=g.useState(""),[ee,te]=g.useState({}),[re,se]=g.useState({}),[ne,ie]=g.useState({}),[ge,Y]=g.useState({}),[ye,I]=g.useState(""),[me,_]=g.useState(""),[le,de]=g.useState(""),Ae=24,Me=48;async function ce(v,D){z(`import:${v}`);try{await p(v,D)}finally{z("")}}async function k(v,D=!1,W=""){z(W?`check-account:${W}`:`${D?"retry":"check"}:${v}`);try{await r(v,D,W)}finally{z("")}}async function fe(v){z(`dedupe:${v}`);try{await E(v)}finally{z("")}}function J(v){const D=be(v.openaiAccounts).map(Z=>[Z.email||Z.name||Z.accountId||Z.id,Z.accountId||"",Z.status||"unchecked",Z.credentialMode||"access-token",Z.planType||"",Z.expiresAt||"",Z.lastCheckedAt||"",Z.lastUsedAt||"",String(Z.requestCount||0),Z.lastErrorCode||"",Z.lastError||""]),W=Z=>`"${Z.replace(/"/g,'""')}"`,f=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...D].map(Z=>Z.map(W).join(",")).join(`\r +`),N=new Blob(["\uFEFF"+f],{type:"text/csv;charset=utf-8"}),G=URL.createObjectURL(N),Q=document.createElement("a");Q.href=G,Q.download=`${v.name||"account-pool"}-health-report.csv`,Q.click(),URL.revokeObjectURL(G)}async function A(v){z(`status:${v.id}`);try{await X(v.id,{status:v.status==="disabled"?"healthy":"disabled",baseUrl:v.baseUrl||Ei(v.provider)||Ti,provider:v.provider||"codex",models:be(v.models).length?v.models:gm.split(",").map(D=>D.trim())})}finally{z("")}}async function L(v,D){const W=D.email||D.name||D.accountId||D.id;if(window.confirm(`删除账号「${W}」?`)){z(`delete-account:${D.id}`);try{await M(v.id,D.id)}finally{z("")}}}return n.jsxs(lt,{title:"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"账号有两种来源,任选其一即可。"}),n.jsx("button",{className:"primary-button",onClick:()=>m(xm("codex")),children:"新增账号池渠道"})]}),n.jsxs("div",{className:"source-guide",children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]}),n.jsxs("div",{className:"channels-stack",children:[b.map(v=>{const D=be(v.openaiAccounts),W=D.filter(V=>V.status==="healthy").length,f=D.filter(V=>V.status==="invalid").length,N=D.filter(V=>!!V.lastErrorCode).length,G=Math.max(0,D.length-W-f),Q=D.filter(V=>V.credentialMode==="refreshable").length,Z=D.filter(V=>V.credentialMode==="browser-session").length,je=Math.max(0,D.length-Q-Z),O=re[v.id]||"all",Se=(ne[v.id]||"").trim().toLowerCase(),Ne=D.filter(V=>{const mt=O==="all"||O==="attention"&&wp(V)||O==="invalid"&&V.status==="invalid"||O==="error"&&!!V.lastErrorCode||O==="refreshable"&&V.credentialMode==="refreshable",Rt=`${V.email||""} ${V.name||""} ${V.accountId||""} ${V.userId||""} ${V.lastError||""}`.toLowerCase();return mt&&(!Se||Rt.includes(Se))}),ot=ge[v.id]||"pool",$=[...Ne].sort((V,mt)=>{if(ot==="pool")return 0;const Rt=ot==="expiry"?V.expiresAt||"9999-12-31":V.lastUsedAt||"",R=ot==="expiry"?mt.expiresAt||"9999-12-31":mt.lastUsedAt||"";return ot==="recent"?R.localeCompare(Rt):Rt.localeCompare(R)}),Je=Math.min($.length,ee[v.id]||Ae),ut=$.slice(0,Je),Ie=Math.max(0,$.length-ut.length),ll=Ie===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:v.name}),n.jsx("span",{children:v.baseUrl||Ei(v.provider)||Ti}),n.jsxs("small",{children:["账号 ",D.length," 个,可用 ",W,",无效 ",f,",未验证 ",G]}),n.jsxs("small",{children:["可续期 ",Q," · 网页会话 ",Z," · 仅 Token ",je]}),n.jsxs("small",{children:["自动检测 ",v.lastCheckedAt?tl(v.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(Ut,{tone:v.status,children:Dt(v.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>de(v.id),disabled:q!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(v.id),disabled:q!==""||D.length===0,children:q===`check:${v.id}`?"检测中":"批量检测"}),f>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(v.id,!0),disabled:q!=="",children:q===`retry:${v.id}`?"复检中":`复检无效 ${f}`}),D.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>fe(v.id),disabled:q!=="",children:q===`dedupe:${v.id}`?"去重中":"账号去重"}),D.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>J(v),disabled:q!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>A(v),disabled:q!=="",children:v.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:ne[v.id]||"",onChange:V=>ie(mt=>({...mt,[v.id]:V.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:ot,onChange:V=>Y(mt=>({...mt,[v.id]:V.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${D.length}`],["attention","需关注"],["invalid",`无效 ${f}`],["error",`有错误 ${N}`],["refreshable",`可续期 ${Q}`]].map(([V,mt])=>n.jsx("button",{type:"button",className:O===V?"selected":"",onClick:()=>se(Rt=>({...Rt,[v.id]:V})),children:mt},V))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(cl,{label:"账号总数",value:D.length}),n.jsx(cl,{label:"可用账号",value:W}),n.jsx(cl,{label:"无效账号",value:f}),n.jsx(cl,{label:"未验证账号",value:G})]}),n.jsx("div",{className:"drawing-channel-models",children:be(v.models).length?be(v.models).map(V=>n.jsx("span",{children:V},V)):n.jsx("span",{children:"未绑定绘图模型"})}),D.length>0&&n.jsxs("div",{className:"account-pool-list",children:[ut.map(V=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:V.email||V.name||V.accountId||V.id,children:V.email||V.name||V.accountId||V.id}),n.jsx("span",{className:`source-tag source-tag-${V.source==="web-login"?"web":"manual"}`,children:V.source==="web-login"?"网页登录":V.source==="web-oauth"?"网页 OAuth":V.source==="oauth"?"Codex OAuth":"导入"})]}),n.jsx("span",{children:V.lastError?`${dm(V.lastErrorCode)}${dm(V.lastErrorCode)?" · ":""}${V.lastError}`:V.lastCheckedAt?`上次检测 ${tl(V.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[V.credentialMode==="refreshable"?"可自动续期":V.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",V.expiresAt?` · 到期 ${tl(V.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",ep(V.planType)]}),V.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",tl(V.lastUsedAt)," · ",V.requestCount||0," 次"]})]}),n.jsx(_p,{limits:V.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(Ut,{tone:V.status==="healthy"?"healthy":V.status==="invalid"?"disabled":"standby",children:V.status==="healthy"?"可用":V.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:q!=="",onClick:()=>k(v.id,!1,V.id),children:q===`check-account:${V.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:q!=="",onClick:()=>L(v,V),children:q===`delete-account:${V.id}`?"删除中":"删除"})]})]},V.id)),Ne.length===0&&n.jsx(Xt,{text:"没有匹配的账号"}),$.length>Ae&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:ll?`已显示全部 ${$.length} 个账号`:`已显示 ${ut.length} 个,还有 ${Ie} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!ll&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(V=>({...V,[v.id]:Math.min($.length,Je+Me)})),children:["再显示 ",Math.min(Me,Ie)," 个"]}),!ll&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(V=>({...V,[v.id]:$.length})),children:"全部显示"}),Je>Ae&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(V=>({...V,[v.id]:Ae})),children:"收起"})]})]})]})]},v.id)}),b.length===0&&n.jsx(Xt,{text:"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),ye&&n.jsx(Op,{channelId:ye,onStart:P,onComplete:T,onClose:()=>I("")}),le&&n.jsx(Ep,{busy:q!=="",onAuthSession:()=>{_(le),de("")},onImport:async v=>{await ce(le,v),de("")},onClose:()=>de("")}),me&&n.jsx(zp,{onImport:async v=>{await ce(me,new File([JSON.stringify(Mp(v))],"authsession.json",{type:"application/json"}))},onClose:()=>_("")})]})}function Ep({busy:c,onAuthSession:m,onImport:p,onClose:r}){return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:E=>E.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:m,disabled:c,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("label",{className:`account-add-option${c?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:c?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:c,onChange:E=>{const M=E.target.files?.[0];M&&p(M),E.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:r,children:"取消"})})]})})}function Mp(c){const m=c.trim(),p=m.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(p)return{sessionToken:p[2],source:"web-login"};try{const r=JSON.parse(m),E=r.tokens&&typeof r.tokens=="object"?r.tokens:{},M=q=>typeof r[q]=="string"?r[q]:typeof E[q]=="string"?E[q]:"",X=M("accessToken")||M("access_token"),P=M("refreshToken")||M("refresh_token"),T=M("sessionToken")||M("session_token"),b=r.user&&typeof r.user=="object"?r.user:{};if(X||P||T)return{accessToken:X||void 0,refreshToken:P||void 0,sessionToken:T||void 0,email:typeof b.email=="string"?b.email:void 0,name:typeof b.name=="string"?b.name:void 0,source:"web-login"}}catch{}return{sessionToken:m,source:"web-login"}}function zp({onImport:c,onClose:m}){const[p,r]=g.useState(""),[E,M]=g.useState(!1),[X,P]=g.useState(""),[T,b]=g.useState("");async function q(){if(!p.trim()){P("请粘贴 authsession");return}M(!0),P(""),b("");try{await c(p.trim()),r(""),b("已导入,继续粘贴下一条即可")}catch(z){P(z instanceof Error?z.message:"导入失败")}finally{M(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:p,onChange:z=>r(z.target.value),placeholder:"eyJhbGci..."})]}),X&&n.jsx("div",{className:"form-error",children:X}),T&&n.jsx("div",{className:"form-success",children:T}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:E,onClick:q,children:E?"导入中":"导入账号"})]})]})})}function Op({channelId:c,onStart:m,onComplete:p,onClose:r}){const[E,M]=g.useState(""),[X,P]=g.useState(""),[T,b]=g.useState(""),[q,z]=g.useState(!1),[ee,te]=g.useState("");async function re(){z(!0),te("");try{const ne=await m(c);M(ne.authorizeUrl),P(ne.state),window.open(ne.authorizeUrl,"_blank","noopener")}catch(ne){te(ne instanceof Error?ne.message:"发起授权失败")}finally{z(!1)}}async function se(){if(!T.trim()){te("请粘贴授权完成后浏览器跳转的回调地址");return}z(!0),te("");try{await p(c,{callbackUrl:T.trim(),state:X}),r()}catch(ne){te(ne instanceof Error?ne.message:"完成授权失败")}finally{z(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card",onClick:ne=>ne.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:re,disabled:q,children:E?"重新生成授权链接":"① 生成授权链接并打开"}),E&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:E,onFocus:ne=>ne.target.select()}),n.jsx("span",{className:"muted-inline",children:"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:T,placeholder:"https://platform.openai.com/auth/callback?code=...&state=...",onChange:ne=>b(ne.target.value),disabled:!E||q})]})]}),ee&&n.jsx("p",{className:"form-error",children:ee}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:r,disabled:q,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:se,disabled:!E||q,children:q?"处理中":"完成授权"})]})]})})}function _p({limits:c}){const m=be(c).filter(p=>p.label||p.name).slice(0,3);return m.length?n.jsx("div",{className:"quota-bars",children:m.map(p=>{const r=Dp(p);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:p.label||p.name}),n.jsx("span",{children:Up(p,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${p.label||p.name}-${p.resetAt||""}`)})}):null}function Dp(c){return typeof c.percentRemaining=="number"&&Number.isFinite(c.percentRemaining)?Math.max(0,Math.min(100,c.percentRemaining)):typeof c.remaining=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,c.remaining/c.limit*100)):typeof c.used=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,(c.limit-c.used)/c.limit*100)):0}function Up(c,m){const p=c.resetAt?` · ${tl(c.resetAt)}`:"";return typeof c.remaining=="number"?`${Math.round(m)}% 剩余${p}`:`${Math.round(m)}%${p}`}function Rp(c){const m=be(c.models).join(" ").toLowerCase(),p=["对话"];c.streamMode!=="disabled"&&p.push("流式"),/(image|dall-e|gpt-image)/.test(m)&&p.push("图片"),(c.openaiAccountCount??c.openaiAccounts?.length??0)>0&&p.push("账号池");const r=c.upstreamKeyCount??0;return r>1&&p.push(`${r} Key 轮询`),p}function wp(c){if(c.status==="invalid"||c.credentialMode==="browser-session")return!0;if(!c.expiresAt)return!1;const m=new Date(c.expiresAt).getTime();return Number.isFinite(m)&&m-Date.now()<=1440*60*1e3}function Hp({channels:c,groups:m,onUpdate:p,onCreate:r,onImport:E,onDelete:M,onSyncModels:X,onCheck:P}){const T=Ta("openai"),[b,q]=g.useState(!1),[z,ee]=g.useState(T.provider),[te,re]=g.useState(T.name),[se,ne]=g.useState(T.baseUrl),[ie,ge]=g.useState(T.models.join(", ")),[Y,ye]=g.useState(""),[I,me]=g.useState(""),[_,le]=g.useState(!1),[de,Ae]=g.useState(!1);function Me(k){const fe=Ta(k);ee(fe.provider),re(fe.name),ne(fe.baseUrl),ge(fe.models.join(", ")),me("")}async function ce(k){k.preventDefault(),le(!0),me("");try{await r({name:te.trim()||Ta(z).name,provider:z,baseUrl:se.trim(),...jm(Y),models:Ic(ie),streamMode:"auto"}),q(!1),ye(""),Me(z)}catch(fe){me(fe instanceof Error?fe.message:"渠道创建失败")}finally{le(!1)}}return n.jsxs(lt,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:c.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:c.filter(k=>k.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>q(k=>!k),children:b?"取消新增":"+ 新增渠道"})]}),b&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ce,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Ta(z).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(k=>n.jsxs("button",{type:"button",className:z===k.provider?"selected":"",onClick:fe=>{Me(k.provider),fe.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:k.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},k.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:te,onChange:k=>re(k.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:ul(z),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:se,onChange:k=>ne(k.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:Y,onChange:k=>ye(k.target.value),placeholder:z==="codex"?"账号池导入后使用":z==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(z!=="codex"&&!se.trim()){me("请先填写 Base URL 再获取模型");return}me(""),Ae(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ie,onChange:k=>ge(k.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:I}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Me(z),disabled:_,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:_,children:_?"创建中":"创建渠道"})]})]}),b&&de&&n.jsx(Sm,{subtitle:`${te.trim()||Ta(z).name} · 勾选需要接入的模型`,current:Ic(ie),loadModels:async()=>{const k=await pe("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:z,baseUrl:se.trim(),upstreamApiKey:Y})});return be(k.models)},onConfirm:async k=>{ge(k.join(", "))},onClose:()=>Ae(!1)}),n.jsxs("div",{className:"channels-stack",children:[c.map(k=>n.jsx(Bp,{channel:k,groups:m,onUpdate:p,onImport:E,onDelete:M,onSyncModels:X,onCheck:P},k.id)),c.length===0&&n.jsx(Xt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Bp({channel:c,groups:m,onUpdate:p,onImport:r,onDelete:E,onSyncModels:M,onCheck:X}){const[P,T]=g.useState(c.name),[b,q]=g.useState(c.provider),[z,ee]=g.useState(c.streamMode||"auto"),[te,re]=g.useState(c.baseUrl),[se,ne]=g.useState(be(c.allowedGroupIds)),[ie,ge]=g.useState(be(c.models).join(", ")),[Y,ye]=g.useState("saved"),[I,me]=g.useState(String(c.inputPricePer1K||0)),[_,le]=g.useState(String(c.outputPricePer1K||0)),[de,Ae]=g.useState(!!c.webEndpoint),[Me,ce]=g.useState(""),[k,fe]=g.useState(""),[J,A]=g.useState(!1),L=c.openaiAccountCount??c.openaiAccounts?.length??0,v=be(c.models).length,D=Rp(c),W=c.status==="disabled",f={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[Y],N=Ni.find($=>$.value===z)||Ni[0],G={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};g.useEffect(()=>{T(c.name),q(c.provider),ee(c.streamMode||"auto"),re(c.baseUrl),ne(be(c.allowedGroupIds)),ge(be(c.models).join(", ")),ye("saved"),me(String(c.inputPricePer1K||0)),le(String(c.outputPricePer1K||0)),Ae(!!c.webEndpoint),ce("")},[c.id,c.name,c.provider,c.streamMode,c.baseUrl,c.models,c.inputPricePer1K,c.outputPricePer1K,c.webEndpoint]);async function Q(){const $=Z();fe("save");try{await p(c.id,$),ce("")}finally{fe("")}}function Z(){const $=Ei(b),Je=!/^https?:\/\//i.test(te.trim())&&$?$:te,ut={name:P.trim()||c.name,provider:b,streamMode:z,baseUrl:Je,inputPricePer1K:Number(I)||0,outputPricePer1K:Number(_)||0,webEndpoint:de,models:ie.split(",").map(Ie=>Ie.trim()).filter(Boolean),allowedGroupIds:se};return Object.assign(ut,jm(Me)),ut}async function je(){const $=c.status==="disabled"?"healthy":"disabled";fe("status");try{await p(c.id,{...Z(),status:$}),ce("")}finally{fe("")}}async function O(){fe("sync");try{await p(c.id,Z()),ce(""),A(!0)}finally{fe("")}}function Se(){const $=Ta(b);ge($.models.join(", ")),ye("template"),$.baseUrl&&!/^https?:\/\//i.test(te.trim())&&re($.baseUrl)}async function Ne(){fe("check");try{await Q(),await X(c.id)}finally{fe("")}}async function ot($){fe("import");try{await r(c.id,$)}finally{fe("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:c.name}),n.jsx("span",{children:ul(b)}),n.jsx("small",{children:c.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:D.map($=>n.jsx("span",{children:$},$))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:v})," 个模型"]}),L>0&&n.jsxs("span",{children:[n.jsx("b",{children:L})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:c.lastError?"is-error":c.lastCheckedAt?"is-ok":"",children:c.lastError?"检测失败":c.lastCheckedAt?`已检测 ${tl(c.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(Ut,{tone:c.status,children:W?"已停用":Dt(c.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:ul(b)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:eo.map($=>n.jsxs("button",{type:"button",className:b===$.value?"selected":"",onClick:Je=>{q($.value);const ut=Ei($.value);ut&&!/^https?:\/\//i.test(te.trim())&&re(ut),Je.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:$.label}),n.jsx("span",{children:$.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},$.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:G[N.value]}),n.jsx("small",{children:N.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ni.map($=>n.jsxs("button",{type:"button",className:z===$.value?"selected":"",onClick:Je=>{ee($.value),Je.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:G[$.value]}),n.jsx("span",{children:$.description})]},$.value))})]})]})]}),(b==="codex"||L>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:de?"ios-switch is-on":"ios-switch","aria-label":de?"关闭网页对话接口":"开启网页对话接口","aria-pressed":de,onClick:()=>Ae($=>!$),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:P,onChange:$=>T($.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:ul(b),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:te,onChange:$=>re($.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:c.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",f]})]}),n.jsx("textarea",{value:ie,onChange:$=>{ge($.target.value),ye("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:Se,disabled:k!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:O,disabled:k!=="",children:k==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(c.upstreamKeyCount??0)>0?` (已配置 ${c.upstreamKeyCount} 个)`:c.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Me,onChange:$=>ce($.target.value),placeholder:b==="codex"?"Codex 账号池不需要上游 Key":b==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:I,onChange:$=>me($.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:_,onChange:$=>le($.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:se.length?`已选择 ${se.length} 个分组`:"全部用户可用"})]}),m.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:m.map($=>{const Je=se.includes($.id);return n.jsxs("button",{type:"button",className:Je?"selected":"","aria-pressed":Je,onClick:()=>ne(ut=>Je?ut.filter(Ie=>Ie!==$.id):[...ut,$.id]),children:[n.jsx("span",{children:$.name}),$.description&&n.jsx("small",{children:$.description})]},$.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:Ne,disabled:k!=="",children:k==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:Q,disabled:k!=="",children:k==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[k==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:k!=="",onChange:$=>{const Je=$.target.files?.[0];Je&&ot(Je),$.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:je,disabled:k!=="",children:c.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>E(c.id),disabled:k!=="",children:"删除渠道"})]})]})]})]}),J&&n.jsx(Sm,{subtitle:`${c.name} · 勾选需要接入的模型`,current:ie.split(",").map($=>$.trim()).filter(Boolean),loadModels:async()=>{const $=await pe(`/api/channels/${c.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return be($.models)},onConfirm:async $=>{await M(c.id,$)},onClose:()=>A(!1)})]})}function Sm({subtitle:c,current:m,loadModels:p,onConfirm:r,onClose:E}){const[M,X]=g.useState(!0),[P,T]=g.useState(""),[b,q]=g.useState([]),[z,ee]=g.useState(new Set),[te,re]=g.useState(""),[se,ne]=g.useState(!1);g.useEffect(()=>{let _=!1;return(async()=>{X(!0),T("");try{const le=await p();if(_)return;const de=new Set,Ae=be(le).map(ce=>ce.trim()).filter(ce=>{if(!ce)return!1;const k=ce.toLowerCase();return de.has(k)?!1:(de.add(k),!0)}),Me=new Set(m.map(ce=>ce.toLowerCase()));q(Ae),ee(new Set(Ae.filter(ce=>Me.has(ce.toLowerCase()))))}catch(le){_||T(le instanceof Error?le.message:"获取上游模型失败")}finally{_||X(!1)}})(),()=>{_=!0}},[]);const ie=te.trim().toLowerCase(),ge=ie?b.filter(_=>_.toLowerCase().includes(ie)):b,Y=ge.length>0&&ge.every(_=>z.has(_));function ye(_){ee(le=>{const de=new Set(le);return de.has(_)?de.delete(_):de.add(_),de})}function I(){ee(_=>{const le=new Set(_);return Y?ge.forEach(de=>le.delete(de)):ge.forEach(de=>le.add(de)),le})}async function me(){const _=new Set(b.map(ce=>ce.toLowerCase())),le=m.filter(ce=>!_.has(ce.toLowerCase())),de=b.filter(ce=>z.has(ce)),Ae=new Set,Me=[...le,...de].filter(ce=>{const k=ce.toLowerCase();return Ae.has(k)?!1:(Ae.add(k),!0)});ne(!0);try{await r(Me),E()}catch{ne(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:E,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:_=>_.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:c})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:E,children:"×"})]}),M?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):P?n.jsx("div",{className:"model-picker-status model-picker-error",children:P}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:te,onChange:_=>re(_.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:I,disabled:ge.length===0,children:Y?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",b.length," 个 · 已选 ",z.size," 个",ie?` · 匹配 ${ge.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[ge.map(_=>{const le=z.has(_),de=m.some(Ae=>Ae.toLowerCase()===_.toLowerCase());return n.jsxs("label",{className:`model-picker-row${le?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:le,onChange:()=>ye(_)}),n.jsx("span",{className:"model-picker-name",children:_}),de&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},_)}),ge.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:E,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:M||!!P||se,onClick:me,children:se?"保存中":`导入所选 (${z.size})`})]})]})})}function qp({logs:c,onCopy:m}){const[p,r]=g.useState(c),[E,M]=g.useState(c.length),[X,P]=g.useState(1),[T,b]=g.useState(""),[q,z]=g.useState("all"),[ee,te]=g.useState(null),[re,se]=g.useState(!1),[ne,ie]=g.useState(!1),ge=25,Y=Math.max(1,Math.ceil(E/ge));g.useEffect(()=>{P(1)},[T,q]),g.useEffect(()=>{X>Y&&P(Y)},[X,Y]),g.useEffect(()=>{const I=new AbortController,me=window.setTimeout(async()=>{se(!0);try{const _=new URLSearchParams({page:String(X),pageSize:String(ge),status:q,q:T.trim()}),le=await pe(`/api/logs?${_}`,{signal:I.signal}),de=be(le.logs);r(de),M(le.total||0),te(Ae=>Ae&&de.some(Me=>Me.id===Ae.id)?Ae:null)}catch(_){_ instanceof DOMException&&_.name==="AbortError"||(r([]),M(0))}finally{I.signal.aborted||se(!1)}},T?250:0);return()=>{window.clearTimeout(me),I.abort()}},[X,T,q]);async function ye(I){if(ee?.id===I.id){te(null);return}te(I),ie(!0);try{const me=await pe(`/api/logs/${encodeURIComponent(I.id)}`);te(me.log)}catch{te(I)}finally{ie(!1)}}return n.jsxs(lt,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(_t,{name:"search"}),n.jsx("input",{value:T,onChange:I=>b(I.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(I=>n.jsx("button",{type:"button",className:q===I.value?"selected":"",onClick:()=>z(I.value),children:I.label},I.value))}),n.jsx("span",{className:"muted-inline",children:re?"加载中":`共 ${E} 条`})]}),n.jsxs("div",{className:ee?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),p.map(I=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:ee?.id===I.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>ye(I),onKeyDown:me=>{(me.key==="Enter"||me.key===" ")&&ye(I)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:to(I)}),n.jsxs("small",{children:[I.id," · ",tl(I.createdAt)," · ",I.latencyMs,"ms"]})]}),n.jsx("span",{children:np(I)}),n.jsx("span",{children:sp(I)}),n.jsx(Ut,{tone:I.status,children:Dt(I.status)})]})},I.id)),!re&&p.length===0&&n.jsx(Xt,{text:T||q!=="all"?"没有匹配的日志":"暂无调用日志"})]}),ee&&n.jsx(Gp,{log:ee,loading:ne,onCopy:m})]}),Y>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:X<=1||re,onClick:()=>P(I=>Math.max(1,I-1)),children:"上一页"}),n.jsxs("span",{children:[X," / ",Y]}),n.jsx("button",{className:"secondary-button",disabled:X>=Y||re,onClick:()=>P(I=>Math.min(Y,I+1)),children:"下一页"})]})]})}function Gp({log:c,loading:m,onCopy:p}){if(!c)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(c.inputTokens||0),E=Number(c.outputTokens||0),M=typeof c.attempts=="number"?Math.max(0,c.attempts):null,X=[["请求 ID",c.id],["状态",Dt(c.status)],["时间",ap(c.createdAt)],["用户 ID",c.userId||"未识别"],["API Key",c.apiKeyPrefix?`${c.apiKeyPrefix}***`:"未识别"],["模型",c.model||"未提供"],["渠道",c.channel||"未选择"],["实际账号",c.account||"未记录"],["响应耗时",`${c.latencyMs} ms`],["尝试次数",M===null?"未记录":String(M)],["是否重试",M===null?"未记录":M>1?"是":"否"],["输入 Tokens",ml(r)],["输出 Tokens",ml(E)],["总 Tokens",ml(r+E)],["扣费",c.cost.toFixed(4)],["错误码",c.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:m?"加载中":"日志详情"}),n.jsx("strong",{children:to(c)})]}),n.jsx(Ut,{tone:c.status,children:Dt(c.status)})]}),n.jsx("div",{className:"log-detail",children:X.map(([P,T])=>n.jsxs("div",{children:[n.jsx("span",{children:P}),n.jsx("strong",{title:T,children:T})]},P))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(c.id,"请求 ID 已复制"),children:"复制请求 ID"}),c.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(c.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function Yp({models:c,channels:m,groups:p}){const[r,E]=g.useState(null),[M,X]=g.useState(null),[P,T]=g.useState("username"),[b,q]=g.useState("0"),[z,ee]=g.useState(""),[te,re]=g.useState({enabled:!0,minReward:.1,maxReward:1}),[se,ne]=g.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ie,ge]=g.useState(null),[Y,ye]=g.useState(null),[I,me]=g.useState(""),[_,le]=g.useState(""),[de,Ae]=g.useState(""),[Me,ce]=g.useState(""),[k,fe]=g.useState(""),[J,A]=g.useState(""),[L,v]=g.useState(""),[D,W]=g.useState(""),[f,N]=g.useState(""),[G,Q]=g.useState(!1),[Z,je]=g.useState("system"),O=c.find(R=>R.recommended&&R.status==="available")?.id||c.find(R=>R.status==="available")?.id||"未配置",Se=m.filter(R=>R.status!=="disabled").length,Ne=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],ot=Ne.find(R=>R.value===Z)||Ne[0];g.useEffect(()=>{Promise.all([pe("/api/settings/discord"),pe("/api/settings/auth"),pe("/api/settings/check-in"),pe("/api/account/me"),pe("/api/settings/maintenance"),pe("/api/health")]).then(([R,Ue,rt,jt,ht,Pe])=>{E(Wc(R.discord)),W(be(R.discord.blockedGuildIds).join(` +`)),X(Ue.auth.registrationEnabled),T(Mi(Ue.auth.registrationMode)),q(String(Ue.auth.defaultBalance||0)),ee(Ue.auth.defaultGroupId||""),re(rt.checkIn),ye(jt.account),me(jt.account?.username||""),le(jt.user.name||""),Ae(jt.account?.email||""),ce(jt.account?.discordUserId||""),ne(ht.maintenance),ge(Pe)}).catch(()=>N("设置加载失败"))},[]);async function $(R=M,Ue=P,rt=Number(b),jt=z){if(R!==null)try{const ht=await pe("/api/settings/auth",{method:"PATCH",body:JSON.stringify({registrationEnabled:R,registrationMode:Ue,defaultBalance:rt,defaultGroupId:jt})});X(ht.auth.registrationEnabled),T(Mi(ht.auth.registrationMode)),q(String(ht.auth.defaultBalance||0)),ee(ht.auth.defaultGroupId||""),N(ht.auth.registrationEnabled?"注册设置已保存":"已关闭用户注册")}catch(ht){N(ht instanceof Error?ht.message:"注册设置保存失败")}}async function Je(){M!==null&&$(!M,P)}async function ut(){Q(!0),N("");try{const R=await pe("/api/settings/check-in",{method:"PATCH",body:JSON.stringify(te)});re(R.checkIn),N(R.checkIn.enabled?"签到奖励设置已保存":"已关闭每日签到")}catch(R){N(R instanceof Error?R.message:"签到设置保存失败")}finally{Q(!1)}}async function Ie(){if(r){Q(!0),N("");try{const R=Wc(r),Ue=D.split(/[\s,]+/).map(jt=>jt.trim()).filter(Boolean),rt=await pe("/api/settings/discord",{method:"PATCH",body:JSON.stringify({...R,blockedGuildIds:Ue,clientSecret:L})});E(Wc(rt.discord)),W(be(rt.discord.blockedGuildIds).join(` +`)),v(""),N("Discord 配置已保存")}catch(R){N(R instanceof Error?R.message:"保存失败,请检查填写内容")}finally{Q(!1)}}}async function ll(){try{const R=await pe("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:I,displayName:_,email:de,discordUserId:Me,currentPassword:k,newPassword:J})});ye(R.account),me(R.account.username),Ae(R.account.email||""),ce(R.account.discordUserId||""),fe(""),A(""),N("管理员账号已保存")}catch(R){N(R instanceof Error?R.message:"账号设置保存失败")}}async function V(){Q(!0),N("");try{const R=await pe("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(se)});ne(R.maintenance),N("维护设置已保存,历史数据已按新规则清理")}catch(R){N(R instanceof Error?R.message:"维护设置保存失败")}finally{Q(!1)}}async function mt(){Q(!0),N("");try{const R=await fetch("/api/backup",{credentials:"include"});if(!R.ok)throw new Error("备份导出失败");const Ue=await R.blob(),jt=(R.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",ht=URL.createObjectURL(Ue),Pe=document.createElement("a");Pe.href=ht,Pe.download=jt,Pe.click(),URL.revokeObjectURL(ht),N("备份已导出,请妥善保管")}catch(R){N(R instanceof Error?R.message:"备份导出失败")}finally{Q(!1)}}async function Rt(R){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){Q(!0),N("");try{const Ue=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:R}),rt=await Ue.json().catch(()=>null);if(!Ue.ok)throw new Error(rt?.error?.message||"备份恢复失败");N(`已恢复 ${rt.users} 个用户、${rt.channels} 条渠道和 ${rt.models} 个模型,请重新登录`)}catch(Ue){N(Ue instanceof Error?Ue.message:"备份恢复失败")}finally{Q(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:Ne.map(R=>n.jsxs("button",{type:"button",className:Z===R.value?"selected":"",onClick:()=>je(R.value),children:[n.jsx("strong",{children:R.label}),n.jsx("small",{children:R.description})]},R.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:ot.label}),n.jsx("span",{children:ot.description})]}),Z==="system"&&n.jsx(lt,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(el,{label:"接口兼容",value:"OpenAI API"}),n.jsx(el,{label:"当前默认模型",value:O}),n.jsx(el,{label:"已配置渠道",value:`${m.length} 个,${Se} 个启用`}),n.jsx(el,{label:"可选供应商",value:`${eo.length} 种`}),n.jsx(el,{label:"运行版本",value:`${ie?.version||"未知"} · ${ie?.commit||"未知"}`}),n.jsx(el,{label:"构建时间",value:ie?.buildTime?tl(ie.buildTime):"本地构建"}),n.jsx(el,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),Z==="cli"&&n.jsxs(lt,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:Ul()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{Ai(Ul()),N("已复制 Base URL")},children:n.jsx(_t,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${Ul()}" +export ANTHROPIC_AUTH_TOKEN="cat_你的_api_key" +export ANTHROPIC_MODEL="${O}" +claude`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Codex CLI"}),n.jsx("span",{children:"OpenAI Chat 协议"})]}),n.jsxs("p",{children:["编辑 ",n.jsx("code",{children:"~/.codex/config.toml"}),":"]}),n.jsx("pre",{children:`model = "${O}" +model_provider = "capi" + +[model_providers.capi] +name = "CAPI" +base_url = "${Ul()}/v1" +env_key = "CAPI_KEY" +wire_api = "chat"`}),n.jsx("p",{children:"然后设置环境变量并运行:"}),n.jsx("pre",{children:`export CAPI_KEY="cat_你的_api_key" +codex`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Aider"}),n.jsx("span",{children:"OpenAI 兼容"})]}),n.jsx("pre",{children:`export OPENAI_API_BASE="${Ul()}" +export OPENAI_API_KEY="cat_你的_api_key" +aider --model openai/${O}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Cline / Roo Code / Kilo Code"}),n.jsx("span",{children:"VS Code 插件"})]}),n.jsxs("p",{children:["在插件设置中选择 ",n.jsx("strong",{children:"OpenAI Compatible"}),":"]}),n.jsx("pre",{children:`Base URL: ${Ul()}/v1 +API Key: cat_你的_api_key +Model ID: ${O}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"通用 OpenAI SDK"}),n.jsx("span",{children:"Python / Node.js"})]}),n.jsx("pre",{children:`export OPENAI_BASE_URL="${Ul()}" +export OPENAI_API_KEY="cat_你的_api_key"`}),n.jsx("pre",{children:`from openai import OpenAI +client = OpenAI() +response = client.chat.completions.create( + model="${O}", + messages=[{"role": "user", "content": "hello"}] +)`})]})]}),f&&n.jsx("p",{className:"cli-message",role:"status",children:f})]}),Z==="maintenance"&&n.jsx(lt,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:se.logRetentionDays,onChange:R=>ne(Ue=>({...Ue,logRetentionDays:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:se.maxLogs,onChange:R=>ne(Ue=>({...Ue,maxLogs:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:se.maxQuotaEntries,onChange:R=>ne(Ue=>({...Ue,maxQuotaEntries:Number(R.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:V,children:G?"保存中":"保存维护设置"})]})]})}),Z==="backup"&&n.jsx(lt,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:G,onClick:mt,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:G,onChange:R=>{const Ue=R.target.files?.[0];Ue&&Rt(Ue),R.target.value=""}})]})]})]})})}),Z==="auth"&&n.jsx(lt,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:M?"启用":"关闭"}),n.jsx("button",{type:"button",className:M?"ios-switch is-on":"ios-switch","aria-label":M?"关闭用户注册":"开放用户注册","aria-pressed":!!M,onClick:Je,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(R=>n.jsx("button",{type:"button",className:P===R.value?"selected":"",onClick:()=>$(M??!0,R.value),children:R.label},R.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:b,onChange:R=>q(R.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>$(M,P,Number(b)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:z,onChange:R=>ee(R.target.value),"aria-label":"默认注册分组",children:[p.map(R=>n.jsx("option",{value:R.id,children:R.name},R.id)),p.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:p.length===0,onClick:()=>$(M,P,Number(b),z),children:"保存"})]})]})]})}),Z==="check-in"&&n.jsx(lt,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:te.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:te.enabled?"ios-switch is-on":"ios-switch","aria-label":te.enabled?"关闭每日签到":"开放每日签到","aria-pressed":te.enabled,onClick:()=>re(R=>({...R,enabled:!R.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:te.minReward,onChange:R=>re(Ue=>({...Ue,minReward:Number(R.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:te.maxReward,onChange:R=>re(Ue=>({...Ue,maxReward:Number(R.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:ut,children:G?"保存中":"保存签到设置"})]})]})}),Z==="admin"&&n.jsx(lt,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:R=>{R.preventDefault(),ll()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:I,onChange:R=>me(R.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:_,onChange:R=>le(R.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:de,onChange:R=>Ae(R.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Me,onChange:R=>ce(R.target.value),placeholder:Y?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:k,onChange:R=>fe(R.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:J,onChange:R=>A(R.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),Z==="discord"&&n.jsx(lt,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:R=>{R.preventDefault(),Ie()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>E({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:R=>E({...r,clientId:R.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:L,onChange:R=>v(R.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:R=>E({...r,redirectUri:R.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:R=>E({...r,allowedGuildId:R.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:R=>E({...r,allowedRoleId:R.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:D,onChange:R=>W(R.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:R=>E({...r,authSuccessUrl:R.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:R=>E({...r,sessionTtlHours:Number(R.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:f}),n.jsx("button",{className:"primary-button",type:"submit",disabled:G,children:G?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function cl({label:c,value:m}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:c}),n.jsx("strong",{children:m})]})}function Lp({groups:c,onCreate:m,onUpdate:p,onDelete:r}){const[E,M]=g.useState(""),[X,P]=g.useState(""),[T,b]=g.useState(!1);async function q(z){if(z.preventDefault(),!!E.trim()){b(!0);try{await m({name:E.trim(),description:X.trim()}),M(""),P("")}finally{b(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(lt,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:q,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:E,onChange:z=>M(z.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:X,onChange:z=>P(z.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:T||!E.trim(),children:T?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(lt,{title:"全部分组",children:c.length===0?n.jsx(Xt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:c.map(z=>n.jsx(Qp,{group:z,onUpdate:p,onDelete:r},z.id))})})]})}function Qp({group:c,onUpdate:m,onDelete:p}){const[r,E]=g.useState(!1),[M,X]=g.useState(c.name),[P,T]=g.useState(c.description),[b,q]=g.useState(!1);async function z(){q(!0);try{await m(c.id,{name:M.trim(),description:P.trim()}),E(!1)}finally{q(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:M,onChange:ee=>X(ee.target.value),placeholder:"分组名称"}),n.jsx("input",{value:P,onChange:ee=>T(ee.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:c.name}),c.description&&n.jsx("span",{children:c.description}),n.jsxs("small",{children:["创建于 ",tl(c.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:z,disabled:b||!M.trim(),children:b?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{X(c.name),T(c.description),E(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>E(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>p(c.id),children:"删除"})]})})]})})}function lt({title:c,children:m}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:c})}),m]})}function Ut({tone:c,children:m}){return n.jsx("span",{className:`badge tone-${c}`,children:m})}function el({label:c,value:m,switchOn:p}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:c}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:m}),typeof p=="boolean"&&n.jsx("div",{className:p?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function Xp({value:c,options:m,onChange:p}){return n.jsx("div",{className:"segmented-control",children:m.map(r=>n.jsx("button",{className:c===r.value?"selected":"",onClick:()=>p(r.value),children:r.label},r.value))})}function Xt({text:c}){return n.jsx("div",{className:"empty",children:c})}V0.createRoot(document.getElementById("root")).render(n.jsx(Y0.StrictMode,{children:n.jsx(rp,{})})); diff --git a/dist/index.html b/dist/index.html index 1893460..3c3004f 100644 --- a/dist/index.html +++ b/dist/index.html @@ -5,8 +5,8 @@ CAPI - - + +
diff --git a/package.json b/package.json index f432d7f..39211d5 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "concurrently \"npm:dev:web\" \"npm:dev:api\"", "dev:web": "vite --host 0.0.0.0", "dev:api": "go run ./cmd/capi", - "clean:dist": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"", + "clean:dist": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true,maxRetries:10,retryDelay:200});if(fs.existsSync('dist')){console.error('clean:dist failed: dist/ still exists - a running process (e.g. the API server) is holding files. Stop it and rebuild, or the old bundles stay behind and get served.');process.exit(1)}\"", "build": "npm run clean:dist && tsc -b && vite build", "preview": "vite preview --host 0.0.0.0", "start": "go run ./cmd/capi" diff --git a/src/App.tsx b/src/App.tsx index b6bb05e..d0bdd91 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1583,6 +1583,276 @@ function AuthScreen({ ); } +type UsageStats = { + requests: number; + cost: number; + inputTokens: number; + outputTokens: number; + successRate: number; +}; + +type UsagePoint = { + day: string; + requests: number; + cost: number; + inputTokens: number; + outputTokens: number; +}; + +type UsageModelPoint = UsagePoint & { model: string }; + +type AccountUsage = { + rangeDays: number; + today: UsageStats; + yesterday: UsageStats; + month: UsageStats; + total: UsageStats; + daily: UsagePoint[]; + models: UsageModelPoint[]; +}; + +// Round an axis maximum up to a clean step so the ticks land on round numbers +// instead of whatever the peak happened to be. The intermediate steps (1.5, +// 2.5, 3, 4, 6, 8) matter: with only 1/2/5/10 a peak of 2.47 would be charted +// against an axis of 5 and use barely half the plot height. +const USAGE_AXIS_STEPS = [1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10]; + +function niceCeil(value: number): number { + if (!(value > 0)) return 1; + const exponent = Math.floor(Math.log10(value)); + const magnitude = Math.pow(10, exponent); + const normalized = value / magnitude; + const step = USAGE_AXIS_STEPS.find((candidate) => normalized <= candidate) ?? 10; + return step * magnitude; +} + +// Bars and gridlines map the axis onto 88% of the plot so the peak's direct +// label always has headroom above the tallest column. +const USAGE_AXIS_SCALE = 88; + +function usageDayLabel(day: string) { + const parts = day.split("-"); + return parts.length === 3 ? `${parts[1]}/${parts[2]}` : day; +} + +type UsageRange = 7 | 14 | 30; + +// UsageSection is the account page's dashboard. Costs are a single series, so +// every mark wears one hue (the theme accent) - never a value ramp, which would +// re-encode bar length as colour and spend the identity channel for nothing. +function UsageSection() { + const [rangeDays, setRangeDays] = useState(14); + const [usage, setUsage] = useState(null); + const [loading, setLoading] = useState(true); + const [failed, setFailed] = useState(false); + const [hoveredDay, setHoveredDay] = useState(""); + + useEffect(() => { + let cancelled = false; + setLoading(true); + fetchJson<{ usage: AccountUsage }>( + `/api/account/usage?days=${rangeDays}&timezoneOffset=${new Date().getTimezoneOffset()}` + ) + .then((data) => { + if (cancelled) return; + setUsage({ ...data.usage, daily: arrayOf(data.usage?.daily), models: arrayOf(data.usage?.models) }); + setFailed(false); + }) + .catch(() => { + if (!cancelled) setFailed(true); + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + return () => { + cancelled = true; + }; + }, [rangeDays]); + + const daily = usage?.daily ?? []; + const models = usage?.models ?? []; + const axisMax = niceCeil(Math.max(0, ...daily.map((point) => point.cost))); + const maxModelCost = Math.max(0, ...models.map((entry) => entry.cost)); + const peakDay = daily.reduce( + (best, point) => (!best || point.cost > best.cost ? point : best), + null + ); + // Keep at most ~5 date labels so they cannot collide on a 30-day range. + const labelStride = Math.max(1, Math.ceil(daily.length / 5)); + const hovered = daily.find((point) => point.day === hoveredDay) || null; + const hoveredIndex = hovered ? daily.indexOf(hovered) : -1; + // Spending more is neither good nor bad, so the delta carries no status colour. + const todayDelta = usage ? usage.today.cost - usage.yesterday.cost : 0; + + return ( +
+
+
+

Usage

+

用量概览

+
+
+ + {!usage && loading &&

正在统计用量…

} + {!usage && !loading && failed &&

用量加载失败,请稍后重试

} + + {usage && ( +
+
+
+ 今日消费 + {formatAmount(usage.today.cost)} + + 较昨日 {todayDelta >= 0 ? "+" : "−"} + {formatAmount(Math.abs(todayDelta))} + +
+
+ 本月消费 + {formatAmount(usage.month.cost)} + {formatTokenCount(usage.month.requests)} 次请求 +
+
+ 今日请求 + {formatTokenCount(usage.today.requests)} + 成功率 {usage.today.successRate}% +
+
+ 累计消费 + {formatAmount(usage.total.cost)} + {formatTokenCount(usage.total.requests)} 次请求 +
+
+ +
+ {([7, 14, 30] as UsageRange[]).map((value) => ( + + ))} +
+ +
+
+ 每日消费 + 近 {usage.rangeDays} 天 +
+ {daily.length === 0 || axisMax <= 0 ? ( +

这段时间还没有消费记录

+ ) : ( + <> +
+ +
+ {daily.map((point, index) => { + const height = axisMax > 0 ? (point.cost / axisMax) * USAGE_AXIS_SCALE : 0; + // A zero-cost day must not draw a mark at all; the bar's + // min-height exists for tiny non-zero values only. + const hasSpend = point.cost > 0; + const isPeak = hasSpend && peakDay !== null && point.day === peakDay.day; + const showLabel = index % labelStride === 0 || index === daily.length - 1; + return ( +
+ + {showLabel ? usageDayLabel(point.day) : ""} +
+ ); + })} + {hovered && ( +
+ {formatAmount(hovered.cost)} + {hovered.day} + {hovered.requests} 次请求 +
+ )} +
+
+ +
+ 查看数据表 +
+
+ 日期 + 请求 + 消费 +
+ {daily + .slice() + .reverse() + .map((point) => ( +
+ {point.day} + {point.requests} + {formatAmount(point.cost)} +
+ ))} +
+
+ + )} +
+ +
+
+ 按模型拆分 + 近 {usage.rangeDays} 天消费 +
+ {models.length === 0 ? ( +

这段时间还没有调用记录

+ ) : ( +
+ {models.map((entry) => ( +
+ {entry.model} + + 0 ? (entry.cost / maxModelCost) * 100 : 0}%` }} + /> + + {formatAmount(entry.cost)} +
+ ))} +
+ )} +
+
+ )} +
+ ); +} + function AccountHome({ theme, setTheme, @@ -1697,6 +1967,8 @@ function AccountHome({ + +
diff --git a/src/styles.css b/src/styles.css index df979fd..3e1af8e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -3654,6 +3654,348 @@ button.table-row:hover { align-self: center; } +/* Usage dashboard. Costs are a single series, so every mark wears one hue + (--blue, which clears 3:1 against both surfaces: 4.02 light / 4.24 dark). + Never a value ramp - that would re-encode bar length as colour. */ +.usage-section { + --usage-mark: var(--blue); + --usage-plot-height: 150px; + --usage-tick-band: 18px; + --usage-axis-gutter: 46px; +} + +.usage-body { + display: grid; + gap: 16px; + transition: opacity 160ms ease; +} + +/* Refetch holds the previous render instead of flashing a skeleton. */ +.usage-body.is-refreshing { + opacity: 0.55; +} + +.usage-placeholder { + margin: 0; + color: var(--muted); + font-size: 13px; +} + +.usage-kpi { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; +} + +.usage-tile { + display: grid; + gap: 3px; + min-width: 0; + padding: 12px; + background: var(--group); + border: 1px solid var(--hairline); + border-radius: 14px; +} + +.usage-tile > span { + color: var(--muted); + font-size: 12px; +} + +/* Proportional figures: tabular-nums makes a value like 121 look loose. */ +.usage-tile > strong { + font-size: 22px; + font-weight: 650; + line-height: 1.15; + overflow-wrap: anywhere; +} + +.usage-tile > small { + color: var(--muted); + font-size: 12px; +} + +.usage-range { + display: inline-flex; + gap: 4px; + width: fit-content; + padding: 3px; + background: var(--group); + border: 1px solid var(--hairline); + border-radius: 999px; +} + +.usage-range button { + min-height: 28px; + padding: 0 12px; + color: var(--muted); + background: transparent; + border: 0; + border-radius: 999px; + cursor: pointer; + font-size: 13px; + font-weight: 700; +} + +.usage-range button.selected { + color: var(--text); + background: var(--surface-solid); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12); +} + +.account-page[data-theme="dark"] .usage-range button.selected { + background: rgba(255, 255, 255, 0.16); + box-shadow: none; +} + +.usage-block { + display: grid; + gap: 10px; +} + +.usage-block-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; +} + +.usage-block-head > strong { + font-size: 14px; +} + +.usage-block-head > span { + color: var(--muted); + font-size: 12px; +} + +/* The container includes the tick band so the axis labels are never clipped + into a nested scrollbar. */ +.usage-plot { + position: relative; + padding-left: var(--usage-axis-gutter); +} + +.usage-grid { + position: absolute; + top: 0; + left: var(--usage-axis-gutter); + right: 0; + height: var(--usage-plot-height); + pointer-events: none; +} + +.usage-gridline { + position: absolute; + left: 0; + right: 0; + border-top: 1px solid var(--hairline); +} + +.usage-gridline > span { + position: absolute; + right: 100%; + margin-right: 8px; + transform: translateY(-50%); + color: var(--muted); + font-size: 11px; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.usage-columns { + position: relative; + display: flex; + align-items: flex-end; + /* The surface gap that separates touching columns. */ + gap: 2px; +} + +.usage-column { + display: flex; + flex: 1 1 0; + flex-direction: column; + align-items: center; + min-width: 0; +} + +/* The hit target is the full column height, so the reader aims at a date + rather than at a 2px bar. */ +.usage-column-hit { + position: relative; + display: flex; + align-items: flex-end; + justify-content: center; + width: 100%; + height: var(--usage-plot-height); + padding: 0; + background: none; + border: 0; + cursor: pointer; +} + +.usage-column-bar { + display: block; + width: min(24px, 100%); + min-height: 2px; + background: var(--usage-mark); + /* Rounded data-end, square at the baseline. */ + border-radius: 4px 4px 0 0; + transition: opacity 160ms ease; +} + +.usage-column-hit.is-hovered .usage-column-bar { + opacity: 0.72; +} + +.usage-column-peak { + position: absolute; + left: 50%; + transform: translateX(-50%); + color: var(--muted); + font-size: 11px; + font-variant-numeric: tabular-nums; + white-space: nowrap; + pointer-events: none; +} + +.usage-column-tick { + height: var(--usage-tick-band); + color: var(--muted); + font-size: 11px; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +/* Anchored just above the tick band so it stays inside the card: above the + container it would cover the block heading, and the top strip belongs to the + peak's direct label. */ +.usage-tooltip { + position: absolute; + bottom: calc(var(--usage-tick-band) + 8px); + z-index: 2; + display: grid; + gap: 1px; + transform: translateX(-50%); + padding: 7px 10px; + color: var(--text); + background: var(--surface-solid); + border: 1px solid var(--hairline); + border-radius: 10px; + box-shadow: var(--shadow); + pointer-events: none; + white-space: nowrap; +} + +/* The value leads; the label follows. */ +.usage-tooltip > strong { + font-size: 14px; + font-variant-numeric: tabular-nums; +} + +.usage-tooltip > span { + color: var(--muted); + font-size: 11px; +} + +.usage-table-toggle > summary { + width: fit-content; + color: var(--muted); + cursor: pointer; + font-size: 12px; +} + +.usage-table { + display: grid; + margin-top: 8px; + overflow: hidden; + border: 1px solid var(--hairline); + border-radius: 12px; +} + +.usage-table-head, +.usage-table-row { + display: grid; + grid-template-columns: minmax(0, 1fr) 72px 88px; + gap: 10px; + align-items: center; + min-height: 32px; + padding: 0 12px; +} + +.usage-table-head { + color: var(--muted); + background: var(--group); + font-size: 11px; + font-weight: 700; +} + +.usage-table-head > span:not(:first-child), +.usage-table-row > span:not(:first-child) { + justify-self: end; + font-variant-numeric: tabular-nums; +} + +.usage-table-row { + border-top: 1px solid var(--hairline); + font-size: 12px; +} + +.usage-models { + display: grid; + gap: 8px; +} + +.usage-model-row { + display: grid; + grid-template-columns: minmax(90px, 160px) minmax(0, 1fr) 72px; + gap: 10px; + align-items: center; +} + +.usage-model-name { + overflow: hidden; + color: var(--text); + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.usage-model-track { + display: block; + height: 10px; + background: var(--group); + border-radius: 999px; +} + +.usage-model-bar { + display: block; + height: 100%; + min-width: 2px; + background: var(--usage-mark); + border-radius: 999px; +} + +.usage-model-value { + justify-self: end; + font-size: 13px; + font-variant-numeric: tabular-nums; +} + +@media (max-width: 720px) { + .usage-kpi { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .usage-model-row { + grid-template-columns: minmax(0, 1fr) 64px; + } + + .usage-model-track { + display: none; + } +} + .account-model-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));