/* ── Reset & Variables ──────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } /* ── Theme: 深邃暗(默认)─ */ :root, [data-theme="dark"] { --bg: #0f0f13; --surface: #18181f; --surface2: #1f1f28; --border: rgba(255,255,255,0.07); --accent: #7c6af5; --accent2: #a89bfa; --text: #e4e4ea; --text2: #8a8a9a; --text3: #55555f; --danger: #f56c6c; --radius: 12px; --radius2: 8px; --ease: cubic-bezier(0.16, 1, 0.3, 1); } /* ── Theme: 纯净白 ─ */ [data-theme="light"] { --bg: #f5f5f7; --surface: #ffffff; --surface2: #f0f0f4; --border: rgba(0,0,0,0.08); --accent: #6c5ce7; --accent2: #5a4bd4; --text: #1a1a2e; --text2: #555570; --text3: #9999aa; --danger: #e74c3c; --radius: 12px; --radius2: 8px; --ease: cubic-bezier(0.16, 1, 0.3, 1); } /* ── Theme: 赛博朋克 ─ */ [data-theme="cyber"] { --bg: #0a0a14; --surface: #10102a; --surface2: #181840; --border: rgba(0,255,255,0.12); --accent: #00f0ff; --accent2: #ff00aa; --text: #e0f8ff; --text2: #7aaccc; --text3: #3a5a7a; --danger: #ff2d55; --radius: 12px; --radius2: 8px; --ease: cubic-bezier(0.16, 1, 0.3, 1); } /* ── Theme: 莫兰迪 ─ */ [data-theme="morandi"] { --bg: #e8e4df; --surface: #f2ede8; --surface2: #ddd8d0; --border: rgba(0,0,0,0.08); --accent: #9b8fa0; --accent2: #7a6f80; --text: #4a4540; --text2: #7a7068; --text3: #a09890; --danger: #c09080; --radius: 12px; --radius2: 8px; --ease: cubic-bezier(0.16, 1, 0.3, 1); } /* ── Theme: 护眼绿 ─ */ [data-theme="green"] { --bg: #1a2416; --surface: #222e1e; --surface2: #2a3a24; --border: rgba(120,200,80,0.12); --accent: #78c850; --accent2: #9fd878; --text: #d4e8c0; --text2: #90b888; --text3: #5a7848; --danger: #e87070; --radius: 12px; --radius2: 8px; --ease: cubic-bezier(0.16, 1, 0.3, 1); } html, body { height: 100%; background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 15px; line-height: 1.5; -webkit-font-smoothing: antialiased; transition: background 0.3s, color 0.3s; } #app { transition: background 0.3s; } button { cursor: pointer; font-family: inherit; } a { color: var(--accent2); text-decoration: none; } a:hover { text-decoration: underline; } /* ── Layout ──────────────────────────────────────────────────── */ #app { max-width: 860px; margin: 0 auto; padding: 0 24px 80px; min-height: 100vh; } /* ── Header ──────────────────────────────────────────────────── */ header { display: flex; align-items: center; justify-content: space-between; padding: 22px 0 24px; } .header-right { display: flex; align-items: center; gap: 8px; } /* ── Theme Switcher ─────────────────────────────────────────── */ .theme-switcher { display: flex; align-items: center; gap: 2px; background: var(--surface); border: 1px solid var(--border); border-radius: 24px; padding: 3px 6px; } .theme-btn { width: 28px; height: 28px; border-radius: 50%; border: none; background: transparent; color: var(--text3); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.15s; } .theme-btn:hover { color: var(--text); background: var(--surface2); transform: scale(1.1); } .theme-btn.active { background: var(--accent); color: #fff; } .theme-btn.active svg { stroke: #fff; fill: #fff; } .logo { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 600; color: var(--text); letter-spacing: -0.3px; } .logo svg { color: var(--accent2); } /* ── Alert ───────────────────────────────────────────────────── */ .alert-banner { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: rgba(124,106,245,0.1); border: 1px solid rgba(124,106,245,0.25); border-radius: var(--radius2); color: var(--text2); font-size: 13px; margin-bottom: 20px; animation: fadeSlideIn 0.4s var(--ease); } .alert-banner svg { color: var(--accent2); flex-shrink: 0; } .link-btn { background: none; border: none; color: var(--accent2); font-size: inherit; padding: 0; text-decoration: underline; cursor: pointer; } /* ── Model Tabs ──────────────────────────────────────────────── */ .model-tabs { display: flex; gap: 8px; margin-bottom: 20px; } .model-tab { flex: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius2); padding: 10px 14px; color: var(--text2); transition: all 0.2s; } .model-tab:hover { border-color: rgba(124,106,245,0.3); color: var(--text); } .model-tab.active { background: rgba(124,106,245,0.12); border-color: rgba(124,106,245,0.5); color: var(--text); } .tab-name { font-size: 13px; font-weight: 600; font-family: 'Courier New', monospace; } .tab-desc { font-size: 11px; color: var(--text3); } .model-tab.active .tab-desc { color: var(--accent2); } /* ── Prompt Tags ─────────────────────────────────────────────── */ .prompt-tags { margin-bottom: 12px; } .tags-label { display: block; font-size: 12px; font-weight: 500; color: var(--text3); margin-bottom: 8px; } .tags-list { display: flex; flex-wrap: wrap; gap: 6px; } .tag-pill { background: var(--surface); border: 1px solid var(--border); border-radius: 20px; color: var(--text2); font-size: 11px; padding: 3px 10px; cursor: pointer; transition: all 0.15s; font-family: inherit; } .tag-pill:hover { background: rgba(124,106,245,0.15); border-color: rgba(124,106,245,0.4); color: var(--accent2); } .tag-pill:active { transform: scale(0.96); } /* ── Prompt ──────────────────────────────────────────────────── */ .prompt-row { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); transition: border-color 0.2s; margin-bottom: 16px; } .prompt-row:focus-within { border-color: rgba(124,106,245,0.4); } textarea { width: 100%; background: transparent; border: none; outline: none; color: var(--text); font-family: inherit; font-size: 15px; line-height: 1.6; padding: 14px 16px 8px; resize: vertical; border-radius: var(--radius); min-height: 100px; } textarea::placeholder { color: var(--text3); } .prompt-footer { display: flex; justify-content: flex-end; padding: 0 14px 10px; } .char-count { font-size: 11px; color: var(--text3); font-variant-numeric: tabular-nums; } /* ── Options Grid ────────────────────────────────────────────── */ .options-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; } .options-col { display: flex; flex-direction: column; gap: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; } .opt-group { display: flex; flex-direction: column; gap: 6px; } .opt-label { font-size: 12px; font-weight: 500; color: var(--text2); } .opt-hint { font-weight: 400; color: var(--text3); font-size: 11px; } .opt-note { font-size: 11px; color: var(--text3); font-style: italic; } /* ── Select ─────────────────────────────────────────────────── */ select { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius2); color: var(--text); font-family: inherit; font-size: 14px; padding: 8px 30px 8px 10px; outline: none; cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a8a9a' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 8px center; transition: border-color 0.2s; width: 100%; } select:focus { border-color: rgba(124,106,245,0.4); } /* ── Number / Text inputs ────────────────────────────────────── */ input[type="number"], input[type="text"] { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius2); color: var(--text); font-family: inherit; font-size: 14px; padding: 8px 10px; outline: none; width: 100%; transition: border-color 0.2s; } input:focus { border-color: rgba(124,106,245,0.4); } input::placeholder { color: var(--text3); } /* Hide number spinners */ input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; } input[type="number"] { -moz-appearance: textfield; } /* ── Stepper ─────────────────────────────────────────────────── */ .stepper { display: flex; align-items: center; gap: 0; width: 100%; } .stepper-btn { background: var(--surface2); border: 1px solid var(--border); color: var(--text2); width: 36px; height: 36px; font-size: 18px; display: flex; align-items: center; justify-content: center; transition: background 0.15s, color 0.15s; flex-shrink: 0; border-radius: var(--radius2); } .stepper-btn:first-child { border-radius: var(--radius2) 0 0 var(--radius2); } .stepper-btn:last-child { border-radius: 0 var(--radius2) var(--radius2) 0; } .stepper-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); } .stepper input { border-radius: 0; border-left: none; border-right: none; text-align: center; width: 52px; flex-shrink: 0; -moz-appearance: textfield; } /* ── Dimension row ───────────────────────────────────────────── */ .dim-row { display: flex; align-items: center; gap: 8px; } .dim-row input { flex: 1; } .dim-x { color: var(--text3); font-size: 14px; flex-shrink: 0; } /* ── Weight slider ───────────────────────────────────────────── */ .weight-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; background: var(--surface2); border-radius: 2px; outline: none; border: none; padding: 0; cursor: pointer; } .weight-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%; background: var(--accent); cursor: pointer; transition: transform 0.15s; } .weight-slider::-webkit-slider-thumb:hover { transform: scale(1.2); } /* ── Toggle switches ─────────────────────────────────────────── */ .toggle-group { display: flex; flex-direction: column; gap: 10px; } .toggle-row { display: flex; align-items: center; gap: 10px; cursor: pointer; } .toggle-row input { display: none; } .toggle-track { width: 36px; height: 20px; background: var(--surface2); border-radius: 10px; position: relative; transition: background 0.2s; flex-shrink: 0; border: 1px solid var(--border); } .toggle-thumb { position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--text3); transition: transform 0.2s, background 0.2s; } .toggle-row input:checked + .toggle-track { background: rgba(124,106,245,0.3); border-color: rgba(124,106,245,0.5); } .toggle-row input:checked + .toggle-track .toggle-thumb { transform: translateX(16px); background: var(--accent); } .toggle-label { font-size: 13px; color: var(--text2); } /* ── Generate Button ─────────────────────────────────────────── */ .generate-btn { display: flex; align-items: center; justify-content: center; gap: 8px; background: var(--accent); color: #fff; border: none; border-radius: var(--radius2); padding: 12px 24px; font-size: 15px; font-weight: 600; width: 100%; height: 48px; transition: background 0.2s, transform 0.15s var(--ease), opacity 0.2s; margin-bottom: 16px; } .generate-btn:hover:not(:disabled) { background: var(--accent2); transform: translateY(-1px); } .generate-btn:active:not(:disabled) { transform: translateY(0); } .generate-btn:disabled { opacity: 0.65; cursor: not-allowed; } .generate-btn .spinner { display: none; animation: spin 0.9s linear infinite; } .generate-btn.loading .btn-icon, .generate-btn.loading .btn-text { display: none; } .generate-btn.loading .spinner { display: inline; } /* ── Error ────────────────────────────────────────────────────── */ .error-msg { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; padding: 10px 14px; background: rgba(245,108,108,0.1); border: 1px solid rgba(245,108,108,0.2); border-radius: var(--radius2); color: var(--danger); font-size: 13px; animation: fadeSlideIn 0.3s var(--ease); } /* ── Result Meta ──────────────────────────────────────────────── */ .result-meta { display: flex; flex-wrap: wrap; gap: 16px; padding: 10px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius2); font-size: 12px; color: var(--text2); margin-bottom: 14px; } .result-meta code { font-family: 'Courier New', monospace; color: var(--accent2); font-size: 11px; } /* ── Image Grid ──────────────────────────────────────────────── */ .image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; } .image-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; animation: fadeSlideIn 0.4s var(--ease); } .image-card img { display: block; width: 100%; height: auto; min-height: 180px; object-fit: cover; background: var(--surface2); } .image-actions { display: flex; gap: 8px; padding: 10px; border-top: 1px solid var(--border); } .action-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 5px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius2); color: var(--text2); font-size: 12px; padding: 6px 10px; transition: background 0.15s, color 0.15s, border-color 0.15s; cursor: pointer; font-family: inherit; } .action-btn:hover { background: rgba(124,106,245,0.12); color: var(--text); border-color: rgba(124,106,245,0.3); } /* ── Icon button ─────────────────────────────────────────────── */ .icon-btn { display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text2); border-radius: var(--radius2); width: 36px; height: 36px; transition: background 0.15s, color 0.15s; flex-shrink: 0; } .icon-btn:hover { background: var(--surface); color: var(--text); } /* ── Modal ───────────────────────────────────────────────────── */ .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; padding: 20px; opacity: 0; pointer-events: none; transition: opacity 0.25s; z-index: 100; } .modal-overlay.open { opacity: 1; pointer-events: all; } .modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); width: 100%; max-width: 420px; transform: translateY(12px) scale(0.97); transition: transform 0.3s var(--ease); } .modal-overlay.open .modal { transform: translateY(0) scale(1); } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 0; } .modal-header h2 { font-size: 16px; font-weight: 600; } .modal-body { padding: 18px 20px; display: flex; flex-direction: column; gap: 18px; } .field { display: flex; flex-direction: column; gap: 7px; } .field label { font-size: 13px; font-weight: 500; color: var(--text2); } .input-row { display: flex; gap: 8px; } .input-row input { flex: 1; } .field-hint { font-size: 11px; color: var(--text3); } .modal-footer { display: flex; justify-content: flex-end; gap: 10px; padding: 0 20px 18px; } .btn-secondary { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius2); color: var(--text2); font-family: inherit; font-size: 14px; padding: 8px 18px; cursor: pointer; transition: background 0.15s, color 0.15s; } .btn-secondary:hover { background: rgba(255,255,255,0.06); color: var(--text); } .btn-primary { background: var(--accent); border: none; border-radius: var(--radius2); color: #fff; font-family: inherit; font-size: 14px; font-weight: 600; padding: 8px 18px; cursor: pointer; transition: background 0.15s; } .btn-primary:hover { background: var(--accent2); } /* ── Animations ──────────────────────────────────────────────── */ @keyframes fadeSlideIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes spin { to { transform: rotate(360deg); } } /* ── Responsive ──────────────────────────────────────────────── */ @media (max-width: 600px) { #app { padding: 0 16px 60px; } .options-grid { grid-template-columns: 1fr; } .image-grid { grid-template-columns: 1fr; } }