:root{ --os-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Inter", "PingFang SC", "Microsoft YaHei", sans-serif; --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono","Courier New", monospace; --bg: #ffffff; --text: #0b0b0c; --muted: rgba(11,11,12,0.62); --surface: rgba(255,255,255,0.92); --surface-2: rgba(0,0,0,0.03); --border: rgba(11,11,12,0.14); --border-weak: rgba(11,11,12,0.08); --shadow-soft: 0 12px 32px rgba(0,0,0,0.06); --shadow: 0 22px 60px rgba(0,0,0,0.10); --radius-lg: 28px; --radius-md: 18px; --radius-sm: 12px; --maxw: 920px; --ring: 0 0 0 3px rgba(0,0,0,0.12); --topbar-h: 56px; --sidebar-w: 260px; --sidebar-collapsed-w: 56px; --devbar-w: 360px; --devbar-collapsed-w: 56px; --sidebar-panel-gap: 14px; } @media (prefers-color-scheme: dark){ :root{ --bg: #0b0b0c; --text: #f4f4f5; --muted: rgba(244,244,245,0.60); --surface: rgba(20,20,22,0.92); --surface-2: rgba(255,255,255,0.07); --border: rgba(244,244,245,0.16); --border-weak: rgba(244,244,245,0.10); --shadow-soft: 0 14px 36px rgba(0,0,0,0.38); --shadow: 0 24px 70px rgba(0,0,0,0.58); --ring: 0 0 0 3px rgba(255,255,255,0.14); } } *{ box-sizing: border-box; } html, body{ height: 100%; } body{ margin: 0; font-family: var(--os-font); color: var(--text); background: var(--bg); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: geometricPrecision; --sidebar-current: var(--sidebar-w); --content-offset: var(--sidebar-current); --devbar-current: 0px; --right-offset: 0px; /* 让 fixed 元素始终居中在内容区(左右侧边栏之间) */ --center-shift: calc((var(--content-offset) - var(--right-offset)) * 0.5); } body.sidebar-collapsed{ --sidebar-current: var(--sidebar-collapsed-w); --content-offset: var(--sidebar-current); } body.dev-mode{ --devbar-current: var(--devbar-w); --right-offset: var(--devbar-current); } body.dev-mode.devbar-collapsed{ --devbar-current: var(--devbar-collapsed-w); --right-offset: var(--devbar-current); } /* 移动端:sidebar/devbar 采用 overlay,不挤压内容区 */ @media (max-width: 760px){ body{ --content-offset: var(--sidebar-collapsed-w); } body.dev-mode, body.dev-mode.devbar-collapsed{ --right-offset: 0px; } } .hidden{ display:none !important; } ::selection{ background: rgba(0,0,0,0.10); } @media (prefers-color-scheme: dark){ ::selection{ background: rgba(255,255,255,0.14); } } /* 主内容区给两侧栏预留空间 */ .main{ margin-left: var(--content-offset); margin-right: var(--right-offset); min-height: 100vh; } /* ========================================================= 0) Sidebar:左侧可收起 ========================================================= */ .sidebar{ position: fixed; left: 0; top: 0; height: 100vh; width: var(--sidebar-current); z-index: 55; overflow: hidden; background: var(--surface); border-right: 1px solid var(--border-weak); box-shadow: var(--shadow-soft); backdrop-filter: blur(10px); transition: width 0.18s ease; } .sidebar-inner{ height: 100%; padding: 12px; display: flex; flex-direction: column; gap: 10px; } .sidebar-icon-btn{ width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); display: grid; place-items: center; cursor: pointer; } .sidebar-icon-btn:hover{ background: var(--surface-2); border-color: var(--border); } .sidebar-action{ width: 100%; height: 44px; border-radius: 16px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); display:flex; align-items:center; gap: 10px; padding: 0 12px; cursor:pointer; } .sidebar-action:hover{ background: var(--surface-2); border-color: var(--border); } .sidebar-action.primary{ border-color: var(--border); } .sidebar-action-icon{ width: 20px; height: 20px; display: grid; place-items:center; font-size: 18px; line-height: 1; flex: 0 0 auto; } .sidebar-action-text{ font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .devbar-sid{ font-family: var(--mono); font-size: 12px; color: var(--muted); padding: 6px 2px 0; white-space: normal; word-break: break-all; user-select: text; } body.dev-mode.devbar-collapsed .devbar-sid{ display:none; } /* 收起态:变成窄轨道,隐藏文字 */ body.sidebar-collapsed .sidebar-inner{ padding: 12px 6px; } body.sidebar-collapsed .sidebar-action{ width: 44px; padding: 0; justify-content: center; border-radius: 999px; } body.sidebar-collapsed .sidebar-action-text{ display:none; } /* 模型选择下拉框 */ .sidebar-model{ width: 100%; display: flex; flex-direction: column; gap: 6px; padding: 2px; } .sidebar-model-label{ font-size: 12px; color: var(--muted); padding: 2px 6px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sidebar-model-select{ width: 100%; height: 36px; border-radius: 12px; border: 1px solid var(--border-weak); background: var(--surface-2); color: var(--text); padding: 0 10px; font-size: 13px; outline: none; } .sidebar-model-select:hover{ border-color: var(--border); } .sidebar-model-select:focus{ border-color: var(--border); box-shadow: var(--ring); } body.sidebar-collapsed .sidebar-model{ display: none; } /* ========================================================= Sidebar panels (Custom Model / TTS) ========================================================= */ .sidebar-panel{ width: 100%; border: 1px solid var(--border-weak); border-radius: 16px; background: var(--surface); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; } .sidebar-scroll .sidebar-panel + .sidebar-panel{ margin-top: var(--sidebar-panel-gap); } .sidebar-panel-title{ font-size: 12px; color: var(--muted); padding: 2px 2px 0; display: flex; align-items: center; gap: 6px; overflow: visible; } .sidebar-panel-title-text{ flex: 0 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ========================================================= Sidebar title help ( ? ) + tooltip ========================================================= */ .sidebar-help{ position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; cursor: pointer; } .sidebar-help-icon{ width: 18px; height: 18px; border-radius: 999px; border: 1px solid var(--border-weak); background: var(--surface-2); color: var(--muted); display: grid; place-items: center; font-size: 11px; font-weight: 600; line-height: 1; } .sidebar-help:hover .sidebar-help-icon{ border-color: var(--border); color: var(--text); } .sidebar-help:focus-visible .sidebar-help-icon{ box-shadow: var(--ring); } .sidebar-help{ position: relative; } .sidebar-help-tooltip{ position: absolute; z-index: 60; left: 0px; right: auto; max-width: calc(var(--sidebar-current) / 2); white-space: normal; max-height: min(35vh, 180px); top: calc(100% + 6px); display: inline-block; width: max-content; overflow: auto; padding: 2px 6px; border-radius: 12px; border: 1px solid var(--border-weak); background: var(--surface); box-shadow: var(--shadow-soft); color: var(--text); font-size: 12px; line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; opacity: 0; visibility: hidden; transform: translateY(-4px); pointer-events: none; transition: opacity .12s ease, transform .12s ease, visibility .12s ease; } .sidebar-help-tooltip::before{ content: ""; position: absolute; top: -6px; left: auto; right: 10px; width: 10px; height: 10px; transform: rotate(45deg); background: var(--surface); border-left: 1px solid var(--border-weak); border-top: 1px solid var(--border-weak); } .sidebar-help:hover .sidebar-help-tooltip, .sidebar-help:focus-visible .sidebar-help-tooltip, .sidebar-help-tooltip:hover{ opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto; } .sidebar-help-tooltip-body{ display: block; color: var(--text); } .sidebar-help-tooltip-cta{ display: block; margin-top: 2px; color: var(--muted); text-decoration: underline; text-underline-offset: 2px; } .sidebar-help-tooltip-text{ text-decoration: underline; text-underline-offset: 2px; } /* show tooltip on hover/focus */ .sidebar-help:hover .sidebar-help-tooltip, .sidebar-help:focus-visible .sidebar-help-tooltip{ opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto; } /* hover bridge */ .sidebar-help{ position: relative; } .sidebar-help::after{ content: ""; position: absolute; left: -10px; right: -10px; top: 100%; height: 14px; background: transparent; } .sidebar-help:hover .sidebar-help-tooltip, .sidebar-help:focus-visible .sidebar-help-tooltip, .sidebar-help-tooltip:hover{ opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto; } .sidebar-subtitle{ font-size: 12px; color: var(--muted); margin-top: 4px; } .sidebar-input{ width: 100%; height: 34px; border-radius: 12px; border: 1px solid var(--border-weak); background: var(--surface-2); color: var(--text); padding: 0 10px; font-size: 13px; outline: none; } .sidebar-input:hover{ border-color: var(--border); } .sidebar-input:focus{ border-color: var(--border); box-shadow: var(--ring); } .sidebar-divider{ height: 1px; background: var(--border-weak); margin: 6px 0 2px; } .sidebar-hint{ font-size: 11px; color: var(--muted); line-height: 1.45; } .sidebar-tts-fields{ display: flex; flex-direction: column; gap: 8px; } /* 收起侧边栏时隐藏配置面板 */ body.sidebar-collapsed .sidebar-panel{ display: none; } /* flex 容器允许子项正确计算滚动高度 */ .sidebar-inner{ min-height: 0; /* 不加这个,很多浏览器下滚动区会失效 */ } /* 顶部固定区:不参与滚动,不允许被挤压 */ .sidebar-top{ display: flex; flex-direction: column; gap: 10px; flex: 0 0 auto; min-height: 0; } /* 滚动区:承载“模型配置 / TTS 配置”等长内容 */ .sidebar-scroll{ flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding-bottom: 12px; /* 避免最后一个输入框贴底被遮挡 */ overscroll-behavior: contain; -webkit-overflow-scrolling: touch; } .sidebar-icon-btn, .sidebar-action{ flex: 0 0 auto; flex-shrink: 0; } .sidebar-action{ min-height: 44px; } body.sidebar-collapsed .sidebar-scroll{ display: none; } /* ========================================================= 1) 顶部栏 Topbar ========================================================= */ .topbar{ position: sticky; top: 0; z-index: 45; height: var(--topbar-h); display: flex; align-items: center; padding: 0 16px; background: var(--surface); border-bottom: 1px solid var(--border-weak); backdrop-filter: blur(10px); box-shadow: 0 10px 24px rgba(0,0,0,0.04); } @media (prefers-color-scheme: dark){ .topbar{ box-shadow: 0 16px 34px rgba(0,0,0,0.32); } } .topbar > .brand{ width: 100%; margin: 0; display: flex; align-items: baseline; gap: 10px; min-width: 0; } .topbar .brand{ font-size: 24px; font-weight: 700; letter-spacing: -0.03em; color: var(--text); opacity: 0.92; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .topbar .ver{ display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 999px; border: 1px solid var(--border-weak); background: var(--surface-2); color: var(--muted); font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: 0; } .topbar .actions{ margin-left: auto; display: flex; align-items: center; gap: 8px; } @media (max-width: 640px){ .topbar{ height: 52px; padding: 0 12px; } .topbar > .brand{ width: min(var(--maxw), calc(100% - 1.25rem)); } } /* ========================================================= 2) 聊天区 ========================================================= */ .chat{ width: min(var(--maxw), calc(100% - 2rem)); margin: 0 auto; padding: 24px 0 240px; } #chat:empty{ padding: 0; } /* 空白页标题 */ .hero{ display: none; position: fixed; left: calc(50% + var(--center-shift)); top: 18vh; transform: translateX(-50%); width: min(var(--maxw), calc(100vw - var(--content-offset) - var(--right-offset) - 2rem)); text-align: center; pointer-events: none; } #chat:empty ~ .hero{ display:block; } .hero-title{ margin: 0; font-size: clamp(34px, 4.2vw, 52px); line-height: 1.06; font-weight: 650; letter-spacing: -0.03em; } /* 消息布局 */ .msg{ margin: 0; padding: 10px 0; display: flex; } .msg.assistant{ justify-content:flex-start; } .msg.user{ justify-content:flex-end; } /* 允许 flex 子项收缩(附件横向滚动的关键) */ .msg.user > div, .msg.assistant > div{ min-width: 0; } /* 覆盖 JS inline max-width(建议从 JS 源头移除) */ .msg.user > div{ max-width: min(70%, 560px) !important; min-width: 0; } .bubble{ max-width: min(74ch, 100%); font-size: 15px; line-height: 1.68; letter-spacing: -0.01em; white-space: normal; word-break: break-word; } .msg.assistant .bubble{ padding: 0; background: transparent; border: none; box-shadow: none; } .msg.user .bubble{ padding: 8px 12px; background: var(--surface-2); border: 1px solid var(--border-weak); border-radius: 16px; font-size: 14.5px; line-height: 1.55; letter-spacing: -0.005em; max-width: min(60ch, 72vw); white-space: pre-wrap; } .bubble a{ color: inherit; text-decoration: underline; text-underline-offset: 2px; } .bubble a:hover{ opacity: 0.88; } .bubble pre{ margin: 12px 0; padding: 12px 14px; border-radius: 16px; background: var(--surface-2); border: 1px solid var(--border-weak); overflow: auto; font-family: var(--mono); font-size: 13px; line-height: 1.6; } .bubble code{ font-family: var(--mono); font-size: 0.92em; padding: 2px 6px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border-weak); } .bubble pre code{ padding: 0; border: none; background: transparent; } /* Markdown 内容排版增强(assistant bubble 内) */ .msg.assistant .bubble h1, .msg.assistant .bubble h2, .msg.assistant .bubble h3{ margin: 18px 0 10px; line-height: 1.25; letter-spacing: -0.02em; } .msg.assistant .bubble p{ margin: 10px 0; } .msg.assistant .bubble ul, .msg.assistant .bubble ol{ margin: 10px 0 10px 1.2em; } .msg.assistant .bubble blockquote{ margin: 12px 0; padding: 8px 12px; border-left: 3px solid var(--border); background: var(--surface-2); border-radius: 12px; color: var(--muted); } .msg.assistant .bubble hr{ border: none; border-top: 1px solid var(--border-weak); margin: 14px 0; } /* ========================================================= 3) 附件缩略图(消息内 & 待发送素材) ========================================================= */ .attach-row{ display: flex; gap: 8px; padding: 6px 0 0; } /* 两类素材条:不换行 + 横向滚动 + 移动端顺滑 */ .media-row, .attach-row{ display: flex; gap: 8px; max-width: 100%; min-width: 0; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; scrollbar-width: thin; } /* WebKit scrollbar */ .media-row::-webkit-scrollbar, .attach-row::-webkit-scrollbar{ height: 6px; } .media-row::-webkit-scrollbar-thumb, .attach-row::-webkit-scrollbar-thumb{ background: var(--border); border-radius: 999px; } .media-row::-webkit-scrollbar-track, .attach-row::-webkit-scrollbar-track{ background: transparent; } /* 用户消息附件:必须从左开始排版,保证可滚动 */ .msg.user .attach-row{ padding-top: 4px; justify-content: flex-start !important; margin-left: 0 !important; width: 100%; min-width: 0; overscroll-behavior-x: contain; touch-action: pan-x; } /* 外层负责靠右,内层负责滚动 */ .attach-wrap{ max-width: 100%; min-width: 0; } .attach-wrap.align-right{ margin-left: auto; } .attach-wrap .attach-row{ width: 100%; min-width: 0; justify-content: flex-start; } /* media item */ .media-item{ position: relative; flex: 0 0 auto; width: 64px; height: 64px; border-radius: 14px; overflow: hidden; background: var(--surface-2); border: 1px solid var(--border-weak); cursor: pointer; } .media-item:hover{ border-color: var(--border); } .media-item img{ width: 100%; height: 100%; object-fit: contain; object-position: center; display:block; } .media-tag{ position: absolute; left: 6px; top: 6px; font-size: 10px; padding: 2px 6px; border-radius: 999px; background: rgba(255,255,255,0.86); border: 1px solid rgba(0,0,0,0.10); color: rgba(0,0,0,0.72); } @media (prefers-color-scheme: dark){ .media-tag{ background: rgba(0,0,0,0.55); border-color: rgba(255,255,255,0.12); color: rgba(255,255,255,0.78); } } .media-play{ position: absolute; right: 8px; bottom: 8px; width: 0; height: 0; border-left: 14px solid rgba(255,255,255,0.92); border-top: 9px solid transparent; border-bottom: 9px solid transparent; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35)); } .media-remove{ position: absolute; right: 6px; top: 6px; width: 22px; height: 22px; border-radius: 999px; border: 1px solid rgba(255,255,255,0.70); background: rgba(0,0,0,0.55); color: rgba(255,255,255,0.96); font-weight: 700; line-height: 20px; text-align: center; cursor: pointer; } @media (prefers-color-scheme: dark){ .media-remove{ border-color: rgba(255,255,255,0.18); background: rgba(255,255,255,0.12); color: rgba(255,255,255,0.96); } } /* FIX: media remove "×" optical center */ .media-remove{ display: grid; place-items: center; padding: 0; line-height: 0; font-size: 0; /* hide text glyph × */ -webkit-appearance: none; appearance: none; } .media-remove{ --x-size: 10px; --x-thick: 2px; --x-nudge-y: 4.5px; } .media-remove::before, .media-remove::after{ content: ""; width: var(--x-size); height: var(--x-thick); background: currentColor; border-radius: 999px; grid-area: 1 / 1; pointer-events: none; display: block; place-self: center; } .media-remove::before{ transform: translateY(var(--x-nudge-y, 0px)) rotate(45deg); } .media-remove::after{ transform: translateY(var(--x-nudge-y, 0px)) rotate(-45deg); } /* ========================================================= 4) 输入框(两层结构) ========================================================= */ .file-input{ display:none; } .composer{ position: fixed; left: calc(50% + var(--center-shift)); bottom: calc(24px + env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 45; width: min(var(--maxw), calc(100vw - var(--content-offset) - var(--right-offset) - 2rem)); padding: 10px 12px; border-radius: var(--radius-lg); background: var(--surface); border: 1px solid var(--border-weak); box-shadow: var(--shadow-soft); backdrop-filter: blur(10px); display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 8px; } #chat:empty ~ .composer{ top: 55vh; bottom: auto; transform: translate(-50%, -50%); } .composer:focus-within{ border-color: var(--border); box-shadow: var(--shadow-soft), var(--ring); } /* 待发送素材:内嵌在输入框里 */ .pending{ display:flex; gap: 8px; padding: 6px 2px 2px; margin: 0 0 2px; border-bottom: 1px solid var(--border-weak); overflow: hidden; } .media-bar-title{ display:none; } .pending .media-row{ flex: 1 1 auto; } /* prompt 单行更紧凑 */ .composer-top{ width: 100%; padding: 0 2px; } .prompt{ width: 100%; min-height: 40px; max-height: 180px; border: none; outline: none; background: transparent; resize: none; overflow-y: hidden; /* 超过 max-height 时建议由 JS 切换为 auto */ overflow-x: hidden; font-family: inherit; font-size: 15px; line-height: 20px; color: var(--text); padding: 10px 8px; } .prompt::placeholder{ color: var(--muted); } .composer-actions{ display: flex; align-items: center; gap: 8px; padding-top: 10px; border-top: 1px solid var(--border-weak); } .composer-actions-spacer{ flex: 1 1 auto; min-width: 0; } /* 左侧 + */ .icon-btn{ width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); display: grid; place-items: center; cursor: pointer; flex: 0 0 auto; } .icon-btn:hover{ background: var(--surface-2); border-color: var(--border); } .icon-btn:active{ transform: translateY(1px); } .icon-btn:disabled{ opacity: 0.35; cursor: not-allowed; transform: none; } /* 发送 */ .send-btn{ width: 44px; height: 44px; border-radius: 999px; border: 1px solid transparent; background: #000; color: #fff; display: grid; place-items: center; cursor: pointer; flex: 0 0 auto; transition: transform 0.08s ease, opacity 0.18s ease; } @media (prefers-color-scheme: dark){ .send-btn{ background: #fff; color: #000; } } .send-btn:hover{ transform: translateY(-1px); } .send-btn:active{ transform: translateY(0); } .send-btn:disabled{ opacity: 0.35; cursor: not-allowed; transform: none; } /* SVG 统一 */ .sidebar-icon-btn svg, .devbar-icon-btn svg, .icon-btn svg, .send-btn svg, .scroll-bottom svg{ width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; } /* ========================================================= 5) toast / tool-card / modal ========================================================= */ .toast{ position: fixed; left: calc(50% + var(--center-shift)); transform: translateX(-50%); bottom: calc(24px + env(safe-area-inset-bottom) + 86px); z-index: 60; padding: 10px 12px; border-radius: 14px; border: 1px solid var(--border-weak); background: var(--surface); box-shadow: var(--shadow-soft); color: var(--text); font-size: 13px; letter-spacing: -0.01em; } details.tool-card{ width: min(480px, 100%); border: 1px solid var(--border-weak); border-radius: 16px; background: var(--surface); overflow: hidden; } details.tool-card > summary{ list-style: none; } details.tool-card > summary::-webkit-details-marker{ display:none; } details.tool-card > summary::marker{ content:""; } .tool-head{ cursor: pointer; padding: 12px 14px; } details.tool-card[open] .tool-head{ border-bottom: 1px solid var(--border-weak); } .media-card{ width: min(480px, 100%); border: 1px solid var(--border-weak); border-radius: 16px; background: var(--surface); padding: 10px 14px 12px; } .media-card .tool-preview{ margin-top: 0; } .msg.assistant.tool-media-msg{ padding-top: 6px; } .tool-line{ display: flex; align-items: center; gap: 10px; min-width: 0; } .tool-left{ display: flex; align-items: center; gap: 8px; min-width: 0; flex: 0 1 auto; } .tool-status{ width: 14px; height: 14px; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; color: var(--muted); } .tool-status.is-running::before{ content: ""; width: 12px; height: 12px; box-sizing: border-box; border: 2px solid var(--muted); border-top-color: transparent; border-radius: 999px; animation: os_tool_spin 0.8s linear infinite; } .tool-status.is-success, .tool-status.is-error{ color: var(--text); } .tool-name{ font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tool-args-preview{ font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; text-align: right; } .tool-progress{ margin-top: 10px; width: min(240px, 100%); height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; } .tool-progress-fill{ height: 100%; width: 0%; background: var(--text); border-radius: 999px; transition: width 0.12s linear; } .tool-body-wrap{ padding: 10px 14px 12px; } .tool-body{ margin: 0; font-family: var(--mono); font-size: 12px; line-height: 1.6; color: var(--muted); white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; } .tool-preview{ margin-top: 10px; display: flex; flex-direction: column; gap: 10px; } .tool-preview-block{ display: flex; flex-direction: column; gap: 8px; } .tool-preview-title{ font-size: 12px; color: var(--muted); user-select: none; } .tool-inline-video{ width: 100%; max-height: 360px; border-radius: 12px; border: 1px solid var(--border-weak); background: rgba(0,0,0,0.06); object-fit: contain; } .tool-preview-actions{ display: flex; align-items: center; gap: 10px; } .tool-preview-btn{ height: 30px; padding: 0 10px; border-radius: 999px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); font-size: 12px; cursor: pointer; } .tool-preview-btn:hover{ background: var(--surface-2); border-color: var(--border); } .tool-preview-link{ font-size: 12px; color: var(--muted); text-decoration: underline; text-underline-offset: 2px; } .tool-preview-link:hover{ opacity: 0.88; } /* Grid thumbnails */ .tool-media-grid{ display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 10px; } .tool-media-item{ border: none; background: transparent; padding: 0; text-align: left; cursor: pointer; } .tool-media-thumb{ width: 100%; aspect-ratio: 16 / 9; border-radius: 12px; overflow: hidden; background: var(--surface-2); border: 1px solid var(--border-weak); position: relative; display: grid; place-items: center; } .tool-media-thumb.is-portrait{ aspect-ratio: 9 / 16; } .tool-media-thumb.is-square{ aspect-ratio: 1 / 1; } .tool-media-thumb img, .tool-media-thumb video{ width: 100%; height: 100%; object-fit: contain; display: block; } .tool-media-play{ position: absolute; right: 10px; bottom: 10px; width: 0; height: 0; border-left: 16px solid rgba(255,255,255,0.92); border-top: 10px solid transparent; border-bottom: 10px solid transparent; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35)); pointer-events: none; } .tool-media-label{ margin-top: 6px; font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tool-media-more{ font-size: 12px; color: var(--muted); } /* Audio preview */ .tool-audio-list{ display: flex; flex-direction: column; gap: 10px; } .tool-audio-item{ border: 1px solid var(--border-weak); background: var(--surface-2); border-radius: 12px; padding: 10px 10px 8px; } .tool-audio-item audio{ width: 100%; } /* 进度条行 */ .tool-progress-row{ display: flex; align-items: center; gap: 10px; margin-top: 8px; } .tool-progress-pct{ font-family: var(--mono); font-size: 12px; line-height: 1; color: var(--muted); min-width: 38px; text-align: right; user-select: none; flex: 0 0 auto; } .tool-progress-row .tool-progress{ flex: 1 1 auto; min-width: 0; } @keyframes os_tool_spin{ from{ transform: rotate(0deg); } to{ transform: rotate(360deg); } } /* modal */ .modal{ position: fixed; inset: 0; z-index: 80; } .modal-backdrop{ position: absolute; inset: 0; background: rgba(0,0,0,0.55); z-index: 0; } .modal-body{ position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: fit-content; max-width: 92vw; max-height: 86vh; background: var(--surface); border: 1px solid var(--border-weak); border-radius: 18px; overflow: hidden; box-shadow: var(--shadow); z-index: 1; } .modal-content{ position: relative; z-index: 1; padding: 0; } .modal-close{ position: absolute; right: 12px; top: 12px; width: 36px; height: 36px; border-radius: 999px; border: 1px solid var(--border-weak); background: var(--surface-2); color: var(--text); cursor: pointer; /* 居中 + 去掉默认按钮内边距 */ display: grid; place-items: center; padding: 0; line-height: 1; font-size: 20px; z-index: 10; pointer-events: auto; } .modal-close:hover{ opacity: 0.88; } /* FIX: modal close "×" optical center */ .modal-close{ display: grid; place-items: center; padding: 0; line-height: 0; font-size: 0; /* hide text glyph × */ -webkit-appearance: none; appearance: none; } .modal-close{ --x-size: 16px; --x-thick: 2px; --x-nudge-y: 8px; } .modal-close::before, .modal-close::after{ content: ""; width: var(--x-size); height: var(--x-thick); background: currentColor; border-radius: 999px; grid-area: 1 / 1; pointer-events: none; display: block; place-self: center; } .modal-close::before{ transform: translateY(var(--x-nudge-y, 0px)) rotate(45deg); } .modal-close::after{ transform: translateY(var(--x-nudge-y, 0px)) rotate(-45deg); } .modal-content img, .modal-content video{ max-width: 100%; max-height: 86vh; width: auto; height: auto; display: block; margin: 0 auto; } .modal-content audio{ width: min(720px, 92vw); display: block; padding: 16px; } .modal-content .file-fallback{ padding: 16px; color: var(--muted); font-size: 13px; } /* ========================================================= 6) 小屏适配 ========================================================= */ @media (max-width: 640px){ .chat{ width: calc(100% - 1.25rem); padding: 24px 0 240px; } #chat:empty{ padding: 0; } .composer{ width: calc(100vw - var(--content-offset) - var(--right-offset) - 1.25rem); bottom: calc(14px + env(safe-area-inset-bottom)); padding: 10px 10px; border-radius: 24px; } #chat:empty ~ .composer{ top: auto; bottom: calc(18px + env(safe-area-inset-bottom)); transform: translateX(-50%); } .msg.user > div{ max-width: 92% !important; } .msg.user .bubble{ max-width: 100%; } } /* ========================================================= 7) Developer mode:Right sidebar (devbar) ========================================================= */ .devbar{ position: fixed; right: 0; top: 0; height: 100vh; width: var(--devbar-current); z-index: 56; overflow: hidden; background: var(--surface); border-left: 1px solid var(--border-weak); box-shadow: var(--shadow-soft); backdrop-filter: blur(10px); transition: width 0.18s ease; } .devbar-inner{ height: 100%; padding: 12px; display: flex; flex-direction: column; gap: 10px; } .devbar-icon-btn{ width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); display: grid; place-items: center; cursor: pointer; } .devbar-icon-btn:hover{ background: var(--surface-2); border-color: var(--border); } .devbar-title{ font-size: 13px; color: var(--muted); padding: 0 2px 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .devbar-log{ flex: 1 1 auto; overflow: auto; border-top: 1px solid var(--border-weak); padding-top: 10px; } .devlog-item{ border: 1px solid var(--border-weak); border-radius: 14px; background: var(--surface); padding: 10px 12px; margin-bottom: 10px; } .devlog-head{ font-family: var(--mono); font-size: 12px; color: var(--muted); margin-bottom: 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .devlog-pre{ margin: 0; font-family: var(--mono); font-size: 12px; line-height: 1.55; color: var(--muted); white-space: pre-wrap; word-break: break-word; } body.dev-mode.devbar-collapsed .devbar-inner{ padding: 12px 6px; } body.dev-mode.devbar-collapsed .devbar-title, body.dev-mode.devbar-collapsed .devbar-log{ display: none; } /* 右下角“到底部”按钮 */ .scroll-bottom{ position: fixed; right: calc(48px + var(--right-offset) + env(safe-area-inset-right)); bottom: calc(24px + env(safe-area-inset-bottom) + 120px); z-index: 62; width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--border-weak); background: var(--surface); box-shadow: var(--shadow-soft); backdrop-filter: blur(10px); display: grid; place-items: center; cursor: pointer; } .scroll-bottom:hover{ background: var(--surface-2); border-color: var(--border); } .scroll-bottom:active{ transform: translateY(1px); } /* 移动端适配 */ /* 1) runtime vars + safe-area fallbacks */ :root{ --vvh: 100vh; /* visual viewport height (px) */ --kb: 0px; /* keyboard overlay inset (px) */ --composer-h: 140px; /* measured composer height (px) */ --composer-gap: 24px; /* distance from bottom edge */ /* safe-area insets fallback */ --sat: 0px; --sar: 0px; --sab: 0px; --sal: 0px; /* solid surface fallback for browsers without backdrop-filter */ --surface-solid: #ffffff; } @media (prefers-color-scheme: dark){ :root{ --surface-solid: #141416; } } @supports (padding-top: env(safe-area-inset-top)){ :root{ --sat: env(safe-area-inset-top); --sar: env(safe-area-inset-right); --sab: env(safe-area-inset-bottom); --sal: env(safe-area-inset-left); } } /* legacy iOS (constant()) */ @supports (padding-top: constant(safe-area-inset-top)){ :root{ --sat: constant(safe-area-inset-top); --sar: constant(safe-area-inset-right); --sab: constant(safe-area-inset-bottom); --sal: constant(safe-area-inset-left); } } /* 2) typography / tap */ html{ -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } button, input, textarea, select, a{ -webkit-tap-highlight-color: transparent; } button, input, textarea, select{ font: inherit; } /* 3) keep center between sidebars*/ body{ --center-shift: calc(((var(--content-offset) - var(--right-offset)) * 0.5) + ((var(--sal) - var(--sar)) * 0.5)); } /* 4) dvh for modern mobile browsers (address bar) */ .main{ min-height: 100vh; min-height: 100dvh; } .sidebar, .devbar{ height: 100vh; height: 100dvh; } /* 5) add iOS Safari prefix for backdrop-filter */ .sidebar, .topbar, .composer, .toast, .devbar, .scroll-bottom, .modal-body{ backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); } /* 6) no backdrop-filter: use solid surfaces for readability */ @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))){ .sidebar, .topbar, .composer, .toast, .devbar, .scroll-bottom, .modal-body{ background: var(--surface-solid); } } /* 7) safe-area top for the sticky header */ .topbar{ height: calc(var(--topbar-h) + var(--sat)); padding: var(--sat) 16px 0; } @media (max-width: 640px){ .topbar{ height: calc(52px + var(--sat)); padding: var(--sat) 12px 0; } :root{ --composer-gap: 14px; } /* compact bottom gap on mobile */ } /* 8) safe-area top for sidebars so the first button isn't under the status bar */ .sidebar-inner{ padding-top: calc(12px + var(--sat)); } body.sidebar-collapsed .sidebar-inner{ padding-top: calc(12px + var(--sat)); } .devbar-inner{ padding-top: calc(12px + var(--sat)); } body.dev-mode.devbar-collapsed .devbar-inner{ padding-top: calc(12px + var(--sat)); } /* 9) dynamic chat bottom padding = composer height + gaps (avoid last msg covered) */ .chat{ padding-bottom: calc(var(--composer-h) + var(--composer-gap) + var(--sab) + var(--kb) + 24px); } @media (max-width: 640px){ .chat{ padding-bottom: calc(var(--composer-h) + var(--composer-gap) + var(--sab) + var(--kb) + 18px); } } /* 10) hero width avoids safe-area left/right */ .hero{ width: min(var(--maxw), calc(100vw - var(--content-offset) - var(--right-offset) - 2rem - var(--sal) - var(--sar))); } /* 11) composer: bottom uses safe-area + keyboard inset; width avoids safe-area */ .composer{ bottom: calc(var(--composer-gap) + var(--sab) + var(--kb)); width: min(var(--maxw), calc(100vw - var(--content-offset) - var(--right-offset) - 2rem - var(--sal) - var(--sar))); } @media (max-width: 640px){ .composer{ width: calc(100vw - var(--content-offset) - var(--right-offset) - 1.25rem - var(--sal) - var(--sar)); bottom: calc(var(--composer-gap) + var(--sab) + var(--kb)); } #chat:empty ~ .composer{ bottom: calc(18px + var(--sab) + var(--kb)); } } /* 12) toast / scroll-to-bottom always stays above composer (and keyboard) */ .toast{ bottom: calc(var(--composer-gap) + var(--sab) + var(--kb) + var(--composer-h) + 12px); } .scroll-bottom{ right: calc(48px + var(--right-offset) + var(--sar)); bottom: calc(var(--composer-gap) + var(--sab) + var(--kb) + var(--composer-h) + 16px); } /* 13) iOS Safari: prevent focus auto-zoom on textarea/select (font-size >= 16px) */ @media (max-width: 640px){ .prompt{ font-size: 16px; line-height: 22px; } .sidebar-model-select{ font-size: 16px; } } /* 14) touch devices: avoid sticky :hover */ @media (hover: none) and (pointer: coarse){ .sidebar-icon-btn:hover, .sidebar-action:hover, .icon-btn:hover, .ghost-icon-btn:hover, .tool-preview-btn:hover, .devbar-icon-btn:hover{ background: transparent; border-color: var(--border-weak); opacity: 0.68; } .sidebar-model-select:hover{ background: var(--surface-2); border-color: var(--border-weak); } .scroll-bottom:hover{ background: var(--surface); border-color: var(--border-weak); } .send-btn:hover{ transform: none; } .tool-preview-link:hover, .modal-close:hover{ opacity: 1; } .media-item:hover{ border-color: var(--border-weak); } } /* ========================================================= Lang switch (topbar) ========================================================= */ .lang-switch{ display: flex; align-items: center; gap: 8px; padding: 6px 10px; /* border: 1px solid var(--border-weak); */ border: 0; border-radius: 999px; background: var(--surface-2); } .lang-chip{ font-size: 12px; font-weight: 650; color: var(--muted); user-select: none; } body.lang-zh .lang-chip.lang-zh, body.lang-en .lang-chip.lang-en{ color: var(--text); } .lang-toggle{ position: relative; width: 44px; height: 24px; display: inline-block; cursor: pointer; } .lang-toggle input{ opacity: 0; width: 0; height: 0; } .lang-slider{ position: absolute; inset: 0; border-radius: 999px; background: var(--surface); border: 1px solid var(--border-weak); transition: border-color .18s ease, background .18s ease; } .lang-slider::before{ content: ""; position: absolute; width: 18px; height: 18px; left: 3px; top: 50%; transform: translateY(-50%); border-radius: 999px; background: var(--text); transition: transform .18s ease; } /* checked => English */ .lang-toggle input:checked + .lang-slider::before{ transform: translate(20px, -50%); } .lang-toggle input:focus-visible + .lang-slider{ box-shadow: var(--ring); } /* ========================================================= Devbar collapsed: 只保留右侧中间一个小箭头(不显示一整列) ========================================================= */ body.dev-mode.devbar-collapsed{ --devbar-current: 0px; /* 覆盖原来的 56px */ --right-offset: 0px; } body.dev-mode.devbar-collapsed .devbar{ width: 0; background: transparent; border-left: 0; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; overflow: visible; } body.dev-mode.devbar-collapsed .devbar-inner{ padding: 0; } body.dev-mode.devbar-collapsed .devbar-title, body.dev-mode.devbar-collapsed .devbar-log, body.dev-mode.devbar-collapsed .devbar-sid{ display: none !important; } body.dev-mode.devbar-collapsed #devbarToggle{ position: fixed; top: 50%; right: calc(10px + var(--sar)); transform: translateY(-50%); width: 36px; height: 36px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border-weak); box-shadow: var(--shadow-soft); z-index: 70; } body.dev-mode.devbar-collapsed #devbarToggle svg{ width: 18px; height: 18px; } body.dev-mode:not(.devbar-collapsed) #devbarToggle svg{ transform: rotate(180deg); } .topbar > .brand{ align-items: center; gap: 10px; } .brand-img{ height: 48px; width: auto; display: block; } @media (max-width: 640px){ .brand-img{ height: 22px; } } #uploadBtn svg{ stroke-width: 2; } .sidebar-fields{ display: flex; flex-direction: column; gap: 8px; } /* ========================================================= Ghost icon buttons ========================================================= */ .ghost-icon-btn{ width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--border-weak); background: transparent; color: var(--text); display: grid; place-items: center; cursor: pointer; flex: 0 0 auto; opacity: 0.68; transition: opacity .12s ease, background .12s ease, border-color .12s ease, transform .08s ease; text-decoration: none; user-select: none; } .ghost-icon-btn:hover{ opacity: 1; background: var(--surface-2); border-color: var(--border); } .ghost-icon-btn:active, .ghost-icon-btn.is-active{ opacity: 1; background: var(--surface-2); border-color: var(--border); transform: translateY(1px); } .ghost-icon-btn:focus-visible{ box-shadow: var(--ring); } .ghost-icon-btn img.os-icon{ width: 20px; height: 20px; display: block; object-fit: contain; pointer-events: none; } .ghost-icon-btn.sm{ width: 44px; height: 44px; } .ghost-icon-btn.sm img.os-icon{ width: 36px; height: 36px; } .topbar-links{ display: flex; align-items: center; gap: 6px; } @media (max-width: 640px){ .topbar-links{ gap: 4px; } .ghost-icon-btn.sm{ width: 34px; height: 34px; } .ghost-icon-btn.sm img.os-icon{ width: 18px; height: 18px; } } .topbar-links .ghost-icon-btn{ border: 0; background: transparent; border-radius: 0; opacity: 0.68; } .topbar-links .ghost-icon-btn:hover, .topbar-links .ghost-icon-btn:active, .topbar-links .ghost-icon-btn.is-active{ background: transparent; opacity: 1; } #quickPromptBtn{ width: 48px; height: 48px; } #quickPromptBtn img.os-icon{ width: 26px; height: 26px; } /* 顶栏三按钮与语言切换的间距 */ .topbar-links{ margin-right: 30px; } .topbar-pill{ display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px 0 10px; border-radius: 999px; border: 0; background: transparent; opacity: 0.72; color: var(--text); text-decoration: none; cursor: pointer; user-select: none; transition: opacity .12s ease, background .12s ease, transform .08s ease; } .topbar-pill:hover{ opacity: 1; background: var(--surface-2); } .topbar-pill:active{ opacity: 1; background: var(--surface-2); transform: translateY(1px); } .topbar-pill .os-icon{ width: 30px; height: 30px; display: block; object-fit: contain; pointer-events: none; } .topbar-pill-text{ font-size: 13px; font-weight: 650; letter-spacing: -0.01em; white-space: nowrap; color: var(--muted); } .topbar-pill:hover .topbar-pill-text, .topbar-pill:active .topbar-pill-text{ color: var(--text); } @media (max-width: 640px){ .topbar-pill-text{ display: none; } .topbar-pill{ padding: 0 10px; gap: 0; } } #quickPromptBtn{ margin-right: 6px; } /* .sidebar-help-tooltip{ width: clamp(220px, 28vw, 320px); } .sidebar-help-tooltip-body{ text-align: justify; text-justify: inter-ideograph; } .sidebar-help-tooltip-cta{ text-align: left; } */ .sidebar-help-tooltip-link{ display: inline-block; margin-top: 6px; font-size: 12px; color: var(--text); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; opacity: 0.92; } .sidebar-help-tooltip-link:hover{ opacity: 1; }