/* ================================================================ duplex-shared.css — Shared styles for Omni & Audio Duplex pages Two independent flex columns, card-on-background layout ================================================================ */ /* ========== Reset & Base ========== */ * { margin: 0; padding: 0; box-sizing: border-box; } [data-comni-origin] { --_comni-v: 1; } [data-tooltip] { position: relative; cursor: help; } [data-tooltip]::after { content: attr(data-tooltip); position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.85); color: #fff; padding: 8px 12px; border-radius: 6px; font-size: 12px; line-height: 1.5; white-space: normal; width: max-content; max-width: 280px; pointer-events: none; opacity: 0; transition: opacity 0.15s ease; transition-delay: 0s; z-index: 1000; } [data-tooltip]:hover::after { opacity: 1; transition-delay: 0.2s; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Noto Sans SC', sans-serif; background: #f5f5f0; color: #2d2d2d; height: 100vh; display: flex; flex-direction: column; } /* ========== Top Notice Banner ========== */ .notice-banner { background: #fff3cd; border-bottom: 1px solid #ffc107; color: #664d03; padding: 8px 20px; font-size: 13px; line-height: 1.5; display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .notice-banner .notice-icon { font-size: 16px; flex-shrink: 0; } .notice-banner .notice-dismiss { margin-left: auto; background: none; border: none; color: #664d03; cursor: pointer; font-size: 18px; line-height: 1; padding: 0 4px; opacity: 0.6; } .notice-banner .notice-dismiss:hover { opacity: 1; } /* ========== Header ========== */ .header { background: #fff; padding: 12px 24px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e5e5e0; flex-shrink: 0; } .header-left { display: flex; align-items: center; gap: 16px; } .header h1 { font-size: 16px; font-weight: 600; color: #2d2d2d; letter-spacing: -0.3px; } .header .nav-links { display: flex; gap: 8px; } .header .nav-links a { font-size: 13px; padding: 4px 12px; border-radius: 6px; text-decoration: none; color: #666; transition: all 0.15s; } .header .nav-links a:hover { background: #f0f0eb; color: #2d2d2d; } .header .nav-links a.active { background: #2d2d2d; color: #fff; } .header .status-badge { font-size: 12px; padding: 3px 10px; border-radius: 10px; background: #f0f0eb; color: #666; } .header .status-badge.online { color: #1a7f37; background: #ddf4e4; } .header-right { display: flex; align-items: center; gap: 10px; } .header-reset-btn { font-size: 11px; padding: 3px 10px; border-radius: 6px; background: transparent; border: 1px solid #e5e5e0; color: #999; cursor: pointer; font-family: inherit; transition: all 0.15s; } .header-reset-btn:hover { color: #cf222e; border-color: #cf222e; background: #fff5f5; } /* ========== Separated Cards Layout: Two Columns + Bottom Controls ========== */ .main { display: grid; grid-template-columns: 1fr 2fr; grid-template-rows: 1fr auto; margin: 20px auto; max-width: 1400px; width: calc(100% - 64px); height: calc(100vh - 100px); gap: 12px; } .col-left, .col-right { display: flex; flex-direction: column; min-height: 0; overflow: hidden; gap: 12px; } /* -- Each panel is an independent card -- */ .panel-media { flex: 1; background: #111; overflow: hidden; position: relative; min-height: 0; border-radius: 10px; border: 1px solid #e5e5e0; } .panel-config { flex: 1; background: #fff; overflow-y: auto; padding: 12px 14px; min-height: 0; border-radius: 10px; border: 1px solid #e5e5e0; } .panel-status { flex: 1; background: #fff; padding: 10px 14px; overflow: visible; min-height: 0; border-radius: 10px; border: 1px solid #e5e5e0; } .panel-sysconfig { flex-shrink: 0; background: #fff; overflow-y: auto; padding: 12px 14px; border-radius: 10px; border: 1px solid #e5e5e0; } .sysconfig-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .sysconfig-col { min-width: 0; } .panel-dialog { flex: 1; background: #fff; display: flex; flex-direction: column; overflow: hidden; min-height: 0; border-radius: 10px; border: 1px solid #e5e5e0; } .panel-controls { grid-column: 1 / -1; background: #fff; display: flex; align-items: center; justify-content: center; gap: 12px; padding: 14px 12px; flex-wrap: wrap; border-radius: 10px; border: 1px solid #e5e5e0; } .ctrl-divider { width: 1px; height: 28px; background: #e0e0dc; flex-shrink: 0; } /* ========== Config Group (details/summary) ========== */ .config-group { border: none; border-bottom: 1px solid #f0f0eb; padding-bottom: 8px; } .config-group:last-child { border-bottom: none; } .config-group summary { font-size: 12px; font-weight: 600; color: #666; cursor: pointer; user-select: none; list-style: none; display: flex; align-items: center; gap: 6px; padding: 6px 0; } .config-group summary::before { content: '\25B8'; font-size: 10px; transition: transform 0.15s; } .config-group[open] summary::before { transform: rotate(90deg); } .config-group .cg-body { display: flex; flex-direction: column; gap: 8px; padding: 4px 0 4px 4px; } .config-group .cg-row { display: flex; flex-direction: column; gap: 3px; } .config-group .cg-row.inline { flex-direction: row; align-items: center; gap: 8px; } .config-group .cg-label { font-size: 11px; color: #999; font-weight: 500; } .config-group .cg-input { width: 100%; font-size: 12px; padding: 6px 10px; border: 1px solid #e5e5e0; border-radius: 6px; background: #fafaf7; color: #2d2d2d; font-family: inherit; resize: vertical; min-height: 32px; line-height: 1.4; } .config-group .cg-input:focus { outline: none; border-color: #999; } .config-group .cg-input-sm { width: 50px; padding: 2px 5px; font-size: 11px; border: 1px solid #333; border-radius: 6px; background: #2d2d2d; color: #fff; text-align: center; } .config-group .cg-input-sm:focus { outline: none; border-color: #666; } /* ========== Control Buttons ========== */ .ctrl-btn { padding: 12px 28px; min-width: 120px; font-size: 15px; font-weight: 500; border: 1px solid #e5e5e0; background: #fff; color: #2d2d2d; border-radius: 10px; cursor: pointer; transition: all 0.15s; font-family: inherit; display: flex; align-items: center; justify-content: center; white-space: nowrap; gap: 6px; } .ctrl-btn:hover { background: #f0f0eb; } .ctrl-btn:disabled { opacity: 0.35; cursor: not-allowed; } .ctrl-btn.primary { background: #2d2d2d; color: #fff; border-color: #2d2d2d; } .ctrl-btn.primary:hover { background: #444; } .ctrl-btn.primary:disabled { background: #999; border-color: #999; } .ctrl-btn.danger { color: #cf222e; border-color: #cf222e; } .ctrl-btn.danger:hover { background: #ffe3e6; } .ctrl-btn.force-listen-active { background: #e85d04; color: #fff; border-color: #e85d04; } .ctrl-btn.force-listen-active:hover { background: #d45203; } .ctrl-btn.cancel { color: #d97706; border-color: #d97706; } .ctrl-btn.cancel:hover { background: #fef3c7; } .ctrl-btn.live { background: #16a34a; color: #fff; border-color: #16a34a; opacity: 1; } .ctrl-btn.live:disabled { background: #16a34a; border-color: #16a34a; opacity: 0.85; cursor: default; } /* ========== Status Panel ========== */ .status-grid { display: grid; grid-template-columns: 1fr; gap: 3px; } .status-divider { height: 6px; } .status-grid .status-row { display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: #888; position: relative; cursor: default; } .status-grid .status-value { font-weight: 500; color: #2d2d2d; font-size: 12px; } .status-grid .status-value.listening { color: #1a7f37; } .status-grid .status-value.speaking { color: #d4a574; } /* Instant tooltip via data-tip — positioned by JS */ .data-tip-popup { position: fixed; z-index: 10000; padding: 5px 10px; border-radius: 6px; background: #333; color: #fff; font-size: 11px; font-weight: 400; line-height: 1.4; white-space: nowrap; pointer-events: none; } /* ========== Conversation / Chat Log ========== */ .conv-header { font-size: 12px; font-weight: 600; color: #666; padding: 8px 14px; border-bottom: 1px solid #f0f0eb; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; } .conv-log { flex: 1; overflow-y: auto; padding: 12px 16px; display: flex; flex-direction: column; gap: 8px; } .conv-entry { font-size: 13px; line-height: 1.5; padding: 4px 0; display: flex; gap: 8px; align-items: flex-start; } .conv-entry .conv-icon { width: 24px; height: 24px; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 12px; flex-shrink: 0; margin-top: 1px; } .conv-entry.speak .conv-icon, .conv-entry.ai .conv-icon { background: #f0e6d9; color: #d4a574; } .conv-entry.user .conv-icon { background: #e8eaf0; color: #555; } .conv-entry.system .conv-icon { background: #f0f0eb; color: #999; } .conv-entry .conv-text { font-size: 13px; line-height: 1.5; color: #2d2d2d; flex: 1; min-width: 0; } .conv-entry.system .conv-text { color: #999; font-size: 12px; } .conv-entry .speaker { font-weight: 600; margin-right: 6px; } .conv-entry .speaker.ai { color: #d4a574; } .conv-entry .speaker.user-tag { color: #666; } .conv-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: #999; font-size: 14px; flex-direction: column; gap: 8px; } .conv-empty .icon { font-size: 28px; opacity: 0.4; } /* ========== Mobile Responsive ========== */ @media (max-width: 768px) { .header { padding: 8px 12px; } .header h1 { font-size: 14px; } .header .nav-links a { font-size: 12px; padding: 3px 8px; } .main { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; margin: 8px; width: calc(100% - 16px); max-width: none; height: auto; max-height: none; gap: 8px; } .col-left, .col-right { gap: 8px; } .panel-media { flex: none; height: 180px; } .panel-config { flex: none; } .panel-status { flex: none; } .panel-dialog { min-height: 200px; } .sysconfig-columns { grid-template-columns: 1fr; } .ctrl-btn { padding: 8px 16px; min-width: 90px; font-size: 13px; } } @media (max-width: 480px) { .header .nav-links a { padding: 3px 6px; font-size: 11px; } .header h1 { font-size: 13px; } .ctrl-btn { padding: 8px 12px; min-width: 70px; font-size: 12px; } } /* ========== Audio Device Selector (shared) ========== */ .cg-select { width: 100%; font-size: 11px; padding: 4px 6px; border: 1px solid #e5e5e0; border-radius: 5px; background: #fafaf7; color: #2d2d2d; font-family: inherit; cursor: pointer; appearance: auto; } .cg-select:focus { outline: none; border-color: #999; } .device-refresh-btn { font-size: 10px; padding: 2px 8px; border: 1px solid #e5e5e0; border-radius: 4px; background: #f0f0eb; color: #888; cursor: pointer; font-family: inherit; margin-top: 2px; } .device-refresh-btn:hover { background: #e5e5e0; color: #2d2d2d; } /* ========== Rec label (shared controls) ========== */ .rec-label { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #ccc; cursor: pointer; user-select: none; } .rec-label input[type="checkbox"] { margin: 0; accent-color: #ff4444; } /* ========== Draggable Mixer Panel (floating, shared) — LUFS layout ========== */ .mixer-panel { position: fixed; z-index: 900; background: #1a1a2e; border: 1px solid #333; border-radius: 10px; width: 380px; box-shadow: 0 6px 24px rgba(0,0,0,0.45); font-family: inherit; color: #ddd; display: none; } .mixer-header { display: flex; align-items: center; gap: 12px; padding: 10px 16px; border-bottom: 1px solid #2a2a3a; cursor: grab; user-select: none; } .mixer-header:active { cursor: grabbing; } .mixer-header-title { font-size: 14px; font-weight: 600; color: #ccc; } .mixer-status { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #777; flex: 1; } .mixer-close { background: none; border: none; color: #666; font-size: 18px; cursor: pointer; padding: 0 2px; line-height: 1; flex-shrink: 0; } .mixer-close:hover { color: #fff; } .mixer-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #555; flex-shrink: 0; margin-right: 2px; } .mixer-dot.on { background: #00ff88; box-shadow: 0 0 4px #00ff88; } /* Section layout */ .mixer-section { padding: 10px 16px; border-top: 1px solid #2a2a3a; } .mixer-section-title { font-size: 10px; font-weight: 700; color: #666; letter-spacing: 1.2px; text-transform: uppercase; margin-bottom: 10px; } /* Source blocks (File, Mic) */ .mixer-source { margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid rgba(255,255,255,0.05); } .mixer-source:last-of-type { border-bottom: none; margin-bottom: 6px; } .mixer-source-header { display: flex; align-items: center; gap: 8px; font-size: 12px; flex-wrap: wrap; margin-bottom: 6px; } .mixer-source-name { font-weight: 600; color: #ccc; width: 32px; flex-shrink: 0; } .mixer-source-row { display: flex; align-items: center; gap: 8px; font-size: 12px; margin-bottom: 6px; } .mixer-info { color: #888; font-size: 11px; font-family: monospace; white-space: nowrap; } /* Number inputs for LUFS targets */ .mx-num { width: 52px; padding: 2px 4px; font-size: 12px; text-align: center; background: #2a2a3a; color: #ddd; border: 1px solid #444; border-radius: 4px; font-family: monospace; } .mx-num:focus { outline: none; border-color: #00ff88; } /* Shared row/label/val */ .mixer-row { display: flex; align-items: center; gap: 10px; font-size: 12px; } .mixer-label { width: 48px; color: #aaa; flex-shrink: 0; font-size: 12px; } .mixer-val { width: 48px; text-align: right; color: #999; font-family: monospace; font-size: 11px; flex-shrink: 0; } .mixer-row input[type="range"], .mixer-source-row input[type="range"] { flex: 1; accent-color: #00ff88; height: 5px; } /* Meter rows */ .meter-row { display: flex; align-items: center; gap: 8px; font-size: 12px; } .meter-label { width: 32px; color: #aaa; flex-shrink: 0; } .meter-bar-bg { flex: 1; height: 6px; background: #2a2a3a; border-radius: 3px; overflow: hidden; } .meter-bar { height: 100%; width: 0; background: linear-gradient(90deg, #00ff88, #ffaa00, #ff4444); border-radius: 3px; transition: width 0.08s ease-out; } .meter-val { width: 64px; text-align: right; color: #999; font-family: monospace; font-size: 11px; flex-shrink: 0; } .mixer-mix-meter { margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.06); } /* Hint text */ .mixer-hint { font-size: 10px; color: #666; margin-top: 4px; } /* Cal button */ .mixer-panel .fo-cal-btn { padding: 3px 8px; font-size: 11px; border-radius: 4px; background: #333; color: #ccc; border: 1px solid #555; cursor: pointer; flex-shrink: 0; white-space: nowrap; } .mixer-panel .fo-cal-btn:hover { background: #444; color: #fff; } .mixer-panel .fo-cal-btn.recording { background: #ff4444; color: #fff; border-color: #ff4444; } .mixer-panel .fo-cal-result { font-size: 11px; color: #888; padding: 6px 16px 10px; display: block; } /* Preview buttons */ .mixer-preview { display: flex; align-items: center; gap: 8px; } .mixer-prev-btn { padding: 5px 14px; font-size: 12px; border-radius: 5px; background: #2a2a3a; color: #ccc; border: 1px solid #444; cursor: pointer; font-family: inherit; } .mixer-prev-btn:hover:not(:disabled) { background: #3a3a4a; color: #fff; } .mixer-prev-btn:disabled { opacity: 0.35; cursor: not-allowed; } .mixer-prev-btn.recording { background: #ff4444; color: #fff; border-color: #ff4444; } /* Mixer toggle button inside file-options */ .fo-mixer-btn { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; font-size: 11px; border-radius: 5px; background: #1e1e2e; color: #aaa; border: 1px solid #444; cursor: pointer; margin-top: 4px; } .fo-mixer-btn:hover { background: #2a2a3a; color: #ddd; } .fo-mixer-btn.active { border-color: #00ff88; color: #00ff88; } @media (max-width: 768px) { .mixer-panel { width: 320px; } } /* ========== Recording Settings Panel (floating, self-contained) ========== */ .rec-settings-btn { min-width: auto !important; padding: 8px 12px !important; font-size: 14px !important; line-height: 1; } .rec-settings-panel { position: fixed; z-index: 900; display: none; background: #1a1a2e; border: 1px solid #333; border-radius: 10px; width: 320px; box-shadow: 0 6px 24px rgba(0,0,0,0.45); font-family: inherit; color: #ddd; } .rec-settings-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 16px; border-bottom: 1px solid #2a2a3a; cursor: grab; user-select: none; } .rec-settings-header:active { cursor: grabbing; } .rec-settings-title { font-size: 14px; font-weight: 600; color: #ccc; } .rec-settings-close { background: none; border: none; color: #666; font-size: 18px; cursor: pointer; padding: 0 2px; line-height: 1; } .rec-settings-close:hover { color: #fff; } .rec-settings-body { padding: 12px 16px; } .rec-settings-section { margin-bottom: 14px; } .rec-settings-section:last-child { margin-bottom: 0; } .rec-settings-label { font-size: 11px; font-weight: 600; color: #888; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; } /* Format radio options */ .rec-fmt-options { display: flex; flex-direction: column; gap: 4px; } .rec-fmt-option { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 6px; cursor: pointer; font-size: 13px; color: #ccc; transition: background 0.1s; } .rec-fmt-option:hover { background: #2a2a3a; } .rec-fmt-option.disabled { opacity: 0.35; cursor: not-allowed; } .rec-fmt-option input[type="radio"] { accent-color: #00cc66; margin: 0; width: 14px; height: 14px; flex-shrink: 0; } .rec-fmt-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #555; flex-shrink: 0; } .rec-fmt-dot.on { background: #00ff88; box-shadow: 0 0 4px #00ff88; } .rec-fmt-dot.warn { background: #ffaa00; box-shadow: 0 0 4px #ffaa00; } .rec-fmt-text { flex: 1; } .rec-fmt-warn { font-size: 10px; color: #ffaa00; white-space: nowrap; flex-shrink: 0; } .rec-fmt-option.has-warning { opacity: 0.7; } /* Quality select */ .rec-settings-select { width: 100%; padding: 6px 10px; font-size: 13px; background: #2a2a3a; color: #ddd; border: 1px solid #444; border-radius: 6px; font-family: inherit; cursor: pointer; appearance: auto; } .rec-settings-select:focus { outline: 1px solid #00cc66; border-color: #00cc66; } /* Subtitle toggle */ .rec-subtitle-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; color: #ccc; } .rec-subtitle-toggle input[type="checkbox"] { accent-color: #00cc66; margin: 0; width: 14px; height: 14px; flex-shrink: 0; } .rec-subtitle-text { flex: 1; } .rec-subtitle-details { margin-top: 8px; padding-left: 22px; display: flex; flex-direction: column; gap: 6px; } .rec-subtitle-param-row { display: flex; align-items: center; gap: 6px; } .rec-subtitle-param-label { font-size: 11px; color: #999; flex: none; min-width: 62px; } .rec-subtitle-param-suffix { font-size: 10px; color: #666; } .rec-settings-num { width: 48px; padding: 3px 6px; border: 1px solid #444; border-radius: 4px; background: #1a1a1a; color: #ccc; font-size: 12px; text-align: center; -moz-appearance: textfield; } .rec-settings-num::-webkit-inner-spin-button, .rec-settings-num::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } /* Detection info footer */ .rec-settings-info { font-size: 11px; color: #666; padding-top: 10px; border-top: 1px solid #2a2a3a; margin-top: 14px; text-align: center; } @media (max-width: 768px) { .rec-settings-panel { width: 280px; } }