/* NISPS Playground - Dark theme, mobile-first */ :root { --bg: #0d0d0d; --bg-surface: #1a1a1a; --bg-elevated: #252525; --text: #ccc; --text-dim: #666; --accent: #00ff88; --accent-dim: #00cc6a; --danger: #ff3366; --good: #00ff88; --bad: #ff6644; --synth-accent: #ff6b35; } * { box-sizing: border-box; margin: 0; padding: 0; } html, body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', 'Segoe UI', system-ui, sans-serif; font-size: 14px; height: 100%; overflow: hidden; touch-action: manipulation; -webkit-user-select: none; user-select: none; } /* --- Layout --- */ .app { display: grid; grid-template-rows: auto 1fr auto auto auto; height: 100vh; height: 100dvh; max-width: 600px; margin: 0 auto; position: relative; } .header, .visual-container, .param-container, .controls-area, .presets, .expand-visual-btn { transition: all 0.2s ease; } /* Header */ .header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid #222; } .header h1 { font-size: 15px; font-weight: 600; letter-spacing: 0.5px; color: var(--accent); } .header-right { display: flex; align-items: center; gap: 8px; } .header button { background: none; border: 1px solid #333; color: var(--text-dim); width: 28px; height: 28px; border-radius: 50%; cursor: pointer; font-size: 14px; } .mode-badge { font-size: 10px; padding: 3px 8px; border-radius: 10px; background: rgba(0, 255, 136, 0.12); border: 1px solid var(--accent-dim); color: var(--accent); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } .mode-badge.synth { background: rgba(255, 107, 53, 0.12); border-color: var(--synth-accent); color: var(--synth-accent); } /* ==================== Side Panel ==================== */ .side-panel-toggle { position: fixed; left: 0; top: 50%; transform: translateY(-50%); z-index: 50; background: var(--bg-surface); border: 1px solid #333; border-left: none; border-radius: 0 8px 8px 0; color: var(--text-dim); font-size: 16px; padding: 12px 6px; cursor: pointer; line-height: 1; transition: background 0.15s; } .side-panel-toggle:hover { background: var(--bg-elevated); color: var(--text); } .side-panel { position: fixed; left: 0; top: 0; bottom: 0; width: 260px; background: var(--bg-surface); border-right: 1px solid #333; z-index: 60; transform: translateX(-100%); transition: transform 0.25s ease; display: flex; flex-direction: column; overflow-y: auto; } .side-panel.open { transform: translateX(0); } .side-panel-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 55; } .side-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 10px; border-bottom: 1px solid #222; } .side-panel-title { font-size: 14px; font-weight: 600; color: var(--text); letter-spacing: 0.5px; } .side-panel-close { background: none; border: none; color: var(--text-dim); font-size: 22px; cursor: pointer; line-height: 1; padding: 0 4px; } .side-panel-tabs { display: flex; gap: 0; padding: 12px 16px; border-bottom: 1px solid #222; } .sp-tab { flex: 1; padding: 8px 0; background: var(--bg-elevated); border: 1px solid #333; color: var(--text-dim); font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.15s; text-transform: uppercase; letter-spacing: 0.5px; } .sp-tab:first-child { border-radius: 6px 0 0 6px; } .sp-tab:last-child { border-radius: 0 6px 6px 0; border-left: none; } .sp-tab.active[data-mode="visual"] { background: rgba(0, 255, 136, 0.12); border-color: var(--accent-dim); color: var(--accent); } .sp-tab.active[data-mode="synth"] { background: rgba(255, 107, 53, 0.12); border-color: var(--synth-accent); color: var(--synth-accent); } .sp-hint { padding: 16px; font-size: 12px; color: var(--text-dim); line-height: 1.5; } /* Synth controls */ .synth-controls { padding: 12px 16px; display: flex; flex-direction: column; gap: 14px; } .synth-section { display: flex; flex-direction: column; gap: 6px; } .synth-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } .synth-label span { color: var(--synth-accent); font-weight: 700; } .synth-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; background: #333; border-radius: 3px; outline: none; } .synth-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 16px; height: 16px; background: var(--synth-accent); border-radius: 50%; cursor: pointer; } .synth-slider::-moz-range-thumb { width: 16px; height: 16px; background: var(--synth-accent); border-radius: 50%; cursor: pointer; border: none; } .synth-select { background: var(--bg-elevated); border: 1px solid #333; color: var(--text); padding: 6px 8px; border-radius: 6px; font-size: 12px; cursor: pointer; } .synth-start-btn { font-size: 12px; } .synth-arp-btn { font-size: 12px; } .synth-arp-btn.playing { background: rgba(255, 107, 53, 0.15); border-color: var(--synth-accent); color: var(--synth-accent); } .synth-status { font-size: 10px; color: var(--text-dim); font-family: monospace; } /* Visual canvas */ .visual-container { position: relative; min-height: 0; } .expand-visual-btn { position: absolute; top: 8px; right: 8px; z-index: 2; background: rgba(26, 26, 26, 0.82); border: 1px solid #333; color: #9f9f9f; border-radius: 12px; font-size: 11px; line-height: 1; padding: 6px 10px; cursor: pointer; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); } .expand-visual-btn:active, .expand-visual-btn[aria-pressed="true"] { border-color: var(--accent-dim); color: var(--accent); background: rgba(0, 255, 136, 0.15); } .visual-container canvas { width: 100%; height: 100%; display: block; } /* Preset pills */ .presets { position: absolute; top: 8px; left: 8px; display: flex; gap: 6px; z-index: 2; } .preset-pill { background: rgba(26, 26, 26, 0.8); border: 1px solid #333; color: var(--text-dim); padding: 4px 10px; border-radius: 12px; font-size: 11px; cursor: pointer; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); } .preset-pill:active { background: rgba(0, 255, 136, 0.15); border-color: var(--accent-dim); color: var(--accent); } /* Parameter display */ .param-container { padding: 6px 12px; background: var(--bg-surface); border-top: 1px solid #222; } .param-row { display: flex; align-items: center; gap: 8px; height: 22px; } .param-label { width: 42px; font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; flex-shrink: 0; } .param-container.synth-mode .param-label { width: 72px; color: #886644; } .param-track { flex: 1; height: 8px; background: #222; border-radius: 4px; overflow: hidden; position: relative; } .draggable .param-track { cursor: ew-resize; height: 14px; border: 1px solid #333; } .draggable .param-track:active { border-color: var(--accent-dim); } .param-fill { height: 100%; border-radius: 4px; transition: width 0.05s ease-out; } .param-value { width: 32px; font-size: 10px; color: var(--text-dim); text-align: right; font-family: monospace; flex-shrink: 0; } /* Controls area */ .controls-area { display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px; background: var(--bg-surface); border-top: 1px solid #222; } .app.expanded { grid-template-rows: auto minmax(0, 1fr) 58px 102px 0; } .app.expanded .header { padding-top: 6px; padding-bottom: 6px; } .app.expanded .header h1 { font-size: 13px; color: #9a9a9a; } .app.expanded .presets { top: 6px; left: 6px; gap: 4px; } .app.expanded .preset-pill { font-size: 10px; padding: 3px 7px; color: #868686; } .app.expanded .param-container { padding: 4px 10px; overflow: hidden; opacity: 0.78; } .app.expanded .param-row { height: 17px; } .app.expanded .param-track { height: 5px; } .app.expanded .draggable .param-track { height: 9px; } .app.expanded .param-label, .app.expanded .param-value { font-size: 9px; } .app.expanded .controls-area { padding: 6px 10px; gap: 8px; overflow: hidden; opacity: 0.82; } .app.expanded #joystick-container { width: 94px; height: 94px; overflow: hidden; } .app.expanded #joystick-container canvas { transform: scale(0.58); transform-origin: top left; } .app.expanded .controls-mode-toggle, .app.expanded .controls-actions { margin-bottom: 4px; } .app.expanded .btn, .app.expanded .mode-btn { font-size: 10px; padding: 5px 10px; border-radius: 6px; } .app.expanded .btn-good, .app.expanded .btn-bad { font-size: 14px; padding: 5px 12px; } .app.expanded .controls-status, .app.expanded .metrics-grid, .app.expanded .loss-plot-wrap { display: none; } #joystick-container { flex-shrink: 0; } #controls-container { flex: 1; min-width: 0; } .controls-mode-toggle { display: flex; gap: 4px; margin-bottom: 8px; } .mode-btn { flex: 1; padding: 6px 0; background: var(--bg-elevated); border: 1px solid #333; color: var(--text-dim); font-size: 12px; border-radius: 6px; cursor: pointer; transition: all 0.15s; } .mode-btn.active { background: rgba(0, 255, 136, 0.1); border-color: var(--accent-dim); color: var(--accent); } .controls-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; } .btn { padding: 8px 14px; background: var(--bg-elevated); border: 1px solid #333; color: var(--text); font-size: 12px; border-radius: 8px; cursor: pointer; transition: all 0.1s; white-space: nowrap; } .btn:active { transform: scale(0.96); } .btn-primary { background: rgba(0, 255, 136, 0.12); border-color: var(--accent-dim); color: var(--accent); } .btn-primary:active { background: rgba(0, 255, 136, 0.25); } .btn-danger { color: var(--danger); border-color: #552233; } .btn-danger:active { background: rgba(255, 51, 102, 0.15); } .btn-good { background: rgba(0, 255, 136, 0.12); border-color: var(--accent-dim); color: var(--good); font-size: 18px; padding: 8px 20px; } .btn-good:active { background: rgba(0, 255, 136, 0.3); } .btn-bad { background: rgba(255, 102, 68, 0.1); border-color: #553322; color: var(--bad); font-size: 18px; padding: 8px 20px; } .btn-bad:active { background: rgba(255, 102, 68, 0.25); } .flash { animation: flash-anim 0.2s ease-out; } @keyframes flash-anim { 0% { box-shadow: 0 0 12px var(--accent); } 100% { box-shadow: none; } } .controls-status { display: flex; gap: 12px; font-size: 11px; color: var(--text-dim); font-family: monospace; margin-bottom: 8px; } .metrics-grid { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; font-size: 10px; margin-bottom: 8px; font-family: monospace; } .metric-label { color: #707070; } .metric-value { color: #b5b5b5; text-align: right; } .loss-plot-wrap { width: 100%; border: 1px solid #2a2a2a; border-radius: 8px; overflow: hidden; } #loss-plot { width: 100%; height: 86px; display: block; } .hidden { display: none !important; } /* Help overlay */ .help-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.85); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 20px; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); } .help-content { background: var(--bg-surface); border: 1px solid #333; border-radius: 12px; padding: 20px; max-width: 360px; max-height: 80vh; overflow-y: auto; font-size: 13px; line-height: 1.5; } .help-content h2 { color: var(--accent); font-size: 16px; margin-bottom: 12px; } .help-content h3 { color: var(--text); font-size: 13px; margin-top: 14px; margin-bottom: 4px; } .help-content p, .help-content li { color: var(--text-dim); margin-bottom: 6px; } .help-content ol { padding-left: 18px; } /* Responsive: wider screens (foldable inner, tablet) */ @media (min-width: 500px) { .app { max-width: 800px; } .controls-area { padding: 12px 16px; } .param-container { padding: 8px 16px; } }