/* ========== Design Tokens ========== */ :root { /* Neutrals: warm-tinted grey, keeps the UI quiet on long sessions. */ --bg-body: #f1f2f5; --bg-surface: #ffffff; --bg-card: #ffffff; --bg-hover: #f2f3f6; --bg-sunken: #f7f8fa; --text-primary: #1f2328; --text-secondary: #6b7280; --text-disabled: #c2c6cd; --border-color: #e4e5e8; --border-strong: #d5d7dc; --border-radius: 8px; --border-radius-sm: 6px; /* Accent: one blue, used for primary actions and progress only. */ --accent: #2563eb; --accent-hover: #1d4ed8; --accent-soft: #eff4ff; /* Status colours keep state readable without shouting. */ --status-success: #15803d; --status-success-soft: #eaf7ee; --status-warning: #b45309; --status-warning-soft: #fdf3e3; --status-info: #1d4ed8; --status-info-soft: #eaf1fe; --status-danger: #b42318; --status-danger-soft: #fdeceb; --shadow-card: 0 1px 2px rgba(16, 24, 40, 0.04), 0 1px 3px rgba(16, 24, 40, 0.06); --shadow-elevated: 0 8px 24px rgba(16, 24, 40, 0.12); --rail-width: 76px; --inspector-width: clamp(300px, 24vw, 380px); --transition-fast: 0.15s ease; --transition-normal: 0.25s ease; } html.dark { --bg-body: #12141a; --bg-surface: #191c23; --bg-card: #191c23; --bg-hover: #22262f; --bg-sunken: #15181e; --text-primary: #e8eaee; --text-secondary: #9aa3b2; --text-disabled: #565d69; --border-color: #2a2f3a; --border-strong: #363c49; --accent: #3b82f6; --accent-hover: #60a5fa; --accent-soft: #1c2534; --status-success: #4ade80; --status-success-soft: #16281d; --status-warning: #fbbf24; --status-warning-soft: #2a2113; --status-info: #60a5fa; --status-info-soft: #172234; --status-danger: #f87171; --status-danger-soft: #2b1a1a; --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4); --shadow-elevated: 0 8px 24px rgba(0, 0, 0, 0.5); } /* ========== Global Base ========== */ * { box-sizing: border-box; } html, body, #app { height: 100%; } body { margin: 0; padding: 0; background-color: var(--bg-body); color: var(--text-primary); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", Arial, sans-serif; font-size: 14px; line-height: 1.5; -webkit-font-smoothing: antialiased; transition: background-color var(--transition-normal), color var(--transition-normal); } #app { min-height: 100%; } .view-bar-spacer { flex: 1; min-width: 8px; } .section-title { margin: 0; font-size: 12px; font-weight: 600; color: var(--text-secondary); letter-spacing: 0.04em; text-transform: uppercase; } /* ========== Auth Screen ========== */ .auth-container { position: fixed; inset: 0; z-index: 1000; display: flex; justify-content: center; align-items: center; padding: 24px; background: var(--bg-body); } .auth-card { background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: 12px; box-shadow: var(--shadow-elevated); padding: 40px 36px 32px; width: 400px; max-width: 100%; } .auth-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; } .auth-brand .auth-mark { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 8px; background: var(--accent); color: #fff; font-size: 15px; font-weight: 700; flex: none; } .auth-brand .auth-name { font-size: 17px; font-weight: 600; color: var(--text-primary); } .auth-card h1 { margin: 0 0 6px; font-size: 20px; font-weight: 600; color: var(--text-primary); text-align: left; } .auth-card .auth-subtitle { margin: 0 0 24px; font-size: 13px; color: var(--text-secondary); text-align: left; } .auth-card .auth-form { display: flex; flex-direction: column; gap: 14px; } .auth-card .auth-form .el-checkbox { height: auto; } .auth-card .auth-btn { width: 100%; font-size: 15px; margin-top: 4px; } /* ========== App Shell ========== */ .app { display: flex; height: 100vh; overflow: hidden; background-color: var(--bg-body); } .workspace { flex: 1; min-width: 0; display: flex; flex-direction: column; padding: 16px; } /* ========== Navigation Rail ========== */ .nav-rail { flex: none; width: var(--rail-width); display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 8px; background: var(--bg-surface); border-right: 1px solid var(--border-color); } .nav-brand { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 9px; background: var(--accent); color: #fff; font-size: 16px; font-weight: 700; margin-bottom: 14px; flex: none; } .nav-items { display: flex; flex-direction: column; gap: 4px; width: 100%; } .nav-item { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 9px 4px 7px; border: 0; border-radius: var(--border-radius); background: none; color: var(--text-secondary); font-family: inherit; font-size: 11px; cursor: pointer; transition: background-color var(--transition-fast), color var(--transition-fast); } .nav-item:hover { background: var(--bg-hover); color: var(--text-primary); } .nav-item.is-active { background: var(--accent-soft); color: var(--accent); } .nav-badge { position: absolute; top: 4px; right: 12px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 10px; font-weight: 600; line-height: 16px; text-align: center; } .nav-label { font-size: 11px; line-height: 1; } .nav-foot { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: 6px; width: 100%; padding-top: 10px; border-top: 1px solid var(--border-color); } .nav-connection { display: inline-flex; align-items: center; gap: 5px; color: var(--status-warning); } .nav-connection.is-connected { color: var(--status-success); } .connection-dot { width: 7px; height: 7px; border-radius: 999px; background: currentColor; flex: none; } .nav-user { max-width: 100%; font-size: 11px; color: var(--text-secondary); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ========== Views ========== */ .view { display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--border-radius); overflow: hidden; } .view-bar { flex: none; display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--border-color); } .view-title { margin: 0; font-size: 16px; font-weight: 600; } .view-count { font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; } .connection { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--status-warning); white-space: nowrap; } .connection.is-connected { color: var(--status-success); } /* ========== Filter Bar ========== */ .filter-bar { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 16px; border-bottom: 1px solid var(--border-color); } .filter { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 8px 0 10px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-surface); } .filter-label { font-size: 11px; color: var(--text-secondary); flex: none; } .filter-select { width: 110px; } .filter-select .el-select__wrapper { min-height: 22px; padding: 0; box-shadow: none; background: transparent; } .filter-select .el-select__placeholder, .filter-select .el-select__selected-item { font-size: 13px; color: var(--text-primary); } .filter-select-sort { width: 118px; } .filter-select-name { width: 96px; } .filter-select-downloader { width: 118px; } /* Segmented control: two or three mutually exclusive modes. */ .segmented { display: inline-flex; padding: 2px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-sunken); gap: 2px; } .segmented button { height: 26px; padding: 0 14px; border: 0; border-radius: var(--border-radius-sm); background: none; color: var(--text-secondary); font-family: inherit; font-size: 13px; cursor: pointer; transition: background-color var(--transition-fast), color var(--transition-fast); } .segmented button:hover { color: var(--text-primary); } .segmented button[aria-pressed="true"] { background: var(--bg-surface); color: var(--text-primary); font-weight: 500; box-shadow: var(--shadow-card); } .segmented.is-quiet { background: transparent; } /* ========== Buttons ========== */ .icon-button { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid var(--border-color); border-radius: var(--border-radius-sm); background: var(--bg-surface); color: var(--text-secondary); cursor: pointer; flex: none; transition: border-color var(--transition-fast), color var(--transition-fast), background-color var(--transition-fast); } .icon-button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } .icon-button:disabled { color: var(--text-disabled); cursor: default; } .icon-button.is-on { color: var(--status-warning); border-color: var(--status-warning); background: var(--status-warning-soft); } .text-button { display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 10px; border: 1px solid var(--border-color); border-radius: var(--border-radius-sm); background: var(--bg-surface); color: var(--text-secondary); font-family: inherit; font-size: 13px; cursor: pointer; flex: none; transition: border-color var(--transition-fast), color var(--transition-fast); } .text-button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } .text-button:disabled { color: var(--text-disabled); cursor: default; } .chip-button { flex: none; height: 30px; padding: 0 12px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-surface); color: var(--text-secondary); font-family: inherit; font-size: 13px; cursor: pointer; } .chip-button:hover { border-color: var(--accent); color: var(--accent); } /* ========== Content Scan Areas ========== */ .list-scroll, .settings-scroll { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 14px 16px; } .settings-scroll { gap: 16px; max-width: 720px; } .empty-state { padding: 64px 20px; text-align: center; font-size: 14px; color: var(--text-secondary); } .hint { margin: 0; font-size: 13px; color: var(--text-secondary); } .hint-action { margin-left: 8px; padding: 0; border: 0; background: none; color: var(--accent); font-family: inherit; font-size: 13px; cursor: pointer; } .search-bar { display: flex; align-items: center; gap: 8px; flex: none; } .search-bar .el-input { flex: 1; min-width: 0; } /* ========== Task Row ========== */ .task-row { display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; align-items: center; gap: 12px; flex: none; padding: 10px 12px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-card); cursor: pointer; transition: border-color var(--transition-fast), background-color var(--transition-fast); } .task-row:hover { border-color: var(--border-strong); background: var(--bg-hover); } .task-row.is-selected { border-color: var(--accent); background: var(--accent-soft); } .task-thumb { display: flex; align-items: center; justify-content: center; width: 46px; height: 62px; border-radius: 4px; background: var(--bg-sunken); color: var(--text-disabled); overflow: hidden; flex: none; } .task-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; } .task-body { min-width: 0; } .task-title { margin: 0; font-size: 14px; line-height: 1.4; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .task-meta { display: flex; flex-wrap: wrap; gap: 4px 12px; margin: 4px 0 0; font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; } .task-progress { display: flex; align-items: center; gap: 8px; margin-top: 6px; } .task-progress .el-progress { flex: 1; min-width: 60px; } .progress-value { font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; } .task-side { display: flex; align-items: center; gap: 10px; flex: none; } .task-acts { display: flex; align-items: center; gap: 6px; } .status-pill { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: 999px; font-size: 12px; font-weight: 500; white-space: nowrap; flex: none; } .status-pill.is-done { color: var(--status-success); background: var(--status-success-soft); } .status-pill.is-running { color: var(--status-info); background: var(--status-info-soft); } .status-pill.is-waiting { color: var(--status-warning); background: var(--status-warning-soft); } /* Remote search result: thumbnail + copy + two clear actions. */ .remote-row { display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; align-items: center; gap: 12px; flex: none; padding: 10px 12px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-card); } .pager-row { display: flex; justify-content: center; gap: 8px; padding: 12px 0 4px; } /* ========== Pager ========== */ .pager { display: inline-flex; align-items: center; gap: 4px; } .pager-readout { display: inline-flex; align-items: center; gap: 6px; margin: 0 6px; font-size: 13px; color: var(--text-secondary); font-variant-numeric: tabular-nums; } .pager-readout .page-total { white-space: nowrap; } button.page-current { min-width: 34px; height: 28px; padding: 0 6px; border: 1px solid var(--border-color); border-radius: var(--border-radius-sm); background: var(--bg-surface); color: var(--text-primary); font-size: 13px; font-weight: 600; font-family: inherit; font-variant-numeric: tabular-nums; cursor: pointer; transition: border-color var(--transition-fast), color var(--transition-fast); } button.page-current:hover { border-color: var(--accent); color: var(--accent); } .page-input { width: 56px; } /* ========== Settings ========== */ .settings-group { display: flex; flex-direction: column; gap: 10px; padding: 16px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-card); } .setting-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-size: 13px; color: var(--text-primary); } .setting-actions { display: inline-flex; align-items: center; gap: 8px; } .usage-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; } .usage-line .usage-value { font-size: 26px; font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums; } .usage-line .usage-note { font-size: 12px; color: var(--text-secondary); } .mono-value { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; word-break: break-all; } /* ========== Detail Inspector ========== */ .inspector { flex: none; width: var(--inspector-width); display: flex; flex-direction: column; min-height: 0; background: var(--bg-surface); border-left: 1px solid var(--border-color); } .inspector-bar { flex: none; display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--border-color); } .inspector-scroll { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; padding: 16px; } .preview-frame { display: flex; align-items: center; justify-content: center; width: 100%; aspect-ratio: 3 / 4; max-height: 320px; border-radius: var(--border-radius-sm); background: var(--bg-sunken); border: 1px solid var(--border-color); overflow: hidden; } .preview-frame img { display: block; width: 100%; height: 100%; object-fit: contain; } .preview-empty { display: inline-flex; flex-direction: column; align-items: center; gap: 8px; font-size: 12px; color: var(--text-disabled); } .inspector-title { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.45; color: var(--text-primary); word-break: break-word; } .inspector-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; } .inspector-badge { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: 999px; background: var(--bg-sunken); color: var(--text-secondary); font-size: 12px; font-variant-numeric: tabular-nums; } .progress-line { display: flex; align-items: center; gap: 8px; } .progress-line .el-progress { flex: 1; } .inspector-facts { display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 6px 12px; margin: 0; padding-top: 4px; border-top: 1px solid var(--border-color); font-size: 13px; line-height: 1.6; } .inspector-facts dt { color: var(--text-secondary); } .inspector-facts dd { margin: 0; color: var(--text-primary); word-break: break-word; } .inspector-facts a { color: var(--accent); text-decoration: none; } .inspector-facts a:hover { text-decoration: underline; } .inspector-label { margin: 0; } .resolution-list { display: flex; flex-direction: column; gap: 6px; } .resolution-list button { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; padding: 9px 12px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-surface); color: var(--text-primary); font-family: inherit; font-size: 13px; cursor: pointer; transition: border-color var(--transition-fast), background-color var(--transition-fast); } .resolution-list button:hover { border-color: var(--border-strong); } .resolution-list button[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 500; } .resolution-size { font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; } .resolution-list button[aria-pressed="true"] .resolution-size { color: var(--accent); } .inspector-actions { flex: none; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding: 12px 16px 16px; border-top: 1px solid var(--border-color); } .inspector-actions.is-remote { grid-template-columns: repeat(2, minmax(0, 1fr)); } .inspector-actions .el-button { margin-left: 0; width: 100%; } .inspector-actions .el-button.is-collected { color: var(--status-warning); border-color: var(--status-warning); background: var(--status-warning-soft); } .inspector-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 24px; color: var(--text-disabled); font-size: 13px; } .inspector-empty p { margin: 0; } /* ========== Dialogs ========== */ .el-dialog { border-radius: 12px; } .el-dialog__title { font-size: 16px; font-weight: 600; } /* ========== Element Plus harmonisation ========== */ .el-button { font-weight: 500; } .el-button--small { font-size: 13px; } .el-button--primary { --el-button-bg-color: var(--accent); --el-button-border-color: var(--accent); --el-button-hover-bg-color: var(--accent-hover); --el-button-hover-border-color: var(--accent-hover); } .el-select { font-size: 13px; } .el-input__inner { font-size: 14px; } /* ========== iOS focus-zoom guard (窄屏) ========== iOS Safari 聚焦字号小于 16px 的输入控件时会放大整个页面,并忽略 viewport 里的 user-scalable=no / maximum-scale。桌面端本身不做调整,只在窄屏(手机 打开桌面入口,或手机横竖屏)下把可聚焦控件拉到 16px;!important 用于压过 Element Plus 的小尺寸变体。 */ @media (max-width: 600px) { input:not([type="checkbox"]):not([type="radio"]), textarea, select, .el-input__inner, .el-textarea__inner, .el-select__input, .el-select__wrapper, .el-input-number .el-input__inner { font-size: 16px !important; } }