/* Arnold — Terminator I/O Web Interface Dark theme, terminal-inspired, responsive. */ :root { --bg: #1a1a2e; --bg-panel: #16213e; --bg-hover: #1e2d4a; --border: #2a3a5c; --text: #c8d6e5; --text-dim: #6b7b8d; --green: #2ecc71; --green-dim: #1a7a42; --red: #e74c3c; --yellow: #f39c12; --cyan: #00cec9; --accent: #6c5ce7; --accent-light:#a29bfe; } * { box-sizing: border-box; margin: 0; padding: 0; } html, body { height: 100%; font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace; font-size: 14px; background: var(--bg); color: var(--text); } body { display: flex; flex-direction: column; min-height: 100vh; } /* ── Status bar ─────────────────────────────────────────────── */ #status-bar { display: flex; align-items: center; justify-content: space-between; padding: 6px 16px; background: #0f1527; border-bottom: 1px solid var(--border); font-size: 13px; flex-shrink: 0; gap: 16px; flex-wrap: wrap; } #status-devices { display: flex; gap: 20px; flex-wrap: wrap; } .device-status { display: flex; align-items: center; gap: 6px; } .device-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .device-dot.connected { background: var(--green); } .device-dot.disconnected { background: var(--red); } #status-message { color: var(--yellow); font-size: 12px; min-height: 1em; } /* ── Main panels ────────────────────────────────────────────── */ #panels { display: flex; flex: 1; gap: 0; overflow: hidden; } .panel { flex: 1; border-right: 1px solid var(--border); padding: 12px 16px; overflow-y: auto; display: flex; flex-direction: column; } .panel:last-child { border-right: none; } .panel-wide { flex: 2; } .panel h2 { font-size: 15px; font-weight: 600; margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border); color: var(--text); flex-shrink: 0; } .sub-header { font-size: 11px; font-weight: 400; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin: 10px 0 6px 0; padding-bottom: 3px; border-bottom: 1px solid var(--border); } .empty-msg { color: var(--text-dim); font-style: italic; padding: 8px 0; } .hidden { display: none !important; } /* ── Signal rows ────────────────────────────────────────────── */ .signal-list { display: flex; flex-direction: column; gap: 2px; } .signal-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-radius: 4px; min-height: 30px; } .signal-row:hover { background: var(--bg-hover); } /* Indicator dot for digital signals */ .indicator { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .indicator.on { background: var(--green); box-shadow: 0 0 6px var(--green); } .indicator.off { background: #3a4a5c; border: 1px solid #4a5a6c; } .indicator.stale { background: #5a5a5a; } .signal-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .signal-value { font-weight: 600; min-width: 40px; text-align: right; } .signal-value.on { color: var(--green); } .signal-value.off { color: var(--text-dim); } .signal-value.stale { color: var(--text-dim); } .signal-value.analog { color: var(--cyan); } /* ── Output controls ────────────────────────────────────────── */ .output-row { cursor: pointer; user-select: none; } .output-row:active { background: #2a3d5c; } .bulk-actions { display: flex; gap: 8px; margin-bottom: 8px; } .bulk-actions button, button.seq-run-btn { padding: 4px 12px; border: 1px solid var(--border); background: var(--bg); color: var(--text); border-radius: 4px; cursor: pointer; font-family: inherit; font-size: 12px; } .bulk-actions button:hover, button.seq-run-btn:hover { background: var(--bg-hover); border-color: var(--accent); } .bulk-actions button:active, button.seq-run-btn:active { background: var(--accent); } /* Analog output controls */ .analog-controls { display: flex; align-items: center; gap: 4px; flex-shrink: 0; } .analog-controls button { width: 28px; height: 28px; border: 1px solid var(--border); background: var(--bg); color: var(--text); border-radius: 4px; cursor: pointer; font-family: inherit; font-size: 16px; font-weight: bold; display: flex; align-items: center; justify-content: center; padding: 0; } .analog-controls button:hover { border-color: var(--cyan); background: var(--bg-hover); } .analog-controls button:active { background: var(--cyan); color: var(--bg); } .analog-controls input { width: 70px; padding: 3px 6px; border: 1px solid var(--border); background: var(--bg); color: var(--cyan); font-family: inherit; font-size: 13px; text-align: right; border-radius: 4px; } .analog-controls input:focus { border-color: var(--cyan); outline: none; } .analog-controls .write-btn { font-size: 12px; width: auto; padding: 0 8px; color: var(--cyan); } .analog-controls .write-btn:hover { background: var(--cyan); color: var(--bg); } .analog-controls .pending { border-color: var(--yellow); color: var(--yellow); } /* ── Sequence panel ─────────────────────────────────────────── */ .seq-item { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 4px; margin-bottom: 4px; } .seq-item:hover { background: var(--bg-hover); } .seq-name { font-weight: 600; flex: 1; } .seq-meta { color: var(--text-dim); font-size: 12px; } .seq-desc { color: var(--text-dim); font-size: 12px; padding: 0 10px 6px 10px; } button.seq-run-btn { border-color: var(--accent); color: var(--accent-light); } button.seq-run-btn:hover { background: var(--accent); color: white; } button.seq-run-btn:disabled { opacity: 0.4; cursor: not-allowed; } /* Run progress */ #run-header { font-weight: 600; color: var(--yellow); margin-bottom: 8px; font-size: 15px; } #run-progress-bar { height: 6px; background: #2a3a5c; border-radius: 3px; margin-bottom: 12px; overflow: hidden; } #run-progress-fill { height: 100%; background: var(--yellow); border-radius: 3px; transition: width 0.2s ease; width: 0%; } .step-row { display: flex; align-items: center; gap: 8px; padding: 3px 8px; border-radius: 3px; font-size: 13px; } .step-row.current { background: rgba(243, 156, 18, 0.15); color: var(--yellow); font-weight: 600; } .step-row.completed { color: var(--green-dim); } .step-row.pending-step { color: var(--text-dim); } .step-icon { width: 16px; text-align: center; flex-shrink: 0; } .step-time { width: 55px; text-align: right; flex-shrink: 0; } .step-action { flex: 1; } /* Last run summary */ #last-run-summary { margin-top: 16px; padding: 10px; border-top: 1px solid var(--border); font-size: 13px; } .run-success { color: var(--green); } .run-failed { color: var(--red); } .run-error { color: var(--red); } /* ── Footer ─────────────────────────────────────────────────── */ #footer { padding: 4px 16px; background: #0f1527; border-top: 1px solid var(--border); font-size: 11px; color: var(--text-dim); text-align: center; flex-shrink: 0; } /* ── Responsive ─────────────────────────────────────────────── */ /* Tablet: stack outputs below inputs, sequences full width below */ @media (max-width: 1024px) { #panels { flex-wrap: wrap; } .panel { flex: 1 1 45%; min-width: 280px; border-right: none; border-bottom: 1px solid var(--border); max-height: 50vh; } .panel-wide { flex: 1 1 100%; max-height: none; } } /* Phone: single column */ @media (max-width: 640px) { #panels { flex-direction: column; } .panel { flex: none; max-height: none; border-right: none; border-bottom: 1px solid var(--border); } .panel-wide { flex: none; } #status-bar { flex-direction: column; align-items: flex-start; gap: 4px; } .signal-row { padding: 6px 8px; } }