*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { /* Warm dark palette — subtle indigo undertone */ --bg: #08080d; --surface: #111117; --surface-hover: #17171e; --surface-active: #1c1c25; --border: #1e1e2a; --border-active: #2c2c3e; --text: #eaeaef; --text-secondary: #9e9eb5; --text-dim: #5a5a6e; --accent: #6366f1; --accent-hover: #818cf8; --accent-glow: rgba(99, 102, 241, 0.2); --accent-glow-md: rgba(99, 102, 241, 0.35); --accent-glow-lg: rgba(99, 102, 241, 0.08); --danger: #f43f5e; --success: #34d399; --radius: 14px; --radius-sm: 8px; --safe-top: env(safe-area-inset-top, 0px); --safe-bottom: env(safe-area-inset-bottom, 0px); } html, body { height: 100%; font-family: "SF Pro Display", -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; background: var(--bg); color: var(--text); -webkit-font-smoothing: antialiased; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; user-select: none; overflow: hidden; } /* Subtle ambient glow at top */ body::after { content: ""; position: fixed; top: -30%; left: 50%; transform: translateX(-50%); width: 600px; height: 600px; background: radial-gradient( circle, rgba(99, 102, 241, 0.04) 0%, transparent 70% ); pointer-events: none; z-index: 0; } #app { position: relative; z-index: 1; display: flex; flex-direction: column; height: 100%; max-width: 480px; margin: 0 auto; padding: calc(16px + var(--safe-top)) 20px calc(16px + var(--safe-bottom)); } /* ─── Header ─── */ header { display: flex; align-items: center; justify-content: space-between; padding: 8px 0 20px; flex-shrink: 0; } header h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.03em; } .status { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 500; color: var(--text-dim); padding: 5px 12px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); transition: all 0.25s ease; } .status .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-dim); transition: all 0.3s ease; flex-shrink: 0; } .status.connected { border-color: rgba(52, 211, 153, 0.15); } .status.connected .dot { background: var(--success); box-shadow: 0 0 6px rgba(52, 211, 153, 0.5); } .status.disconnected .dot { background: var(--danger); box-shadow: 0 0 6px rgba(244, 63, 94, 0.4); } .status.connecting .dot { background: var(--accent); animation: pulse 1.4s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } /* ─── Preview ─── */ #preview-section { flex-shrink: 0; padding-bottom: 12px; } .preview-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; min-height: 80px; max-height: 160px; overflow-y: auto; transition: border-color 0.3s ease, box-shadow 0.3s ease, background 0.3s ease; } .preview-box.active { border-color: rgba(99, 102, 241, 0.4); box-shadow: 0 0 0 1px var(--accent-glow), 0 4px 24px -4px rgba(99, 102, 241, 0.15); background: linear-gradient( 180deg, rgba(99, 102, 241, 0.03) 0%, var(--surface) 100% ); } #preview-text { font-size: 16px; line-height: 1.6; word-break: break-word; } #preview-text.placeholder { color: var(--text-dim); } /* ─── Mic Button ─── */ #mic-section { display: flex; flex-direction: column; align-items: center; padding: 20px 0 16px; flex-shrink: 0; gap: 14px; } .mic-wrapper { position: relative; display: flex; align-items: center; justify-content: center; touch-action: none; } #mic-btn { position: relative; z-index: 1; width: 96px; height: 96px; border-radius: 50%; border: 2px solid var(--border); background: linear-gradient(145deg, var(--surface-hover), var(--surface)); color: var(--text-secondary); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); -webkit-user-select: none; touch-action: none; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.04); } #mic-btn svg { transition: transform 0.2s ease; } #mic-btn:disabled { opacity: 0.3; cursor: not-allowed; } #mic-btn:not(:disabled):active, #mic-btn.recording { background: var(--accent); border-color: var(--accent-hover); color: #fff; transform: scale(1.06); box-shadow: 0 0 32px var(--accent-glow-md), 0 0 80px var(--accent-glow); } #mic-btn.recording { animation: mic-breathe 1.8s ease-in-out infinite; } @keyframes mic-breathe { 0%, 100% { box-shadow: 0 0 32px var(--accent-glow-md), 0 0 80px var(--accent-glow); } 50% { box-shadow: 0 0 48px var(--accent-glow-md), 0 0 120px var(--accent-glow), 0 0 200px var(--accent-glow-lg); } } /* Wave rings — radiate outward when recording */ .mic-rings { position: absolute; inset: 0; pointer-events: none; } .mic-rings .ring { position: absolute; inset: 0; border-radius: 50%; border: 1.5px solid var(--accent); opacity: 0; } #mic-btn.recording + .mic-rings .ring { animation: ring-expand 2.4s cubic-bezier(0.2, 0, 0.2, 1) infinite; } #mic-btn.recording + .mic-rings .ring:nth-child(2) { animation-delay: 0.8s; } #mic-btn.recording + .mic-rings .ring:nth-child(3) { animation-delay: 1.6s; } @keyframes ring-expand { 0% { transform: scale(1); opacity: 0.35; } 100% { transform: scale(2); opacity: 0; } } .mic-hint { font-size: 13px; color: var(--text-dim); letter-spacing: 0.01em; transition: color 0.3s ease; } /* ─── History ─── */ #history-section { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; } .history-header { display: flex; align-items: center; justify-content: space-between; padding-bottom: 10px; flex-shrink: 0; } .history-header h2 { font-size: 13px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.06em; } .text-btn { background: none; border: none; color: var(--text-dim); font-size: 12px; font-weight: 500; cursor: pointer; padding: 4px 10px; border-radius: var(--radius-sm); transition: all 0.15s ease; } .text-btn:active { color: var(--danger); background: rgba(244, 63, 94, 0.08); } #history-list { list-style: none; flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; } #history-list li { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; margin-bottom: 8px; font-size: 14px; line-height: 1.5; cursor: pointer; transition: all 0.15s ease; display: flex; align-items: flex-start; gap: 12px; animation: slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; animation-delay: calc(var(--i, 0) * 40ms); } #history-list li:active { background: var(--surface-active); border-color: var(--border-active); transform: scale(0.985); } #history-list li .hist-text { flex: 1; word-break: break-word; } #history-list li .hist-time { font-size: 11px; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; padding-top: 2px; font-variant-numeric: tabular-nums; } @keyframes slide-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } #history-empty { text-align: center; padding: 40px 0; } .placeholder { color: var(--text-dim); font-size: 14px; } /* ─── Scrollbar ─── */ .preview-box::-webkit-scrollbar, #history-list::-webkit-scrollbar { width: 3px; } .preview-box::-webkit-scrollbar-track, #history-list::-webkit-scrollbar-track { background: transparent; } .preview-box::-webkit-scrollbar-thumb, #history-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } /* ─── Toast ─── */ .toast { position: fixed; bottom: calc(80px + var(--safe-bottom, 0px)); left: 50%; transform: translateX(-50%) translateY(8px); background: rgba(28, 28, 37, 0.85); color: var(--text); padding: 10px 22px; border-radius: 24px; font-size: 13px; font-weight: 500; z-index: 999; opacity: 0; transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); pointer-events: none; border: 1px solid var(--border); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); } .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }