} | null => {
- try {
- const records = JSON.parse(
- localStorage.getItem(SEARCH_CACHE_KEY) || '[]'
- ) as AISearchCacheRecord[]
- const normalizedQuery = query.trim().toLowerCase()
- for (const record of records) {
- const location = parseSearchCacheKey(record.key)
- if (record.version === 1 && location?.query === normalizedQuery) {
- return { record, location }
- }
- }
- return null
- } catch {
- return null
- }
-}
-
-const writeSearchCache = (record: AISearchCacheRecord): void => {
- try {
- const records = JSON.parse(
- localStorage.getItem(SEARCH_CACHE_KEY) || '[]'
- ) as AISearchCacheRecord[]
- const nextRecords = [record, ...records.filter((item) => item.key !== record.key)].slice(
- 0,
- SEARCH_CACHE_LIMIT
- )
- localStorage.setItem(SEARCH_CACHE_KEY, JSON.stringify(nextRecords))
- } catch {
- // A large message result must not break the search itself.
- }
-}
-
-const inlineMarkdown = (value: string, keyPrefix: string): React.ReactNode[] =>
- value.split(/(\*\*.*?\*\*|`.*?`|\*.*?\*)/g).map((part, index) => {
- const key = `${keyPrefix}-${index}`
- if (part.startsWith('**') && part.endsWith('**')) {
- return {part.slice(2, -2)}
- }
- if (part.startsWith('`') && part.endsWith('`')) {
- return {part.slice(1, -1)}
- }
- if (part.startsWith('*') && part.endsWith('*')) {
- return {part.slice(1, -1)}
- }
- return {part}
- })
-
-const renderMarkdown = (value: string): React.ReactNode =>
- value.split(/\r?\n/).map((line, index) => {
- const key = `markdown-${index}`
- if (!line.trim()) return
- const heading = /^(#{1,3})\s+(.+)$/.exec(line)
- if (heading) {
- const Heading = `h${heading[1].length}` as 'h1' | 'h2' | 'h3'
- return {inlineMarkdown(heading[2], key)}
- }
- const bullet = /^\s*[-*]\s+(.+)$/.exec(line)
- if (bullet) {
- return (
-
- •
- {inlineMarkdown(bullet[1], key)}
-
- )
- }
- const numbered = /^\s*\d+[.)]\s+(.+)$/.exec(line)
- if (numbered) {
- return (
-
- {line.trim().match(/^\d+/)?.[0]}.
- {inlineMarkdown(numbered[1], key)}
-
- )
- }
- return {inlineMarkdown(line, key)}
- })
+import type {
+ AISearchCacheRecord,
+ AISearchWorkspaceProps,
+ EvidenceItem,
+ GroupMemberName,
+ SearchPassSummary,
+ SearchRange,
+ SearchScope,
+ SearchStage,
+ SenderDirectory
+} from './searchTypes'
+import {
+ RANGE_LABELS,
+ SEARCH_CACHE_KEY,
+ SEARCH_HISTORY_KEY,
+ buildLocalSearchPlan,
+ buildSearchCacheKey,
+ compactCacheItem,
+ currentTimestamp,
+ evidenceIdentity,
+ formatMemberName,
+ formatMessageDate,
+ formatMessageTime,
+ getRangeStart,
+ includesSearchAlias,
+ messageDateKey,
+ messageIdentity,
+ messageText,
+ mergeSearchPlans,
+ normalizeSearchText,
+ parseSearchCacheKey,
+ parseSearchPlanResponse,
+ readSearchCache,
+ readSearchCacheByQuery,
+ selectEvenly,
+ selectEvidenceByDate,
+ senderName,
+ writeSearchCache
+} from './searchUtils'
+import { renderMarkdown } from './searchMarkdown'
export function AISearchWorkspace({
contacts,
diff --git a/src/renderer/src/components/search/searchMarkdown.tsx b/src/renderer/src/components/search/searchMarkdown.tsx
new file mode 100644
index 0000000..b6e5a2b
--- /dev/null
+++ b/src/renderer/src/components/search/searchMarkdown.tsx
@@ -0,0 +1,46 @@
+import React from 'react'
+
+const inlineMarkdown = (value: string, keyPrefix: string): React.ReactNode[] =>
+ value.split(/(\*\*.*?\*\*|`.*?`|\*.*?\*)/g).map((part, index) => {
+ const key = `${keyPrefix}-${index}`
+ if (part.startsWith('**') && part.endsWith('**')) {
+ return {part.slice(2, -2)}
+ }
+ if (part.startsWith('`') && part.endsWith('`')) {
+ return {part.slice(1, -1)}
+ }
+ if (part.startsWith('*') && part.endsWith('*')) {
+ return {part.slice(1, -1)}
+ }
+ return {part}
+ })
+
+export const renderMarkdown = (value: string): React.ReactNode =>
+ value.split(/\r?\n/).map((line, index) => {
+ const key = `markdown-${index}`
+ if (!line.trim()) return
+ const heading = /^(#{1,3})\s+(.+)$/.exec(line)
+ if (heading) {
+ const Heading = `h${heading[1].length}` as 'h1' | 'h2' | 'h3'
+ return {inlineMarkdown(heading[2], key)}
+ }
+ const bullet = /^\s*[-*]\s+(.+)$/.exec(line)
+ if (bullet) {
+ return (
+
+ •
+ {inlineMarkdown(bullet[1], key)}
+
+ )
+ }
+ const numbered = /^\s*\d+[.)]\s+(.+)$/.exec(line)
+ if (numbered) {
+ return (
+
+ {line.trim().match(/^\d+/)?.[0]}.
+ {inlineMarkdown(numbered[1], key)}
+
+ )
+ }
+ return {inlineMarkdown(line, key)}
+ })
diff --git a/src/renderer/src/components/search/searchTypes.ts b/src/renderer/src/components/search/searchTypes.ts
new file mode 100644
index 0000000..e796cf4
--- /dev/null
+++ b/src/renderer/src/components/search/searchTypes.ts
@@ -0,0 +1,59 @@
+import type { AIRuntimeModelConfig } from '../../../../shared/ai-provider'
+import type { Contact, Message } from '../../../../shared/types'
+
+export type SearchStage = 'idle' | 'loading' | 'result' | 'insufficient'
+export type SearchScope = 'global' | 'conversation'
+export type SearchRange = 'today' | '7d' | '30d' | 'all'
+export type SearchIntent = 'general' | 'topic' | 'participants' | 'mixed'
+
+export interface EvidenceItem {
+ contact: Contact
+ message: Message
+}
+
+export interface AISearchCacheRecord {
+ version: 1
+ key: string
+ createdAt: number
+ answer: string
+ evidence: EvidenceItem[]
+ senderNames: Record
+ messageCount: number
+}
+
+export interface GroupMemberName {
+ wxid: string
+ nickname?: string
+ groupNickname?: string
+ remark?: string
+ wechatNickname?: string
+}
+
+export interface SenderDirectory {
+ displayNames: Record
+ aliases: Record
+}
+
+export interface SearchQueryPlan {
+ intent: SearchIntent
+ keywords: string[]
+ variants: string[]
+ source: 'local' | 'ai' | 'hybrid'
+}
+
+export interface SearchPassSummary {
+ label: string
+ keywords: string[]
+ messageCount: number
+}
+
+export interface AISearchWorkspaceProps {
+ contacts: Contact[]
+ selectedContact: Contact | null
+ dbReady: boolean
+ aiModelConfig: AIRuntimeModelConfig
+ onSelectContact: (contact: Contact) => void
+ onOpenEvidence: (contact: Contact, createTime?: number) => void
+ onOpenAISettings: () => void
+ onNotice: (message: string) => void
+}
diff --git a/src/renderer/src/components/search/searchUtils.ts b/src/renderer/src/components/search/searchUtils.ts
new file mode 100644
index 0000000..0f7ea07
--- /dev/null
+++ b/src/renderer/src/components/search/searchUtils.ts
@@ -0,0 +1,372 @@
+import type { Contact, Message } from '../../../../shared/types'
+import type { AISearchCacheRecord, EvidenceItem, GroupMemberName, SearchIntent, SearchQueryPlan, SearchRange, SearchScope } from './searchTypes'
+
+export const RANGE_LABELS: Record = {
+ today: '今天',
+ '7d': '近 7 天',
+ '30d': '近 30 天',
+ all: '全部历史'
+}
+
+export const SEARCH_CACHE_KEY = 'wxe_ai_search_cache_v8'
+export const SEARCH_HISTORY_KEY = 'wxe_ai_search_history_v1'
+export const SEARCH_CACHE_LIMIT = 20
+export const currentTimestamp = (): number => Date.now()
+
+const SEARCH_INTENT_PHRASES = [
+ '全局搜一下',
+ '全局搜索',
+ '搜索一下',
+ '搜一下',
+ '查询一下',
+ '查一下',
+ '找一下',
+ '我和谁聊过',
+ '谁和我聊过',
+ '哪些人和我聊过',
+ '最近讨论了什么',
+ '最近聊了什么',
+ '最近说了什么',
+ '讨论了什么',
+ '讨论什么',
+ '聊了什么',
+ '聊些什么',
+ '说了什么',
+ '说些什么',
+ '最近讨论',
+ '最近聊天',
+ '这个话题',
+ '相关话题',
+ '的聊天',
+ '的内容',
+ '的记录',
+ '关于',
+ '聊天',
+ '记录',
+ '聊天记录',
+ '帮我',
+ '请问'
+].sort((left, right) => right.length - left.length)
+
+const SEARCH_STOP_WORDS = new Set([
+ '我',
+ '谁',
+ '什么',
+ '哪些',
+ '哪个',
+ '人',
+ '和',
+ '聊过',
+ '说过',
+ '提到',
+ '讨论',
+ '聊天',
+ '记录',
+ '说',
+ '聊',
+ '话题',
+ '内容',
+ '相关',
+ '最近',
+ '一下'
+])
+
+export const messageText = (message: Message): string =>
+ String(message.content || '').trim() || `[${message.type || '消息'}]`
+
+export const normalizeSearchText = (value: string): string => value.toLowerCase().replace(/\s+/g, '')
+
+export const includesSearchAlias = (query: string, alias: string): boolean => {
+ const normalizedAlias = normalizeSearchText(alias.trim())
+ return Boolean(normalizedAlias) && normalizeSearchText(query).includes(normalizedAlias)
+}
+
+const extractSearchKeywords = (query: string): string[] => {
+ const cleanedQuery = SEARCH_INTENT_PHRASES.reduce(
+ (value, phrase) => value.split(phrase).join(' '),
+ query.toLowerCase()
+ )
+ const tokens = cleanedQuery
+ .split(/[\s,,。!?!?、::;;"“”‘’()()[\]【】]+/)
+ .map((token) => token.trim())
+ .filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token))
+ return Array.from(new Set(tokens))
+}
+
+const getFuzzySearchKeywords = (keywords: string[]): string[] =>
+ Array.from(
+ new Set(
+ keywords.flatMap((keyword) => {
+ const variants = [keyword]
+ if (/^[\u4e00-\u9fff]+$/.test(keyword) && keyword.length > 2) {
+ variants.push(keyword.slice(-2))
+ }
+ return variants
+ })
+ )
+ )
+
+const normalizeSearchTerms = (terms: unknown): string[] => {
+ if (!Array.isArray(terms)) return []
+ return Array.from(
+ new Set(
+ terms
+ .filter((term): term is string => typeof term === 'string')
+ .map((term) => term.trim())
+ .filter((term) => term.length >= 2 && term.length <= 32)
+ )
+ ).slice(0, 16)
+}
+
+export const buildLocalSearchPlan = (query: string): SearchQueryPlan => {
+ const keywords = extractSearchKeywords(query)
+ const asksParticipants = /我和谁|谁和我|哪些人|哪个人|哪些联系人/.test(query)
+ const intent: SearchIntent = asksParticipants
+ ? keywords.length
+ ? 'mixed'
+ : 'participants'
+ : keywords.length
+ ? 'topic'
+ : 'general'
+ return {
+ intent,
+ keywords,
+ variants: getFuzzySearchKeywords(keywords),
+ source: 'local'
+ }
+}
+
+export const parseSearchPlanResponse = (value: string): Partial | null => {
+ const jsonMatch = value.match(/\{[\s\S]*\}/)
+ if (!jsonMatch) return null
+ try {
+ const parsed = JSON.parse(jsonMatch[0]) as Record
+ const intent = ['general', 'topic', 'participants', 'mixed'].includes(String(parsed.intent))
+ ? (parsed.intent as SearchIntent)
+ : undefined
+ return {
+ intent,
+ keywords: normalizeSearchTerms(parsed.keywords),
+ variants: normalizeSearchTerms(parsed.variants)
+ }
+ } catch {
+ return null
+ }
+}
+
+export const mergeSearchPlans = (
+ localPlan: SearchQueryPlan,
+ aiPlan: Partial | null
+): SearchQueryPlan => {
+ if (!aiPlan) return localPlan
+ const keywords = normalizeSearchTerms([...(localPlan.keywords || []), ...(aiPlan.keywords || [])])
+ const variants = normalizeSearchTerms([
+ ...getFuzzySearchKeywords(keywords),
+ ...(localPlan.variants || []),
+ ...(aiPlan.variants || [])
+ ])
+ return {
+ intent: aiPlan.intent || localPlan.intent,
+ keywords,
+ variants,
+ source: 'hybrid'
+ }
+}
+
+export const messageIdentity = (message: Message): string =>
+ message.localId
+ ? `local:${message.localId}`
+ : message.id || `${message.createTime}:${message.content}`
+
+export const evidenceIdentity = ({ contact, message }: EvidenceItem): string =>
+ `${contact.md5}:${messageIdentity(message)}`
+
+export const formatMessageTime = (message: Message): string => {
+ if (message.datetime) return message.datetime
+ if (message.createTime) return new Date(message.createTime * 1000).toLocaleString('zh-CN')
+ return '未知时间'
+}
+
+export const getRangeStart = (range: SearchRange): number | undefined => {
+ if (range === 'all') return undefined
+ if (range === 'today') {
+ const now = new Date()
+ return Math.floor(new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000)
+ }
+ const days = range === '7d' ? 7 : 30
+ return Math.floor(Date.now() / 1000) - days * 86400
+}
+
+export const messageDateKey = (message: Message): string => {
+ if (!message.createTime) return 'unknown'
+ const date = new Date(message.createTime * 1000)
+ const year = date.getFullYear()
+ const month = String(date.getMonth() + 1).padStart(2, '0')
+ const day = String(date.getDate()).padStart(2, '0')
+ return `${year}-${month}-${day}`
+}
+
+export const formatMessageDate = (dateKey: string): string => {
+ if (dateKey === 'unknown') return '--/--'
+ const [, month, day] = dateKey.split('-')
+ return `${month}/${day}`
+}
+
+export const selectEvenly = (items: T[], count: number): T[] => {
+ if (count >= items.length) return items
+ if (count <= 0) return []
+ if (count === 1) return [items[items.length - 1]]
+ return Array.from({ length: count }, (_item, index) => {
+ const itemIndex = Math.round((index * (items.length - 1)) / (count - 1))
+ return items[itemIndex]
+ })
+}
+
+export const selectEvidenceByDate = (items: EvidenceItem[], maxItems: number): EvidenceItem[] => {
+ const buckets = new Map()
+ items.forEach((item) => {
+ const key = messageDateKey(item.message)
+ const bucket = buckets.get(key) || []
+ bucket.push(item)
+ buckets.set(key, bucket)
+ })
+ const entries = Array.from(buckets.entries()).sort(([left], [right]) => left.localeCompare(right))
+ const targetCount = Math.min(maxItems, items.length)
+ const counts = entries.map(() => 0)
+ let remaining = targetCount
+ while (remaining > 0) {
+ let bestIndex = -1
+ let bestRemaining = 0
+ entries.forEach(([, bucket], index) => {
+ const available = bucket.length - counts[index]
+ if (available > bestRemaining) {
+ bestIndex = index
+ bestRemaining = available
+ }
+ })
+ if (bestIndex < 0) break
+ counts[bestIndex] += 1
+ remaining -= 1
+ }
+ return entries
+ .flatMap((entry, index) => selectEvenly(entry[1], counts[index]))
+ .sort((left, right) => (left.message.createTime || 0) - (right.message.createTime || 0))
+}
+
+const looksLikeUserId = (value: string): boolean =>
+ value.startsWith('wxid_') || value.includes('@chatroom') || /^\d{6,}$/.test(value)
+
+export const formatMemberName = (member: GroupMemberName): string =>
+ member.groupNickname || member.wechatNickname || member.nickname || member.remark || member.wxid
+
+export const senderName = (message: Message, contact: Contact, names: Record): string => {
+ const identifiers = [message.senderId, message.from, message.name].filter(
+ (value): value is string => Boolean(value?.trim())
+ )
+ const mappedName = identifiers.map((value) => names[value]).find(Boolean)
+ if (mappedName) return mappedName
+ if (message.name && !looksLikeUserId(message.name)) return message.name
+ if (message.isSender) return '我'
+ return contact.type === 'user' ? contact.m_nsNickName || '联系人' : '群成员'
+}
+
+export const compactCacheItem = ({ contact, message }: EvidenceItem): EvidenceItem => ({
+ contact: {
+ md5: contact.md5,
+ m_nsUsrName: contact.m_nsUsrName,
+ m_nsNickName: contact.m_nsNickName,
+ type: contact.type,
+ avatar: contact.avatar
+ },
+ message: {
+ id: message.id,
+ from: message.from,
+ type: message.type,
+ datetime: message.datetime,
+ content: message.content,
+ isSender: message.isSender,
+ name: message.name,
+ senderId: message.senderId,
+ localId: message.localId,
+ serverId: message.serverId,
+ createTime: message.createTime
+ }
+})
+
+export const buildSearchCacheKey = (
+ scope: SearchScope,
+ contactMd5: string,
+ range: SearchRange,
+ query: string
+): string => JSON.stringify([scope, contactMd5, range, query.trim().toLowerCase()])
+
+export const parseSearchCacheKey = (
+ key: string
+): { scope: SearchScope; contactMd5: string; range: SearchRange; query: string } | null => {
+ try {
+ const parts = JSON.parse(key) as unknown
+ if (
+ !Array.isArray(parts) ||
+ !['global', 'conversation'].includes(String(parts[0])) ||
+ !['today', '7d', '30d', 'all'].includes(String(parts[2])) ||
+ typeof parts[3] !== 'string'
+ ) {
+ return null
+ }
+ return {
+ scope: parts[0] as SearchScope,
+ contactMd5: typeof parts[1] === 'string' ? parts[1] : '',
+ range: parts[2] as SearchRange,
+ query: parts[3]
+ }
+ } catch {
+ return null
+ }
+}
+
+export const readSearchCache = (key: string): AISearchCacheRecord | null => {
+ try {
+ const records = JSON.parse(
+ localStorage.getItem(SEARCH_CACHE_KEY) || '[]'
+ ) as AISearchCacheRecord[]
+ const record = records.find((item) => item.version === 1 && item.key === key)
+ return record || null
+ } catch {
+ return null
+ }
+}
+
+export const readSearchCacheByQuery = (
+ query: string
+): { record: AISearchCacheRecord; location: ReturnType } | null => {
+ try {
+ const records = JSON.parse(
+ localStorage.getItem(SEARCH_CACHE_KEY) || '[]'
+ ) as AISearchCacheRecord[]
+ const normalizedQuery = query.trim().toLowerCase()
+ for (const record of records) {
+ const location = parseSearchCacheKey(record.key)
+ if (record.version === 1 && location?.query === normalizedQuery) {
+ return { record, location }
+ }
+ }
+ return null
+ } catch {
+ return null
+ }
+}
+
+export const writeSearchCache = (record: AISearchCacheRecord): void => {
+ try {
+ const records = JSON.parse(
+ localStorage.getItem(SEARCH_CACHE_KEY) || '[]'
+ ) as AISearchCacheRecord[]
+ const nextRecords = [record, ...records.filter((item) => item.key !== record.key)].slice(
+ 0,
+ SEARCH_CACHE_LIMIT
+ )
+ localStorage.setItem(SEARCH_CACHE_KEY, JSON.stringify(nextRecords))
+ } catch {
+ // A large message result must not break the search itself.
+ }
+}
diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx
index b54070d..0654178 100644
--- a/src/renderer/src/main.tsx
+++ b/src/renderer/src/main.tsx
@@ -1,11 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
-import './styles/tokens.css'
-import './assets/main.css'
-import './styles/search.css'
-import './styles/archive.css'
-import './styles/settings-advanced.css'
+import './styles/index.scss'
window.addEventListener('error', (event) => {
void window.api
diff --git a/src/renderer/src/assets/base.css b/src/renderer/src/styles/_base.scss
similarity index 100%
rename from src/renderer/src/assets/base.css
rename to src/renderer/src/styles/_base.scss
diff --git a/src/renderer/src/styles/tokens.css b/src/renderer/src/styles/_tokens.scss
similarity index 100%
rename from src/renderer/src/styles/tokens.css
rename to src/renderer/src/styles/_tokens.scss
diff --git a/src/renderer/src/styles/api.scss b/src/renderer/src/styles/api.scss
new file mode 100644
index 0000000..7fe1c81
--- /dev/null
+++ b/src/renderer/src/styles/api.scss
@@ -0,0 +1,769 @@
+@media (max-width: 700px) {
+ .settings-account-overview {
+ grid-template-columns: minmax(0, 1fr);
+ }
+ .settings-account-actions {
+ grid-row: auto;
+ grid-column: 1;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ .settings-account-root {
+ grid-column: 1;
+ }
+ .database-key-status-card dl,
+ .database-key-diagnostics dl {
+ grid-template-columns: 1fr;
+ }
+ .database-key-auto-heading {
+ flex-direction: column;
+ }
+ .database-key-phases {
+ grid-template-columns: 1fr;
+ }
+ .database-key-phases li {
+ padding: 0 0 0 28px;
+ text-align: left;
+ }
+ .database-key-phases li::before {
+ top: -2px;
+ left: 0;
+ transform: none;
+ }
+ .image-decrypt-status dl,
+ .image-key-grid {
+ grid-template-columns: 1fr;
+ }
+ .image-decrypt-status .image-decrypt-wide {
+ grid-column: 1;
+ }
+ .image-auto-heading {
+ flex-direction: column;
+ }
+ .image-auto-phases {
+ grid-template-columns: 1fr;
+ }
+ .image-auto-phases li {
+ padding: 0 0 0 28px;
+ text-align: left;
+ }
+ .image-auto-phases li::before {
+ top: -2px;
+ left: 0;
+ transform: none;
+ }
+ .image-auto-success {
+ grid-template-columns: 1fr;
+ }
+ .image-auto-success button {
+ grid-column: 1;
+ grid-row: auto;
+ justify-self: start;
+ }
+ .image-resource-checks > div {
+ align-items: flex-start;
+ }
+ .image-resource-checks small {
+ white-space: normal;
+ text-align: right;
+ }
+ .ai-provider-card dl,
+ .ai-provider-form-grid,
+ .ai-provider-advanced > div {
+ grid-template-columns: 1fr;
+ }
+ .ai-provider-form-grid .wide,
+ .ai-provider-advanced .wide {
+ grid-column: 1;
+ }
+ .ai-model-row {
+ grid-template-columns: 1fr;
+ }
+}
+.api-center-layout > * {
+ min-width: 0;
+ min-height: 0;
+ box-sizing: border-box;
+}
+.api-section-heading h2,
+.api-introduction h2,
+.api-integrations h2,
+.api-runtime-title h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font: 700 17px/24px var(--wxex-font);
+}
+.ready-text {
+ color: var(--wxex-success);
+}
+.api-main {
+ position: relative;
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+.api-main-scroll {
+ flex: 1;
+ min-width: 0;
+ min-height: 0;
+ overflow-y: auto;
+ padding: 22px 28px 36px;
+}
+.api-workspace-heading {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+.api-title-line {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+}
+.api-title-line h1 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font: 700 22px/30px var(--wxex-font);
+}
+.api-workspace-heading p {
+ margin: 4px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 13px/19px var(--wxex-font);
+}
+.api-skill-status,
+.api-version {
+ padding: 2px 7px;
+ border-radius: 5px;
+ font: 700 11px/17px var(--wxex-font);
+}
+.api-skill-status.ready {
+ color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+}
+.api-skill-status.error {
+ color: var(--wxex-danger);
+ background: #fff1f1;
+}
+.api-version {
+ color: var(--wxex-text-muted);
+ background: var(--wxex-bg-app);
+}
+.api-header-actions,
+.api-tester-actions,
+.api-runtime-actions,
+.api-skill-file-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+.api-header-actions button,
+.api-tester-actions button,
+.api-runtime-actions button,
+.api-endpoint-row button,
+.api-response-summary + pre + p + button,
+.api-skill-file-actions button {
+ min-height: 32px;
+ padding: 0 11px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px/18px var(--wxex-font);
+}
+.api-header-actions button:hover,
+.api-tester-actions button:hover,
+.api-runtime-actions button:hover,
+.api-endpoint-row button:hover,
+.api-skill-file-actions button:hover {
+ border-color: var(--wxex-brand);
+ color: var(--wxex-brand);
+}
+.api-primary-button {
+ border-color: var(--wxex-brand) !important;
+ background: var(--wxex-brand) !important;
+ color: #fff !important;
+}
+.api-primary-button:hover:not(:disabled),
+.api-primary-button:focus-visible,
+.api-primary-button:active {
+ background: var(--wxex-brand-hover) !important;
+ color: #fff !important;
+}
+.api-primary-button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+}
+.api-trust-bar {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 10px;
+ margin-top: 16px;
+ padding: 10px 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: #f5f8f6;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-trust-bar i {
+ width: 3px;
+ height: 3px;
+ border-radius: 50%;
+ background: var(--wxex-text-muted);
+}
+.api-introduction {
+ margin-top: 24px;
+ padding: 18px 20px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-lg);
+ background: var(--wxex-bg-elevated);
+}
+.api-introduction p {
+ margin: 10px 0 16px;
+ color: var(--wxex-text-secondary);
+ font: 13px/20px var(--wxex-font);
+}
+.api-flow {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 12px;
+ border: 1px dashed var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-flow span,
+.api-flow strong {
+ padding: 7px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 5px;
+ background: #fff;
+ white-space: nowrap;
+}
+.api-flow strong {
+ color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+}
+.api-flow b {
+ color: var(--wxex-text-muted);
+ font-size: 17px;
+}
+.api-endpoint-catalog,
+.api-request-tester {
+ margin-top: 26px;
+}
+.skill-install-flow {
+ margin-top: 26px;
+ padding: 18px 20px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-lg);
+ background: var(--wxex-bg-elevated);
+}
+.skill-flow-steps {
+ display: grid;
+ gap: 16px;
+ margin-top: 16px;
+}
+.skill-flow-steps > section {
+ position: relative;
+ display: grid;
+ grid-template-columns: 26px minmax(0, 1fr);
+ gap: 10px;
+ color: var(--wxex-text-muted);
+}
+.skill-flow-steps > section:not(:last-child)::after {
+ position: absolute;
+ top: 28px;
+ left: 12px;
+ bottom: -16px;
+ width: 1px;
+ background: var(--wxex-border);
+ content: '';
+}
+.skill-flow-steps > section > b {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ width: 24px;
+ height: 24px;
+ place-items: center;
+ border: 1px solid var(--wxex-border);
+ border-radius: 50%;
+ background: var(--wxex-bg-elevated);
+ font: 700 12px/1 var(--wxex-font);
+}
+.skill-flow-steps > section.active > b,
+.skill-flow-steps > section.done > b {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+}
+.skill-flow-steps h3 {
+ margin: 1px 0 5px;
+ color: var(--wxex-text-primary);
+ font: 700 14px/20px var(--wxex-font);
+}
+.skill-flow-steps p {
+ margin: 3px 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.skill-flow-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-top: 10px;
+}
+.skill-flow-actions button,
+.api-skill-details button {
+ min-height: 30px;
+ padding: 0 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: #fff;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px/18px var(--wxex-font);
+}
+.skill-flow-actions button:disabled,
+.api-skill-details button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+}
+.skill-target-selector {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-top: 8px;
+}
+.skill-target-selector button {
+ min-height: 30px;
+ padding: 0 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: #fff;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 600 12px/18px var(--wxex-font);
+}
+.skill-target-selector button.active {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+}
+.api-skill-details {
+ margin-top: 16px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+}
+.api-skill-details summary {
+ padding: 12px 14px;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 700 13px/18px var(--wxex-font);
+}
+.api-skill-details > dl,
+.api-skill-details > div {
+ margin: 0;
+ padding: 0 14px 14px;
+}
+.api-skill-details dl div {
+ display: grid;
+ grid-template-columns: 72px minmax(0, 1fr);
+ gap: 8px;
+ padding: 4px 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-skill-details dd {
+ margin: 0;
+ color: var(--wxex-text-primary);
+}
+.api-skill-more {
+ position: relative;
+}
+.api-skill-more summary {
+ display: grid;
+ min-height: 32px;
+ place-items: center;
+ padding: 0 11px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px/18px var(--wxex-font);
+ list-style: none;
+}
+.api-skill-more[open] > button {
+ position: absolute;
+ z-index: 2;
+ top: 36px;
+ right: 0;
+ width: 170px;
+ padding: 9px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: #fff;
+ color: var(--wxex-text-primary);
+ box-shadow: var(--wxex-shadow-popover);
+ font: 12px/18px var(--wxex-font);
+ text-align: left;
+}
+.api-section-heading {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 12px;
+}
+.api-section-heading > span {
+ color: var(--wxex-text-muted);
+ font: 12px/18px var(--wxex-font);
+}
+.api-endpoint-table {
+ margin-top: 12px;
+ overflow: hidden;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+}
+.api-endpoint-head,
+.api-endpoint-row {
+ display: grid;
+ grid-template-columns: 72px minmax(128px, 1.1fr) minmax(150px, 1.2fr) 90px;
+ align-items: center;
+ gap: 12px;
+ padding: 11px 14px;
+}
+.api-endpoint-head {
+ background: #f1f4f2;
+ color: var(--wxex-text-secondary);
+ font: 700 12px/18px var(--wxex-font);
+}
+.api-endpoint-row {
+ min-height: 54px;
+ border-top: 1px solid var(--wxex-border);
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-endpoint-row.active {
+ background: #f7faf8;
+}
+.api-endpoint-row code {
+ color: var(--wxex-text-primary);
+ font:
+ 12px/18px ui-monospace,
+ monospace;
+}
+.api-endpoint-row small {
+ display: block;
+ color: var(--wxex-text-muted);
+}
+.api-endpoint-row > span:last-child {
+ display: flex;
+ gap: 4px;
+}
+.api-endpoint-row button {
+ min-height: 26px;
+ padding: 0 7px;
+ font-size: 11px;
+}
+.api-method {
+ display: inline-block;
+ color: var(--wxex-brand);
+ font:
+ 700 11px/18px ui-monospace,
+ monospace;
+}
+.api-method.post {
+ color: var(--wxex-ai);
+}
+.api-request-meta {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin: 12px 0;
+ padding: 10px 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: #f5f8f6;
+ overflow: hidden;
+}
+.api-request-meta code {
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font:
+ 12px/18px ui-monospace,
+ monospace;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.api-param-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 10px;
+}
+.api-param-grid label,
+.api-json-input {
+ display: grid;
+ gap: 5px;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-param-grid label span b {
+ margin-left: 5px;
+ color: var(--wxex-danger);
+ font-size: 11px;
+}
+.api-param-grid input,
+.api-json-input textarea {
+ box-sizing: border-box;
+ width: 100%;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ outline: none;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-param-grid input {
+ height: 34px;
+ padding: 0 9px;
+}
+.api-json-input {
+ margin-top: 10px;
+}
+.api-json-input textarea {
+ min-height: 180px;
+ padding: 10px;
+ resize: vertical;
+ font-family: ui-monospace, monospace;
+}
+.api-tester-actions {
+ justify-content: flex-end;
+ margin-top: 12px;
+}
+.api-inline-error {
+ margin: 10px 0 0;
+ padding: 8px 10px;
+ border: 1px solid rgba(200, 90, 90, 0.35);
+ border-radius: var(--wxex-radius-sm);
+ background: #fff4f4;
+ color: var(--wxex-danger);
+ font: 12px/18px var(--wxex-font);
+}
+.api-runtime-panel {
+ border-left: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+ overflow: hidden;
+}
+.api-runtime-scroll {
+ height: 100%;
+ overflow-y: auto;
+}
+.api-runtime-scroll section {
+ padding: 18px 16px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+.api-runtime-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+}
+.api-runtime-title > span {
+ font: 700 12px/18px var(--wxex-font);
+}
+.api-runtime-title .ready {
+ color: var(--wxex-success);
+}
+.api-runtime-title .stopped {
+ color: var(--wxex-text-muted);
+}
+.api-runtime-scroll h3 {
+ margin: 0 0 12px;
+ color: var(--wxex-text-primary);
+ font: 700 14px/20px var(--wxex-font);
+}
+.api-runtime-scroll dl {
+ margin: 14px 0;
+}
+.api-runtime-scroll dl div {
+ display: flex;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 5px 0;
+ font: 12px/18px var(--wxex-font);
+}
+.api-runtime-scroll dt {
+ color: var(--wxex-text-secondary);
+}
+.api-runtime-scroll dd {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ text-align: right;
+}
+.warning-text {
+ color: var(--wxex-warning);
+}
+.api-runtime-actions {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+}
+.api-runtime-actions button {
+ min-height: 30px;
+ padding: 0 6px;
+}
+.api-security-warning {
+ margin: 12px 16px;
+ padding: 9px 10px;
+ border-left: 3px solid var(--wxex-warning);
+ background: #fff8ec;
+ color: #915d1e;
+ font: 12px/18px var(--wxex-font);
+}
+.api-response-summary {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ color: var(--wxex-text-primary);
+ font:
+ 12px/18px ui-monospace,
+ monospace;
+}
+.api-runtime-scroll pre {
+ max-height: 180px;
+ overflow: auto;
+ margin: 10px 0 8px;
+ padding: 10px;
+ border-radius: var(--wxex-radius-sm);
+ background: #1f2824;
+ color: #cde7dc;
+ font:
+ 11px/16px ui-monospace,
+ monospace;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+.api-response-meta,
+.api-empty-text {
+ margin: 0 0 9px;
+ color: var(--wxex-text-muted);
+ font: 11px/17px var(--wxex-font);
+}
+.api-history {
+ display: grid;
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.api-history li {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 2px 8px;
+ padding-bottom: 8px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+.api-history span {
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font:
+ 11px/17px ui-monospace,
+ monospace;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.api-history b {
+ font: 700 11px/17px var(--wxex-font);
+}
+.api-history small {
+ grid-column: 1 / -1;
+ color: var(--wxex-text-muted);
+ font: 11px/16px var(--wxex-font);
+}
+.api-privacy {
+ background: #f5f8f6;
+}
+.api-privacy p {
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.api-markdown-overlay {
+ position: absolute;
+ inset: 0;
+ z-index: 4;
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ padding: 20px;
+ background: rgba(32, 39, 36, 0.24);
+}
+.api-markdown-overlay > div {
+ display: flex;
+ width: min(820px, 100%);
+ flex-direction: column;
+ min-height: 0;
+ padding: 14px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-lg);
+ background: #fff;
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.16);
+}
+.api-markdown-overlay header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+.api-markdown-overlay header > div {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.api-markdown-overlay header span {
+ color: var(--wxex-text-muted);
+ font: 12px/18px var(--wxex-font);
+}
+.api-markdown-overlay button {
+ min-height: 30px;
+ padding: 0 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: #fff;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+}
+.api-markdown-overlay pre,
+.skill-markdown-preview {
+ min-height: 0;
+ overflow: auto;
+ margin: 14px 0 0;
+ white-space: pre-wrap;
+ color: var(--wxex-text-primary);
+ font: 12px/19px var(--wxex-font);
+}
+.skill-markdown-preview h1 {
+ font-size: 20px;
+}
+.skill-markdown-preview h2 {
+ margin-top: 18px;
+ font-size: 16px;
+}
+.skill-markdown-preview p {
+ margin: 6px 0;
+}
+.skill-markdown-preview li {
+ margin-left: 18px;
+}
diff --git a/src/renderer/src/styles/archive.css b/src/renderer/src/styles/archive.scss
similarity index 53%
rename from src/renderer/src/styles/archive.css
rename to src/renderer/src/styles/archive.scss
index dbb84fb..91c0d6f 100644
--- a/src/renderer/src/styles/archive.css
+++ b/src/renderer/src/styles/archive.scss
@@ -1,10 +1,10 @@
.archive-jump-target-group {
z-index: 2;
-}
-.archive-jump-message {
- z-index: 1;
- animation: archive-jump-flash 0.72s ease-in-out 2;
+ .archive-jump-message {
+ z-index: 1;
+ animation: archive-jump-flash 0.72s ease-in-out 2;
+ }
}
@keyframes archive-jump-flash {
@@ -20,9 +20,11 @@
}
@media (prefers-reduced-motion: reduce) {
- .archive-jump-message {
- outline: 3px solid rgba(38, 128, 103, 0.58);
- outline-offset: 5px;
- animation: none;
+ .archive-jump-target-group {
+ .archive-jump-message {
+ outline: 3px solid rgba(38, 128, 103, 0.58);
+ outline-offset: 5px;
+ animation: none;
+ }
}
}
diff --git a/src/renderer/src/styles/chat.scss b/src/renderer/src/styles/chat.scss
new file mode 100644
index 0000000..6914cb7
--- /dev/null
+++ b/src/renderer/src/styles/chat.scss
@@ -0,0 +1,1843 @@
+.chat-window {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ background-color: var(--wxex-bg-main);
+ height: 100%;
+ min-height: 0;
+ min-width: 0;
+ color: var(--wxex-text-primary);
+ overflow: hidden;
+
+ &.empty {
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+.chat-archive-header {
+ box-sizing: border-box;
+ min-height: 70px;
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ border-bottom: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+ padding: 12px 18px;
+ -webkit-app-region: drag;
+}
+
+.chat-title-block {
+ min-width: 0;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.chat-title-avatar {
+ width: 42px;
+ height: 42px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ overflow: hidden;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ font-size: 15px;
+ font-weight: 700;
+
+ img {
+ width: 100%;
+ height: 100%;
+ display: block;
+ object-fit: cover;
+ }
+}
+
+.chat-title-text {
+ min-width: 0;
+
+ h2 {
+ overflow: hidden;
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 19px;
+ font-weight: 700;
+ line-height: 26px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+}
+
+.chat-title-meta {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 18px;
+
+ span + span::before {
+ content: '';
+ display: inline-block;
+ width: 3px;
+ height: 3px;
+ margin-right: 8px;
+ border-radius: 999px;
+ background: var(--wxex-text-muted);
+ vertical-align: middle;
+ }
+}
+
+.chat-header-actions {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 8px;
+ flex: 0 0 auto;
+ -webkit-app-region: no-drag;
+}
+
+.chat-icon-button,
+.chat-tool-button,
+.chat-ai-button {
+ box-sizing: border-box;
+ height: 32px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ border: 1px solid transparent;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 13px/18px var(--wxex-font);
+}
+
+.chat-icon-button {
+ width: 32px;
+ padding: 0;
+}
+
+.chat-tool-button {
+ padding: 0 9px;
+ border-color: var(--wxex-border);
+ background: var(--wxex-bg-elevated);
+}
+
+.chat-icon-button:hover,
+.chat-tool-button:hover {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+}
+
+.chat-tool-button:disabled,
+.chat-ai-button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+}
+
+.chat-ai-button {
+ padding: 0 12px;
+ border-color: var(--wxex-ai);
+ background: var(--wxex-ai);
+ color: #ffffff;
+ font-weight: 600;
+}
+
+.chat-ai-button:hover:not(:disabled) {
+ background: #5a60c6;
+}
+
+.chat-icon-button svg,
+.chat-tool-button svg,
+.chat-ai-button svg,
+.chat-content-search svg,
+.data-trust-bar svg {
+ width: 17px;
+ height: 17px;
+}
+
+.chat-icon-button path,
+.chat-tool-button path,
+.chat-ai-button path,
+.chat-content-search path,
+.data-trust-bar path,
+.chat-icon-button circle,
+.chat-tool-button circle,
+.chat-ai-button circle,
+.chat-content-search circle,
+.data-trust-bar circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.chat-menu {
+ position: relative;
+}
+
+.chat-dropdown-menu {
+ position: absolute;
+ top: calc(100% + 6px);
+ left: 0;
+ z-index: 40;
+ min-width: 150px;
+ overflow: hidden;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ box-shadow: var(--wxex-shadow-popover);
+ padding: 4px;
+
+ &.right {
+ right: 0;
+ left: auto;
+ }
+
+ button {
+ box-sizing: border-box;
+ width: 100%;
+ display: block;
+ border: 0;
+ border-radius: var(--wxex-radius-sm);
+ background: transparent;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 13px/18px var(--wxex-font);
+ padding: 7px 9px;
+ text-align: left;
+ white-space: nowrap;
+
+ &:hover {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ }
+ }
+}
+
+.chat-content-search {
+ box-sizing: border-box;
+ width: 280px;
+ height: 34px;
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ padding: 0 5px 0 10px;
+ color: var(--wxex-text-muted);
+
+ input {
+ min-width: 0;
+ flex: 1;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: 13px/18px var(--wxex-font);
+ }
+
+ svg {
+ width: 17px;
+ height: 17px;
+ }
+
+ path,
+ circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ }
+}
+
+.chat-content-search-count {
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ white-space: nowrap;
+}
+
+.data-trust-bar {
+ box-sizing: border-box;
+ min-height: 34px;
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ border-bottom: 1px solid var(--wxex-border);
+ background: #f3f6f4;
+ color: var(--wxex-text-secondary);
+ padding: 0 18px;
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.data-trust-left,
+.data-trust-right,
+.data-trust-item {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.data-trust-right {
+ flex-wrap: wrap;
+ justify-content: flex-end;
+}
+
+.data-trust-item {
+ color: var(--wxex-success);
+}
+
+.data-trust-dot {
+ width: 3px;
+ height: 3px;
+ border-radius: 999px;
+ background: var(--wxex-text-muted);
+}
+
+.message-list {
+ flex: 1;
+ overflow-y: auto;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.wechat-message-list {
+ min-height: 0;
+ padding: 18px 28px 24px;
+ background: #f0f2ef;
+}
+
+.virtual-message-list {
+ position: relative;
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.virtual-message-group {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: flow-root;
+ width: 100%;
+}
+
+.wechat-message-row {
+ margin-bottom: 14px;
+}
+
+.message-loading-pill {
+ align-self: center;
+ margin: 0 0 12px;
+ padding: 5px 12px;
+ border-radius: var(--wxex-radius-md);
+ background: rgba(255, 255, 255, 0.78);
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+.wechat-message-row {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ width: 100%;
+
+ &.mine {
+ justify-content: flex-end;
+
+ .message-stack {
+ align-items: flex-end;
+ }
+
+ .message-bubble-wrap {
+ align-items: flex-end;
+ }
+
+ .message-bubble {
+ border-color: rgba(36, 122, 99, 0.16);
+ background: #e7f2ee;
+ color: var(--wxex-text-primary);
+ }
+
+ .message-hover-time {
+ right: calc(100% + 8px);
+ left: auto;
+ }
+
+ .image-message-bubble {
+ background: transparent;
+ }
+
+ .video-message-bubble {
+ background: #101412;
+ }
+
+ .voice-icon {
+ background: rgba(36, 122, 99, 0.14);
+ }
+
+ .quoted-message {
+ background: rgba(255, 255, 255, 0.18);
+ color: rgba(255, 255, 255, 0.82);
+ }
+ }
+
+ &.other {
+ .quoted-message {
+ background: #f0f0f0;
+ color: #666;
+ }
+ }
+}
+
+.wechat-system-message-row {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+ margin: 2px 0 6px;
+}
+
+.wechat-system-message {
+ max-width: min(78%, 760px);
+ padding: 6px 12px;
+ border-radius: var(--wxex-radius-md);
+ background: rgba(255, 255, 255, 0.72);
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 1.5;
+ text-align: center;
+ word-break: break-word;
+}
+
+.wechat-system-message-meta {
+ color: #a0a7ab;
+ font-size: 11px;
+}
+
+.message-avatar {
+ width: 38px;
+ height: 38px;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ flex: 0 0 38px;
+ font-size: 13px;
+}
+
+.mine-avatar {
+ background: var(--wxex-brand-soft);
+}
+
+.message-avatar-spacer {
+ width: 38px;
+ flex: 0 0 38px;
+}
+
+.message-stack {
+ max-width: min(70%, 760px);
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.message-sender-name {
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ margin: 0 0 4px 2px;
+}
+
+.message-bubble-wrap {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ margin-top: 4px;
+
+ &.is-followup {
+ margin-top: 2px;
+ }
+
+ &:hover {
+ .message-hover-time {
+ visibility: visible;
+ opacity: 1;
+ }
+ }
+}
+
+.message-bubble {
+ position: relative;
+ padding: 9px 13px;
+ border: 1px solid rgba(221, 227, 224, 0.74);
+ border-radius: var(--wxex-radius-md);
+ background: #ffffff;
+ color: var(--wxex-text-primary);
+ font-size: 14px;
+ line-height: 1.55;
+ word-break: break-word;
+
+ &::before {
+ display: none;
+ }
+}
+
+.message-meta {
+ display: none;
+}
+
+.message-hover-time,
+.message-accessible-sender {
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+}
+
+.message-recalled-status {
+ align-self: flex-end;
+ margin-top: 3px;
+ color: #c63c32;
+ font-size: 11px;
+ font-weight: 600;
+ line-height: 16px;
+}
+
+.message-hover-time {
+ position: absolute;
+ top: 50%;
+ left: calc(100% + 8px);
+ z-index: 1;
+ visibility: hidden;
+ opacity: 0;
+ pointer-events: none;
+ transform: translateY(-50%);
+ transition: opacity 0.12s ease;
+ white-space: nowrap;
+}
+
+.message-accessible-sender {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip: rect(0 0 0 0);
+}
+
+.chat-time-separator {
+ align-self: center;
+ margin: 8px 0 12px;
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.message-text {
+ min-width: 0;
+}
+
+.inline-wechat-emoji {
+ display: inline-block;
+ margin: 0 1px;
+ vertical-align: -5px;
+ object-fit: contain;
+}
+
+.voice-bubble {
+ min-width: 138px;
+}
+
+.image-message-bubble {
+ padding: 0;
+ overflow: hidden;
+ background: transparent;
+ box-shadow: none;
+ white-space: normal;
+}
+
+.wechat-message-row.mine .image-message-bubble {
+ background: transparent;
+}
+
+.image-message-bubble::before {
+ display: none;
+}
+
+.video-message-bubble {
+ padding: 0;
+ overflow: hidden;
+ background: #101412;
+ border-color: rgba(0, 0, 0, 0.12);
+}
+
+.wechat-message-row.mine .video-message-bubble {
+ background: #101412;
+}
+
+.video-message {
+ position: relative;
+ width: min(320px, 48vw);
+ min-height: 140px;
+ background: #101412;
+}
+
+.video-content {
+ display: block;
+ width: 100%;
+ max-height: 360px;
+ object-fit: contain;
+ background: #101412;
+}
+
+.video-duration {
+ position: absolute;
+ right: 8px;
+ top: 8px;
+ padding: 2px 6px;
+ border-radius: 8px;
+ color: #fff;
+ background: rgba(0, 0, 0, 0.55);
+ font-size: 11px;
+ pointer-events: none;
+}
+
+.video-placeholder {
+ display: grid;
+ place-items: center;
+ width: min(260px, 44vw);
+ min-height: 120px;
+ padding: 16px;
+ color: rgba(255, 255, 255, 0.78);
+ text-align: center;
+}
+
+.image-bubble {
+ position: relative;
+ max-width: min(260px, 46vw);
+ max-height: 220px;
+ min-width: 96px;
+ min-height: 72px;
+ border-radius: var(--wxex-radius-md);
+ overflow: hidden;
+ background: #fff;
+ cursor: zoom-in;
+ border: 1px solid var(--wxex-border);
+
+ &:hover {
+ .image-actions {
+ opacity: 1;
+ }
+ }
+}
+.image-bubble .image-content {
+ display: block;
+ max-width: min(260px, 46vw);
+ max-height: 220px;
+ width: auto;
+ height: auto;
+ object-fit: contain;
+ background: #f7f7f7;
+}
+
+.image-loading,
+.image-placeholder,
+.image-error {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ padding: 14px 18px;
+ color: var(--wxex-text-secondary);
+ font-size: 13px;
+}
+
+.image-loading-skeleton {
+ width: 110px;
+ height: 72px;
+ border-radius: var(--wxex-radius-md);
+ background: linear-gradient(90deg, #edf1ef 0%, #f7f8f7 50%, #edf1ef 100%);
+ background-size: 200% 100%;
+ animation: image-skeleton-shimmer 1.2s linear infinite;
+}
+
+.image-actions {
+ position: absolute;
+ right: 6px;
+ bottom: 6px;
+ opacity: 0;
+ transition: opacity 0.15s ease;
+}
+
+.image-quality-badge {
+ position: absolute;
+ right: 6px;
+ bottom: 6px;
+ max-width: calc(100% - 12px);
+ padding: 3px 6px;
+ border-radius: 5px;
+ background: rgba(0, 0, 0, 0.5);
+ color: #fff;
+ font-size: 11px;
+ line-height: 1.3;
+ pointer-events: none;
+}
+
+@keyframes image-skeleton-shimmer {
+ 0% {
+ background-position: 200% 0;
+ }
+ 100% {
+ background-position: -200% 0;
+ }
+}
+
+.image-action-btn {
+ border: 0;
+ border-radius: 5px;
+ background: rgba(0, 0, 0, 0.48);
+ color: #fff;
+ cursor: pointer;
+ padding: 4px 6px;
+}
+
+.voice-message {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ white-space: nowrap;
+}
+
+.voice-icon {
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(36, 122, 99, 0.12);
+ color: var(--wxex-brand);
+ font-size: 10px;
+ line-height: 1;
+}
+
+.wechat-message-row.mine .voice-icon {
+ background: rgba(36, 122, 99, 0.14);
+}
+
+.voice-error {
+ color: var(--wxex-text-secondary);
+}
+
+.voice-error-text {
+ color: var(--wxex-text-secondary);
+}
+
+.voice-bars {
+ display: inline-flex;
+ align-items: center;
+ gap: 3px;
+ height: 16px;
+
+ i {
+ width: 3px;
+ border-radius: 3px;
+ background: currentColor;
+ opacity: 0.75;
+
+ &:nth-child(1) {
+ height: 7px;
+ }
+
+ &:nth-child(2) {
+ height: 13px;
+ }
+
+ &:nth-child(3) {
+ height: 9px;
+ }
+ }
+}
+
+.sticker-message {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ align-items: flex-start;
+}
+
+.sticker-image {
+ display: block;
+ max-width: 140px;
+ max-height: 140px;
+ border-radius: 6px;
+ object-fit: contain;
+}
+
+.sticker-placeholder {
+ color: #666;
+ font-size: 14px;
+}
+
+.sticker-md5 {
+ max-width: 180px;
+ color: #999;
+ font-size: 11px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.quote-message {
+ min-width: 160px;
+ max-width: 320px;
+}
+
+.quoted-message {
+ display: flex;
+ gap: 4px;
+ max-width: 100%;
+ margin-bottom: 8px;
+ padding: 6px 8px;
+ border-radius: 4px;
+ background: rgba(255, 255, 255, 0.18);
+ color: rgba(255, 255, 255, 0.82);
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+.wechat-message-row.other .quoted-message {
+ background: #f0f0f0;
+ color: #666;
+}
+
+.quoted-sender {
+ flex: 0 1 auto;
+ min-width: 0;
+ font-weight: 600;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ &::after {
+ content: ':';
+ }
+}
+
+.quoted-text {
+ flex: 0 0 auto;
+}
+
+.quote-reply {
+ font-size: 14px;
+ line-height: 1.5;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.chat-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 13px;
+
+ th {
+ text-align: left;
+ padding: 8px;
+ border-bottom: 1px solid var(--border-color);
+ background-color: #f9f9f9;
+ color: #666;
+ font-weight: normal;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ position: relative;
+ }
+
+ td {
+ padding: 8px;
+ border-bottom: 1px solid #eee;
+ vertical-align: top;
+ color: #333;
+ }
+
+ tr:hover {
+ background-color: #f0f0f0;
+ }
+}
+
+.column-resizer {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ width: 5px;
+ cursor: col-resize;
+ z-index: 2;
+}
+
+.column-resizer:hover {
+ background-color: #ccc;
+}
+
+.col-sender {
+ width: 80px;
+}
+
+.col-type {
+ width: 80px;
+}
+
+.col-time {
+ width: 150px;
+}
+
+.col-content {
+}
+
+.chat-toolbar {
+ padding: 10px;
+ border-top: 1px solid var(--border-color);
+ display: flex;
+ gap: 10px;
+ background-color: #fff;
+ flex-wrap: wrap;
+
+ .toolbar-btn {
+ padding: 4px 12px;
+ border: 1px solid #dcdcdc;
+ border-radius: 4px;
+ background-color: #fff;
+ font-size: 12px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+
+ &:hover {
+ background-color: #f5f5f5;
+ }
+ }
+}
+
+.empty-state {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ color: #999;
+}
+
+.chat-status-bar {
+ box-sizing: border-box;
+ min-height: 38px;
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ border-top: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+ color: var(--wxex-text-secondary);
+ padding: 0 18px;
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.chat-status-actions {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 10px;
+
+ button {
+ border: 0;
+ background: transparent;
+ color: var(--wxex-brand);
+ cursor: pointer;
+ font: 12px/18px var(--wxex-font);
+ padding: 0;
+
+ &:hover {
+ color: var(--wxex-brand-hover);
+ }
+
+ &:disabled {
+ color: var(--wxex-text-muted);
+ cursor: default;
+ }
+ }
+}
+
+.chat-avatar-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ white-space: nowrap;
+}
+
+.chat-avatar-toggle input {
+ margin: 0;
+ accent-color: var(--wxex-brand);
+}
+
+.chat-avatar-note {
+ max-width: 320px;
+ color: var(--wxex-text-muted);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.chat-avatar-reload {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ white-space: nowrap;
+}
+
+.chat-avatar-reload svg {
+ width: 14px;
+ height: 14px;
+ fill: none;
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 1.8;
+}
+
+.chat-avatar-reload svg.is-spinning {
+ animation: chat-avatar-spin 0.8s linear infinite;
+}
+
+@keyframes chat-avatar-spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.chat-status-separator {
+ width: 1px;
+ height: 14px;
+ background: var(--wxex-border);
+}
+
+@media (max-width: 1120px) {
+ .chat-avatar-note {
+ display: none;
+ }
+}
+
+.empty-conversation-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ color: var(--wxex-text-secondary);
+ text-align: center;
+
+ h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 20px;
+ line-height: 28px;
+ }
+
+ p {
+ margin: 0;
+ color: var(--wxex-text-muted);
+ font-size: 13px;
+ line-height: 20px;
+ }
+}
+
+.database-login-page {
+ --login-primary: #247a63;
+ --login-primary-dark: #00604c;
+ --login-border: #d7dfda;
+ --login-surface: #f7faf6;
+ --login-surface-low: #f1f4f1;
+ --login-text: #181c1b;
+ --login-muted: #5f6965;
+ width: 100vw;
+ min-width: 760px;
+ height: 100vh;
+ min-height: 560px;
+ display: grid;
+ grid-template-columns: minmax(300px, 40%) 1fr;
+ overflow: hidden;
+ color: var(--login-text);
+ background: #fff;
+}
+
+.database-login-brand {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ padding: clamp(36px, 6vh, 72px) clamp(36px, 5vw, 72px) 28px;
+ background: var(--login-surface-low);
+ border-right: 1px solid var(--login-border);
+}
+
+.database-login-brand-content {
+ width: min(360px, 100%);
+ margin: auto 0;
+}
+
+.database-login-logo {
+ width: 56px;
+ height: 56px;
+ display: grid;
+ place-items: center;
+ margin-bottom: 24px;
+ border-radius: 10px;
+ color: #fff;
+ background: var(--login-primary-dark);
+ box-shadow: 0 4px 12px rgba(0, 96, 76, 0.12);
+}
+
+.database-login-logo svg {
+ width: 29px;
+ height: 29px;
+}
+
+.database-login-brand h1 {
+ margin: 0;
+ font-size: 25px;
+ line-height: 32px;
+ font-weight: 650;
+ letter-spacing: -0.02em;
+ color: var(--login-primary-dark);
+}
+
+.database-login-tagline {
+ margin: 4px 0 26px;
+ color: var(--login-primary);
+ font-size: 14px;
+ line-height: 22px;
+ font-weight: 600;
+}
+
+.database-login-description {
+ max-width: 320px;
+ margin: 0 0 30px;
+ color: var(--login-muted);
+ font-size: 13px;
+ line-height: 21px;
+}
+
+.database-login-promises {
+ display: grid;
+ gap: 10px;
+}
+
+.database-login-promises > div {
+ min-height: 44px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 0 14px;
+ border: 1px solid rgba(190, 201, 195, 0.62);
+ border-radius: 7px;
+ color: #35423d;
+ background: rgba(255, 255, 255, 0.42);
+ font-size: 13px;
+ font-weight: 550;
+}
+
+.database-login-promises svg {
+ width: 18px;
+ height: 18px;
+ color: var(--login-primary);
+}
+
+.database-login-brand-footer {
+ margin-top: auto;
+ padding-top: 24px;
+ color: #78827e;
+ font-family: 'Work Sans', Inter, sans-serif;
+ font-size: 10px;
+ font-weight: 650;
+ letter-spacing: 0.11em;
+}
+
+.database-login-workspace {
+ display: grid;
+ place-items: center;
+ min-width: 0;
+ padding: 48px clamp(40px, 7vw, 96px);
+ background: #fff;
+}
+
+.database-login-panel {
+ width: min(520px, 100%);
+}
+
+.database-login-tabs {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 4px;
+ padding: 4px;
+ margin-bottom: 28px;
+ border: 1px solid var(--login-border);
+ border-radius: 8px;
+ background: #e9eeeb;
+}
+
+.database-login-tabs button {
+ min-height: 38px;
+ border: 0;
+ border-radius: 5px;
+ color: #66716c;
+ background: transparent;
+ cursor: pointer;
+ font-size: 13px;
+ font-weight: 550;
+}
+
+.database-login-tabs button.active {
+ color: var(--login-primary-dark);
+ background: #fff;
+ box-shadow: 0 1px 3px rgba(24, 28, 27, 0.08);
+}
+
+.database-login-state-card {
+ padding: 18px;
+ border: 1px solid var(--login-border);
+ border-radius: 9px;
+ background: var(--login-surface);
+}
+
+.database-login-state-card.error {
+ border-color: #efc4be;
+ border-left: 3px solid #ba1a1a;
+ background: #fff9f8;
+}
+
+.database-login-state-heading {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 18px;
+}
+
+.database-login-state-icon {
+ flex: 0 0 auto;
+ width: 30px;
+ height: 30px;
+ display: grid;
+ place-items: center;
+ border-radius: 50%;
+ color: var(--login-primary);
+ background: #e2f0eb;
+}
+
+.database-login-state-card.error .database-login-state-icon {
+ color: #ba1a1a;
+ background: #ffebe8;
+}
+
+.database-login-state-icon svg {
+ width: 17px;
+ height: 17px;
+}
+
+.database-login-state-heading strong {
+ display: block;
+ margin: 1px 0 4px;
+ font-size: 14px;
+ line-height: 20px;
+}
+
+.database-login-state-heading p {
+ margin: 0;
+ color: var(--login-muted);
+ font-size: 12px;
+ line-height: 18px;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.database-login-diagnostics {
+ margin: 0;
+ border-top: 1px solid #e2e7e4;
+}
+
+.database-login-diagnostics > div {
+ min-height: 43px;
+ display: grid;
+ grid-template-columns: 112px 1fr;
+ align-items: center;
+ border-bottom: 1px solid #e2e7e4;
+}
+
+.database-login-diagnostics > div:last-child {
+ border-bottom: 0;
+}
+
+.database-login-diagnostics dt {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: #6e7874;
+ font-family: 'Work Sans', Inter, sans-serif;
+ font-size: 10px;
+ font-weight: 650;
+ letter-spacing: 0.04em;
+}
+
+.database-login-diagnostics dd {
+ min-width: 0;
+ margin: 0;
+ color: #35423d;
+ font-size: 12px;
+ text-align: right;
+}
+
+.database-login-path-input-wrap {
+ position: relative;
+ display: block;
+ width: 100%;
+}
+
+.database-login-diagnostics input {
+ width: 100%;
+ height: 36px;
+ padding: 7px 0;
+ border: 0;
+ outline: 0;
+ color: #4c5752;
+ background: transparent;
+ font: inherit;
+ text-align: right;
+ text-overflow: ellipsis;
+}
+
+.database-login-path-value {
+ position: absolute;
+ right: 0;
+ bottom: calc(100% + 7px);
+ z-index: 25;
+ width: min(520px, calc(100vw - 48px));
+ padding: 9px 11px;
+ border: 1px solid #d7dfda;
+ border-radius: 7px;
+ color: #35423d;
+ background: #fff;
+ box-shadow: 0 6px 18px rgba(24, 28, 27, 0.13);
+ font-size: 11px;
+ line-height: 17px;
+ text-align: left;
+ overflow-wrap: anywhere;
+ opacity: 0;
+ pointer-events: none;
+ transform: translateY(4px);
+ transition:
+ opacity 120ms ease,
+ transform 120ms ease;
+}
+
+.database-login-path-input-wrap:hover .database-login-path-value,
+.database-login-path-input-wrap:focus-within .database-login-path-value {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.database-login-primary,
+.database-login-secondary {
+ width: 100%;
+ min-height: 44px;
+ margin-top: 22px;
+ border-radius: 7px;
+ cursor: pointer;
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.database-login-primary {
+ border: 1px solid var(--login-primary);
+ color: #fff;
+ background: var(--login-primary);
+ box-shadow: 0 2px 5px rgba(0, 96, 76, 0.16);
+}
+
+.database-login-primary:hover:not(:disabled) {
+ border-color: var(--login-primary-dark);
+ background: var(--login-primary-dark);
+}
+
+.database-login-primary:disabled {
+ cursor: not-allowed;
+ opacity: 0.52;
+ box-shadow: none;
+}
+
+.database-login-auto > a {
+ display: block;
+ margin-top: 16px;
+ color: var(--login-primary);
+ font-size: 12px;
+ text-align: center;
+ text-decoration: none;
+}
+
+.database-login-manual {
+ padding-top: 2px;
+}
+
+.database-login-field {
+ margin-bottom: 20px;
+}
+
+.database-login-field > label {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ margin-bottom: 8px;
+ color: #35423d;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.database-login-path-help {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+}
+
+.database-login-path-help-icon {
+ width: 15px;
+ height: 15px;
+ display: inline-grid;
+ place-items: center;
+ border: 1px solid #9a6b18;
+ border-radius: 50%;
+ color: #8a5d0b;
+ background: #fff8e6;
+ cursor: help;
+ font-family: Inter, sans-serif;
+ font-size: 10px;
+ font-weight: 700;
+ line-height: 1;
+}
+
+.database-login-path-tooltip {
+ position: absolute;
+ left: 50%;
+ bottom: calc(100% + 9px);
+ z-index: 20;
+ width: 260px;
+ padding: 9px 11px;
+ border: 1px solid #d7dfda;
+ border-radius: 7px;
+ color: #35423d;
+ background: #fff;
+ box-shadow: 0 6px 18px rgba(24, 28, 27, 0.12);
+ font-family: Inter, sans-serif;
+ font-size: 11px;
+ font-weight: 400;
+ line-height: 17px;
+ letter-spacing: 0;
+ opacity: 0;
+ pointer-events: none;
+ transform: translate(-50%, 4px);
+ transition:
+ opacity 120ms ease,
+ transform 120ms ease;
+}
+
+.database-login-path-help:hover .database-login-path-tooltip,
+.database-login-path-help:focus-within .database-login-path-tooltip {
+ opacity: 1;
+ transform: translate(-50%, 0);
+}
+
+.database-login-field > input,
+.database-login-key-input {
+ width: 100%;
+ min-height: 42px;
+ border: 1px solid var(--login-border);
+ border-radius: 7px;
+ background: #fff;
+}
+
+.database-login-field > input {
+ padding: 0 12px;
+ color: var(--login-text);
+ font-size: 13px;
+ outline: none;
+}
+
+.database-login-key-input {
+ display: flex;
+ align-items: center;
+}
+
+.database-login-key-input:focus-within,
+.database-login-field > input:focus {
+ border-color: var(--login-primary);
+ box-shadow: 0 0 0 3px rgba(36, 122, 99, 0.1);
+}
+
+.database-login-key-input input {
+ flex: 1;
+ min-width: 0;
+ height: 40px;
+ padding: 0 4px 0 12px;
+ border: 0;
+ outline: 0;
+ color: var(--login-text);
+ background: transparent;
+ font-size: 13px;
+}
+
+.database-login-key-input button {
+ width: 38px;
+ height: 38px;
+ display: grid;
+ place-items: center;
+ border: 0;
+ color: #65706b;
+ background: transparent;
+ cursor: pointer;
+}
+
+.database-login-key-input svg {
+ width: 18px;
+ height: 18px;
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.database-login-field small {
+ display: block;
+ margin-top: 7px;
+ color: #77817d;
+ font-size: 11px;
+}
+
+.database-login-message {
+ padding: 10px 12px;
+ border-radius: 7px;
+ color: #57625d;
+ background: var(--login-surface-low);
+ font-size: 12px;
+ line-height: 18px;
+ white-space: pre-wrap;
+}
+
+.database-login-message.success {
+ color: var(--login-primary-dark);
+ background: #edf7f3;
+}
+
+.database-login-message.error {
+ color: #93000a;
+ background: #fff0ee;
+}
+
+.database-login-secondary {
+ margin-top: 10px;
+ border: 1px solid var(--login-border);
+ color: #3f4945;
+ background: #fff;
+}
+
+.database-login-secondary:hover {
+ border-color: var(--login-primary);
+ color: var(--login-primary-dark);
+ background: var(--login-surface);
+}
+
+.database-login-footer-actions {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 42px;
+ padding-top: 16px;
+ border-top: 1px solid #e5e9e6;
+ color: #8a938f;
+ font-size: 11px;
+}
+
+.database-login-footer-actions button {
+ padding: 0;
+ border: 0;
+ color: #78827e;
+ background: transparent;
+ cursor: pointer;
+ font-size: 11px;
+}
+
+.database-login-footer-actions button:hover {
+ color: #93000a;
+}
+
+@media (max-width: 900px), (max-height: 620px) {
+ .database-login-brand {
+ padding: 30px;
+ }
+
+ .database-login-description {
+ margin-bottom: 20px;
+ }
+
+ .database-login-workspace {
+ padding: 30px;
+ }
+}
+
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1000;
+}
+
+.modal-content {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ min-width: 400px;
+ max-width: 90vw;
+ max-height: 90vh;
+ overflow: auto;
+}
+
+.ai-settings-modal {
+ width: min(460px, 90vw);
+}
+
+.ai-settings-modal h3 {
+ margin: 0 0 18px;
+}
+
+.ai-filter-section {
+ margin-bottom: 16px;
+}
+
+.ai-filter-label {
+ margin-bottom: 7px;
+ color: #333;
+ font-size: 14px;
+ font-weight: 600;
+}
+
+.ai-date-options {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 6px;
+}
+
+.ai-date-options label {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ justify-content: center;
+ gap: 5px;
+ padding: 8px 6px;
+ border: 1px solid #d8dcdf;
+ border-radius: 6px;
+ background: #fff;
+ color: #4a5257;
+ cursor: pointer;
+ font-size: 13px;
+}
+
+.ai-date-options label.selected {
+ border-color: #07c160;
+ background: #eefaf3;
+ color: #078f49;
+}
+
+.ai-date-options input,
+.ai-type-options input {
+ margin: 0;
+ accent-color: #07c160;
+}
+
+.ai-type-options {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 8px 10px;
+ padding: 11px;
+ border: 1px solid #e1e4e6;
+ border-radius: 6px;
+ background: #f8f9fa;
+}
+
+.ai-type-options label {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 6px;
+ color: #3f474c;
+ cursor: pointer;
+ font-size: 13px;
+ white-space: nowrap;
+}
+
+.image-preview-modal {
+ width: min(520px, 92vw);
+ max-height: 88vh;
+ background: #f7f8fa;
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.18);
+ padding: 16px;
+ overflow: hidden;
+}
+
+.report-preview-frame {
+ border: 1px solid #d8dde3;
+ border-radius: 10px;
+ background: #eef1f4;
+ padding: 12px;
+}
+
+.report-preview-scroller {
+ max-height: calc(88vh - 120px);
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding-right: 4px;
+}
+
+.report-preview-image {
+ display: block;
+ width: min(430px, 100%);
+ height: auto;
+ margin: 0 auto;
+ border-radius: 8px;
+ border: 1px solid #ccd3d9;
+ background: #fff;
+}
+
+.report-preview-actions {
+ margin-top: 12px;
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+
+.image-viewer-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 1200;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(16, 24, 28, 0.28);
+ backdrop-filter: blur(1px);
+ overscroll-behavior: contain;
+}
+
+.image-viewer-window {
+ width: min(1280px, 96vw);
+ height: min(900px, 92vh);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ border: 1px solid rgba(0, 0, 0, 0.14);
+ border-radius: 8px;
+ background: #eaf0f1;
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22);
+}
+
+.image-viewer-titlebar {
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 12px 0 16px;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ background: rgba(255, 255, 255, 0.78);
+ color: #333;
+ font-size: 14px;
+
+ button {
+ width: 28px;
+ height: 28px;
+ border: 0;
+ border-radius: 50%;
+ background: transparent;
+ color: #555;
+ cursor: pointer;
+ font-size: 18px;
+ line-height: 1;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.08);
+ }
+ }
+}
+
+.image-viewer-tools {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.image-viewer-title {
+ margin-right: 8px;
+ font-weight: 500;
+}
+
+.image-viewer-zoom {
+ min-width: 44px;
+ color: #666;
+ text-align: center;
+}
+
+.image-viewer-divider {
+ width: 1px;
+ height: 18px;
+ background: rgba(0, 0, 0, 0.12);
+}
+
+.image-viewer-stage {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 28px;
+ overflow: hidden;
+ overscroll-behavior: contain;
+ cursor: grab;
+ user-select: none;
+
+ img {
+ max-width: none;
+ max-height: none;
+ width: auto;
+ height: auto;
+ object-fit: contain;
+ box-shadow: 0 3px 16px rgba(0, 0, 0, 0.12);
+ transform-origin: center center;
+ transition: transform 0.08s ease-out;
+ user-select: none;
+ pointer-events: none;
+ }
+}
diff --git a/src/renderer/src/styles/conversation.scss b/src/renderer/src/styles/conversation.scss
new file mode 100644
index 0000000..a5be2fb
--- /dev/null
+++ b/src/renderer/src/styles/conversation.scss
@@ -0,0 +1,523 @@
+.conversation-sidebar {
+ box-sizing: border-box;
+ display: flex;
+ height: 100%;
+ min-height: 0;
+ flex: 0 0 auto;
+ flex-direction: column;
+ overflow: hidden;
+ border-right: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-sidebar);
+ color: var(--wxex-text-primary);
+}
+
+.conversation-sidebar-header {
+ box-sizing: border-box;
+ flex: 0 0 auto;
+ padding: 16px 14px 12px;
+ border-bottom: 1px solid var(--wxex-border);
+ -webkit-app-region: drag;
+}
+
+.conversation-sidebar-title-row {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 12px;
+ margin-bottom: 12px;
+
+ h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 24px;
+ }
+
+ span {
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 18px;
+ white-space: nowrap;
+ }
+}
+
+.conversation-search {
+ box-sizing: border-box;
+ display: flex;
+ height: 34px;
+ align-items: center;
+ gap: 8px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ padding: 0 10px;
+ color: var(--wxex-text-muted);
+ -webkit-app-region: no-drag;
+
+ &:focus-within {
+ border-color: rgba(36, 122, 99, 0.58);
+ color: var(--wxex-brand);
+ }
+
+ input {
+ width: 100%;
+ min-width: 0;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: 13px/18px var(--wxex-font);
+
+ &::placeholder {
+ color: var(--wxex-text-muted);
+ }
+ }
+}
+
+.conversation-search-icon {
+ width: 17px;
+ height: 17px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+}
+
+.conversation-search-icon svg {
+ width: 17px;
+ height: 17px;
+}
+
+.conversation-search-icon circle,
+.conversation-search-icon path {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.conversation-date-range {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 6px;
+ margin-top: 10px;
+ -webkit-app-region: no-drag;
+}
+
+.conversation-date-range-button {
+ box-sizing: border-box;
+ height: 30px;
+ min-width: 0;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 12px/16px var(--wxex-font);
+ white-space: nowrap;
+
+ &:hover {
+ border-color: rgba(36, 122, 99, 0.28);
+ color: var(--wxex-text-primary);
+ }
+
+ &.active {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #ffffff;
+ font-weight: 600;
+ }
+}
+
+.conversation-list {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ padding: 8px 8px 12px;
+}
+
+.conversation-virtual-content {
+ position: relative;
+ width: 100%;
+}
+
+.conversation-virtual-row {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+}
+
+.conversation-section + .conversation-section {
+ margin-top: 6px;
+}
+
+.conversation-section-header {
+ box-sizing: border-box;
+ width: 100%;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ border: 0;
+ border-radius: var(--wxex-radius-sm);
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 600 12px/16px var(--wxex-font);
+ padding: 0 8px;
+ text-align: left;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.48);
+ color: var(--wxex-text-primary);
+ }
+}
+
+.conversation-section-chevron {
+ width: 16px;
+ height: 16px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+
+ svg {
+ width: 14px;
+ height: 14px;
+ }
+
+ path {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ }
+}
+
+.conversation-section-title {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.conversation-section-list {
+ position: relative;
+ overflow: visible;
+}
+
+.export-config-scroll > .export-section:not(.export-format-top):has(.export-format-grid) {
+ display: none;
+}
+
+.conversation-section-virtual-content {
+ position: relative;
+ width: 100%;
+}
+
+.conversation-section-virtual-row {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ height: 58px;
+}
+
+.conversation-section-empty {
+ padding: 10px 12px 12px 28px;
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.conversation-item {
+ box-sizing: border-box;
+ position: relative;
+ width: 100%;
+ min-height: 58px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border: 0;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font-family: var(--wxex-font);
+ padding: 8px 10px 8px 13px;
+ text-align: left;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.56);
+ }
+
+ &.active {
+ background: var(--wxex-brand-soft);
+
+ .conversation-item-active-mark {
+ background: var(--wxex-brand);
+ }
+ }
+}
+
+.conversation-item-active-mark {
+ position: absolute;
+ top: 10px;
+ bottom: 10px;
+ left: 0;
+ width: 3px;
+ border-radius: 0 999px 999px 0;
+ background: transparent;
+}
+
+.conversation-item-avatar {
+ box-sizing: border-box;
+ width: 40px;
+ height: 40px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ overflow: hidden;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ font-size: 14px;
+ font-weight: 700;
+
+ img {
+ width: 100%;
+ height: 100%;
+ display: block;
+ object-fit: cover;
+ }
+}
+
+.conversation-item-body {
+ min-width: 0;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.conversation-item-name {
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 18px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.conversation-item-meta {
+ overflow: hidden;
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 16px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.conversation-sidebar-account {
+ box-sizing: border-box;
+ flex: 0 0 auto;
+ border-top: 1px solid var(--wxex-border);
+ padding: 10px;
+}
+
+.conversation-sidebar-account .account-summary {
+ min-height: 58px;
+ padding: 8px;
+}
+
+.conversation-sidebar-account .account-summary-text {
+ flex: 1;
+}
+
+.sidebar {
+ background-color: var(--sidebar-bg);
+ border-right: 1px solid var(--border-color);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ min-height: 0;
+ flex-shrink: 0;
+ /* Prevent shrinking */
+}
+
+.sidebar-header {
+ flex: 0 0 auto;
+ padding: 10px;
+ border-bottom: 1px solid var(--border-color);
+ -webkit-app-region: drag;
+}
+
+.sidebar-footer {
+ padding: 10px;
+ border-top: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 14px;
+}
+
+.sidebar-btn {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ color: #666;
+
+ &:hover {
+ color: #333;
+ }
+}
+
+.sidebar-status {
+ color: #07c160;
+ font-size: 12px;
+}
+
+.search-input {
+ width: 100%;
+ padding: 5px;
+ border-radius: 4px;
+ border: 1px solid #ccc;
+ -webkit-app-region: no-drag;
+}
+
+.date-range-selector {
+ display: flex;
+ gap: 5px;
+ margin-top: 8px;
+ justify-content: space-between;
+}
+
+.range-btn {
+ padding: 2px 6px;
+ font-size: 10px;
+ border: 1px solid #ccc;
+ border-radius: 10px;
+ background: #fff;
+ cursor: pointer;
+ color: #666;
+ flex: 1;
+ text-align: center;
+
+ &.active {
+ background: #07c160;
+ color: #fff;
+ border-color: #07c160;
+ }
+}
+
+.contact-list {
+ flex: 1;
+ overflow-y: auto;
+}
+
+.section-header {
+ padding: 8px 10px;
+ background-color: #f0f0f0;
+ font-size: 12px;
+ color: #666;
+ font-weight: bold;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ user-select: none;
+
+ &:hover {
+ background-color: #e0e0e0;
+ }
+
+ .arrow {
+ margin-right: 5px;
+ font-size: 10px;
+ width: 12px;
+ }
+}
+
+.section-empty {
+ padding: 10px 14px 12px 27px;
+ color: #888;
+ font-size: 12px;
+}
+
+.contact-item {
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+
+ &:hover {
+ background-color: var(--sidebar-hover);
+ }
+
+ &.active {
+ background-color: var(--sidebar-active);
+ }
+}
+
+.contact-avatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 4px;
+ background-color: #ccc;
+ margin-right: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 12px;
+ color: #fff;
+ overflow: hidden;
+ flex-shrink: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+.message-avatar {
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+.contact-info {
+ flex: 1;
+ overflow: hidden;
+}
+
+.contact-name {
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.resizer {
+ width: 4px;
+ cursor: col-resize;
+ background-color: transparent;
+ border-right: 1px solid transparent;
+ transition:
+ background-color 0.2s,
+ border-color 0.2s;
+ z-index: 10;
+}
+
+.resizer:hover,
+.resizer:active {
+ border-color: rgba(36, 122, 99, 0.22);
+ background-color: rgba(36, 122, 99, 0.06);
+}
diff --git a/src/renderer/src/styles/export.scss b/src/renderer/src/styles/export.scss
new file mode 100644
index 0000000..42fc60e
--- /dev/null
+++ b/src/renderer/src/styles/export.scss
@@ -0,0 +1,951 @@
+/* Export workspace */
+.export-workspace {
+ display: grid;
+ grid-template-columns: 292px minmax(520px, 1fr) 360px;
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ min-height: 0;
+ background: var(--wxex-bg-main);
+}
+
+.export-contact-panel,
+.export-config-panel,
+.export-preview-panel {
+ min-width: 0;
+ min-height: 0;
+ background: var(--wxex-bg-elevated);
+}
+
+.export-contact-panel {
+ display: flex;
+ flex-direction: column;
+ border-right: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-sidebar);
+}
+
+.export-panel-header {
+ padding: 20px 16px 12px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.export-panel-title-row,
+.export-section-heading,
+.export-preview-heading,
+.export-action-bar,
+.export-target-path,
+.export-media-master,
+.export-account-summary {
+ display: flex;
+ align-items: center;
+}
+
+.export-panel-title-row {
+ justify-content: space-between;
+ gap: 8px;
+ margin-bottom: 14px;
+
+ h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 17px;
+ font-weight: 700;
+ }
+}
+
+.export-count-badge {
+ padding: 3px 8px;
+ border-radius: 5px;
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-secondary);
+ font-size: 11px;
+ white-space: nowrap;
+}
+
+.export-search-field {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ height: 38px;
+ padding: 0 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 7px;
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-muted);
+
+ input {
+ width: 100%;
+ min-width: 0;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: 13px/20px var(--wxex-font);
+ }
+}
+
+.export-filter-tabs {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 3px;
+ margin-top: 12px;
+ padding: 3px;
+ border-radius: 7px;
+ background: #e3e9e5;
+
+ button {
+ border: 0;
+ border-radius: 5px;
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 600 12px/30px var(--wxex-font);
+
+ &.active {
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ box-shadow: 0 1px 2px rgba(32, 39, 36, 0.06);
+ }
+ }
+}
+
+.export-contact-list {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ padding: 8px 0;
+}
+
+.export-contact-item {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ gap: 10px;
+ padding: 11px 16px;
+ border: 0;
+ border-left: 3px solid transparent;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ text-align: left;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.58);
+ }
+
+ &.active {
+ border-left-color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+ }
+}
+
+.export-contact-avatar,
+.export-account-avatar,
+.export-chat-avatar,
+.export-preview-avatar {
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ overflow: hidden;
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ font-weight: 700;
+}
+
+.export-contact-avatar {
+ width: 38px;
+ height: 38px;
+ border-radius: 8px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.export-contact-copy,
+.export-account-summary > span:last-child {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+
+ strong {
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ small {
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ }
+}
+
+.export-account-summary {
+ small.ready {
+ color: var(--wxex-success);
+ }
+}
+
+.export-account-summary {
+ gap: 9px;
+ padding: 14px 16px;
+ border: 0;
+ border-top: 1px solid var(--wxex-border);
+ background: transparent;
+ text-align: left;
+ cursor: pointer;
+}
+
+.export-account-avatar {
+ width: 34px;
+ height: 34px;
+ border-radius: 50%;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.export-config-panel {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+
+.export-config-scroll {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ padding: 24px 28px 28px;
+}
+
+.export-config-header {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ margin-bottom: 26px;
+
+ h1 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 20px;
+ font-weight: 700;
+ line-height: 28px;
+ }
+
+ p {
+ margin: 2px 0 0;
+ color: var(--wxex-text-secondary);
+ font-size: 13px;
+ }
+}
+.export-chat-avatar {
+ width: 52px;
+ height: 52px;
+ border-radius: 10px;
+ font-size: 22px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.export-section {
+ margin-bottom: 25px;
+
+ h3 {
+ margin: 0 0 12px;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+ font-weight: 700;
+ }
+}
+.export-section-heading {
+ justify-content: space-between;
+ gap: 12px;
+
+ span {
+ color: var(--wxex-brand);
+ font-size: 12px;
+ }
+}
+
+.export-range-toggle {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 8px;
+
+ button {
+ border: 0;
+ border-radius: 5px;
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: 600 12px/30px var(--wxex-font);
+ border: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-elevated);
+ line-height: 36px;
+
+ &.active {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+ box-shadow: none;
+ }
+ }
+}
+
+.export-date-fields {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px;
+ margin-top: 10px;
+ padding: 12px;
+ border-radius: 8px;
+ background: #f0f3f0;
+
+ label {
+ display: grid;
+ gap: 5px;
+ color: var(--wxex-text-secondary);
+ font-size: 11px;
+ }
+
+ input {
+ width: 100%;
+ min-width: 0;
+ padding: 8px 9px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 6px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font: 13px/20px var(--wxex-font);
+ }
+}
+
+.export-kind-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 4px 20px;
+ padding: 14px;
+ border-radius: 8px;
+ background: #f0f3f0;
+}
+.export-check-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-height: 28px;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+ cursor: pointer;
+
+ input {
+ width: 16px;
+ height: 16px;
+ accent-color: var(--wxex-brand);
+ }
+
+ &.unsupported {
+ color: var(--wxex-text-muted);
+ cursor: not-allowed;
+
+ input {
+ cursor: not-allowed;
+ }
+ }
+}
+.export-unsupported-hint {
+ display: inline-grid;
+ width: 16px;
+ height: 16px;
+ place-items: center;
+ border: 1px solid #c57923;
+ border-radius: 50%;
+ color: #a85e13;
+ font-size: 11px;
+ font-weight: 700;
+ line-height: 1;
+}
+.export-name-mode-grid {
+ display: flex;
+ gap: 8px;
+ padding: 10px;
+ border-radius: 8px;
+ background: #f0f3f0;
+}
+.export-name-mode-option {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ flex: 1;
+ min-height: 32px;
+ padding: 0 8px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 6px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+ cursor: pointer;
+
+ input {
+ accent-color: var(--wxex-brand);
+ }
+}
+
+.export-media-master {
+ justify-content: space-between;
+ gap: 12px;
+ padding: 13px 14px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 7px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+
+ input {
+ width: 17px;
+ height: 17px;
+ accent-color: var(--wxex-brand);
+ }
+}
+.export-media-options {
+ display: grid;
+ gap: 2px;
+ margin-top: 8px;
+ padding: 9px 13px;
+ border-radius: 8px;
+ background: #f0f3f0;
+
+ &.disabled {
+ opacity: 0.52;
+ }
+}
+.export-resource-statuses {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-top: 9px;
+
+ span {
+ padding: 3px 7px;
+ border-radius: 4px;
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-success);
+ font-size: 10px;
+ }
+}
+.export-helper-text {
+ margin: 9px 0 0;
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+}
+
+.export-format-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 8px;
+
+ button {
+ min-height: 78px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 8px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+
+ &.active {
+ border: 2px solid var(--wxex-brand);
+ background: #f2f8f5;
+ }
+ }
+
+ strong {
+ display: block;
+ font-size: 13px;
+ }
+
+ small {
+ display: block;
+ margin-top: 6px;
+ color: var(--wxex-success);
+ font-size: 10px;
+ }
+}
+.export-html-options {
+ display: grid;
+ gap: 8px;
+ margin-top: 10px;
+ padding: 11px 13px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 8px;
+ background: #f0f3f0;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+
+ input {
+ accent-color: var(--wxex-brand);
+ }
+}
+
+.export-save-section {
+ display: grid;
+ gap: 12px;
+
+ > label {
+ display: grid;
+ gap: 5px;
+ color: var(--wxex-text-secondary);
+ font-size: 11px;
+
+ input {
+ width: 100%;
+ min-width: 0;
+ padding: 8px 9px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 6px;
+ outline: 0;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font: 13px/20px var(--wxex-font);
+ }
+ }
+}
+.export-target-path {
+ gap: 10px;
+ padding: 9px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 7px;
+ background: #fff;
+ color: var(--wxex-text-secondary);
+ font-size: 11px;
+
+ strong {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font-weight: 500;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ button {
+ padding: 5px 8px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 5px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 11px var(--wxex-font);
+ }
+}
+
+.export-action-bar {
+ flex: 0 0 58px;
+ gap: 8px;
+ padding: 0 22px;
+ border-top: 1px solid var(--wxex-border);
+ background: #fff;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+}
+.export-ready-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--wxex-success);
+
+ &.completed {
+ background: var(--wxex-brand);
+ }
+}
+.export-target-summary {
+ flex: 1;
+ min-width: 0;
+ margin-left: 14px;
+ overflow: hidden;
+ color: var(--wxex-text-muted);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.export-reset-button {
+ border: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px var(--wxex-font);
+}
+.export-primary-button {
+ min-width: 132px;
+ padding: 10px 16px;
+ border: 0;
+ border-radius: 7px;
+ background: var(--wxex-brand);
+ color: #fff;
+ cursor: pointer;
+ font: 700 12px var(--wxex-font);
+
+ &:disabled {
+ cursor: default;
+ opacity: 0.55;
+ }
+}
+
+.export-preview-panel {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ border-left: 1px solid var(--wxex-border);
+ background: #fbfcfb;
+}
+.export-preview-heading {
+ justify-content: space-between;
+ flex: 0 0 52px;
+ padding: 0 18px;
+ border-bottom: 1px solid var(--wxex-border);
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+
+ span {
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ }
+}
+.export-message-preview {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ padding: 16px 14px;
+}
+.export-preview-date {
+ width: fit-content;
+ margin: 0 auto 18px;
+ padding: 4px 9px;
+ border-radius: 10px;
+ background: #e9eeeb;
+ color: var(--wxex-text-secondary);
+ font-size: 10px;
+}
+.export-preview-message {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ width: min(100%, 620px);
+ margin: 0 auto 15px;
+
+ &.mine {
+ flex-direction: row-reverse;
+
+ .export-preview-bubble {
+ background: #95ec69;
+ }
+ }
+
+ &.system {
+ justify-content: center;
+ flex-direction: row;
+
+ .export-preview-avatar {
+ display: none;
+ }
+
+ .export-preview-bubble {
+ max-width: 92%;
+ padding: 5px 10px;
+ border: 0;
+ border-radius: 5px;
+ background: #e9eeeb;
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ text-align: center;
+ box-shadow: none;
+
+ small {
+ display: none;
+ }
+ }
+ }
+}
+.export-preview-avatar {
+ width: 30px;
+ height: 30px;
+ border-radius: 7px;
+ font-size: 11px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+.export-preview-bubble {
+ max-width: 78%;
+ padding: 9px 10px;
+ border-radius: 8px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font-size: 12px;
+ line-height: 18px;
+ box-shadow: 0 1px 2px rgba(32, 39, 36, 0.05);
+
+ small {
+ display: block;
+ margin-bottom: 3px;
+ color: var(--wxex-text-muted);
+ font-size: 10px;
+ }
+}
+.export-preview-stats {
+ flex: 0 0 auto;
+ display: grid;
+ gap: 12px;
+ padding: 18px;
+ border-top: 1px solid var(--wxex-border);
+}
+
+.export-task-center-button {
+ align-self: flex-start;
+ margin: 0 0 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 6px;
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ cursor: pointer;
+ padding: 7px 11px;
+ font: 600 12px/18px var(--wxex-font);
+}
+
+.export-task-center {
+ margin: 0 0 18px;
+ padding: 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 8px;
+ background: var(--wxex-bg-elevated);
+}
+
+.export-task-row {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto auto;
+ align-items: center;
+ gap: 12px;
+ padding: 9px 0;
+ border-top: 1px solid var(--wxex-border);
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+
+ &:first-of-type {
+ margin-top: 8px;
+ }
+
+ > span:first-child {
+ display: grid;
+ gap: 2px;
+ min-width: 0;
+ }
+
+ strong,
+ small {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ strong {
+ color: var(--wxex-text-primary);
+ }
+
+ button {
+ border: 1px solid var(--wxex-border);
+ border-radius: 5px;
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ padding: 4px 8px;
+ }
+}
+
+.export-task-progress {
+ position: relative;
+ width: 110px;
+ height: 6px;
+ overflow: hidden;
+ border-radius: 999px;
+ background: var(--wxex-border);
+
+ i {
+ display: block;
+ height: 100%;
+ border-radius: inherit;
+ background: var(--wxex-brand);
+ }
+
+ b {
+ position: absolute;
+ top: 10px;
+ right: 0;
+ color: var(--wxex-text-muted);
+ font-size: 10px;
+ font-weight: 500;
+ }
+}
+.export-preview-panel .export-preview-stats:not(.export-preview-real-stats) {
+ display: none;
+}
+.export-preview-stats span,
+.export-complete-summary span {
+ display: flex;
+ justify-content: space-between;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+}
+.export-preview-stats strong,
+.export-complete-summary strong {
+ color: var(--wxex-text-primary);
+ font-weight: 600;
+}
+
+.export-job-state {
+ display: grid;
+ align-content: center;
+ gap: 12px;
+ height: 100%;
+ padding: 28px;
+ text-align: center;
+
+ h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 18px;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 18px;
+ }
+
+ ol {
+ display: grid;
+ gap: 10px;
+ margin: 8px 0;
+ padding: 0;
+ list-style: none;
+ text-align: left;
+ }
+
+ li {
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+
+ &::before {
+ display: inline-grid;
+ width: 16px;
+ height: 16px;
+ margin-right: 8px;
+ place-items: center;
+ border: 1px solid var(--wxex-border);
+ border-radius: 50%;
+ content: '';
+ vertical-align: -3px;
+ }
+
+ &.done {
+ color: var(--wxex-success);
+
+ &::before {
+ border-color: var(--wxex-success);
+ background: var(--wxex-success);
+ content: '✓';
+ color: #fff;
+ font-size: 10px;
+ }
+ }
+
+ &.current {
+ color: var(--wxex-text-primary);
+ font-weight: 600;
+
+ &::before {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ box-shadow: inset 0 0 0 4px #fff;
+ }
+ }
+ }
+
+ > strong {
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ font-weight: 500;
+ }
+}
+.export-progress-bar {
+ height: 6px;
+ overflow: hidden;
+ border-radius: 4px;
+ background: #e2e9e4;
+
+ span {
+ display: block;
+ height: 100%;
+ border-radius: 4px;
+ background: var(--wxex-brand);
+ transition: width 0.2s ease;
+ }
+}
+.export-job-state > strong {
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ font-weight: 500;
+}
+.export-cancel-button,
+.export-open-folder-button {
+ padding: 10px 14px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 7px;
+ background: #fff;
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px var(--wxex-font);
+}
+.export-success-icon {
+ width: 58px;
+ height: 58px;
+ margin: 0 auto 4px;
+ border: 5px solid var(--wxex-brand-soft);
+ border-radius: 50%;
+ background: #fff;
+ color: var(--wxex-brand);
+ font-size: 30px;
+ line-height: 48px;
+}
+.export-complete-summary {
+ display: grid;
+ gap: 12px;
+ margin: 12px 0;
+ padding: 14px;
+ border-radius: 8px;
+ background: #eef3ef;
+ text-align: left;
+}
+
+@media (max-width: 1100px) {
+ .export-workspace {
+ grid-template-columns: 248px minmax(460px, 1fr);
+ }
+ .export-preview-panel {
+ display: none;
+ }
+}
diff --git a/src/renderer/src/styles/foundation.scss b/src/renderer/src/styles/foundation.scss
new file mode 100644
index 0000000..84eead1
--- /dev/null
+++ b/src/renderer/src/styles/foundation.scss
@@ -0,0 +1,348 @@
+:root {
+ --bg-color: #f5f5f5;
+ --sidebar-bg: #e7e7e7;
+ --sidebar-hover: #d6d6d6;
+ --sidebar-active: #c6c6c6;
+ --chat-bg: #f5f5f5;
+ --message-bg-user: #95ec69;
+ --message-bg-other: #ffffff;
+ --text-color: #000000;
+ --border-color: #dcdcdc;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: var(--wxex-font);
+ background-color: var(--wxex-bg-app);
+ color: var(--wxex-text-primary);
+ height: 100vh;
+ overflow: hidden;
+}
+
+#root {
+ height: 100%;
+ display: flex;
+}
+
+.app-shell {
+ box-sizing: border-box;
+ display: flex;
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+ min-width: 0;
+ overflow: hidden;
+ background: var(--wxex-bg-app);
+}
+
+.app-primary-rail {
+ box-sizing: border-box;
+ width: var(--wxex-nav-width);
+ flex: 0 0 var(--wxex-nav-width);
+ height: 100%;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border-right: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-sidebar);
+ padding: 12px 8px;
+ overflow: hidden;
+ -webkit-app-region: drag;
+}
+
+.app-brand {
+ box-sizing: border-box;
+ width: 42px;
+ height: 42px;
+ display: grid;
+ place-items: center;
+ border: 0;
+ border-radius: 12px;
+ background: transparent;
+ -webkit-app-region: no-drag;
+
+ img {
+ display: block;
+ width: 42px;
+ height: 42px;
+ border-radius: 12px;
+ }
+}
+
+.primary-navigation {
+ box-sizing: border-box;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 6px;
+ width: 100%;
+ margin-top: 18px;
+ -webkit-app-region: no-drag;
+}
+
+.primary-nav-item {
+ width: 100%;
+ height: 58px;
+ flex: 0 0 58px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ border: 0;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font-family: var(--wxex-font);
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.46);
+ color: var(--wxex-text-primary);
+ }
+
+ &.active {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ }
+}
+
+.primary-nav-mark {
+ width: 24px;
+ height: 24px;
+ display: grid;
+ place-items: center;
+
+ svg {
+ width: 22px;
+ height: 22px;
+ }
+
+ path,
+ circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ }
+}
+
+.primary-nav-label {
+ font-size: 12px;
+ line-height: 16px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+.app-rail-account {
+ box-sizing: border-box;
+ width: 100%;
+ flex: 0 0 auto;
+ -webkit-app-region: no-drag;
+}
+
+.account-summary {
+ box-sizing: border-box;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border: 0;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font-family: var(--wxex-font);
+ text-align: left;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.72);
+ }
+}
+
+.account-summary.compact {
+ justify-content: center;
+ cursor: pointer;
+ padding: 8px 0;
+}
+
+.account-summary-avatar {
+ box-sizing: border-box;
+ position: relative;
+ width: 38px;
+ height: 38px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ font-size: 14px;
+ font-weight: 700;
+ overflow: hidden;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.account-summary-status {
+ position: absolute;
+ right: 2px;
+ bottom: 2px;
+ width: 9px;
+ height: 9px;
+ border: 2px solid var(--wxex-bg-elevated);
+ border-radius: 999px;
+ background: var(--wxex-text-muted);
+
+ &.ready {
+ background: var(--wxex-success);
+ }
+}
+
+.account-summary:not(.compact) .account-summary-avatar .account-summary-status {
+ display: none;
+}
+
+.account-summary-text {
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.account-summary-name {
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 18px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.account-summary-meta {
+ overflow: hidden;
+ color: var(--wxex-text-muted);
+ font-size: 12px;
+ line-height: 16px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.account-summary-state {
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 16px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.account-summary-state-dot {
+ width: 7px;
+ height: 7px;
+ flex: 0 0 auto;
+ border-radius: 999px;
+ background: var(--wxex-text-muted);
+
+ &.ready {
+ background: var(--wxex-success);
+ }
+}
+
+.account-summary-settings {
+ box-sizing: border-box;
+ width: 28px;
+ height: 28px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ border: 0;
+ border-radius: var(--wxex-radius-sm);
+ background: transparent;
+ color: var(--wxex-text-muted);
+ cursor: pointer;
+
+ &:hover {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ }
+
+ svg {
+ width: 17px;
+ height: 17px;
+ }
+
+ path {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ }
+}
+
+.app-shell-main {
+ box-sizing: border-box;
+ flex: 1;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ display: flex;
+ align-items: stretch;
+ overflow: hidden;
+ padding-top: var(--wxex-shell-content-top);
+ background: var(--wxex-bg-main);
+}
+
+.app-page-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ color: var(--wxex-text-secondary);
+ text-align: center;
+
+ h2 {
+ margin: 0 0 8px;
+ color: var(--wxex-text-primary);
+ font-size: 20px;
+ font-weight: 600;
+ line-height: 28px;
+ }
+
+ p {
+ margin: 0;
+ font-size: 13px;
+ line-height: 20px;
+ }
+}
+.app-page-placeholder-eyebrow {
+ margin-bottom: 8px;
+ color: var(--wxex-brand);
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 0;
+}
+
+
+.app-container {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+ min-width: 0;
+ align-items: stretch;
+ overflow: hidden;
+}
diff --git a/src/renderer/src/styles/index.scss b/src/renderer/src/styles/index.scss
new file mode 100644
index 0000000..46df485
--- /dev/null
+++ b/src/renderer/src/styles/index.scss
@@ -0,0 +1,16 @@
+@use './_tokens';
+@use './_base';
+
+@use './foundation';
+@use './conversation';
+@use './chat';
+@use './rich-message';
+@use './shell-overlays';
+@use './reports-core';
+@use './settings';
+@use './api';
+@use './reports-templates';
+@use './export';
+@use './search';
+@use './archive';
+@use './settings-advanced';
diff --git a/src/renderer/src/styles/reports-core.scss b/src/renderer/src/styles/reports-core.scss
new file mode 100644
index 0000000..20261c7
--- /dev/null
+++ b/src/renderer/src/styles/reports-core.scss
@@ -0,0 +1,1444 @@
+.report-page {
+ display: grid;
+ grid-template-columns: 292px minmax(420px, 1fr) 304px;
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+ min-width: 0;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+
+.report-center-page {
+ display: grid;
+ grid-template-columns: 292px minmax(420px, 1fr) 304px;
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+ min-width: 0;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+
+.report-page > *,
+.report-center-page > * {
+ min-height: 0;
+ min-width: 0;
+}
+
+.report-source-sidebar {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow: hidden;
+ border-right: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-sidebar);
+}
+
+.report-source-header {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 18px 16px 12px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.report-source-header h2,
+.ai-report-header h1,
+.report-task-header h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+}
+
+.report-source-header h2 {
+ font: 700 18px/24px var(--wxex-font);
+}
+
+.report-source-header p,
+.ai-report-header p,
+.report-task-header p {
+ margin: 4px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-source-header > span {
+ flex: 0 0 auto;
+ margin-top: 3px;
+ color: var(--wxex-text-muted);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-source-search {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 8px;
+ margin: 12px 14px;
+ padding: 0 10px;
+ height: 36px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-muted);
+}
+
+.report-source-search svg {
+ width: 16px;
+ height: 16px;
+}
+
+.report-source-search path,
+.report-source-search circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.report-source-search input {
+ min-width: 0;
+ flex: 1;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: 13px/18px var(--wxex-font);
+}
+
+.report-source-list {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow-y: auto;
+ padding: 0 10px 12px;
+}
+
+.report-source-item {
+ position: relative;
+ display: flex;
+ width: 100%;
+ min-width: 0;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 10px 10px 12px;
+ border: 0;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-primary);
+ text-align: left;
+ cursor: pointer;
+ font-family: var(--wxex-font);
+}
+
+.report-source-item:hover {
+ background: rgba(255, 255, 255, 0.62);
+}
+
+.report-source-item.active {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+}
+
+.report-source-item.active::before {
+ position: absolute;
+ left: 0;
+ top: 8px;
+ bottom: 8px;
+ width: 3px;
+ border-radius: 4px;
+ background: var(--wxex-brand);
+ content: '';
+}
+
+.report-source-avatar {
+ display: grid;
+ width: 36px;
+ height: 36px;
+ flex: 0 0 auto;
+ place-items: center;
+ overflow: hidden;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ font: 700 14px/1 var(--wxex-font);
+}
+
+.report-source-avatar img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.report-source-text {
+ display: grid;
+ min-width: 0;
+}
+
+.report-source-text span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.report-source-text span {
+ color: inherit;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-source-empty {
+ padding: 18px 8px;
+ color: var(--wxex-text-muted);
+ font: 13px/18px var(--wxex-font);
+}
+
+.report-source-account {
+ flex: 0 0 auto;
+ padding: 12px;
+ border-top: 1px solid var(--wxex-border);
+}
+
+.ai-report-workspace {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+
+.ai-report-header {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 18px;
+ padding: 22px 28px 16px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.ai-report-header h1 {
+ font: 700 21px/28px var(--wxex-font);
+}
+
+.ai-report-header p {
+ font-size: 13px;
+}
+
+.report-inline-error {
+ max-width: 320px;
+ padding: 8px 10px;
+ border: 1px solid rgba(200, 90, 90, 0.35);
+ border-radius: var(--wxex-radius-md);
+ background: #fff4f4;
+ color: var(--wxex-danger);
+ font: 12px/17px var(--wxex-font);
+}
+
+.ai-report-body {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 18px 28px 20px;
+}
+
+.ai-report-body > * {
+ max-width: 720px;
+}
+
+.ai-report-body > .report-section + .report-section {
+ margin-top: 28px;
+}
+
+.report-empty-state,
+.report-config-section,
+.report-privacy-note,
+.report-result-panel {
+ margin-bottom: 16px;
+ padding: 16px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-lg);
+ background: var(--wxex-bg-elevated);
+}
+
+.report-empty-state h2,
+.report-privacy-note h3,
+.report-config-section h3,
+.report-result-panel h3 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font: 700 15px/20px var(--wxex-font);
+}
+
+.report-timeout-section {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+}
+
+.report-timeout-section p {
+ margin: 6px 0 0;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+}
+
+.report-timeout-section label {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 8px;
+ color: var(--wxex-text-secondary);
+ font-size: 13px;
+}
+
+.report-timeout-section input {
+ width: 96px;
+ height: 36px;
+ padding: 0 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: #fff;
+ color: var(--wxex-text-primary);
+ font: 500 13px var(--wxex-font);
+}
+
+.report-empty-state p,
+.report-privacy-note p {
+ margin: 6px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 13px/19px var(--wxex-font);
+}
+
+.report-section-heading {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ margin-bottom: 12px;
+}
+
+.report-section-heading span {
+ color: var(--wxex-text-muted);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-section-heading span.danger {
+ color: var(--wxex-danger);
+}
+
+.report-range-options,
+.report-density-options {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8px;
+}
+
+.report-density-options {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.report-range-options button,
+.report-density-options button,
+.report-model-summary button,
+.report-result-actions button,
+.report-task-error button,
+.ai-report-footer button {
+ min-height: 34px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-range-options button.active,
+.report-density-options button.active {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+}
+
+.report-range-options button:disabled,
+.report-density-options button:disabled {
+ color: var(--wxex-text-muted);
+ cursor: not-allowed;
+ opacity: 0.75;
+}
+
+.report-range-options button span,
+.report-density-options button span {
+ display: block;
+ margin-top: 2px;
+ font: 11px/14px var(--wxex-font);
+}
+
+.report-type-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px;
+}
+
+.report-check-row {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ align-items: start;
+ gap: 8px;
+ padding: 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: #fbfcfb;
+ color: var(--wxex-text-primary);
+}
+
+.report-check-row input {
+ margin-top: 2px;
+ accent-color: var(--wxex-brand);
+}
+
+.report-check-row span {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+}
+
+.report-check-row b {
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-check-row small {
+ color: var(--wxex-text-muted);
+ font: 12px/16px var(--wxex-font);
+}
+
+.report-check-row em {
+ color: var(--wxex-text-secondary);
+ font: normal 12px/18px var(--wxex-font);
+}
+
+.report-readonly-modules {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px;
+ cursor: default;
+}
+
+.report-readonly-modules span {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 10px;
+ border: 1px solid #e9eeeb;
+ border-radius: var(--wxex-radius-md);
+ background: #f7f9f8;
+ color: var(--wxex-text-secondary);
+ font: 12px/17px var(--wxex-font);
+ cursor: default;
+}
+
+.report-readonly-modules svg {
+ width: 14px;
+ height: 14px;
+ flex: 0 0 auto;
+ color: var(--wxex-text-muted);
+}
+
+.report-readonly-modules rect,
+.report-readonly-modules path {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.report-model-summary {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.report-model-summary p {
+ margin: 4px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 13px/18px var(--wxex-font);
+}
+
+.report-model-summary button,
+.report-result-actions button,
+.report-task-error button {
+ padding: 0 12px;
+}
+
+.report-result-preview {
+ max-height: 460px;
+ overflow: auto;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: #f6f4f0;
+ text-align: center;
+}
+
+.report-result-preview img {
+ display: inline-block;
+ width: min(100%, 430px);
+ height: auto;
+}
+
+.report-result-actions {
+ display: flex;
+ gap: 8px;
+ margin-top: 10px;
+}
+
+.report-action-status {
+ margin: 8px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/16px var(--wxex-font);
+}
+
+.ai-report-footer {
+ display: flex;
+ flex: 0 0 auto;
+ min-height: 66px;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 12px 28px;
+ border-top: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+}
+
+.report-footer-note,
+.report-footer-actions span {
+ min-width: 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-footer-note {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.report-footer-actions {
+ display: flex;
+ min-width: 0;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 12px;
+}
+
+.report-footer-actions span {
+ max-width: 280px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.ai-report-footer button {
+ min-width: 132px;
+ padding: 0 16px;
+ border-color: var(--wxex-ai);
+ background: var(--wxex-ai);
+ color: #fff;
+}
+
+.ai-report-footer button.secondary {
+ min-width: 92px;
+ border-color: var(--wxex-border);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+}
+
+.ai-report-footer button:disabled {
+ border-color: var(--wxex-border);
+ background: #e8ebe9;
+ color: var(--wxex-text-muted);
+ cursor: not-allowed;
+}
+
+.report-task-panel {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow: hidden;
+ border-left: 1px solid var(--wxex-border);
+ background: #f7f9f8;
+}
+
+.report-task-header {
+ flex: 0 0 auto;
+ padding: 20px 18px 14px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.report-task-header h2 {
+ font: 700 16px/22px var(--wxex-font);
+}
+
+.report-task-steps {
+ flex: 0 0 auto;
+ padding: 16px 18px;
+}
+
+.report-task-step {
+ display: grid;
+ grid-template-columns: 18px minmax(0, 1fr);
+ gap: 10px;
+ padding: 0 0 18px;
+ color: var(--wxex-text-muted);
+}
+
+.report-task-step b {
+ display: block;
+ color: inherit;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-task-step small {
+ color: var(--wxex-text-muted);
+ font: 12px/16px var(--wxex-font);
+}
+
+.report-task-dot {
+ width: 12px;
+ height: 12px;
+ margin-top: 3px;
+ border: 2px solid var(--wxex-border);
+ border-radius: 50%;
+ background: transparent;
+}
+
+.report-task-step.done {
+ color: var(--wxex-success);
+}
+
+.report-task-step.done .report-task-dot {
+ border-color: var(--wxex-success);
+ background: var(--wxex-success);
+}
+
+.report-task-step.active {
+ color: var(--wxex-ai);
+}
+
+.report-task-step.active .report-task-dot {
+ border-color: var(--wxex-ai);
+ background: var(--wxex-ai-soft);
+}
+
+.report-task-error,
+.report-task-success,
+.report-task-note {
+ margin: 0 18px 14px;
+ padding: 12px;
+ border-radius: var(--wxex-radius-md);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-task-error {
+ border: 1px solid rgba(200, 90, 90, 0.35);
+ background: #fff4f4;
+ color: var(--wxex-danger);
+}
+
+.report-task-success {
+ border: 1px solid rgba(46, 139, 104, 0.28);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-success);
+}
+
+.report-task-note {
+ margin-top: auto;
+ flex: 0 0 auto;
+ color: var(--wxex-text-secondary);
+ background: var(--wxex-ai-soft);
+}
+
+.report-task-error p,
+.report-task-success p {
+ margin: 4px 0 10px;
+}
+
+.report-task-error button + button {
+ margin-left: 8px;
+}
+
+.report-task-log-path {
+ display: block;
+ margin-top: 8px;
+ overflow-wrap: anywhere;
+ color: var(--wxex-text-secondary);
+ font: 11px/16px var(--wxex-font);
+}
+
+@media (max-width: 1120px) {
+ .report-page {
+ grid-template-columns: 268px minmax(360px, 1fr) 280px;
+ }
+
+ .report-type-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .report-readonly-modules {
+ grid-template-columns: 1fr;
+ }
+}
+
+.agent-hub-workspace {
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ overflow: auto;
+ padding: 34px 40px 48px;
+ background: #fafbfa;
+}
+.agent-hub-header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 24px;
+ max-width: 1080px;
+ margin: 0 auto 28px;
+}
+.agent-hub-eyebrow,
+.agent-hub-card-kicker {
+ color: var(--wxex-brand);
+ font: 700 11px/16px var(--wxex-font);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+.agent-hub-header h1 {
+ margin: 4px 0 6px;
+ color: var(--wxex-text-primary);
+ font: 750 28px/36px var(--wxex-font);
+}
+.agent-hub-header p,
+.agent-hub-card p {
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font: 13px/20px var(--wxex-font);
+}
+.agent-hub-runtime {
+ display: inline-flex;
+ align-items: center;
+ padding: 6px 10px;
+ border-radius: 999px;
+ background: #f0f2f0;
+ color: var(--wxex-text-muted);
+ font: 700 12px/18px var(--wxex-font);
+}
+.agent-hub-runtime.online {
+ background: #e8f6ed;
+ color: #24864b;
+}
+.agent-hub-runtime.error {
+ background: #fff0ef;
+ color: var(--wxex-danger);
+}
+.agent-hub-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.75fr);
+ gap: 20px;
+ max-width: 1080px;
+ margin: 0 auto;
+}
+.agent-hub-card {
+ box-sizing: border-box;
+ min-width: 0;
+ border: 1px solid var(--wxex-border);
+ border-radius: 18px;
+ background: var(--wxex-bg-elevated);
+ box-shadow: 0 8px 28px rgba(28, 38, 31, 0.045);
+}
+.agent-hub-login-card {
+ min-height: 520px;
+ padding: 26px;
+ display: flex;
+ flex-direction: column;
+}
+.agent-hub-capability-card {
+ padding: 26px;
+ align-self: start;
+}
+.agent-hub-card-heading {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+ padding-bottom: 20px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+.agent-hub-card h2 {
+ margin: 4px 0 0;
+ color: var(--wxex-text-primary);
+ font: 700 19px/27px var(--wxex-font);
+}
+.agent-hub-status {
+ display: inline-flex;
+ align-items: center;
+ gap: 7px;
+ padding: 5px 9px;
+ border-radius: 999px;
+ background: #f2f3f2;
+ color: var(--wxex-text-secondary);
+ font: 650 12px/18px var(--wxex-font);
+ white-space: nowrap;
+}
+.agent-hub-status i {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #9aa39d;
+}
+.agent-hub-status.online {
+ background: #e8f6ed;
+ color: #24864b;
+}
+.agent-hub-status.online i {
+ background: #35a663;
+}
+.agent-hub-status.waiting_scan,
+.agent-hub-status.scanned,
+.agent-hub-status.starting {
+ background: #fff5de;
+ color: #9b6a12;
+}
+.agent-hub-status.waiting_scan i,
+.agent-hub-status.scanned i,
+.agent-hub-status.starting i {
+ background: #d89b2b;
+}
+.agent-hub-status.error {
+ background: #fff0ef;
+ color: var(--wxex-danger);
+}
+.agent-hub-status.error i {
+ background: var(--wxex-danger);
+}
+.agent-hub-empty-login {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 280px;
+ text-align: center;
+}
+.agent-hub-empty-login h3,
+.agent-hub-connected h3,
+.agent-hub-qr-copy h3 {
+ margin: 18px 0 6px;
+ color: var(--wxex-text-primary);
+ font: 700 16px/24px var(--wxex-font);
+}
+.agent-hub-empty-login p {
+ max-width: 360px;
+}
+.agent-hub-phone {
+ width: 64px;
+ height: 88px;
+ position: relative;
+ border: 2px solid #9eb3a5;
+ border-radius: 13px;
+ background: linear-gradient(145deg, #f6fbf7, #eaf4ed);
+}
+.agent-hub-phone::before {
+ content: '';
+ position: absolute;
+ top: 8px;
+ left: 22px;
+ width: 18px;
+ height: 3px;
+ border-radius: 3px;
+ background: #b8c8bd;
+}
+.agent-hub-phone span {
+ position: absolute;
+ left: 23px;
+ bottom: 8px;
+ width: 16px;
+ height: 16px;
+ border: 1.5px solid var(--wxex-brand);
+ border-radius: 50%;
+}
+.agent-hub-actions {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+ min-height: 38px;
+ padding-top: 18px;
+}
+.agent-hub-button {
+ height: 38px;
+ padding: 0 16px;
+ border: 1px solid transparent;
+ border-radius: 9px;
+ font: 650 13px/20px var(--wxex-font);
+ cursor: pointer;
+}
+.agent-hub-button:disabled {
+ opacity: 0.55;
+ cursor: default;
+}
+.agent-hub-button.primary {
+ background: var(--wxex-brand);
+ color: #fff;
+}
+.agent-hub-button.secondary {
+ border-color: var(--wxex-border-strong);
+ background: #fff;
+ color: var(--wxex-text-primary);
+}
+.agent-hub-button.danger {
+ border-color: #f0c6c2;
+ background: #fff8f7;
+ color: var(--wxex-danger);
+}
+.agent-hub-qr-panel {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 32px;
+ min-height: 320px;
+ padding: 22px 0;
+}
+.agent-hub-qr-frame {
+ box-sizing: border-box;
+ width: 220px;
+ height: 220px;
+ flex: 0 0 220px;
+ display: grid;
+ place-items: center;
+ padding: 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 16px;
+ background: #fff;
+ box-shadow: 0 10px 30px rgba(23, 44, 30, 0.08);
+}
+.agent-hub-qr-frame img {
+ width: 100%;
+ height: 100%;
+ display: block;
+ image-rendering: pixelated;
+}
+.agent-hub-qr-copy {
+ max-width: 260px;
+}
+.agent-hub-qr-copy h3 {
+ margin-top: 0;
+}
+.agent-hub-qr-copy .agent-hub-button {
+ margin-top: 18px;
+}
+.agent-hub-connected {
+ flex: 1;
+ min-height: 300px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+}
+.agent-hub-connected h3 {
+ margin: 0 0 4px;
+}
+.agent-hub-connected-icon {
+ width: 48px;
+ height: 48px;
+ display: grid;
+ place-items: center;
+ border-radius: 50%;
+ background: #e4f5ea;
+ color: #23834a;
+ font: 800 22px/1 var(--wxex-font);
+}
+.agent-hub-capability-card > p {
+ margin-top: 8px;
+}
+.agent-hub-example {
+ margin: 24px 0 20px;
+ padding: 16px;
+ border-radius: 12px;
+ background: var(--wxex-brand-soft);
+}
+.agent-hub-example span {
+ display: block;
+ color: var(--wxex-text-muted);
+ font: 600 11px/16px var(--wxex-font);
+}
+.agent-hub-example strong {
+ display: block;
+ margin-top: 4px;
+ color: var(--wxex-brand);
+ font: 700 14px/21px var(--wxex-font);
+}
+.agent-hub-capability-card ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.agent-hub-capability-card li {
+ display: flex;
+ align-items: center;
+ gap: 9px;
+ padding: 9px 0;
+ border-bottom: 1px solid var(--wxex-border);
+ color: var(--wxex-text-secondary);
+ font: 13px/19px var(--wxex-font);
+}
+.agent-hub-capability-card li:last-child {
+ border-bottom: 0;
+}
+.agent-hub-capability-card li i {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--wxex-brand);
+}
+.agent-hub-example strong + strong {
+ margin-top: 9px;
+ padding-top: 9px;
+ border-top: 1px solid rgba(36, 122, 99, 0.15);
+}
+.agent-hub-capability-card li i.offline {
+ background: var(--wxex-danger);
+}
+.agent-hub-log-card {
+ max-width: 1080px;
+ margin: 20px auto 0;
+ padding: 22px;
+}
+.agent-hub-log-heading {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ margin-bottom: 14px;
+}
+.agent-hub-log-heading h2 {
+ margin-top: 3px;
+}
+.agent-hub-log-actions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.agent-hub-log-actions select,
+.agent-hub-log-actions button {
+ height: 32px;
+ border: 1px solid var(--wxex-border-strong);
+ border-radius: 8px;
+ background: #fff;
+ color: var(--wxex-text-secondary);
+ font: 600 12px/18px var(--wxex-font);
+}
+.agent-hub-log-actions select {
+ padding: 0 28px 0 10px;
+}
+.agent-hub-log-actions button {
+ padding: 0 11px;
+ cursor: pointer;
+}
+.agent-hub-log-actions button:disabled {
+ opacity: 0.45;
+ cursor: default;
+}
+.agent-hub-log-body {
+ height: 250px;
+ overflow: auto;
+ padding: 12px 14px;
+ border: 1px solid #26312a;
+ border-radius: 11px;
+ background: #18201b;
+ color: #dfe9e2;
+}
+.agent-hub-log-line {
+ display: grid;
+ grid-template-columns: 78px 94px minmax(0, 1fr);
+ gap: 9px;
+ align-items: baseline;
+ min-height: 24px;
+ font:
+ 12px/19px ui-monospace,
+ SFMono-Regular,
+ Menlo,
+ monospace;
+}
+.agent-hub-log-line time {
+ color: #84938a;
+}
+.agent-hub-log-line .source {
+ color: #76d49a;
+}
+.agent-hub-log-line .source.wechat-connector {
+ color: #7dbcf1;
+}
+.agent-hub-log-line .source.system {
+ color: #d8bd6b;
+}
+.agent-hub-log-line code {
+ min-width: 0;
+ color: inherit;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+.agent-hub-log-line.warn code {
+ color: #f1cf77;
+}
+.agent-hub-log-line.error code {
+ color: #ff9690;
+}
+.agent-hub-log-empty {
+ height: 100%;
+ display: grid;
+ place-items: center;
+ color: #84938a;
+ font: 12px/20px var(--wxex-font);
+}
+.agent-hub-log-note {
+ margin-top: 9px !important;
+ color: var(--wxex-text-muted) !important;
+ font-size: 11px !important;
+}
+@media (max-width: 900px) {
+ .agent-hub-workspace {
+ padding: 24px;
+ }
+ .agent-hub-grid {
+ grid-template-columns: 1fr;
+ }
+ .agent-hub-qr-panel {
+ flex-direction: column;
+ text-align: center;
+ }
+ .agent-hub-capability-card {
+ width: 100%;
+ }
+}
+
+.ai-vision-test {
+ display: grid;
+ gap: 16px;
+}
+
+.ai-vision-test > header,
+.ai-vision-test > footer,
+.ai-vision-model {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+}
+
+.ai-vision-test h2,
+.ai-vision-test h3,
+.ai-vision-test p {
+ margin: 0;
+}
+
+.ai-vision-test h2 {
+ color: #202724;
+ font-size: 15px;
+}
+
+.ai-vision-test header h3 {
+ margin-top: 12px;
+ color: #35403b;
+ font-size: 13px;
+}
+
+.ai-vision-test header p,
+.ai-vision-model,
+.ai-vision-upload small {
+ margin-top: 4px;
+ color: #66706b;
+ font-size: 12px;
+}
+
+.ai-vision-capability {
+ border-radius: 999px;
+ padding: 5px 9px;
+ background: #f1f3f2;
+ color: #66706b;
+ white-space: nowrap;
+ font-size: 12px;
+}
+
+.ai-vision-capability.supported {
+ background: #eaf5f1;
+ color: #2e8b68;
+}
+
+.ai-vision-model {
+ justify-content: flex-start;
+ margin: 0;
+}
+
+.ai-vision-upload {
+ display: flex;
+ min-height: 112px;
+ align-items: center;
+ justify-content: center;
+ gap: 14px;
+ border: 1px dashed #bfc9c4;
+ border-radius: 10px;
+ padding: 14px;
+ background: #f7f9f8;
+ color: #35403b;
+ text-align: center;
+ cursor: pointer;
+}
+
+.ai-vision-upload:hover {
+ border-color: #247a63;
+ background: #f2f8f5;
+}
+
+.ai-vision-upload input {
+ display: none;
+}
+
+.ai-vision-upload.has-image {
+ justify-content: flex-start;
+ text-align: left;
+}
+
+.ai-vision-upload img {
+ width: 112px;
+ height: 82px;
+ flex: 0 0 auto;
+ border-radius: 8px;
+ object-fit: cover;
+}
+
+.ai-vision-upload strong,
+.ai-vision-upload small {
+ display: block;
+}
+
+.ai-vision-prompt {
+ display: grid;
+ gap: 7px;
+ color: #46514c;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.ai-vision-prompt textarea {
+ width: 100%;
+ border: 1px solid #d5ddda;
+ border-radius: 8px;
+ outline: none;
+ padding: 10px;
+ resize: vertical;
+ background: #f4f7f5;
+ color: #202724;
+ font: 13px/1.6 var(--wxex-font);
+}
+
+.ai-vision-prompt textarea:focus {
+ border-color: #247a63;
+ box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08);
+}
+
+.ai-vision-privacy {
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.6;
+}
+
+.ai-vision-error {
+ border-left: 3px solid #c85a5a;
+ padding: 9px 11px;
+ background: #fff2f2;
+ color: #a84444;
+ font-size: 12px;
+}
+
+.ai-vision-result {
+ display: grid;
+ gap: 12px;
+ border: 1px solid #dce7e2;
+ border-radius: 9px;
+ padding: 14px;
+ background: #f7faf9;
+}
+
+.ai-vision-result dl {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 12px;
+ margin: 0;
+}
+
+.ai-vision-result dt {
+ color: #929a96;
+ font-size: 11px;
+}
+
+.ai-vision-result dd {
+ margin: 4px 0 0;
+ color: #35403b;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.ai-vision-result > p {
+ white-space: pre-wrap;
+ color: #3d4742;
+ font-size: 13px;
+ line-height: 1.7;
+}
+
+.ai-vision-test > footer {
+ justify-content: flex-end;
+}
+
+.ai-vision-test > footer button {
+ min-height: 34px;
+ border: 1px solid #d5ddda;
+ border-radius: 7px;
+ padding: 0 13px;
+ background: #fff;
+ color: #46514c;
+ cursor: pointer;
+}
+
+.ai-vision-test > footer button:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+.report-density-options button:disabled:hover {
+ border-color: var(--wxex-border);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-muted);
+}
+
+.report-density-options button.active:disabled {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ opacity: 1;
+ cursor: default;
+}
+
+.report-history-sidebar {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow: hidden;
+ border-right: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-sidebar);
+}
+
+.report-history-header {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 18px 16px 12px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.report-history-header h2,
+.report-settings-panel header h2,
+.report-viewer-header h1 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+}
+
+.report-history-header h2 {
+ font: 700 18px/24px var(--wxex-font);
+}
+
+.report-history-header p,
+.report-settings-panel header p,
+.report-viewer-header p {
+ margin: 4px 0 0;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-history-header > span {
+ color: var(--wxex-text-muted);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-history-search {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 8px;
+ margin: 12px 14px 8px;
+ padding: 0 10px;
+ height: 36px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-muted);
+}
+
+.report-history-search svg {
+ width: 16px;
+ height: 16px;
+}
+
+.report-history-search path,
+.report-history-search circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.8;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.report-history-search input {
+ min-width: 0;
+ flex: 1;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: 13px/18px var(--wxex-font);
+}
+
+.report-history-create {
+ flex: 0 0 auto;
+ height: 36px;
+ margin: 0 14px 12px;
+ border: 1px solid var(--wxex-brand);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-brand);
+ color: #fff;
+ cursor: pointer;
+ font: 700 13px/18px var(--wxex-font);
+}
+
+.report-history-list {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 0 10px 12px;
+}
+
diff --git a/src/renderer/src/styles/reports-templates.scss b/src/renderer/src/styles/reports-templates.scss
new file mode 100644
index 0000000..1aca12a
--- /dev/null
+++ b/src/renderer/src/styles/reports-templates.scss
@@ -0,0 +1,821 @@
+@media (max-width: 1100px) {
+ .api-center-layout {
+ grid-template-columns: minmax(0, 1fr) 280px;
+ }
+ .api-main-scroll {
+ padding: 18px;
+ }
+ .api-header-actions {
+ max-width: 260px;
+ justify-content: flex-end;
+ }
+ .api-endpoint-head,
+ .api-endpoint-row {
+ grid-template-columns: 56px minmax(110px, 1fr) minmax(100px, 1fr) 78px;
+ gap: 7px;
+ padding: 10px;
+ }
+ .api-flow {
+ overflow-x: auto;
+ justify-content: flex-start;
+ }
+}
+
+.report-history-list-title {
+ padding: 4px 4px 8px;
+ color: var(--wxex-text-secondary);
+ font: 700 13px/18px var(--wxex-font);
+}
+
+.report-history-group {
+ margin: 0 0 10px;
+}
+
+.report-history-group h3 {
+ margin: 0;
+ padding: 6px 4px;
+ color: var(--wxex-text-muted);
+ font: 700 12px/16px var(--wxex-font);
+}
+
+.report-history-item {
+ position: relative;
+ display: flex;
+ width: 100%;
+ min-width: 0;
+ box-sizing: border-box;
+ gap: 10px;
+ padding: 10px 54px 10px 12px;
+ border: 0;
+ border-radius: var(--wxex-radius-md);
+ background: transparent;
+ color: var(--wxex-text-primary);
+ text-align: left;
+ cursor: pointer;
+ font-family: var(--wxex-font);
+}
+
+.report-history-item:hover {
+ background: rgba(255, 255, 255, 0.62);
+}
+
+.report-history-item.active {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+}
+
+.report-history-item.active::before {
+ position: absolute;
+ left: 0;
+ top: 8px;
+ bottom: 8px;
+ width: 3px;
+ border-radius: 4px;
+ background: var(--wxex-brand);
+ content: '';
+}
+
+.report-history-avatar {
+ display: grid;
+ width: 36px;
+ height: 36px;
+ flex: 0 0 auto;
+ place-items: center;
+ overflow: hidden;
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ font: 700 14px/1 var(--wxex-font);
+}
+
+.report-history-avatar img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.report-history-text {
+ display: grid;
+ flex: 1 1 auto;
+ min-width: 0;
+ gap: 2px;
+}
+
+.report-history-text b,
+.report-history-text small,
+.report-history-text em {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.report-history-text b {
+ color: inherit;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-history-text small,
+.report-history-text em {
+ color: var(--wxex-text-muted);
+ font: normal 12px/16px var(--wxex-font);
+}
+
+.report-history-delete {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ display: grid;
+ width: 38px;
+ height: 26px;
+ place-items: center;
+ border: 1px solid rgba(198, 72, 72, 0.22);
+ border-radius: var(--wxex-radius-sm);
+ background: rgba(198, 72, 72, 0.06);
+ color: #a64242;
+ cursor: pointer;
+ font: 600 12px/16px var(--wxex-font);
+ opacity: 0;
+ transform: translateY(-50%);
+ transition: opacity 0.12s ease;
+}
+
+.report-history-item:hover .report-history-delete,
+.report-history-delete:focus {
+ opacity: 1;
+}
+
+.report-history-empty {
+ display: grid;
+ gap: 10px;
+ padding: 18px 8px;
+ color: var(--wxex-text-muted);
+ font: 13px/18px var(--wxex-font);
+}
+
+.report-history-empty button,
+.report-center-empty button {
+ justify-self: start;
+ min-height: 32px;
+ padding: 0 12px;
+ border: 1px solid var(--wxex-brand);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-brand);
+ color: #fff;
+ cursor: pointer;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-history-account {
+ flex: 0 0 auto;
+ padding: 12px;
+ border-top: 1px solid var(--wxex-border);
+}
+
+.report-delete-confirm {
+ position: fixed;
+ inset: 0;
+ z-index: 30;
+ display: grid;
+ place-items: center;
+ background: rgba(32, 39, 36, 0.28);
+}
+
+.report-delete-confirm-card {
+ display: grid;
+ width: min(360px, calc(100vw - 48px));
+ gap: 12px;
+ padding: 18px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-lg);
+ background: var(--wxex-bg-main);
+ box-shadow: var(--wxex-shadow-popover);
+}
+
+.report-delete-confirm-card h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font: 700 18px/24px var(--wxex-font);
+}
+
+.report-delete-confirm-card p {
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font: 13px/20px var(--wxex-font);
+}
+
+.report-delete-confirm-card > div {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.report-delete-confirm-card button {
+ min-height: 32px;
+ padding: 0 14px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-delete-confirm-card button.danger {
+ border-color: #a64242;
+ background: #a64242;
+ color: #fff;
+}
+
+.report-delete-error {
+ color: #a64242 !important;
+}
+
+.report-viewer {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow: hidden;
+ background: #f2f1ee;
+}
+
+.report-viewer-header {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 18px 22px 12px;
+ border-bottom: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+}
+
+.report-viewer-header h1 {
+ font: 700 20px/27px var(--wxex-font);
+}
+
+.report-viewer-toolbar {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 8px;
+}
+
+.report-viewer-toolbar button,
+.report-zoom-bar button,
+.report-more-popover button,
+.report-settings-section button {
+ min-height: 32px;
+ padding: 0 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 13px/18px var(--wxex-font);
+}
+
+.report-viewer-toolbar button.primary {
+ border-color: var(--wxex-ai);
+ background: var(--wxex-ai);
+ color: #fff;
+}
+
+.report-viewer-toolbar button:disabled {
+ color: var(--wxex-text-muted);
+ cursor: not-allowed;
+ opacity: 0.72;
+}
+
+.report-more-menu {
+ position: relative;
+}
+
+.report-more-popover {
+ position: absolute;
+ top: 38px;
+ right: 0;
+ z-index: 8;
+ min-width: 128px;
+ padding: 6px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-md);
+ background: var(--wxex-bg-elevated);
+ box-shadow: var(--wxex-shadow-popover);
+}
+
+.report-more-popover button {
+ width: 100%;
+ border: 0;
+ text-align: left;
+}
+
+.report-viewer-status {
+ flex: 0 0 auto;
+ padding: 8px 22px;
+ border-bottom: 1px solid var(--wxex-border);
+ background: var(--wxex-ai-soft);
+ color: var(--wxex-ai);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-viewer-stage {
+ display: block;
+ flex: 1 1 auto;
+ min-height: 0;
+ min-width: 0;
+ overflow: auto;
+ padding: 22px;
+}
+
+.report-canvas {
+ width: max-content;
+ margin: 0 auto;
+ padding: 0;
+ background: #fff;
+ box-shadow: 0 8px 24px rgba(32, 39, 36, 0.14);
+}
+
+.report-canvas img {
+ display: block;
+ max-width: none;
+ height: auto;
+}
+
+.report-zoom-bar {
+ display: flex;
+ flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-height: 48px;
+ border-top: 1px solid var(--wxex-border);
+ background: var(--wxex-bg-main);
+}
+
+.report-zoom-bar span {
+ min-width: 48px;
+ color: var(--wxex-text-secondary);
+ text-align: center;
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-center-empty {
+ display: grid;
+ align-self: center;
+ justify-self: center;
+ max-width: 360px;
+ gap: 12px;
+ margin: auto;
+ color: var(--wxex-text-secondary);
+ text-align: center;
+}
+
+.report-center-empty-icon {
+ display: grid;
+ width: 54px;
+ height: 54px;
+ place-items: center;
+ justify-self: center;
+ border: 1px solid rgba(104, 110, 220, 0.18);
+ border-radius: 18px;
+ background: var(--wxex-ai-soft);
+ color: var(--wxex-ai);
+}
+
+.report-center-empty-icon svg {
+ width: 28px;
+ height: 28px;
+}
+
+.report-center-empty-icon path {
+ fill: currentColor;
+}
+
+.report-center-empty h2 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font: 700 18px/24px var(--wxex-font);
+}
+
+.report-center-empty p {
+ margin: 0;
+ font: 13px/20px var(--wxex-font);
+}
+
+.report-center-empty button {
+ justify-self: center;
+}
+
+.report-settings-panel {
+ display: flex;
+ min-width: 0;
+ min-height: 0;
+ height: 100%;
+ flex-direction: column;
+ overflow-y: auto;
+ border-left: 1px solid var(--wxex-border);
+ background: #f7f9f8;
+}
+
+.report-settings-panel header {
+ flex: 0 0 auto;
+ padding: 20px 18px 14px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.report-settings-panel header h2 {
+ font: 700 16px/22px var(--wxex-font);
+}
+
+.report-settings-section {
+ margin: 0;
+ padding: 16px 18px;
+ border-bottom: 1px solid var(--wxex-border);
+}
+
+.report-settings-section h3 {
+ margin: 0 0 8px;
+ color: var(--wxex-text-primary);
+ font: 700 14px/20px var(--wxex-font);
+}
+
+.report-settings-section p,
+.report-settings-section code {
+ margin: 0 0 10px;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-settings-section code {
+ display: block;
+ max-width: 100%;
+ overflow-wrap: anywhere;
+ padding: 8px;
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-bg-elevated);
+}
+
+.report-settings-section.muted {
+ color: var(--wxex-text-muted);
+}
+
+.report-export-list {
+ display: grid;
+ gap: 8px;
+ margin-bottom: 10px;
+}
+
+.report-export-list div {
+ display: flex;
+ justify-content: space-between;
+ gap: 12px;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-export-list b {
+ min-width: 0;
+ color: var(--wxex-text-primary);
+ font-weight: 600;
+ overflow-wrap: anywhere;
+ text-align: right;
+}
+
+.report-generation-log {
+ display: grid;
+ gap: 10px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.report-generation-log li {
+ display: grid;
+ grid-template-columns: 18px minmax(0, 1fr);
+ gap: 8px;
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+
+.report-generation-log li > span {
+ color: var(--wxex-brand);
+ font-weight: 700;
+}
+
+.report-generation-log b,
+.report-generation-log time,
+.report-generation-log small {
+ display: block;
+}
+
+.report-generation-log b {
+ color: var(--wxex-text-primary);
+ font-weight: 600;
+}
+
+.report-generation-log time {
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+}
+
+.report-generation-log small {
+ color: var(--wxex-text-secondary);
+ font: 600 11px/16px var(--wxex-font);
+}
+
+@media (max-width: 1120px) {
+ .report-center-page {
+ grid-template-columns: 268px minmax(360px, 1fr) 280px;
+ }
+
+ .report-viewer-header {
+ flex-direction: column;
+ }
+}
+
+/* ============================================================ */
+/* 日报模板选择器 + 预览器 */
+/* ============================================================ */
+.report-section-desc {
+ margin: 0 0 12px;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 1.6;
+}
+
+.report-template-list {
+ display: grid;
+ gap: 10px;
+}
+
+.report-template-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 14px;
+ border: 1.5px solid var(--wxex-border);
+ border-radius: 12px;
+ background: #fff;
+ transition:
+ border-color 0.2s,
+ background 0.2s;
+}
+
+.report-template-item.active {
+ border-color: var(--wxex-primary, #07c160);
+ background: #f0fbf3;
+}
+
+.report-template-item.disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+.report-template-item > label {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ min-width: 0;
+}
+
+.report-template-item input[type='radio'] {
+ accent-color: var(--wxex-primary, #07c160);
+}
+
+.report-template-body {
+ flex: 1;
+ min-width: 0;
+}
+
+.report-template-title {
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--wxex-text-primary, #1f2933);
+}
+
+.report-template-tagline {
+ margin-top: 4px;
+ font-size: 12px;
+ color: var(--wxex-text-secondary, #485465);
+ line-height: 1.5;
+}
+
+.report-template-preview-btn {
+ padding: 6px 12px;
+ font-size: 12px;
+ font-weight: 600;
+ border-radius: 8px;
+ border: 1px solid var(--wxex-border);
+ background: #fff;
+ color: var(--wxex-text-primary, #1f2933);
+ cursor: pointer;
+ transition:
+ background 0.2s,
+ color 0.2s,
+ border-color 0.2s;
+}
+
+.report-template-preview-btn:hover {
+ background: var(--wxex-primary, #07c160);
+ color: #fff;
+ border-color: var(--wxex-primary, #07c160);
+}
+
+/* 预览遮罩 */
+.report-template-preview-mask {
+ position: fixed;
+ inset: 0;
+ background: rgba(15, 23, 42, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 999;
+ padding: 20px;
+}
+
+.report-template-preview-card {
+ background: #f3f5f7;
+ border-radius: 18px;
+ padding: 18px;
+ width: min(380px, 100%);
+ max-height: 90vh;
+ overflow-y: auto;
+ box-shadow: 0 16px 60px rgba(15, 23, 42, 0.25);
+}
+
+.report-template-preview-card h4 {
+ margin: 0 0 6px;
+ font-size: 17px;
+ font-weight: 800;
+}
+
+.report-template-preview-card p.muted {
+ margin: 0 0 14px;
+ font-size: 12px;
+ color: var(--wxex-text-secondary, #485465);
+ line-height: 1.5;
+}
+
+.report-template-preview-frame {
+ display: grid;
+ gap: 8px;
+ background: #fff;
+ border-radius: 14px;
+ padding: 12px;
+ border: 1px solid var(--wxex-border);
+}
+
+.fake-card {
+ background: #f7faf9;
+ border-radius: 10px;
+ padding: 10px 12px;
+}
+
+.fake-hero {
+ background: linear-gradient(135deg, #edf9f1 0%, #f7fbf8 100%);
+}
+
+.fake-title {
+ font-size: 14px;
+ font-weight: 800;
+ color: #076c39;
+}
+
+.fake-sub {
+ margin-top: 2px;
+ font-size: 11px;
+ color: #485465;
+}
+
+.fake-section {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.fake-bar {
+ width: 4px;
+ height: 14px;
+ border-radius: 2px;
+ background: var(--wxex-primary, #07c160);
+}
+
+.fake-section-title {
+ font-size: 12px;
+ font-weight: 700;
+ color: #1f2933;
+}
+
+.report-template-preview-close {
+ margin-top: 14px;
+ width: 100%;
+ padding: 10px;
+ border-radius: 10px;
+ border: none;
+ background: var(--wxex-primary, #07c160);
+ color: #fff;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.settings-auto-login-card {
+ padding: 18px 20px;
+}
+.settings-auto-login-card label {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+ cursor: pointer;
+}
+.settings-auto-login-card label > span {
+ display: grid;
+ gap: 4px;
+}
+.settings-auto-login-card b {
+ color: var(--wxex-text-primary);
+ font: 700 13px/19px var(--wxex-font);
+}
+.settings-auto-login-card small {
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.settings-auto-login-card input {
+ width: 18px;
+ height: 18px;
+ accent-color: var(--wxex-brand);
+}
+.settings-recall-card {
+ padding: 18px 20px;
+}
+.settings-recall-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(220px, 0.8fr);
+ gap: 18px;
+ align-items: center;
+}
+.settings-recall-option {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+ min-width: 0;
+ cursor: pointer;
+}
+.settings-recall-option span {
+ display: grid;
+ gap: 4px;
+}
+.settings-recall-option b {
+ color: var(--wxex-text-primary);
+ font: 700 13px/19px var(--wxex-font);
+}
+.settings-recall-option small {
+ color: var(--wxex-text-secondary);
+ font: 12px/18px var(--wxex-font);
+}
+.settings-recall-option input {
+ width: 18px;
+ height: 18px;
+ flex: 0 0 auto;
+ accent-color: var(--wxex-brand);
+}
+.settings-recall-notice {
+ display: grid;
+ gap: 3px;
+ padding-left: 14px;
+ border-left: 2px solid #e5b45f;
+ color: #765326;
+ font: 12px/18px var(--wxex-font);
+}
+.settings-recall-notice strong {
+ font-weight: 700;
+}
+.settings-recall-notice span {
+ color: #8a6a3e;
+}
+.api-upload-test-row {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin: 10px 0;
+}
+.api-upload-test-row button {
+ min-height: 32px;
+ padding: 0 12px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-primary);
+ cursor: pointer;
+ font: 600 12px/18px var(--wxex-font);
+}
+.api-upload-test-row span {
+ color: var(--wxex-text-muted);
+ font: 11px/17px var(--wxex-font);
+}
+
diff --git a/src/renderer/src/styles/rich-message.scss b/src/renderer/src/styles/rich-message.scss
new file mode 100644
index 0000000..ec96e2f
--- /dev/null
+++ b/src/renderer/src/styles/rich-message.scss
@@ -0,0 +1,331 @@
+/* Voice Player */
+.voice-message {
+ cursor: pointer;
+ user-select: none;
+}
+
+.voice-loading {
+ opacity: 0.6;
+}
+
+.voice-error {
+ opacity: 1;
+}
+
+.voice-loading-text {
+ font-size: 12px;
+ color: var(--wxex-text-muted);
+}
+
+.voice-error-text {
+ color: var(--wxex-text-secondary);
+}
+
+.voice-duration {
+ font-size: 12px;
+ margin-left: 4px;
+ min-width: 32px;
+}
+
+.voice-icon.playing {
+ background: rgba(36, 122, 99, 0.18);
+}
+
+/* Rich Message Bubbles */
+.location-message {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ min-width: 180px;
+ max-width: 280px;
+
+ .location-icon {
+ box-sizing: border-box;
+ min-width: 34px;
+ padding: 4px 6px;
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ font-size: 12px;
+ font-weight: 600;
+ flex-shrink: 0;
+ }
+
+ .location-info {
+ flex: 1;
+ overflow: hidden;
+ }
+
+ .location-name {
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .location-label {
+ font-size: 12px;
+ color: var(--wxex-text-secondary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .location-coords {
+ font-size: 11px;
+ color: var(--wxex-text-muted);
+ margin-top: 2px;
+ }
+}
+
+.wechat-message-row.mine {
+ .location-message {
+ flex-direction: row-reverse;
+ }
+}
+
+.card-message {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-width: 160px;
+ max-width: 240px;
+}
+
+.card-avatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 6px;
+ background: #07c160;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ font-weight: 500;
+ flex-shrink: 0;
+}
+
+.card-info {
+ flex: 1;
+ overflow: hidden;
+}
+
+.card-nickname {
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.card-username {
+ font-size: 12px;
+ color: #666;
+ cursor: pointer;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ &:hover {
+ color: #07c160;
+ }
+}
+
+.share-message {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ cursor: pointer;
+ min-width: 180px;
+ max-width: 280px;
+}
+
+.share-appname {
+ font-size: 11px;
+ color: #999;
+}
+
+.share-title {
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.share-desc {
+ font-size: 12px;
+ color: #666;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.share-url {
+ font-size: 11px;
+ color: #999;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.mini-program-message {
+ width: min(280px, 48vw);
+ overflow: hidden;
+ color: var(--wxex-text-primary);
+}
+
+.mini-program-title {
+ margin-bottom: 8px;
+ font-size: 14px;
+ line-height: 20px;
+ word-break: break-word;
+}
+
+.mini-program-description {
+ margin: -4px 0 8px;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.mini-program-preview {
+ .image-bubble,
+ .image-content {
+ width: 100%;
+ max-width: 100%;
+ max-height: 220px;
+ border-radius: 4px;
+ }
+
+ .image-content {
+ object-fit: cover;
+ }
+
+ .image-actions {
+ display: none;
+ }
+
+ .image-content.image-fallback {
+ width: 64px;
+ height: 64px;
+ margin: 28px auto;
+ border-radius: 8px;
+ object-fit: cover;
+ }
+}
+
+.mini-program-inline-image {
+ display: block;
+ width: 100%;
+ max-height: 220px;
+ border-radius: 4px;
+ object-fit: cover;
+ cursor: zoom-in;
+}
+
+.mini-program-icon {
+ display: block;
+ width: 52px;
+ height: 52px;
+ margin: 8px 0;
+ border-radius: 6px;
+ object-fit: cover;
+}
+
+.mini-program-footer {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ margin-top: 8px;
+ padding-top: 7px;
+ border-top: 1px solid var(--wxex-border);
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ line-height: 16px;
+}
+
+.red-packet-message {
+ width: min(280px, 48vw);
+ overflow: hidden;
+ border-radius: 6px;
+ background: #fa9d3b;
+ color: #fff;
+
+ &.is-clickable {
+ cursor: pointer;
+ }
+}
+
+.red-packet-main {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-height: 72px;
+ padding: 12px 14px;
+}
+
+.red-packet-icon {
+ display: grid;
+ width: 36px;
+ height: 36px;
+ flex: 0 0 36px;
+ place-items: center;
+ border: 2px solid rgba(255, 239, 170, 0.92);
+ border-radius: 50%;
+ color: #fff1a8;
+ font-size: 18px;
+ font-weight: 700;
+}
+
+.red-packet-copy {
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.red-packet-copy strong {
+ overflow: hidden;
+ font-size: 15px;
+ font-weight: 500;
+ line-height: 21px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.red-packet-copy small {
+ color: rgba(255, 255, 255, 0.82);
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.red-packet-footer {
+ padding: 5px 14px;
+ background: #fff;
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ line-height: 16px;
+}
+
+.voip-message {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ white-space: nowrap;
+}
+
+.voip-icon {
+ box-sizing: border-box;
+ padding: 3px 6px;
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-brand);
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.voip-status {
+ font-size: 13px;
+}
diff --git a/src/renderer/src/styles/search.css b/src/renderer/src/styles/search.scss
similarity index 75%
rename from src/renderer/src/styles/search.css
rename to src/renderer/src/styles/search.scss
index 17e5a90..8ca88bf 100644
--- a/src/renderer/src/styles/search.css
+++ b/src/renderer/src/styles/search.scss
@@ -21,24 +21,21 @@
padding: 14px 22px 12px;
border-bottom: 1px solid var(--wxex-border);
background: rgba(250, 251, 250, 0.94);
-}
-.ai-search-header h1,
-.ai-search-header p {
- margin: 0;
-}
+ h1 {
+ margin: 0;
+ color: var(--wxex-text-primary);
+ font-size: 20px;
+ font-weight: 700;
+ line-height: 28px;
+ }
-.ai-search-header h1 {
- color: var(--wxex-text-primary);
- font-size: 20px;
- font-weight: 700;
- line-height: 28px;
-}
-
-.ai-search-header p {
- color: var(--wxex-text-secondary);
- font-size: 12px;
- line-height: 18px;
+ p {
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 18px;
+ }
}
.ai-search-kicker {
@@ -57,28 +54,36 @@
color: var(--wxex-text-secondary);
font-size: 12px;
line-height: 18px;
-}
-.ai-search-model-status > span:first-child {
- width: 8px;
- height: 8px;
- flex: 0 0 auto;
- border-radius: 50%;
- background: var(--wxex-text-muted);
-}
+ > span:first-child {
+ width: 8px;
+ height: 8px;
+ flex: 0 0 auto;
+ border-radius: 50%;
+ background: var(--wxex-text-muted);
+ }
-.ai-search-model-status > span.ready {
- background: var(--wxex-success);
-}
+ > span {
+ &.ready {
+ background: var(--wxex-success);
+ }
-.ai-search-model-status > span.warning {
- background: var(--wxex-warning);
-}
+ &.warning {
+ background: var(--wxex-warning);
+ }
+ }
-.ai-search-model-status > span:nth-child(2) {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+ > span:nth-child(2) {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ button {
+ padding: 5px 8px;
+ color: var(--wxex-brand);
+ white-space: nowrap;
+ }
}
.ai-search-model-status button,
@@ -93,12 +98,6 @@
font: inherit;
}
-.ai-search-model-status button {
- padding: 5px 8px;
- color: var(--wxex-brand);
- white-space: nowrap;
-}
-
.ai-search-grid {
display: grid;
flex: 1;
@@ -134,25 +133,26 @@
justify-content: space-between;
gap: 10px;
margin-bottom: 14px;
-}
-.ai-search-panel-heading div {
- display: flex;
- flex-direction: column;
- gap: 2px;
-}
+ div {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
-.ai-search-panel-heading span:first-child {
- color: var(--wxex-text-muted);
- font-size: 10px;
- line-height: 15px;
-}
+ span:first-child {
+ color: var(--wxex-text-muted);
+ font-size: 10px;
+ line-height: 15px;
+ }
+
+ strong {
+ color: var(--wxex-text-primary);
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 20px;
+ }
-.ai-search-panel-heading strong {
- color: var(--wxex-text-primary);
- font-size: 14px;
- font-weight: 700;
- line-height: 20px;
}
.ai-search-local-badge,
@@ -179,33 +179,17 @@
padding: 3px;
border-radius: var(--wxex-radius-sm);
background: var(--wxex-bg-elevated);
-}
-.ai-search-scope-toggle button,
-.ai-search-range-grid button,
-.ai-search-history button {
- border: 0;
- border-radius: var(--wxex-radius-sm);
- background: transparent;
- color: var(--wxex-text-secondary);
- cursor: pointer;
- font: inherit;
-}
+ button {
+ padding: 7px 4px;
+ font-size: 11px;
-.ai-search-scope-toggle button {
- padding: 7px 4px;
- font-size: 11px;
-}
-
-.ai-search-scope-toggle button.active,
-.ai-search-range-grid button.active {
- background: var(--wxex-brand);
- color: var(--wxex-brand);
- font-weight: 700;
-}
-
-.ai-search-scope-toggle button.active {
- color: #fff;
+ &.active {
+ background: var(--wxex-brand);
+ color: #fff;
+ font-weight: 700;
+ }
+ }
}
.ai-search-scope-help {
@@ -235,24 +219,24 @@
border: 1px solid var(--wxex-border);
border-radius: var(--wxex-radius-sm);
background: var(--wxex-bg-elevated);
-}
-.ai-search-filter-input svg {
- width: 15px;
- height: 15px;
- flex: 0 0 auto;
- color: var(--wxex-text-muted);
-}
+ svg {
+ width: 15px;
+ height: 15px;
+ flex: 0 0 auto;
+ color: var(--wxex-text-muted);
+ }
-.ai-search-filter-input input {
- width: 100%;
- min-width: 0;
- border: 0;
- outline: 0;
- background: transparent;
- color: var(--wxex-text-primary);
- font: inherit;
- font-size: 11px;
+ input {
+ width: 100%;
+ min-width: 0;
+ border: 0;
+ outline: 0;
+ background: transparent;
+ color: var(--wxex-text-primary);
+ font: inherit;
+ font-size: 11px;
+ }
}
.ai-search-contact-list {
@@ -277,11 +261,11 @@
cursor: pointer;
font: inherit;
text-align: left;
-}
-.ai-search-contact:hover,
-.ai-search-contact.active {
- background: var(--wxex-brand-soft);
+ &:hover,
+ &.active {
+ background: var(--wxex-brand-soft);
+ }
}
.ai-search-contact-avatar {
@@ -296,12 +280,12 @@
color: var(--wxex-brand);
font-size: 12px;
font-weight: 700;
-}
-.ai-search-contact-avatar img {
- width: 100%;
- height: 100%;
- object-fit: cover;
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
}
.ai-search-contact > span:last-child {
@@ -337,6 +321,31 @@
background: var(--wxex-bg-elevated);
grid-template-columns: 1fr 1fr;
margin-bottom: 16px;
+
+ button {
+ border: 0;
+ border-radius: var(--wxex-radius-sm);
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: inherit;
+ min-height: 34px;
+ padding: 7px 4px;
+ border: 1px solid transparent;
+ font-size: 11px;
+
+ &:hover {
+ border-color: var(--wxex-brand);
+ color: var(--wxex-brand);
+ }
+
+ &.active {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+ box-shadow: 0 1px 3px rgba(34, 89, 74, 0.2);
+ }
+ }
}
.ai-search-field-heading {
@@ -356,26 +365,6 @@
font-weight: 700;
}
-.ai-search-range-grid button {
- min-height: 34px;
- padding: 7px 4px;
- border: 1px solid transparent;
- font-size: 11px;
-}
-
-.ai-search-range-grid button:hover {
- border-color: var(--wxex-brand);
- color: var(--wxex-brand);
-}
-
-.ai-search-range-grid button.active,
-.ai-search-range-grid button.active:hover {
- border-color: var(--wxex-brand);
- background: var(--wxex-brand);
- color: #fff;
- box-shadow: 0 1px 3px rgba(34, 89, 74, 0.2);
-}
-
.ai-search-filter-note {
display: flex;
gap: 6px;
@@ -386,28 +375,34 @@
color: var(--wxex-text-secondary);
font-size: 10px;
line-height: 16px;
-}
-.ai-search-filter-note span {
- color: var(--wxex-success);
+ span {
+ color: var(--wxex-success);
+ }
}
.ai-search-history {
margin-top: 18px;
-}
-.ai-search-history button {
- min-width: 0;
- padding: 5px 0;
- overflow: hidden;
- text-align: left;
- text-overflow: ellipsis;
- white-space: nowrap;
- font-size: 10px;
-}
+ button {
+ min-width: 0;
+ padding: 5px 0;
+ overflow: hidden;
+ border: 0;
+ border-radius: var(--wxex-radius-sm);
+ background: transparent;
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: inherit;
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 10px;
-.ai-search-history button:hover {
- color: var(--wxex-brand);
+ &:hover {
+ color: var(--wxex-brand);
+ }
+ }
}
.ai-search-history-item {
@@ -415,10 +410,10 @@
align-items: center;
gap: 5px;
min-width: 0;
-}
-.ai-search-history-item > button:first-child {
- flex: 1;
+ > button:first-child {
+ flex: 1;
+ }
}
.ai-search-history-delete {
@@ -434,11 +429,11 @@
font-size: 16px !important;
line-height: 18px;
text-align: center !important;
-}
-.ai-search-history-delete:hover {
- background: var(--wxex-brand-soft);
- color: var(--wxex-danger, #b34d46) !important;
+ &:hover {
+ background: var(--wxex-brand-soft);
+ color: var(--wxex-danger, #b34d46) !important;
+ }
}
.ai-search-main {
@@ -468,6 +463,22 @@
padding: 48px 24px;
flex-direction: column;
text-align: center;
+
+ h2 {
+ margin: 7px 0 8px;
+ color: var(--wxex-text-primary);
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 26px;
+ }
+
+ p {
+ max-width: 440px;
+ margin: 0;
+ color: var(--wxex-text-secondary);
+ font-size: 12px;
+ line-height: 20px;
+ }
}
.ai-search-empty-mark {
@@ -482,24 +493,18 @@
font-size: 28px;
}
-.ai-search-empty h2,
-.ai-search-loading h2,
-.ai-search-insufficient h2 {
- margin: 7px 0 8px;
- color: var(--wxex-text-primary);
- font-size: 18px;
- font-weight: 700;
- line-height: 26px;
-}
+.ai-search-insufficient {
+ button {
+ margin-top: 20px;
+ padding: 8px 12px;
+ font-size: 11px;
-.ai-search-empty p,
-.ai-search-loading p,
-.ai-search-insufficient p {
- max-width: 440px;
- margin: 0;
- color: var(--wxex-text-secondary);
- font-size: 12px;
- line-height: 20px;
+ &.primary {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+ }
+ }
}
.ai-search-prompts {
@@ -508,22 +513,22 @@
justify-content: center;
gap: 7px;
margin-top: 22px;
-}
-.ai-search-prompts button {
- padding: 7px 10px;
- border: 1px solid var(--wxex-border);
- border-radius: 999px;
- background: var(--wxex-bg-elevated);
- color: var(--wxex-text-secondary);
- cursor: pointer;
- font: inherit;
- font-size: 11px;
-}
+ button {
+ padding: 7px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: 999px;
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-text-secondary);
+ cursor: pointer;
+ font: inherit;
+ font-size: 11px;
-.ai-search-prompts button:hover {
- border-color: var(--wxex-brand);
- color: var(--wxex-brand);
+ &:hover {
+ border-color: var(--wxex-brand);
+ color: var(--wxex-brand);
+ }
+ }
}
.ai-search-spinner {
@@ -550,14 +555,15 @@
color: var(--wxex-text-muted);
font-size: 11px;
text-align: left;
-}
-.ai-search-loading-steps .done {
- color: var(--wxex-success);
-}
-.ai-search-loading-steps .active {
- color: var(--wxex-brand);
- font-weight: 700;
+ .done {
+ color: var(--wxex-success);
+ }
+
+ .active {
+ color: var(--wxex-brand);
+ font-weight: 700;
+ }
}
.ai-search-result {
@@ -573,21 +579,21 @@
gap: 18px;
padding-bottom: 20px;
border-bottom: 1px solid var(--wxex-border);
-}
-.ai-search-result-header h2 {
- margin: 6px 0 5px;
- color: var(--wxex-text-primary);
- font-size: 18px;
- font-weight: 700;
- line-height: 26px;
-}
+ h2 {
+ margin: 6px 0 5px;
+ color: var(--wxex-text-primary);
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 26px;
+ }
-.ai-search-result-header p {
- margin: 0;
- color: var(--wxex-text-muted);
- font-size: 11px;
- line-height: 16px;
+ p {
+ margin: 0;
+ color: var(--wxex-text-muted);
+ font-size: 11px;
+ line-height: 16px;
+ }
}
.ai-search-result-actions {
@@ -596,19 +602,17 @@
flex-wrap: wrap;
justify-content: flex-end;
gap: 6px;
-}
-.ai-search-result-actions button {
- padding: 7px 9px;
- font-size: 11px;
-}
+ button {
+ padding: 7px 9px;
+ font-size: 11px;
-.ai-search-result-actions button.primary,
-.ai-search-composer button.primary,
-.ai-search-insufficient button.primary {
- border-color: var(--wxex-brand);
- background: var(--wxex-brand);
- color: #fff;
+ &.primary {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+ }
+ }
}
.ai-search-summary-block {
@@ -656,12 +660,6 @@
font-weight: 700;
}
-.ai-search-insufficient button {
- margin-top: 20px;
- padding: 8px 12px;
- font-size: 11px;
-}
-
.ai-search-composer {
padding: 12px 18px 14px;
border-top: 1px solid var(--wxex-border);
@@ -678,13 +676,16 @@
line-height: 15px;
}
-.ai-search-composer-meta strong {
- color: var(--wxex-brand);
- font-weight: 700;
-}
-.ai-search-composer-meta em {
- font-style: normal;
- color: var(--wxex-text-secondary);
+.ai-search-composer-meta {
+ strong {
+ color: var(--wxex-brand);
+ font-weight: 700;
+ }
+
+ em {
+ font-style: normal;
+ color: var(--wxex-text-secondary);
+ }
}
.ai-search-composer-row {
@@ -692,41 +693,50 @@
align-items: flex-end;
gap: 8px;
margin-top: 7px;
-}
-.ai-search-composer textarea {
- width: 100%;
- min-width: 0;
- resize: none;
- padding: 9px 10px;
- border: 1px solid var(--wxex-border);
- border-radius: var(--wxex-radius-sm);
- outline: 0;
- background: var(--wxex-bg-main);
- color: var(--wxex-text-primary);
- font: inherit;
- font-size: 12px;
- line-height: 18px;
-}
+ textarea {
+ width: 100%;
+ min-width: 0;
+ resize: none;
+ padding: 9px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ outline: 0;
+ background: var(--wxex-bg-main);
+ color: var(--wxex-text-primary);
+ font: inherit;
+ font-size: 12px;
+ line-height: 18px;
-.ai-search-composer textarea:focus {
- border-color: var(--wxex-brand);
-}
-.ai-search-composer button {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 9px 13px;
- white-space: nowrap;
- font-size: 11px;
-}
-.ai-search-composer button span {
- font-size: 16px;
- line-height: 12px;
-}
-.ai-search-composer button:disabled {
- opacity: 0.6;
- cursor: wait;
+ &:focus {
+ border-color: var(--wxex-brand);
+ }
+ }
+
+ button {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 9px 13px;
+ white-space: nowrap;
+ font-size: 11px;
+
+ span {
+ font-size: 16px;
+ line-height: 12px;
+ }
+
+ &.primary {
+ border-color: var(--wxex-brand);
+ background: var(--wxex-brand);
+ color: #fff;
+ }
+
+ &:disabled {
+ opacity: 0.6;
+ cursor: wait;
+ }
+ }
}
.ai-search-composer-foot {
justify-content: space-between;
diff --git a/src/renderer/src/styles/settings-advanced.css b/src/renderer/src/styles/settings-advanced.css
deleted file mode 100644
index 4663c07..0000000
--- a/src/renderer/src/styles/settings-advanced.css
+++ /dev/null
@@ -1,46 +0,0 @@
-.settings-debug-card {
- display: grid;
- gap: 14px;
-}
-
-.settings-debug-card > label {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 18px;
-}
-
-.settings-debug-card > label > span {
- display: grid;
- gap: 5px;
-}
-
-.settings-debug-card b {
- color: var(--wxex-text-primary);
- font-size: 13px;
-}
-
-.settings-debug-card small {
- color: var(--wxex-text-secondary);
- font-size: 11px;
- line-height: 18px;
-}
-
-.settings-debug-actions {
- display: flex;
- align-items: center;
- gap: 10px;
- padding-top: 12px;
- border-top: 1px solid var(--wxex-border);
-}
-
-.settings-debug-actions button {
- padding: 7px 10px;
- border: 1px solid var(--wxex-border);
- border-radius: var(--wxex-radius-sm);
- background: var(--wxex-bg-elevated);
- color: var(--wxex-brand);
- cursor: pointer;
- font: inherit;
- font-size: 11px;
-}
diff --git a/src/renderer/src/styles/settings-advanced.scss b/src/renderer/src/styles/settings-advanced.scss
new file mode 100644
index 0000000..ad28dc7
--- /dev/null
+++ b/src/renderer/src/styles/settings-advanced.scss
@@ -0,0 +1,46 @@
+.settings-debug-card {
+ display: grid;
+ gap: 14px;
+
+ > label {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 18px;
+
+ > span {
+ display: grid;
+ gap: 5px;
+ }
+ }
+
+ b {
+ color: var(--wxex-text-primary);
+ font-size: 13px;
+ }
+
+ small {
+ color: var(--wxex-text-secondary);
+ font-size: 11px;
+ line-height: 18px;
+ }
+}
+
+.settings-debug-actions {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding-top: 12px;
+ border-top: 1px solid var(--wxex-border);
+
+ button {
+ padding: 7px 10px;
+ border: 1px solid var(--wxex-border);
+ border-radius: var(--wxex-radius-sm);
+ background: var(--wxex-bg-elevated);
+ color: var(--wxex-brand);
+ cursor: pointer;
+ font: inherit;
+ font-size: 11px;
+ }
+}
diff --git a/src/renderer/src/styles/settings.scss b/src/renderer/src/styles/settings.scss
new file mode 100644
index 0000000..ea4695b
--- /dev/null
+++ b/src/renderer/src/styles/settings.scss
@@ -0,0 +1,1628 @@
+/* API-01 本地 API 中心 */
+.api-center-layout {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) 320px;
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ background: var(--wxex-bg-main);
+}
+
+/* SETTINGS-01: formal settings workspace. The legacy SettingsPanel remains only as a fallback source. */
+.settings-workspace {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ background: #fafbfa;
+}
+
+.settings-page-panel {
+ display: none;
+ min-width: 0;
+ min-height: 0;
+ flex: 1 1 auto;
+
+ &.active {
+ display: flex;
+ }
+}
+.settings-sidebar {
+ width: 294px;
+ flex: 0 0 294px;
+ min-width: 0;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ background: #eef2f0;
+ border-right: 1px solid #dde3e0;
+
+ header {
+ padding: 22px 20px 16px;
+ border-bottom: 1px solid #dde3e0;
+
+ h1 {
+ margin: 0;
+ color: #202724;
+ font-size: 20px;
+ }
+
+ p {
+ margin: 5px 0 16px;
+ color: #66706b;
+ font-size: 12px;
+ }
+ }
+}
+.settings-search {
+ height: 34px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 0 10px;
+ border: 1px solid #dde3e0;
+ border-radius: 8px;
+ background: #fff;
+ color: #66706b;
+
+ input {
+ min-width: 0;
+ width: 100%;
+ border: 0;
+ outline: 0;
+ color: #202724;
+ background: transparent;
+ font: inherit;
+ font-size: 12px;
+ }
+}
+.settings-sidebar-list {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ padding: 12px 8px;
+
+ section {
+ margin: 0 0 18px;
+ }
+
+ h2 {
+ margin: 0 12px 6px;
+ color: #929a96;
+ font-size: 12px;
+ font-weight: 500;
+ }
+
+ button {
+ position: relative;
+ display: block;
+ width: 100%;
+ border: 0;
+ padding: 9px 12px;
+ background: transparent;
+ color: #39433e;
+ text-align: left;
+ font: 600 13px inherit;
+ cursor: pointer;
+ border-radius: 8px;
+
+ &.active {
+ background: #fff;
+ color: #202724;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 7px;
+ bottom: 7px;
+ width: 3px;
+ border-radius: 0 3px 3px 0;
+ background: #247a63;
+ }
+ }
+ }
+}
+.settings-sidebar-account {
+ flex: 0 0 auto;
+ padding: 10px;
+ border-top: 1px solid #dde3e0;
+}
+.settings-page {
+ position: relative;
+ display: flex;
+ flex: 1;
+ min-width: 0;
+ min-height: 0;
+ flex-direction: column;
+}
+.settings-page-header {
+ flex: 0 0 auto;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 18px;
+ padding: 24px 34px;
+ border-bottom: 1px solid #eef1ef;
+ background: #fafbfa;
+
+ h1 {
+ margin: 0;
+ color: #202724;
+ font-size: 21px;
+ }
+
+ p {
+ margin: 6px 0 0;
+ color: #66706b;
+ font-size: 13px;
+ }
+}
+.settings-status-badge {
+ margin-top: 5px;
+ flex: 0 0 auto;
+ border-radius: 16px;
+ padding: 7px 12px;
+ background: #edf5f1;
+ color: #2e8b68;
+ font-size: 12px;
+
+ &::before {
+ content: '●';
+ margin-right: 6px;
+ font-size: 9px;
+ }
+
+ &.checking {
+ background: #eef4f8;
+ color: #4f7188;
+ }
+
+ &.warning {
+ background: #fff6e8;
+ color: #a56a24;
+ }
+
+ &.error {
+ background: #f9eeee;
+ color: #c85a5a;
+ }
+
+ &.unavailable {
+ background: #f1f3f2;
+ color: #66706b;
+ }
+}
+.settings-page-scroll {
+ flex: 1;
+ min-height: 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+.settings-page-content {
+ box-sizing: border-box;
+ width: min(100%, 860px);
+ padding: 34px 34px 64px;
+}
+.settings-privacy-notice {
+ display: flex;
+ gap: 14px;
+ align-items: flex-start;
+ padding: 17px;
+ border: 1px solid #bfded3;
+ border-radius: 10px;
+ background: #f0f7f4;
+ color: #36564d;
+
+ svg {
+ flex: 0 0 24px;
+ width: 24px;
+ stroke: #247a63;
+ fill: none;
+ stroke-width: 1.8;
+ }
+
+ strong {
+ color: #294b41;
+ font-size: 14px;
+ }
+
+ p {
+ margin: 5px 0 0;
+ color: #66706b;
+ font-size: 13px;
+ line-height: 1.6;
+ }
+}
+.settings-section-heading {
+ margin: 30px 0 14px;
+ color: #3d4742;
+ font-size: 16px;
+}
+.settings-card {
+ border: 1px solid #dde3e0;
+ border-radius: 10px;
+ background: #fff;
+ padding: 24px 26px;
+}
+.settings-account-overview {
+ display: grid;
+ grid-template-columns: minmax(190px, 1fr) minmax(220px, 1fr) auto;
+ gap: 24px;
+ align-items: center;
+}
+.settings-account-primary {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 15px;
+}
+.settings-avatar {
+ width: 66px;
+ height: 66px;
+ flex: 0 0 auto;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+ border-radius: 9px;
+ background: #dcede6;
+ color: #247a63;
+ font-size: 23px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+.settings-account-identity {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+}
+.settings-account-identity span,
+.settings-account-root > span,
+.settings-account-facts dt {
+ color: #929a96;
+ font-size: 12px;
+}
+.settings-account-identity strong,
+.settings-account-identity small {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.settings-account-identity strong {
+ color: #35403b;
+ font-size: 14px;
+}
+.settings-account-identity small {
+ color: #66706b;
+ font:
+ 12px/18px ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.settings-account-facts {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ margin: 0;
+}
+.settings-account-facts div {
+ min-width: 0;
+}
+.settings-account-facts dd {
+ overflow: hidden;
+ margin: 3px 0 0;
+ color: #35403b;
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.settings-connection-text.success {
+ color: #2e8b68;
+}
+.settings-connection-text.warning {
+ color: #a56a24;
+}
+.settings-connection-text.error {
+ color: #c85a5a;
+}
+.settings-account-actions {
+ display: grid;
+ gap: 8px;
+}
+.settings-account-actions button {
+ min-height: 34px;
+ white-space: nowrap;
+}
+.settings-account-root {
+ grid-column: 1/-1;
+ display: grid;
+ min-width: 0;
+ gap: 7px;
+ padding-top: 19px;
+ border-top: 1px solid #edf0ee;
+}
+.settings-account-root > div {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 8px;
+}
+.settings-account-root code {
+ min-width: 0;
+ flex: 1;
+ overflow: hidden;
+ padding: 10px 12px;
+ border: 1px solid #dde3e0;
+ border-radius: 8px;
+ background: #f2f5f3;
+ color: #46514c;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font:
+ 12px/18px ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.settings-icon-button {
+ display: grid;
+ width: 36px;
+ height: 36px;
+ flex: 0 0 auto;
+ place-items: center;
+ border: 1px solid #dde3e0;
+ border-radius: 8px;
+ background: #fff;
+ color: #66706b;
+ cursor: pointer;
+}
+.settings-icon-button:hover:not(:disabled) {
+ border-color: #247a63;
+ color: #247a63;
+}
+.settings-icon-button:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+.settings-icon-button svg {
+ width: 17px;
+ fill: none;
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 1.8;
+}
+.settings-health-card {
+ padding: 12px;
+}
+.settings-diagnostic-summary {
+ margin: 0 0 10px;
+ padding: 9px 11px;
+ border-left: 3px solid #c68635;
+ border-radius: 6px;
+ background: #fff8ec;
+ color: #79501f;
+ font-size: 12px;
+ line-height: 1.55;
+}
+.settings-diagnostics {
+ display: grid;
+ gap: 8px;
+}
+.settings-diagnostic {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-width: 0;
+ padding: 13px;
+ border: 1px solid #edf0ee;
+ border-radius: 8px;
+}
+.settings-diagnostic-icon {
+ display: grid;
+ width: 18px;
+ height: 18px;
+ flex: 0 0 auto;
+ place-items: center;
+ border: 1px solid #929a96;
+ border-radius: 50%;
+ color: #929a96;
+ font-size: 11px;
+ font-weight: 700;
+}
+.settings-diagnostic-icon.success {
+ border-color: #2e8b68;
+ color: #2e8b68;
+}
+.settings-diagnostic-icon.warning {
+ border-color: #c68635;
+ color: #c68635;
+}
+.settings-diagnostic-icon.error {
+ border-color: #c85a5a;
+ color: #c85a5a;
+}
+.settings-diagnostic-icon.checking {
+ border-color: #cbd7d2;
+ border-top-color: #247a63;
+ animation: settings-spin 0.8s linear infinite;
+}
+.settings-diagnostic span {
+ color: #3d4742;
+ font-size: 13px;
+}
+.settings-diagnostic small {
+ margin-left: auto;
+ overflow: hidden;
+ color: #66706b;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.settings-empty-state {
+ display: grid;
+ flex: 1;
+ place-content: center;
+ color: #66706b;
+ text-align: center;
+}
+.settings-empty-state h2 {
+ color: #202724;
+}
+/* SETTINGS-02: database key */
+.database-key-content {
+ padding-bottom: 48px;
+}
+.database-key-badge.unconfigured {
+ background: #f1f3f2;
+ color: #66706b;
+}
+.database-key-badge.validating {
+ background: #eef4f8;
+ color: #4f7188;
+}
+.database-key-badge.invalid {
+ background: #f9eeee;
+ color: #c85a5a;
+}
+.database-key-status-card dl {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 18px 36px;
+ margin: 0 0 20px;
+}
+.database-key-status-card dl div {
+ min-width: 0;
+}
+.database-key-status-card dt,
+.database-key-diagnostics dt {
+ color: #929a96;
+ font-size: 12px;
+}
+.database-key-status-card dd,
+.database-key-diagnostics dd {
+ overflow: hidden;
+ margin: 5px 0 0;
+ color: #35403b;
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.database-key-mono {
+ font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
+}
+.database-key-success {
+ color: #2e8b68 !important;
+}
+.database-key-muted {
+ color: #66706b !important;
+}
+.database-key-primary,
+.database-key-secondary {
+ min-height: 36px;
+ padding: 0 15px;
+ border: 1px solid #247a63;
+ border-radius: 8px;
+ cursor: pointer;
+ font: 600 13px/1 inherit;
+}
+.database-key-primary {
+ background: #247a63;
+ color: #fff;
+}
+.database-key-secondary {
+ background: #fff;
+ color: #247a63;
+}
+.database-key-primary:hover:not(:disabled) {
+ background: #1d6754;
+}
+.database-key-secondary:hover:not(:disabled) {
+ background: #f0f7f4;
+}
+.database-key-primary:disabled,
+.database-key-secondary:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+.database-key-editor label {
+ display: block;
+ margin-bottom: 9px;
+ color: #46514c;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+.database-key-input-row {
+ display: flex;
+ min-width: 0;
+ height: 42px;
+ border: 1px solid #d5ddda;
+ border-radius: 8px;
+ background: #f4f7f5;
+}
+.database-key-input-row:focus-within {
+ border-color: #247a63;
+ box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09);
+}
+.database-key-input-row input {
+ min-width: 0;
+ flex: 1;
+ border: 0;
+ outline: 0;
+ padding: 0 14px;
+ background: transparent;
+ color: #202724;
+ font:
+ 13px/1.4 ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.database-key-input-row button {
+ display: grid;
+ width: 38px;
+ flex: 0 0 38px;
+ place-items: center;
+ border: 0;
+ background: transparent;
+ color: #66706b;
+ cursor: pointer;
+}
+.database-key-input-row button:hover:not(:disabled) {
+ color: #247a63;
+}
+.database-key-input-row button:disabled {
+ cursor: not-allowed;
+ opacity: 0.4;
+}
+.database-key-input-row svg {
+ width: 17px;
+ fill: none;
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 1.8;
+}
+.database-key-editor > p {
+ margin: 9px 0 0;
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.6;
+}
+.database-key-actions {
+ display: flex;
+ gap: 9px;
+ margin-top: 18px;
+}
+.database-key-feedback {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px 18px;
+ margin-top: 12px;
+ padding: 12px 15px;
+ border-radius: 8px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.database-key-feedback.checking {
+ background: #f1f4f3;
+ color: #66706b;
+}
+.database-key-feedback.checking i {
+ width: 14px;
+ height: 14px;
+ border: 2px solid #c8d5d0;
+ border-top-color: #247a63;
+ border-radius: 50%;
+ animation: settings-spin 0.8s linear infinite;
+}
+.database-key-feedback.success {
+ border: 1px solid #bfded3;
+ background: #eaf5f1;
+ color: #2e765d;
+}
+.database-key-feedback.success strong {
+ width: 100%;
+}
+.database-key-feedback.error {
+ border: 1px solid #efcaca;
+ background: #fff2f2;
+ color: #a84444;
+}
+.database-key-auto-heading {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 24px;
+}
+.database-key-auto strong {
+ color: #35403b;
+ font-size: 14px;
+}
+.database-key-auto p {
+ margin: 6px 0 0;
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.6;
+}
+.database-key-prerequisites {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px 20px;
+ margin: 18px 0 0;
+ padding: 14px 0 0;
+ border-top: 1px solid #edf0ee;
+ list-style: none;
+ color: #8b5c25;
+ font-size: 12px;
+}
+.database-key-prerequisites li::before {
+ content: '○';
+ margin-right: 6px;
+}
+.database-key-prerequisites li.ok {
+ color: #2e8b68;
+}
+.database-key-prerequisites li.ok::before {
+ content: '✓';
+}
+.database-key-phases {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 8px;
+ margin: 18px 0 0;
+ padding: 0;
+ counter-reset: key-phase;
+ list-style: none;
+}
+.database-key-phases li {
+ position: relative;
+ padding-top: 24px;
+ color: #929a96;
+ text-align: center;
+ font-size: 11px;
+}
+.database-key-phases li::before {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ display: grid;
+ width: 18px;
+ height: 18px;
+ place-items: center;
+ border: 1px solid #d5ddda;
+ border-radius: 50%;
+ background: #fff;
+ content: counter(key-phase);
+ counter-increment: key-phase;
+ transform: translateX(-50%);
+}
+.database-key-phases li.active {
+ color: #247a63;
+}
+.database-key-phases li.active::before {
+ border-color: #247a63;
+ background: #247a63;
+ color: #fff;
+}
+.database-key-auto-error {
+ display: grid;
+ gap: 4px;
+ margin-top: 16px;
+ padding: 12px 14px;
+ border-left: 3px solid #c68635;
+ background: #fff8ec;
+ color: #79501f;
+ font-size: 12px;
+}
+.database-key-auto-error span {
+ overflow-wrap: anywhere;
+}
+.database-key-auto-error p {
+ color: #79501f;
+}
+.database-key-auto-error button {
+ justify-self: start;
+ border: 0;
+ padding: 4px 0;
+ background: transparent;
+ color: #247a63;
+ cursor: pointer;
+ font: 600 12px inherit;
+}
+.database-key-security-info {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 1px;
+ overflow: hidden;
+ border: 1px solid #e3e8e5;
+ border-radius: 9px;
+ background: #e3e8e5;
+}
+.database-key-security-info span {
+ display: grid;
+ gap: 6px;
+ padding: 15px;
+ background: #f5f7f6;
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.database-key-security-info strong {
+ color: #35403b;
+ font-size: 13px;
+}
+.database-key-diagnostics {
+ margin-top: 22px;
+ border: 1px solid #dde3e0;
+ border-radius: 9px;
+ background: #fff;
+}
+.database-key-diagnostics summary {
+ padding: 14px 16px;
+ color: #46514c;
+ cursor: pointer;
+ font-size: 13px;
+ font-weight: 600;
+}
+.database-key-diagnostics dl {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 14px 28px;
+ margin: 0;
+ padding: 2px 16px 16px;
+}
+.database-key-diagnostics button {
+ margin: 0 16px 16px;
+ border: 0;
+ padding: 0;
+ background: transparent;
+ color: #247a63;
+ cursor: pointer;
+ font: 600 12px inherit;
+}
+.database-key-connection-actions {
+ margin-top: 30px;
+}
+.database-key-connection-actions > h2 {
+ margin: 0 0 14px;
+ color: #3d4742;
+ font-size: 15px;
+}
+.database-key-connection-actions > div {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+ padding: 16px 20px;
+ border: 1px solid #dde3e0;
+ border-radius: 9px;
+ background: #fff;
+}
+.database-key-connection-actions span {
+ display: grid;
+ gap: 4px;
+}
+.database-key-connection-actions strong {
+ color: #35403b;
+ font-size: 13px;
+}
+.database-key-connection-actions small {
+ color: #66706b;
+ font-size: 12px;
+}
+.database-key-connection-actions button {
+ min-height: 34px;
+ flex: 0 0 auto;
+ border: 1px solid #247a63;
+ border-radius: 8px;
+ padding: 0 13px;
+ background: #fff;
+ color: #247a63;
+ cursor: pointer;
+}
+.database-key-connection-actions button:hover:not(:disabled) {
+ background: #f0f7f4;
+}
+.database-key-danger {
+ margin-top: 30px;
+ padding-bottom: 1px;
+}
+.database-key-danger > h2 {
+ margin: 0 0 14px;
+ color: #c85a5a;
+ font-size: 15px;
+}
+.database-key-danger > div {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+ padding: 16px 20px;
+ border: 1px solid #efcdcd;
+ background: #fff7f7;
+}
+.database-key-danger > div:first-of-type {
+ border-radius: 9px 9px 0 0;
+}
+.database-key-danger > div:last-of-type {
+ border-top: 0;
+ border-radius: 0 0 9px 9px;
+}
+.database-key-danger span {
+ display: grid;
+ gap: 4px;
+}
+.database-key-danger strong {
+ color: #4a3c3c;
+ font-size: 13px;
+}
+.database-key-danger small {
+ color: #786868;
+ font-size: 12px;
+}
+.database-key-danger button {
+ min-height: 34px;
+ flex: 0 0 auto;
+ border: 1px solid #e8baba;
+ border-radius: 8px;
+ padding: 0 13px;
+ background: #fff;
+ color: #c85a5a;
+ cursor: pointer;
+}
+.database-key-danger button:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+.database-key-confirm-backdrop {
+ position: fixed;
+ z-index: 30;
+ inset: 0;
+ display: grid;
+ place-items: center;
+ padding: 24px;
+ background: rgba(25, 32, 29, 0.34);
+}
+.database-key-confirm {
+ width: min(100%, 430px);
+ padding: 22px;
+ border-radius: 12px;
+ background: #fff;
+ box-shadow: 0 18px 50px rgba(24, 35, 30, 0.2);
+}
+.database-key-confirm h2 {
+ margin: 0;
+ color: #202724;
+ font-size: 17px;
+}
+.database-key-confirm p {
+ margin: 12px 0 22px;
+ color: #66706b;
+ font-size: 13px;
+ line-height: 1.7;
+}
+.database-key-confirm > div {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+.database-key-confirm button {
+ min-height: 34px;
+ border: 1px solid #dde3e0;
+ border-radius: 8px;
+ padding: 0 14px;
+ background: #fff;
+ color: #46514c;
+ cursor: pointer;
+}
+.database-key-confirm button.danger {
+ border-color: #c85a5a;
+ background: #c85a5a;
+ color: #fff;
+}
+/* SETTINGS-03: image decryption */
+.image-decryption-content {
+ padding-bottom: 48px;
+}
+.image-decrypt-badge.unconfigured {
+ background: #f1f3f2;
+ color: #66706b;
+}
+.image-decrypt-badge.partial {
+ background: #fff6e8;
+ color: #a56a24;
+}
+.image-decrypt-status dl {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 18px 30px;
+ margin: 0 0 20px;
+}
+.image-decrypt-status dl div {
+ min-width: 0;
+}
+.image-decrypt-status dt {
+ color: #929a96;
+ font-size: 12px;
+}
+.image-decrypt-status dd {
+ overflow: hidden;
+ margin: 5px 0 0;
+ color: #35403b;
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.image-decrypt-status .image-decrypt-wide {
+ grid-column: span 2;
+}
+.image-decrypt-mono {
+ font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
+}
+.image-state-success {
+ color: #2e8b68 !important;
+}
+.image-state-muted {
+ color: #66706b !important;
+}
+.image-state-error {
+ color: #c85a5a !important;
+}
+.image-resource-checks {
+ padding: 10px 18px;
+}
+.image-resource-checks > div {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 11px;
+ padding: 13px 2px;
+ border-bottom: 1px solid #edf0ee;
+}
+.image-resource-checks > div:last-child {
+ border-bottom: 0;
+}
+.image-resource-checks strong {
+ color: #3d4742;
+ font-size: 13px;
+}
+.image-resource-checks small {
+ margin-left: auto;
+ overflow: hidden;
+ color: #66706b;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 12px;
+}
+.image-resource-icon {
+ display: grid;
+ width: 18px;
+ height: 18px;
+ flex: 0 0 auto;
+ place-items: center;
+ border-radius: 50%;
+ background: #f1f3f2;
+ color: #66706b;
+ font-size: 11px;
+ font-weight: 700;
+}
+.image-resource-icon.available {
+ background: #e6f2ed;
+ color: #2e8b68;
+}
+.image-resource-icon.unavailable {
+ background: #f9eaea;
+ color: #c85a5a;
+}
+.image-key-editor {
+ display: grid;
+ gap: 17px;
+}
+.image-key-editor label {
+ display: grid;
+ min-width: 0;
+ gap: 8px;
+ color: #46514c;
+ font-size: 12px;
+ font-weight: 600;
+}
+.image-key-editor input,
+.image-test-section select {
+ box-sizing: border-box;
+ width: 100%;
+ height: 40px;
+ border: 1px solid #d5ddda;
+ border-radius: 8px;
+ outline: 0;
+ padding: 0 12px;
+ background: #f4f7f5;
+ color: #202724;
+ font:
+ 12px/1.4 ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.image-key-editor input:focus,
+.image-test-section select:focus {
+ border-color: #247a63;
+ box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09);
+}
+.image-key-grid {
+ display: grid;
+ grid-template-columns: 180px minmax(0, 1fr);
+ gap: 14px;
+}
+.image-key-editor > p {
+ margin: 0;
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.6;
+}
+.image-test-section > div:first-child strong,
+.image-auto-detect strong,
+.image-auto-unavailable strong {
+ color: #35403b;
+ font-size: 14px;
+}
+.image-test-section > div:first-child p,
+.image-auto-detect p,
+.image-auto-unavailable p {
+ margin: 6px 0 0;
+ color: #66706b;
+ font-size: 12px;
+ line-height: 1.6;
+}
+.image-test-section > label {
+ display: block;
+ margin: 18px 0 8px;
+ color: #46514c;
+ font-size: 12px;
+ font-weight: 600;
+}
+.image-test-actions {
+ display: flex;
+ gap: 9px;
+ margin-top: 14px;
+}
+.image-test-result {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px 18px;
+ margin-top: 14px;
+ padding: 12px 14px;
+ border-radius: 8px;
+ color: #2e765d;
+ font-size: 12px;
+}
+.image-test-result.success {
+ border: 1px solid #bfded3;
+ background: #eaf5f1;
+}
+.image-test-result.error {
+ border: 1px solid #efcaca;
+ background: #fff2f2;
+ color: #a84444;
+}
+.image-test-result p {
+ width: 100%;
+ margin: 2px 0 0;
+}
+.image-step-list {
+ list-style: none;
+ margin: 14px 0 0;
+ padding: 12px 14px;
+ border-radius: 8px;
+ border: 1px solid #e5ecea;
+ background: #f7faf9;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ font-size: 12px;
+}
+.image-step {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.image-step-icon {
+ width: 18px;
+ height: 18px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ font-size: 12px;
+ font-weight: 600;
+}
+.image-step-ok .image-step-icon {
+ background: #2e765d;
+ color: #fff;
+}
+.image-step-fail .image-step-icon {
+ background: #a84444;
+ color: #fff;
+}
+.image-step-fail span:last-child {
+ color: #a84444;
+}
+.image-step-pending .image-step-icon {
+ background: #d6dde0;
+ color: #6a7378;
+}
+.image-step-pending span:last-child {
+ color: #98a1a4;
+}
+.image-step-skipped .image-step-icon {
+ background: transparent;
+ color: #b8c0c4;
+}
+.image-step-skipped span:last-child {
+ color: #b8c0c4;
+ text-decoration: line-through;
+}
+.image-inline-error {
+ margin: 14px 0 0;
+ color: #a84444;
+ font-size: 12px;
+}
+.image-auto-heading {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 24px;
+}
+.image-auto-detect ul {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px 22px;
+ margin: 17px 0 0;
+ padding: 14px 0 0;
+ border-top: 1px solid #edf0ee;
+ list-style: none;
+ color: #8b5c25;
+ font-size: 12px;
+}
+.image-auto-detect li::before {
+ content: '○';
+ margin-right: 6px;
+}
+.image-auto-detect li.ok {
+ color: #2e8b68;
+}
+.image-auto-detect li.ok::before {
+ content: '✓';
+}
+.image-auto-progress {
+ margin-top: 12px !important;
+ padding: 9px 12px;
+ border-radius: 7px;
+ background: #f1f4f3;
+}
+.image-auto-scope-hint {
+ display: inline-block;
+ margin-top: 4px;
+ color: #7d8c8a;
+ font-size: 11px;
+}
+.image-auto-unavailable {
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+.image-key-danger > div {
+ border-radius: 9px !important;
+}
+.image-key-danger {
+ margin-top: 30px;
+}
+.image-auto-phases {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8px;
+ margin: 18px 0 0;
+ padding: 0;
+ counter-reset: image-auto-phase;
+ list-style: none;
+}
+.image-auto-phases li {
+ position: relative;
+ padding-top: 24px;
+ color: #929a96;
+ text-align: center;
+ font-size: 11px;
+}
+.image-auto-phases li::before {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ display: grid;
+ width: 18px;
+ height: 18px;
+ place-items: center;
+ border: 1px solid #d5ddda;
+ border-radius: 50%;
+ background: #fff;
+ content: counter(image-auto-phase);
+ counter-increment: image-auto-phase;
+ transform: translateX(-50%);
+}
+.image-auto-phases li.active {
+ color: #247a63;
+}
+.image-auto-phases li.active::before {
+ border-color: #247a63;
+ background: #247a63;
+ color: #fff;
+}
+.image-auto-error {
+ margin: 12px 0 0 !important;
+ padding: 10px 12px;
+ border-left: 3px solid #c85a5a;
+ background: #fff2f2;
+ color: #a84444 !important;
+}
+.image-auto-success {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 7px 20px;
+ align-items: center;
+ margin-top: 14px;
+ padding: 14px 16px;
+ border: 1px solid #bfded3;
+ border-radius: 8px;
+ background: #eaf5f1;
+ color: #2e765d;
+ font-size: 12px;
+}
+.image-auto-success strong {
+ grid-column: 1;
+ color: #2e765d;
+}
+.image-auto-success span {
+ grid-column: 1;
+}
+.image-auto-success button {
+ grid-column: 2;
+ grid-row: 1/4;
+}
+/* SETTINGS-04: AI provider center */
+.ai-model-content {
+ padding-bottom: 48px;
+}
+.ai-model-default {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+}
+.ai-model-default > div {
+ display: grid;
+ gap: 5px;
+}
+.ai-model-default > div > span,
+.ai-model-default small {
+ color: #66706b;
+ font-size: 12px;
+}
+.ai-model-default strong {
+ color: #202724;
+ font-size: 18px;
+}
+.ai-model-page-error {
+ padding: 11px 14px;
+ border-left: 3px solid #c85a5a;
+ background: #fff2f2;
+ color: #a84444;
+ font-size: 12px;
+}
+.ai-provider-list {
+ display: grid;
+ gap: 12px;
+}
+.ai-provider-card {
+ border: 1px solid #dde3e0;
+ border-radius: 10px;
+ background: #fff;
+ padding: 19px 20px;
+}
+.ai-provider-card header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 18px;
+}
+.ai-provider-card h3 {
+ margin: 0 0 5px;
+ color: #202724;
+ font-size: 15px;
+}
+.ai-provider-card header span {
+ color: #66706b;
+ font-size: 12px;
+}
+.ai-provider-status {
+ border-radius: 12px;
+ padding: 4px 8px;
+ background: #f1f3f2;
+}
+.ai-provider-status.connected {
+ background: #eaf5f1;
+ color: #2e8b68 !important;
+}
+.ai-provider-status.error {
+ background: #fff2f2;
+ color: #c85a5a !important;
+}
+.ai-provider-card dl {
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr;
+ gap: 18px;
+ margin: 18px 0;
+}
+.ai-provider-card dt {
+ color: #929a96;
+ font-size: 11px;
+}
+.ai-provider-card dd {
+ overflow: hidden;
+ margin: 5px 0 0;
+ color: #3d4742;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 12px;
+}
+.ai-provider-card footer {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ padding-top: 14px;
+ border-top: 1px solid #edf0ee;
+}
+.ai-provider-card button,
+.ai-provider-editor button {
+ min-height: 32px;
+ border: 1px solid #d5ddda;
+ border-radius: 7px;
+ padding: 0 11px;
+ background: #fff;
+ color: #46514c;
+ cursor: pointer;
+ font: 600 12px inherit;
+}
+.ai-provider-card button:hover,
+.ai-provider-editor button:hover {
+ border-color: #247a63;
+ color: #247a63;
+}
+.ai-provider-card button:disabled,
+.ai-provider-editor button:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+.ai-provider-card button.danger,
+.ai-provider-editor button.danger {
+ color: #c85a5a;
+}
+.ai-provider-error {
+ margin: 0 0 12px;
+ color: #a84444;
+ font-size: 12px;
+}
+.ai-provider-empty {
+ color: #66706b;
+ text-align: center;
+}
+.ai-provider-empty p {
+ margin: 6px 0 0;
+ font-size: 12px;
+}
+.ai-provider-editor {
+ display: grid;
+ gap: 18px;
+ margin-top: 22px;
+}
+.ai-provider-editor > header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 18px;
+}
+.ai-provider-editor h2,
+.ai-provider-editor h3 {
+ margin: 0;
+ color: #35403b;
+ font-size: 15px;
+}
+.ai-provider-editor header p {
+ margin: 5px 0 0;
+ color: #66706b;
+ font-size: 12px;
+}
+.ai-provider-editor label {
+ display: grid;
+ gap: 7px;
+ color: #46514c;
+ font-size: 12px;
+ font-weight: 600;
+}
+.ai-provider-editor input:not([type='checkbox']):not([type='radio']),
+.ai-provider-editor select,
+.ai-provider-editor textarea {
+ box-sizing: border-box;
+ width: 100%;
+ border: 1px solid #d5ddda;
+ border-radius: 7px;
+ outline: 0;
+ padding: 9px 10px;
+ background: #f4f7f5;
+ color: #202724;
+ font:
+ 12px/1.4 ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.ai-provider-editor input:focus,
+.ai-provider-editor select:focus,
+.ai-provider-editor textarea:focus {
+ border-color: #247a63;
+ box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08);
+}
+.ai-provider-form-grid,
+.ai-provider-advanced > div {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 14px;
+}
+.ai-provider-form-grid .wide,
+.ai-provider-advanced .wide {
+ grid-column: 1/-1;
+}
+.ai-model-table-heading {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+.ai-model-table {
+ display: grid;
+ gap: 9px;
+}
+.ai-model-row {
+ display: grid;
+ grid-template-columns: 1fr 1fr repeat(3, auto) 110px auto auto;
+ gap: 8px;
+ align-items: center;
+ padding: 11px;
+ border: 1px solid #e3e8e5;
+ border-radius: 8px;
+}
+.ai-model-row label {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ white-space: nowrap;
+ font-weight: 400;
+}
+.ai-provider-advanced,
+.ai-provider-preview {
+ border: 1px solid #e3e8e5;
+ border-radius: 8px;
+}
+.ai-provider-advanced summary,
+.ai-provider-preview summary {
+ padding: 12px 14px;
+ cursor: pointer;
+ color: #46514c;
+ font-size: 13px;
+ font-weight: 600;
+}
+.ai-provider-advanced > div {
+ padding: 2px 14px 14px;
+}
+.ai-provider-advanced textarea {
+ min-height: 90px;
+ resize: vertical;
+}
+.ai-provider-preview pre {
+ overflow: auto;
+ max-height: 280px;
+ margin: 0;
+ padding: 0 14px 14px;
+ color: #46514c;
+ font:
+ 11px/1.6 ui-monospace,
+ SFMono-Regular,
+ Consolas,
+ monospace;
+}
+.ai-provider-editor > footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+@keyframes settings-spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+@media (max-width: 900px) {
+ .settings-sidebar {
+ width: 248px;
+ flex-basis: 248px;
+ }
+ .settings-page-content {
+ padding: 24px;
+ }
+ .settings-page-header {
+ padding: 20px 24px;
+ }
+ .settings-recall-grid {
+ grid-template-columns: 1fr;
+ }
+ .settings-recall-notice {
+ padding-top: 10px;
+ padding-left: 0;
+ border-top: 2px solid #e5b45f;
+ border-left: 0;
+ }
+ .settings-account-overview {
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 18px;
+ }
+ .settings-account-facts {
+ grid-column: 1/-1;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ .settings-account-actions {
+ grid-row: 1;
+ grid-column: 2;
+ }
+ .database-key-security-info {
+ grid-template-columns: 1fr;
+ }
+ .image-decrypt-status dl {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ .image-decrypt-status .image-decrypt-wide {
+ grid-column: span 2;
+ }
+ .ai-model-row {
+ grid-template-columns: 1fr 1fr;
+ }
+ .ai-model-row label,
+ .ai-model-row button {
+ justify-self: start;
+ }
+}
diff --git a/src/renderer/src/styles/shell-overlays.scss b/src/renderer/src/styles/shell-overlays.scss
new file mode 100644
index 0000000..43719c9
--- /dev/null
+++ b/src/renderer/src/styles/shell-overlays.scss
@@ -0,0 +1,446 @@
+/* Sidebar 自助卡片 + 入口 */
+.sidebar-footer {
+ padding: 10px 12px;
+ border-top: 1px solid var(--border-color);
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ background-color: #f3f4f5;
+ transition: background-color 0.15s ease;
+ user-select: none;
+
+ &:hover {
+ background-color: #e6e9eb;
+ }
+}
+
+.sidebar-self-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 6px;
+ background-color: #07c160;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ font-weight: 500;
+ overflow: hidden;
+ flex-shrink: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.sidebar-self-info {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+}
+
+.sidebar-self-nickname {
+ font-size: 13px;
+ font-weight: 500;
+ color: #1f2429;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.sidebar-self-wxid {
+ font-size: 11px;
+ color: #8a9298;
+ margin-top: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.sidebar-self-arrow {
+ color: #8a9298;
+ font-size: 18px;
+ flex-shrink: 0;
+}
+
+/* 启动自动连接 Splash */
+.boot-splash {
+ position: fixed;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 14px;
+ background: linear-gradient(180deg, #f5f7f8 0%, #eceff1 100%);
+ z-index: 2000;
+ animation: boot-splash-fade-in 0.2s ease-out;
+}
+
+@keyframes boot-splash-fade-in {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.boot-splash-spinner {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ border: 3px solid rgba(7, 193, 96, 0.18);
+ border-top-color: #07c160;
+ animation: boot-splash-spin 0.9s linear infinite;
+}
+
+@keyframes boot-splash-spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.boot-splash-title {
+ font-size: 15px;
+ font-weight: 500;
+ color: #1f2429;
+}
+
+.boot-splash-subtitle {
+ font-size: 12px;
+ color: #6f767c;
+}
+
+.boot-splash-detail {
+ min-height: 18px;
+ font-size: 12px;
+ color: #8a9298;
+}
+
+.boot-splash-progress {
+ width: min(320px, 72vw);
+ height: 6px;
+ margin-top: 2px;
+ overflow: hidden;
+ border-radius: 999px;
+ background: rgba(7, 193, 96, 0.12);
+}
+
+.boot-splash-progress-bar {
+ height: 100%;
+ border-radius: inherit;
+ background: #07c160;
+ transition: width 0.18s ease-out;
+}
+
+/* 设置面板 */
+.settings-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(15, 21, 26, 0.45);
+ backdrop-filter: blur(2px);
+ z-index: 1100;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: settings-fade-in 0.16s ease-out;
+}
+
+@keyframes settings-fade-in {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.settings-modal {
+ width: min(560px, 92vw);
+ max-height: 84vh;
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 24px 60px rgba(15, 21, 26, 0.28);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ animation: settings-pop-in 0.18s ease-out;
+}
+
+@keyframes settings-pop-in {
+ from {
+ transform: translateY(8px) scale(0.98);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0) scale(1);
+ opacity: 1;
+ }
+}
+
+.settings-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 22px;
+ border-bottom: 1px solid #ececec;
+
+ h2 {
+ margin: 0;
+ font-size: 17px;
+ font-weight: 600;
+ color: #1f2429;
+ }
+}
+
+.settings-close {
+ background: transparent;
+ border: 0;
+ color: #7d858a;
+ font-size: 26px;
+ line-height: 1;
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ cursor: pointer;
+ transition: background-color 0.15s ease;
+
+ &:hover {
+ background: #f0f2f4;
+ color: #1f2429;
+ }
+}
+
+.settings-body {
+ padding: 12px 22px 22px;
+ overflow-y: auto;
+}
+
+.settings-section {
+ margin-top: 14px;
+ padding: 14px 16px;
+ border-radius: 10px;
+ background: #fafbfc;
+ border: 1px solid #ececec;
+}
+
+.settings-section:first-child {
+ margin-top: 6px;
+}
+
+.settings-section-title {
+ font-size: 12px;
+ font-weight: 600;
+ color: #6f767c;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ margin-bottom: 10px;
+}
+
+.settings-row {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-wrap: wrap;
+ margin-top: 8px;
+}
+
+.settings-row:first-child {
+ margin-top: 0;
+}
+
+.settings-input {
+ flex: 1;
+ min-width: 0;
+ padding: 8px 11px;
+ border: 1px solid #d4d9dc;
+ border-radius: 6px;
+ background: #fff;
+ font-size: 13px;
+ color: #1f2429;
+ font-family: 'SF Mono', Menlo, Consolas, monospace;
+ outline: none;
+ transition:
+ border-color 0.15s ease,
+ box-shadow 0.15s ease;
+}
+
+.settings-input:focus {
+ border-color: #07c160;
+ box-shadow: 0 0 0 3px rgba(7, 193, 96, 0.12);
+}
+
+.settings-input-half {
+ flex: 0 1 140px;
+}
+
+.settings-input-quarter {
+ flex: 0 1 90px;
+}
+
+.settings-btn {
+ padding: 7px 14px;
+ border: 1px solid #d4d9dc;
+ border-radius: 6px;
+ background: #fff;
+ color: #30383d;
+ cursor: pointer;
+ font-size: 13px;
+ transition:
+ border-color 0.15s ease,
+ background-color 0.15s ease,
+ color 0.15s ease;
+
+ &:hover:not(:disabled) {
+ border-color: #07c160;
+ color: #078f49;
+ }
+
+ &:disabled {
+ opacity: 0.55;
+ cursor: not-allowed;
+ }
+}
+
+.settings-btn-primary {
+ background: #07c160;
+ color: #fff;
+ border-color: #07c160;
+
+ &:hover:not(:disabled) {
+ background: #06ad56;
+ color: #fff;
+ border-color: #06ad56;
+ }
+}
+
+.settings-hint {
+ margin-top: 10px;
+ font-size: 11px;
+ color: #8a9298;
+ line-height: 1.6;
+}
+
+.settings-hint code {
+ background: #eef0f2;
+ padding: 1px 5px;
+ border-radius: 3px;
+ font-size: 10.5px;
+}
+
+.settings-status {
+ font-size: 12px;
+ color: #59636a;
+}
+
+.settings-status.ok {
+ color: #078f49;
+}
+
+.settings-status.fail {
+ color: #c73737;
+}
+
+.settings-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ font-size: 13px;
+ color: #30383d;
+
+ input {
+ width: 16px;
+ height: 16px;
+ accent-color: #07c160;
+ cursor: pointer;
+ }
+}
+
+.settings-self {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.settings-self-avatar {
+ width: 56px;
+ height: 56px;
+ border-radius: 10px;
+ background: #07c160;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 22px;
+ font-weight: 500;
+ overflow: hidden;
+ flex-shrink: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.settings-self-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.settings-self-nickname {
+ font-size: 15px;
+ font-weight: 600;
+ color: #1f2429;
+}
+
+.settings-self-wxid {
+ font-size: 12px;
+ color: #6f767c;
+ margin-top: 2px;
+ font-family: 'SF Mono', Menlo, Consolas, monospace;
+}
+
+.settings-self-account {
+ font-size: 11px;
+ color: #8a9298;
+ margin-top: 2px;
+ word-break: break-all;
+}
+
+.settings-self-empty {
+ font-size: 13px;
+ color: #8a9298;
+}
+
+.settings-path {
+ display: inline-block;
+ font-family: 'SF Mono', Menlo, Consolas, monospace;
+ font-size: 11px;
+ background: #eef0f2;
+ padding: 3px 7px;
+ border-radius: 4px;
+ color: #30383d;
+ word-break: break-all;
+ max-width: 100%;
+}
+
+.app-toast {
+ position: fixed;
+ top: 18px;
+ left: calc(var(--wxex-nav-width) + 50%);
+ z-index: 40;
+ transform: translateX(-50%);
+ padding: 9px 14px;
+ border: 1px solid rgba(198, 134, 53, 0.35);
+ border-radius: var(--wxex-radius-md);
+ background: #fff9ef;
+ color: #7b4b14;
+ font: 13px/18px var(--wxex-font);
+ box-shadow: var(--wxex-shadow-popover);
+}