4925 lines
104 KiB
CSS
4925 lines
104 KiB
CSS
/* Global reset and base */
|
|
*, *::before, *::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
html {
|
|
font-size: clamp(13px, 1.5vh, 18px);
|
|
}
|
|
|
|
body {
|
|
background: #0f1117;
|
|
color: #e2e8f0;
|
|
font-family: system-ui, 'Segoe UI', Roboto, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#app {
|
|
width: 100%;
|
|
max-width: none;
|
|
margin: 0;
|
|
text-align: left;
|
|
border: none;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* ── Connection banner ─────────────────────────────────────────────────── */
|
|
|
|
.connection-banner {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 1000;
|
|
background: #7f1d1d;
|
|
color: #fca5a5;
|
|
text-align: center;
|
|
font-size: 0.8rem;
|
|
padding: 0.3rem 1rem;
|
|
}
|
|
|
|
/* ── ViewMode ──────────────────────────────────────────────────────────── */
|
|
|
|
.view-mode {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
background: #0f1117;
|
|
}
|
|
|
|
.toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 1rem;
|
|
height: 2.75rem;
|
|
background: #1a1f2e;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.toolbar-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
|
|
.toolbar-center {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.toolbar-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
flex: 1;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.app-name {
|
|
font-size: 1rem;
|
|
font-weight: 800;
|
|
color: #60a5fa;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
|
|
.iface-name {
|
|
font-size: 0.85rem;
|
|
color: #94a3b8;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.parse-error {
|
|
font-size: 0.78rem;
|
|
color: #f87171;
|
|
background: rgba(248, 113, 113, 0.1);
|
|
border: 1px solid rgba(248, 113, 113, 0.3);
|
|
border-radius: 4px;
|
|
padding: 0.15rem 0.5rem;
|
|
}
|
|
|
|
.status-chip {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
font-size: 0.75rem;
|
|
padding: 0.2rem 0.6rem;
|
|
border-radius: 9999px;
|
|
background: #1e293b;
|
|
color: #94a3b8;
|
|
border: 1px solid #334155;
|
|
text-transform: capitalize;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.status-chip.connected {
|
|
background: #14532d;
|
|
color: #86efac;
|
|
border-color: #166534;
|
|
}
|
|
|
|
.status-chip.disconnected {
|
|
background: #7f1d1d;
|
|
color: #fca5a5;
|
|
border-color: #991b1b;
|
|
}
|
|
|
|
.status-chip.connecting {
|
|
background: #1e293b;
|
|
color: #fbbf24;
|
|
border-color: #92400e;
|
|
}
|
|
|
|
.status-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: currentColor;
|
|
}
|
|
|
|
.btn-edit {
|
|
background: #2d3748;
|
|
border: none;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
padding: 0.25rem 0.7rem;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.btn-edit:hover {
|
|
background: #374151;
|
|
}
|
|
|
|
/* ── User identity chip ──────────────────────────────────────────────────── */
|
|
/* ── Access denied screen ────────────────────────────────────────────────── */
|
|
.access-denied {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
text-align: center;
|
|
color: #e2e8f0;
|
|
padding: 2rem;
|
|
}
|
|
|
|
.access-denied h1 {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 0.5rem;
|
|
color: #fca5a5;
|
|
}
|
|
|
|
.access-denied p {
|
|
max-width: 32rem;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.content {
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
/* ── Bottom status bar (connection chip + panel context) ─────────────────── */
|
|
.statusbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 1.6rem;
|
|
padding: 0 0.75rem;
|
|
background: #141925;
|
|
border-top: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
gap: 1rem;
|
|
font-size: 0.72rem;
|
|
color: #94a3b8;
|
|
}
|
|
.statusbar-left,
|
|
.statusbar-right { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
|
|
.statusbar-iface { color: #cbd5e1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.statusbar-muted { color: #64748b; }
|
|
.statusbar-hist { color: #fbbf24; }
|
|
.statusbar .status-chip { padding: 0.05rem 0.5rem; font-size: 0.7rem; }
|
|
|
|
/* ── Panel resize handle ─────────────────────────────────────────────────── */
|
|
|
|
.panel-resize-handle {
|
|
width: 5px;
|
|
flex-shrink: 0;
|
|
background: transparent;
|
|
cursor: ew-resize;
|
|
position: relative;
|
|
z-index: 10;
|
|
transition: background 0.15s;
|
|
}
|
|
.panel-resize-handle:hover,
|
|
.panel-resize-handle.dragging {
|
|
background: #4a9eff55;
|
|
}
|
|
|
|
/* ── EditMode ──────────────────────────────────────────────────────────── */
|
|
|
|
.edit-mode {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
width: 100%;
|
|
background: #0f1117;
|
|
color: #475569;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
/* ── InterfaceList panel ───────────────────────────────────────────────── */
|
|
|
|
.panel {
|
|
width: 260px;
|
|
min-width: 260px;
|
|
background: #1a1f2e;
|
|
border-right: 1px solid #2d3748;
|
|
display: flex;
|
|
flex-direction: column;
|
|
transition: width 0.2s ease, min-width 0.2s ease;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.panel.collapsed {
|
|
width: 40px;
|
|
min-width: 40px;
|
|
}
|
|
|
|
.panel-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0.5rem 0.5rem 0.75rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
min-height: 2.5rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.panel.collapsed .panel-header {
|
|
justify-content: center;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.panel-title {
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.icon-btn {
|
|
background: none;
|
|
border: none;
|
|
color: #64748b;
|
|
cursor: pointer;
|
|
font-size: 0.75rem;
|
|
padding: 0.2rem 0.4rem;
|
|
border-radius: 3px;
|
|
line-height: 1;
|
|
}
|
|
|
|
.icon-btn:hover {
|
|
background: #2d3748;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.panel-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
.panel-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.4rem;
|
|
padding: 0.5rem 0.6rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.panel-btn {
|
|
flex: 1;
|
|
background: #2d3748;
|
|
border: none;
|
|
color: #e2e8f0;
|
|
font-size: 0.78rem;
|
|
padding: 0.3rem 0.5rem;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.panel-btn:hover {
|
|
background: #374151;
|
|
}
|
|
|
|
.panel-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0.5rem 0;
|
|
}
|
|
|
|
.hint {
|
|
color: #475569;
|
|
font-size: 0.8rem;
|
|
padding: 0.75rem 0.75rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.iface-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.iface-item {
|
|
padding: 0.5rem 0.75rem;
|
|
color: #cbd5e1;
|
|
font-size: 0.85rem;
|
|
cursor: pointer;
|
|
border-radius: 3px;
|
|
margin: 1px 4px;
|
|
}
|
|
|
|
.iface-item:hover {
|
|
background: #2d3748;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
/* ── Canvas ────────────────────────────────────────────────────────────── */
|
|
|
|
.canvas-container {
|
|
flex: 1;
|
|
position: relative;
|
|
overflow: auto;
|
|
background: #0f1117;
|
|
min-width: 0;
|
|
}
|
|
|
|
.placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
color: #475569;
|
|
font-size: 0.95rem;
|
|
text-align: center;
|
|
padding: 2rem;
|
|
}
|
|
|
|
.canvas-area {
|
|
position: relative;
|
|
/* width/height set inline from interface dimensions */
|
|
}
|
|
|
|
/* View mode: widgets shed their card chrome (border/background/shadow) so they
|
|
blend with the canvas background. Edit mode (EditCanvas) keeps the chrome so
|
|
widgets stay visible and selectable. Internal elements (gauge arc, bar track,
|
|
plot chart, inputs) keep their own styling. */
|
|
.canvas-view-bare .textview,
|
|
.canvas-view-bare .gauge,
|
|
.canvas-view-bare .barh,
|
|
.canvas-view-bare .barv,
|
|
.canvas-view-bare .led-widget,
|
|
.canvas-view-bare .multiled-widget,
|
|
.canvas-view-bare .setvalue,
|
|
.canvas-view-bare .toggle-widget,
|
|
.canvas-view-bare .plot-widget {
|
|
background: transparent;
|
|
border-color: transparent;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* ── TextLabel widget ──────────────────────────────────────────────────────── */
|
|
|
|
.textlabel {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
box-sizing: border-box;
|
|
font-size: 0.9rem;
|
|
color: #e2e8f0;
|
|
font-family: system-ui, sans-serif;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Overlay shown over a widget disabled via action.widget logic: dims it and
|
|
blocks interaction while still surfacing the right-click context menu. */
|
|
.widget-disable-overlay {
|
|
position: absolute;
|
|
z-index: 10;
|
|
background: rgba(20, 25, 35, 0.45);
|
|
cursor: not-allowed;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* ── Unknown widget ────────────────────────────────────────────────────────── */
|
|
|
|
.unknown-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #1e2535;
|
|
border: 1px dashed #3d4f6e;
|
|
border-radius: 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.unknown-label {
|
|
color: #475569;
|
|
font-size: 0.75rem;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
|
|
/* ── Context Menu ──────────────────────────────────────────────────────── */
|
|
|
|
.ctx-menu {
|
|
position: fixed;
|
|
z-index: 9000;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
|
min-width: 180px;
|
|
padding: 4px 0;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.ctx-item {
|
|
display: block;
|
|
width: 100%;
|
|
background: none;
|
|
border: none;
|
|
color: #cbd5e1;
|
|
font-size: 0.85rem;
|
|
padding: 0.4rem 0.9rem;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.ctx-item:hover {
|
|
background: #2d3748;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.ctx-divider {
|
|
height: 1px;
|
|
background: #2d3748;
|
|
margin: 4px 0;
|
|
}
|
|
|
|
.ctx-signal-info {
|
|
padding: 0.3rem 0.9rem;
|
|
font-size: 0.75rem;
|
|
color: #475569;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
|
|
/* ── Widgets — shared ──────────────────────────────────────────────────── */
|
|
|
|
.quality-dot {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── TextView widget ───────────────────────────────────────────────────── */
|
|
|
|
.textview {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4em;
|
|
padding: 0 0.6em;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
box-sizing: border-box;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.textview .label {
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.textview .value {
|
|
font-family: ui-monospace, Consolas, monospace;
|
|
font-size: 0.9rem;
|
|
color: #e2e8f0;
|
|
min-width: 4ch;
|
|
}
|
|
|
|
.textview .unit {
|
|
color: #64748b;
|
|
font-size: 0.75rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── Gauge widget ──────────────────────────────────────────────────────── */
|
|
|
|
.gauge {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
font-family: system-ui, sans-serif;
|
|
padding: 4px;
|
|
}
|
|
|
|
.gauge .quality-dot {
|
|
position: absolute;
|
|
top: 5px;
|
|
right: 5px;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.gauge-svg {
|
|
width: 100%;
|
|
flex: 1;
|
|
}
|
|
|
|
.gauge-value {
|
|
fill: #e2e8f0;
|
|
font-size: 14px;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
|
|
.gauge-unit {
|
|
fill: #64748b;
|
|
font-size: 6px;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.gauge-range {
|
|
fill: #475569;
|
|
font-size: 6px;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.gauge-label {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
width: 100%;
|
|
padding: 0 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* ── BarH widget ───────────────────────────────────────────────────────── */
|
|
|
|
.barh {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
justify-content: center;
|
|
gap: 3px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
padding: 6px 10px;
|
|
font-family: system-ui, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.barh .quality-dot {
|
|
position: absolute;
|
|
top: 5px;
|
|
right: 5px;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.barh .bar-label {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.barh .bar-track {
|
|
width: 100%;
|
|
height: 12px;
|
|
background: #2d3748;
|
|
border-radius: 3px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.barh .bar-fill {
|
|
height: 100%;
|
|
background: #4a9eff;
|
|
border-radius: 3px;
|
|
transition: width 0.15s ease;
|
|
}
|
|
|
|
.barh .bar-value {
|
|
display: flex;
|
|
gap: 4px;
|
|
align-items: baseline;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.barh .value {
|
|
font-family: ui-monospace, monospace;
|
|
font-size: 0.85rem;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.barh .unit {
|
|
font-size: 0.7rem;
|
|
color: #64748b;
|
|
}
|
|
|
|
/* ── BarV widget ───────────────────────────────────────────────────────── */
|
|
|
|
.barv {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 3px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
padding: 6px 8px;
|
|
font-family: system-ui, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.barv .quality-dot {
|
|
position: absolute;
|
|
top: 5px;
|
|
right: 5px;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.barv .bar-label {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.barv .bar-value {
|
|
display: flex;
|
|
gap: 3px;
|
|
align-items: baseline;
|
|
}
|
|
|
|
.barv .value {
|
|
font-family: ui-monospace, monospace;
|
|
font-size: 0.85rem;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.barv .unit {
|
|
font-size: 0.7rem;
|
|
color: #64748b;
|
|
}
|
|
|
|
.barv .bar-track {
|
|
width: 24px;
|
|
flex: 1;
|
|
background: #2d3748;
|
|
border-radius: 3px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.barv .bar-fill {
|
|
width: 100%;
|
|
background: #4a9eff;
|
|
border-radius: 3px;
|
|
transition: height 0.15s ease;
|
|
}
|
|
|
|
/* ── LED widget ────────────────────────────────────────────────────────── */
|
|
|
|
.led-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
padding: 4px;
|
|
font-family: system-ui, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.led-circle {
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.led-circle.blink {
|
|
animation: blink-slow 1.8s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes blink-slow {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.3; }
|
|
}
|
|
|
|
.led-label {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
width: 100%;
|
|
}
|
|
|
|
/* ── MultiLed widget ───────────────────────────────────────────────────── */
|
|
|
|
.multiled-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
align-items: flex-start;
|
|
justify-content: flex-start;
|
|
gap: 4px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
padding: 6px;
|
|
font-family: system-ui, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.bit-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 2px;
|
|
min-width: 20px;
|
|
}
|
|
|
|
.multiled-widget .led-circle {
|
|
width: 14px;
|
|
height: 14px;
|
|
}
|
|
|
|
.bit-label {
|
|
font-size: 0.6rem;
|
|
color: #64748b;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ── SetValue widget ───────────────────────────────────────────────────── */
|
|
|
|
.setvalue {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
padding: 0 8px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
font-family: system-ui, sans-serif;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.setvalue .quality-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sv-label {
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sv-input {
|
|
width: 80px;
|
|
background: #0f1117;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
font-size: 0.85rem;
|
|
padding: 2px 5px;
|
|
flex-shrink: 0;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
|
|
.sv-input:focus {
|
|
outline: none;
|
|
border-color: #4a9eff;
|
|
}
|
|
|
|
.sv-select {
|
|
flex: 1;
|
|
width: auto;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.sv-current {
|
|
font-family: ui-monospace, monospace;
|
|
font-size: 0.85rem;
|
|
color: #e2e8f0;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sv-unit {
|
|
font-size: 0.7rem;
|
|
color: #64748b;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sv-btn {
|
|
background: #2563eb;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 4px;
|
|
padding: 3px 10px;
|
|
font-size: 0.8rem;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
/* Config selector widget — a labelled combo of a config set's instances whose
|
|
choice is written to a panel-local variable. */
|
|
.configselect {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 0 8px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
font-family: system-ui, sans-serif;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.cs-label {
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.cs-select {
|
|
flex: 1;
|
|
width: auto;
|
|
background: #0f1117;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
font-size: 0.85rem;
|
|
padding: 2px 5px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.cs-select:focus {
|
|
outline: none;
|
|
border-color: #4a9eff;
|
|
}
|
|
|
|
.sv-btn:hover {
|
|
background: #1d4ed8;
|
|
}
|
|
|
|
.sv-btn:active {
|
|
background: #1e40af;
|
|
}
|
|
|
|
/* Read-only: user lacks permission to write this signal (.sv-select shares
|
|
.sv-input). */
|
|
.sv-input:disabled,
|
|
.sv-btn:disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
}
|
|
.sv-btn:disabled:hover { background: #2563eb; }
|
|
|
|
/* ── Toggle switch widget ──────────────────────────────────────────────── */
|
|
.toggle-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 0 8px;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
font-family: system-ui, sans-serif;
|
|
white-space: nowrap;
|
|
}
|
|
.toggle-label {
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
flex-shrink: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.toggle-switch {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
margin-left: auto;
|
|
background: none;
|
|
border: none;
|
|
padding: 0;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
}
|
|
.toggle-track {
|
|
position: relative;
|
|
width: 34px;
|
|
height: 18px;
|
|
border-radius: 9999px;
|
|
background: #3d4f6e;
|
|
transition: background 0.15s;
|
|
flex-shrink: 0;
|
|
}
|
|
.toggle-knob {
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
width: 14px;
|
|
height: 14px;
|
|
border-radius: 50%;
|
|
background: #e2e8f0;
|
|
transition: transform 0.15s;
|
|
}
|
|
.toggle-on .toggle-track { background: #22c55e; }
|
|
.toggle-on .toggle-knob { transform: translateX(16px); }
|
|
.toggle-unknown .toggle-track { background: #4b5563; }
|
|
.toggle-state {
|
|
font-size: 0.72rem;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
min-width: 1.6rem;
|
|
text-align: left;
|
|
}
|
|
.toggle-on .toggle-state { color: #86efac; }
|
|
.toggle-switch:disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* ── Button widget ─────────────────────────────────────────────────────── */
|
|
|
|
.button-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-sizing: border-box;
|
|
padding: 4px;
|
|
}
|
|
|
|
.button-widget .btn {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #1e3a5f;
|
|
color: #e2e8f0;
|
|
border: 1px solid #2d5a9e;
|
|
border-radius: 6px;
|
|
font-size: 0.9rem;
|
|
font-family: system-ui, sans-serif;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.button-widget .btn:hover {
|
|
background: #2563eb;
|
|
border-color: #3b82f6;
|
|
}
|
|
|
|
.button-widget .btn:active {
|
|
background: #1d4ed8;
|
|
transform: scale(0.97);
|
|
}
|
|
|
|
/* Read-only: user lacks permission to write this signal. */
|
|
.button-widget .btn:disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
}
|
|
.button-widget .btn:disabled:hover {
|
|
background: #1e3a5f;
|
|
border-color: #2d5a9e;
|
|
}
|
|
.button-widget .btn:disabled:active {
|
|
transform: none;
|
|
}
|
|
|
|
/* ── ImageWidget ───────────────────────────────────────────────────────── */
|
|
|
|
.image-widget {
|
|
position: absolute;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 4px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.image-placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
height: 100%;
|
|
color: #475569;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
/* ── LinkWidget ────────────────────────────────────────────────────────── */
|
|
|
|
.link-widget {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.link-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #1e293b;
|
|
color: #60a5fa;
|
|
border: 1px solid #334155;
|
|
border-radius: 6px;
|
|
font-size: 0.85rem;
|
|
font-family: system-ui, sans-serif;
|
|
cursor: pointer;
|
|
padding: 0 10px;
|
|
justify-content: center;
|
|
transition: background 0.15s, border-color 0.15s;
|
|
}
|
|
|
|
.link-btn:hover {
|
|
background: #1e3a5f;
|
|
border-color: #3b82f6;
|
|
color: #93c5fd;
|
|
}
|
|
|
|
.link-icon { font-size: 1rem; flex-shrink: 0; }
|
|
.link-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
/* ── PlotWidget ────────────────────────────────────────────────────────── */
|
|
|
|
.plot-widget {
|
|
position: absolute;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.chart-area {
|
|
overflow: visible;
|
|
}
|
|
|
|
/* ── Plot hover toolbar (pause / window / clear / screenshot) ─────────────── */
|
|
.plot-toolbar {
|
|
position: absolute;
|
|
top: 4px;
|
|
right: 4px;
|
|
z-index: 12;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 3px;
|
|
padding: 2px 3px;
|
|
background: rgba(15, 17, 23, 0.85);
|
|
border: 1px solid #2d3748;
|
|
border-radius: 5px;
|
|
opacity: 0;
|
|
transition: opacity 0.12s;
|
|
pointer-events: none;
|
|
}
|
|
.plot-widget:hover .plot-toolbar { opacity: 1; pointer-events: auto; }
|
|
.plot-tb-btn {
|
|
background: none;
|
|
border: none;
|
|
color: #cbd5e1;
|
|
font-size: 0.8rem;
|
|
line-height: 1;
|
|
padding: 2px 5px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
.plot-tb-btn:hover { background: #2d3748; }
|
|
.plot-tb-active { background: #2563eb; color: #fff; }
|
|
.plot-tb-active:hover { background: #1d4ed8; }
|
|
.plot-tb-select {
|
|
background: #0f1117;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
font-size: 0.72rem;
|
|
padding: 1px 3px;
|
|
cursor: pointer;
|
|
}
|
|
.plot-tb-select:focus { outline: none; border-color: #4a9eff; }
|
|
|
|
/* ── Plot measurement readout (cursor A/B + Δt + per-series Δ) ─────────────── */
|
|
.measure-readout {
|
|
position: absolute;
|
|
top: 30px;
|
|
left: 4px;
|
|
z-index: 12;
|
|
max-width: 70%;
|
|
padding: 4px 6px;
|
|
background: rgba(15, 17, 23, 0.9);
|
|
border: 1px solid #2d3748;
|
|
border-radius: 5px;
|
|
font-size: 0.7rem;
|
|
line-height: 1.35;
|
|
color: #cbd5e1;
|
|
pointer-events: auto;
|
|
}
|
|
.measure-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
justify-content: space-between;
|
|
white-space: nowrap;
|
|
}
|
|
.measure-head {
|
|
font-weight: 600;
|
|
color: #e2e8f0;
|
|
border-bottom: 1px solid #2d3748;
|
|
margin-bottom: 2px;
|
|
padding-bottom: 2px;
|
|
}
|
|
.measure-name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
max-width: 9rem;
|
|
}
|
|
.measure-vals { color: #e2e8f0; }
|
|
.measure-delta { color: #94a3b8; }
|
|
|
|
/* uPlot dark overrides */
|
|
.chart-area .u-wrap { background: transparent; }
|
|
.chart-area .u-legend { color: #94a3b8; font-size: 0.75rem; }
|
|
.chart-area .u-value { color: #e2e8f0; }
|
|
|
|
/* Legend position for the uPlot (timeseries) chart. uPlot always renders its
|
|
legend below the canvas, so to honour "top" we make the chart root a flex
|
|
column and reorder the legend above the plot. ECharts plots position their
|
|
own legend internally (see echartsOption), so these rules don't apply there. */
|
|
.plot-widget.legend-top .chart-area .uplot { display: flex; flex-direction: column; }
|
|
.plot-widget.legend-top .chart-area .u-legend { order: -1; }
|
|
|
|
/* ── Edit Mode layout ──────────────────────────────────────────────────── */
|
|
|
|
.edit-mode-layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
background: #0f1117;
|
|
outline: none;
|
|
}
|
|
|
|
.edit-badge {
|
|
font-size: 0.7rem;
|
|
font-weight: 700;
|
|
background: #7c3aed;
|
|
color: #e9d5ff;
|
|
padding: 0.1rem 0.45rem;
|
|
border-radius: 3px;
|
|
letter-spacing: 0.05em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.iface-name-input {
|
|
background: transparent;
|
|
border: none;
|
|
border-bottom: 1px solid #3d4f6e;
|
|
color: #e2e8f0;
|
|
font-size: 0.9rem;
|
|
padding: 0 4px;
|
|
width: 200px;
|
|
outline: none;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.iface-name-input:focus {
|
|
border-bottom-color: #60a5fa;
|
|
}
|
|
|
|
.dirty-dot {
|
|
color: #f59e0b;
|
|
font-size: 0.9rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.toolbar-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #2d3748;
|
|
border: none;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
line-height: 1.2;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-family: system-ui, sans-serif;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.toolbar-btn:hover { background: #374151; }
|
|
|
|
.toolbar-btn-primary {
|
|
background: #2563eb;
|
|
color: #fff;
|
|
}
|
|
|
|
.toolbar-btn-primary:hover:not(:disabled) { background: #1d4ed8; }
|
|
.toolbar-btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
|
|
.toolbar-btn-active {
|
|
background: #1e40af;
|
|
color: #93c5fd;
|
|
border: 1px solid #3b82f6;
|
|
}
|
|
|
|
/* time-nav styles are in the time-nav-bar section at the bottom of this file */
|
|
|
|
/* Overlay shown inside a plot widget while history is loading or unavailable */
|
|
.hist-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.8rem;
|
|
color: #94a3b8;
|
|
background: rgba(26, 31, 46, 0.75);
|
|
pointer-events: none;
|
|
}
|
|
.hist-overlay-warn { color: #fbbf24; }
|
|
|
|
.edit-body {
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
/* ── Center column tabs (Layout / Logic) ────────────────────────────────── */
|
|
|
|
.edit-center {
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.center-tabs {
|
|
display: flex;
|
|
gap: 0;
|
|
background: #0f1117;
|
|
border-bottom: 1px solid #1e2433;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.center-tab {
|
|
padding: 0.4rem 1rem;
|
|
font-size: 0.8rem;
|
|
color: #94a3b8;
|
|
background: transparent;
|
|
border: none;
|
|
border-right: 1px solid #1e2433;
|
|
border-bottom: 2px solid transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.center-tab:hover { color: #e2e8f0; background: #161b27; }
|
|
|
|
.center-tab-active {
|
|
color: #e2e8f0;
|
|
border-bottom-color: #3b82f6;
|
|
background: #161b27;
|
|
}
|
|
|
|
/* ── Logic flow editor (Node-RED style) ─────────────────────────────────── */
|
|
|
|
.flow-editor {
|
|
flex: 1;
|
|
display: flex;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Palette of node types to add */
|
|
.flow-palette {
|
|
width: 10rem;
|
|
flex: 0 0 auto;
|
|
border-right: 1px solid #1e2433;
|
|
background: #0f1117;
|
|
padding: 0.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.flow-palette-toolbar {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
margin-bottom: 0.15rem;
|
|
}
|
|
.flow-palette-toolbar .toolbar-btn { flex: 1; }
|
|
|
|
.flow-palette-title {
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: #64748b;
|
|
}
|
|
|
|
.flow-palette-btn {
|
|
text-align: left;
|
|
padding: 0.4rem 0.6rem;
|
|
font-size: 0.8rem;
|
|
color: #e2e8f0;
|
|
background: #161b27;
|
|
border: 1px solid #1e2433;
|
|
border-left-width: 3px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.flow-palette-btn:hover { background: #1c2230; }
|
|
.flow-palette-trigger { border-left-color: #f59e0b; }
|
|
.flow-palette-gate { border-left-color: #a855f7; }
|
|
.flow-palette-flow { border-left-color: #10b981; }
|
|
.flow-palette-action { border-left-color: #3b82f6; }
|
|
.flow-palette-hint { margin-top: 0.5rem; font-size: 0.7rem; line-height: 1.4; }
|
|
.flow-palette-hint code { background: #1e2433; padding: 0 0.2em; border-radius: 3px; }
|
|
|
|
/* Scrollable node canvas */
|
|
.flow-canvas {
|
|
flex: 1;
|
|
min-width: 0;
|
|
position: relative;
|
|
overflow: auto;
|
|
background:
|
|
repeating-linear-gradient(0deg, transparent 0 19px, #161b2733 19px 20px),
|
|
repeating-linear-gradient(90deg, transparent 0 19px, #161b2733 19px 20px),
|
|
#0b0e14;
|
|
}
|
|
|
|
.flow-canvas-inner {
|
|
position: relative;
|
|
width: 125rem;
|
|
height: 87.5rem;
|
|
}
|
|
|
|
.flow-wires {
|
|
position: absolute;
|
|
top: 0; left: 0;
|
|
width: 100%; height: 100%;
|
|
pointer-events: none;
|
|
overflow: visible;
|
|
}
|
|
|
|
.flow-wire {
|
|
fill: none;
|
|
stroke: #475569;
|
|
stroke-width: 2;
|
|
pointer-events: stroke;
|
|
cursor: pointer;
|
|
}
|
|
.flow-wire:hover { stroke: #64748b; }
|
|
.flow-wire-selected { stroke: #ef4444; stroke-width: 2.5; }
|
|
.flow-wire-pending { stroke: #3b82f6; stroke-dasharray: 5 4; }
|
|
|
|
/* Synthetic-editor data-type wire colouring (scoped to .synth-graph so the
|
|
Logic / ControlLogic editors that share .flow-wire are unaffected). Scalar
|
|
keeps the default slate; array (waveform) signals are purple. */
|
|
.synth-graph .flow-wire.synth-wire-array { stroke: #a855f7; }
|
|
.synth-graph .flow-wire.synth-wire-array:hover { stroke: #c084fc; }
|
|
|
|
/* Node block */
|
|
.flow-node {
|
|
position: absolute;
|
|
background: #161b27;
|
|
border: 1px solid #1e2433;
|
|
border-radius: 6px;
|
|
box-shadow: 0 2px 6px #0006;
|
|
cursor: move;
|
|
user-select: none;
|
|
}
|
|
.flow-node-trigger { border-top: 3px solid #f59e0b; }
|
|
.flow-node-gate { border-top: 3px solid #a855f7; }
|
|
.flow-node-flow { border-top: 3px solid #10b981; }
|
|
.flow-node-action { border-top: 3px solid #3b82f6; }
|
|
.flow-node-selected { border-color: #3b82f6; box-shadow: 0 0 0 2px #3b82f680; }
|
|
.flow-node-error { border-color: #ef4444; box-shadow: 0 0 0 2px #ef444455; }
|
|
.flow-node-error.flow-node-selected { box-shadow: 0 0 0 2px #ef4444aa; }
|
|
|
|
.flow-node-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.3rem 0.5rem;
|
|
}
|
|
.flow-node-title { font-size: 0.78rem; font-weight: 600; color: #e2e8f0; }
|
|
.flow-node-del {
|
|
background: none; border: none; color: #64748b;
|
|
cursor: pointer; font-size: 0.75rem; line-height: 1; padding: 0;
|
|
}
|
|
.flow-node-del:hover { color: #ef4444; }
|
|
|
|
.flow-node-body {
|
|
padding: 0 0.5rem 0.4rem;
|
|
font-size: 0.7rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Ports — input/output positions are set inline (in rem-scaled px) so they
|
|
stay aligned with the node geometry on any root font size. */
|
|
.flow-port {
|
|
position: absolute;
|
|
width: 0.75rem;
|
|
height: 0.75rem;
|
|
border-radius: 50%;
|
|
background: #0b0e14;
|
|
border: 2px solid #64748b;
|
|
cursor: crosshair;
|
|
}
|
|
.flow-port:hover { border-color: #3b82f6; background: #3b82f6; }
|
|
.flow-port-then { border-color: #10b981; }
|
|
.flow-port-body { border-color: #10b981; }
|
|
.flow-port-else { border-color: #ef4444; }
|
|
|
|
/* Synthetic-editor port data-type colouring (scoped to .synth-graph so the
|
|
Logic / ControlLogic editors that share .flow-port are unaffected). An 'any'
|
|
port (accepts either type) keeps the default slate; scalar is blue, array
|
|
purple — mirroring the wire palette so a port previews what it carries/accepts. */
|
|
.synth-graph .flow-port-type-scalar { border-color: #3b82f6; }
|
|
.synth-graph .flow-port-type-array { border-color: #a855f7; }
|
|
.synth-graph .flow-port-type-any { border-color: #64748b; }
|
|
|
|
.flow-port-label {
|
|
position: absolute;
|
|
right: 10px;
|
|
font-size: 0.6rem;
|
|
color: #64748b;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Named input ports (Formula/Lua) show their variable name beside the port. */
|
|
.flow-port-label-in {
|
|
position: absolute;
|
|
left: 0.55rem;
|
|
font-size: 0.6rem;
|
|
color: #94a3b8;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Named-input editor row in the inspector */
|
|
.synth-var-row {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
align-items: center;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
.synth-var-row > input { flex: 1; min-width: 0; }
|
|
|
|
/* Expression field: signal-insert helper row */
|
|
.flow-expr-insert {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
margin-top: 0.35rem;
|
|
}
|
|
.flow-expr-insert > * { flex: 1; min-width: 0; }
|
|
.prop-input-error { border-color: #ef4444; }
|
|
|
|
/* Inspector */
|
|
.flow-inspector {
|
|
width: 15rem;
|
|
flex: 0 0 auto;
|
|
border-left: 1px solid #1e2433;
|
|
background: #0f1117;
|
|
padding: 0.75rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* Local-variable editor in the palette */
|
|
.flow-localvars {
|
|
margin-top: 0.5rem;
|
|
border-top: 1px solid #1e2433;
|
|
padding-top: 0.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.3rem;
|
|
}
|
|
.flow-localvars-empty { padding: 0; }
|
|
.flow-localvar-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.35rem;
|
|
padding: 0.2rem 0.4rem;
|
|
background: #161b27;
|
|
border: 1px solid #1e2433;
|
|
border-left: 3px solid #14b8a6;
|
|
border-radius: 4px;
|
|
}
|
|
.flow-localvar-name {
|
|
font-size: 0.78rem;
|
|
color: #e2e8f0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.flow-localvar-add { text-align: center; border-left-color: #14b8a6; }
|
|
.flow-localvar-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.3rem;
|
|
}
|
|
.flow-localvar-actions {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
}
|
|
.flow-localvar-actions .panel-btn { flex: 1; }
|
|
|
|
/* Repeated rows in inspector editors (export columns, dialog fields). */
|
|
.flow-row-edit {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
margin-bottom: 0.35rem;
|
|
}
|
|
.flow-row-edit .prop-input { flex: 1; min-width: 0; }
|
|
.flow-row-add {
|
|
width: 100%;
|
|
margin-top: 0.15rem;
|
|
}
|
|
|
|
.flow-field-edit {
|
|
border: 1px solid #2a3548;
|
|
border-radius: 4px;
|
|
padding: 0.4rem;
|
|
margin-bottom: 0.4rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.35rem;
|
|
}
|
|
.flow-field-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
}
|
|
.flow-field-head .prop-input { flex: 1; min-width: 0; }
|
|
.flow-field-kind {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
flex: 0 0 auto;
|
|
}
|
|
.flow-field-add {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
/* ── History pane ───────────────────────────────────────────────────────── */
|
|
|
|
.history-pane {
|
|
width: 280px;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #11151f;
|
|
border-left: 1px solid #1f2733;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.history-pane-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 12px;
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
border-bottom: 1px solid #1f2733;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.history-save-row {
|
|
display: flex;
|
|
gap: 6px;
|
|
padding: 10px 12px;
|
|
border-bottom: 1px solid #1f2733;
|
|
}
|
|
|
|
.history-tag-input {
|
|
flex: 1;
|
|
min-width: 0;
|
|
background: #0a0d14;
|
|
border: 1px solid #2a3543;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
padding: 4px 8px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.history-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 6px;
|
|
}
|
|
|
|
.history-empty {
|
|
padding: 16px 12px;
|
|
color: #64748b;
|
|
font-size: 12px;
|
|
text-align: center;
|
|
}
|
|
|
|
.history-item {
|
|
padding: 8px 10px;
|
|
border: 1px solid #1f2733;
|
|
border-radius: 6px;
|
|
margin-bottom: 6px;
|
|
background: #0e1219;
|
|
}
|
|
|
|
.history-item-current {
|
|
border-color: #2563eb;
|
|
background: #0f1830;
|
|
}
|
|
|
|
.history-item-main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.history-version {
|
|
font-weight: 600;
|
|
font-size: 12px;
|
|
color: #93c5fd;
|
|
}
|
|
|
|
.history-tag {
|
|
font-size: 11px;
|
|
padding: 1px 6px;
|
|
border-radius: 10px;
|
|
background: #1e293b;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.history-current-badge {
|
|
font-size: 10px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
padding: 1px 6px;
|
|
border-radius: 10px;
|
|
background: #2563eb;
|
|
color: #fff;
|
|
}
|
|
|
|
.history-item-meta {
|
|
font-size: 11px;
|
|
color: #64748b;
|
|
margin-top: 3px;
|
|
}
|
|
|
|
.history-item-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.history-action-btn {
|
|
flex: 1 1 auto;
|
|
font-size: 11px;
|
|
padding: 3px 6px;
|
|
background: #1e293b;
|
|
border: 1px solid #2a3543;
|
|
border-radius: 4px;
|
|
color: #cbd5e1;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.history-action-btn:hover {
|
|
background: #2a3543;
|
|
}
|
|
|
|
/* ── Edit Canvas ────────────────────────────────────────────────────────── */
|
|
|
|
.edit-canvas-container {
|
|
flex: 1;
|
|
position: relative;
|
|
overflow: auto;
|
|
background: #0a0d14;
|
|
background-image:
|
|
linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
|
|
background-size: 20px 20px;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Widget overlays */
|
|
.widget-overlay {
|
|
position: absolute;
|
|
box-sizing: border-box;
|
|
cursor: move;
|
|
border: 1px solid transparent;
|
|
transition: border-color 0.1s;
|
|
z-index: 10;
|
|
}
|
|
|
|
.widget-overlay:hover {
|
|
border-color: rgba(96, 165, 250, 0.4);
|
|
}
|
|
|
|
.widget-overlay.selected {
|
|
border: 2px solid #60a5fa;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.overlay-delete {
|
|
position: absolute;
|
|
top: -14px;
|
|
right: -14px;
|
|
width: 18px;
|
|
height: 18px;
|
|
border-radius: 50%;
|
|
background: #ef4444;
|
|
color: #fff;
|
|
border: none;
|
|
font-size: 0.65rem;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
line-height: 1;
|
|
z-index: 30;
|
|
padding: 0;
|
|
}
|
|
|
|
.overlay-delete:hover { background: #dc2626; }
|
|
|
|
/* Resize handles */
|
|
.resize-handle {
|
|
position: absolute;
|
|
width: 8px;
|
|
height: 8px;
|
|
background: #60a5fa;
|
|
border: 1px solid #1e40af;
|
|
border-radius: 1px;
|
|
z-index: 20;
|
|
}
|
|
|
|
.resize-n { top: -4px; left: 50%; transform: translateX(-50%); cursor: n-resize; }
|
|
.resize-s { bottom: -4px; left: 50%; transform: translateX(-50%); cursor: s-resize; }
|
|
.resize-e { right: -4px; top: 50%; transform: translateY(-50%); cursor: e-resize; }
|
|
.resize-w { left: -4px; top: 50%; transform: translateY(-50%); cursor: w-resize; }
|
|
.resize-ne { top: -4px; right: -4px; cursor: ne-resize; }
|
|
.resize-nw { top: -4px; left: -4px; cursor: nw-resize; }
|
|
.resize-se { bottom: -4px; right: -4px; cursor: se-resize; }
|
|
.resize-sw { bottom: -4px; left: -4px; cursor: sw-resize; }
|
|
|
|
/* ── Widget Type Picker ──────────────────────────────────────────────────── */
|
|
|
|
.widget-picker-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 8000;
|
|
}
|
|
|
|
.widget-picker {
|
|
position: fixed;
|
|
background: #1a1f2e;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 8px;
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
|
|
min-width: 220px;
|
|
max-height: 420px;
|
|
overflow-y: auto;
|
|
z-index: 8001;
|
|
}
|
|
|
|
.widget-picker-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
border-bottom: 1px solid #2d3748;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.widget-picker-list { padding: 4px 0; }
|
|
|
|
.widget-picker-item {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.5rem;
|
|
width: 100%;
|
|
background: none;
|
|
border: none;
|
|
color: #e2e8f0;
|
|
padding: 0.4rem 0.75rem;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.widget-picker-item:hover { background: #2d3748; }
|
|
|
|
.wpt-label { font-size: 0.85rem; font-weight: 500; }
|
|
.wpt-desc { font-size: 0.75rem; color: #64748b; }
|
|
|
|
/* ── Signal Tree ─────────────────────────────────────────────────────────── */
|
|
|
|
.signal-tree-panel {
|
|
border-right: 1px solid #2d3748;
|
|
}
|
|
|
|
.signal-tree-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
/* ── Signal tree tab bar ──────────────────────────────────────────────────── */
|
|
|
|
.signal-tree-tabs {
|
|
display: flex;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.stab {
|
|
flex: 1;
|
|
background: none;
|
|
border: none;
|
|
border-bottom: 2px solid transparent;
|
|
color: #64748b;
|
|
cursor: pointer;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
padding: 0.35rem 0;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
transition: color 0.15s, border-color 0.15s;
|
|
}
|
|
.stab:hover { color: #94a3b8; }
|
|
.stab-active { color: #e2e8f0; border-bottom-color: #4a9eff; }
|
|
|
|
/* ── Groups tree ──────────────────────────────────────────────────────────── */
|
|
|
|
.groups-tree {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.groups-toolbar {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
padding: 0.3rem 0.5rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.group-list { overflow-y: auto; flex: 1; padding: 0.25rem 0; }
|
|
|
|
.group-add-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
padding: 0.2rem 0.5rem;
|
|
}
|
|
.group-add-root { padding: 0.25rem 0.5rem; }
|
|
.group-add-input {
|
|
flex: 1;
|
|
background: #0f1117;
|
|
border: 1px solid #4a9eff;
|
|
border-radius: 3px;
|
|
color: #e2e8f0;
|
|
font-size: 0.78rem;
|
|
padding: 2px 6px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.group-folder { margin-bottom: 1px; }
|
|
|
|
.group-folder-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.2rem;
|
|
padding: 0.15rem 0.4rem;
|
|
cursor: default;
|
|
border-radius: 3px;
|
|
font-size: 0.8rem;
|
|
color: #94a3b8;
|
|
min-height: 1.7rem;
|
|
}
|
|
.group-folder-header:hover { background: #1e293b; color: #cbd5e1; }
|
|
.group-folder-header:hover .group-folder-actions { opacity: 1; }
|
|
|
|
.group-folder-arrow { font-size: 0.65rem; flex-shrink: 0; width: 0.9rem; text-align: center; cursor: pointer; }
|
|
.group-folder-name { flex: 1; font-weight: 600; cursor: pointer; user-select: none; }
|
|
.group-folder-count {
|
|
font-size: 0.65rem;
|
|
color: #475569;
|
|
background: #1e293b;
|
|
border-radius: 8px;
|
|
padding: 0 5px;
|
|
min-width: 1.1rem;
|
|
text-align: center;
|
|
}
|
|
.group-folder-actions {
|
|
display: flex;
|
|
gap: 1px;
|
|
opacity: 0;
|
|
transition: opacity 0.15s;
|
|
}
|
|
.group-folder-actions .icon-btn { font-size: 0.65rem; padding: 1px 3px; }
|
|
|
|
.group-rename-input {
|
|
flex: 1;
|
|
background: #0f1117;
|
|
border: 1px solid #4a9eff;
|
|
border-radius: 3px;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
padding: 1px 4px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.group-folder-children {
|
|
padding-left: 1rem;
|
|
border-left: 1px solid #1e293b;
|
|
margin-left: 0.7rem;
|
|
}
|
|
|
|
.group-signal-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
padding: 0.15rem 0.4rem;
|
|
font-size: 0.78rem;
|
|
color: #94a3b8;
|
|
border-radius: 3px;
|
|
cursor: grab;
|
|
min-height: 1.5rem;
|
|
}
|
|
.group-signal-item:hover { background: #1e293b; color: #cbd5e1; }
|
|
.group-signal-item:hover .group-node-remove { opacity: 1; }
|
|
|
|
.group-signal-ds {
|
|
color: #475569;
|
|
font-size: 0.7rem;
|
|
flex-shrink: 0;
|
|
}
|
|
.group-signal-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
.group-node-remove { opacity: 0; transition: opacity 0.15s; margin-left: auto; flex-shrink: 0; }
|
|
|
|
.signal-tree-search {
|
|
padding: 0.4rem 0.5rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.signal-filter {
|
|
width: 100%;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
padding: 0.25rem 0.5rem;
|
|
outline: none;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.signal-filter:focus { border-color: #4a9eff; }
|
|
|
|
.signal-list { overflow-y: auto; flex: 1; }
|
|
|
|
.signal-group { margin-bottom: 2px; }
|
|
|
|
.signal-group-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
padding: 0.3rem 0.5rem;
|
|
cursor: pointer;
|
|
color: #94a3b8;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
user-select: none;
|
|
}
|
|
|
|
.signal-group-header:hover { color: #cbd5e1; }
|
|
|
|
.signal-group-arrow { font-size: 0.7rem; flex-shrink: 0; }
|
|
.signal-group-name { flex: 1; }
|
|
.signal-group-count {
|
|
font-size: 0.7rem;
|
|
background: #2d3748;
|
|
border-radius: 10px;
|
|
padding: 0 5px;
|
|
color: #64748b;
|
|
}
|
|
|
|
.signal-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
padding: 0.25rem 0.5rem 0.25rem 1.25rem;
|
|
cursor: grab;
|
|
border-radius: 3px;
|
|
margin: 1px 4px;
|
|
user-select: none;
|
|
}
|
|
|
|
.signal-item:hover { background: #1e2535; }
|
|
.signal-item:active { cursor: grabbing; }
|
|
|
|
.signal-name { font-size: 0.8rem; color: #cbd5e1; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.signal-unit { font-size: 0.7rem; color: #64748b; flex-shrink: 0; }
|
|
|
|
/* Signal tree toolbar (+ Synthetic, CSV, Refresh) */
|
|
.signal-tree-toolbar {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
padding: 0.3rem 0.5rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* Row containing filter input + CF search button */
|
|
.signal-search-row {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
align-items: center;
|
|
}
|
|
|
|
/* "+" button inside group header */
|
|
.signal-add-btn {
|
|
margin-left: auto;
|
|
font-size: 0.85rem;
|
|
opacity: 0;
|
|
transition: opacity 0.15s;
|
|
}
|
|
.signal-group-header:hover .signal-add-btn { opacity: 1; }
|
|
|
|
/* Inline add-signal row */
|
|
.signal-add-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
padding: 0.2rem 0.5rem 0.2rem 1.5rem;
|
|
}
|
|
.signal-add-input {
|
|
flex: 1;
|
|
font-size: 0.8rem;
|
|
background: #1a2236;
|
|
border: 1px solid #4a5568;
|
|
border-radius: 4px;
|
|
color: #e2e8f0;
|
|
padding: 0.15rem 0.4rem;
|
|
outline: none;
|
|
}
|
|
.signal-add-input:focus { border-color: #63b3ed; }
|
|
|
|
/* Custom (manually added) signal items */
|
|
.signal-custom { opacity: 0.85; }
|
|
.signal-custom .signal-name { font-style: italic; }
|
|
|
|
/* Remove button on custom items */
|
|
.signal-remove-btn {
|
|
margin-left: auto;
|
|
font-size: 0.7rem;
|
|
opacity: 0;
|
|
transition: opacity 0.15s;
|
|
flex-shrink: 0;
|
|
}
|
|
.signal-item:hover .signal-remove-btn { opacity: 1; }
|
|
|
|
/* ── Synthetic Wizard ─────────────────────────────────────────────────────── */
|
|
|
|
.wizard-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,0.6);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 200;
|
|
}
|
|
|
|
.wizard {
|
|
background: #1e2535;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 8px;
|
|
width: min(600px, 92vw);
|
|
min-width: 380px;
|
|
min-height: 440px;
|
|
max-width: 95vw;
|
|
max-height: 92vh;
|
|
resize: both;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
|
}
|
|
|
|
/* Synthetic-signal node editor: a large modal hosting the shared .flow-editor
|
|
layout (palette | canvas | inspector). */
|
|
.synth-graph {
|
|
background: #1e2535;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 8px;
|
|
width: 92vw;
|
|
height: 88vh;
|
|
max-width: 95vw;
|
|
max-height: 92vh;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
|
position: relative;
|
|
}
|
|
|
|
/* Quick-add HUD (S = signal, N = node) */
|
|
.synth-hud-backdrop {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(10, 14, 22, 0.45);
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: center;
|
|
padding-top: 12vh;
|
|
z-index: 20;
|
|
}
|
|
.synth-hud {
|
|
width: 26rem;
|
|
max-width: 80%;
|
|
background: #1a1f2e;
|
|
border: 1px solid #3a4660;
|
|
border-radius: 8px;
|
|
box-shadow: 0 12px 40px rgba(0,0,0,0.55);
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.synth-hud-input {
|
|
border: none;
|
|
border-bottom: 1px solid #2d3748;
|
|
background: #0f1117;
|
|
color: #e2e8f0;
|
|
font-size: 0.9rem;
|
|
padding: 0.6rem 0.75rem;
|
|
outline: none;
|
|
}
|
|
.synth-hud-list {
|
|
max-height: 18rem;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.synth-hud-item {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 0.5rem;
|
|
padding: 0.4rem 0.75rem;
|
|
background: none;
|
|
border: none;
|
|
color: #e2e8f0;
|
|
font-size: 0.85rem;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
.synth-hud-item:hover { background: #243049; }
|
|
.synth-hud-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.synth-hud-item-meta { color: #64748b; font-size: 0.72rem; flex-shrink: 0; }
|
|
.synth-hud-empty { padding: 0.6rem 0.75rem; }
|
|
|
|
.wizard-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.75rem 1rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-weight: 600;
|
|
font-size: 0.95rem;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.wizard-body {
|
|
padding: 1rem;
|
|
overflow-y: auto;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.wizard-footer {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
justify-content: flex-end;
|
|
padding: 0.75rem 1rem;
|
|
border-top: 1px solid #2d3748;
|
|
}
|
|
|
|
.wizard-section-title {
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
color: #64748b;
|
|
letter-spacing: 0.06em;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.wizard-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2rem;
|
|
}
|
|
.wizard-field label {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
/* Side-by-side fields */
|
|
.wizard-field-row {
|
|
flex-direction: row;
|
|
gap: 0.5rem;
|
|
}
|
|
.wizard-field-row > .wizard-field { flex: 1; }
|
|
|
|
.wizard-error {
|
|
color: #fc8181;
|
|
font-size: 0.8rem;
|
|
background: rgba(252,129,129,0.1);
|
|
border: 1px solid #fc8181;
|
|
border-radius: 4px;
|
|
padding: 0.4rem 0.6rem;
|
|
}
|
|
|
|
/* ── Synthetic Editor ────────────────────────────────────────────────────── */
|
|
|
|
/* ── Lua editor ────────────────────────────────────────────────────────────── */
|
|
|
|
.lua-editor {
|
|
position: relative;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
background: #0a0d14;
|
|
font-family: ui-monospace, 'Cascadia Code', 'Fira Code', monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
min-height: 6em;
|
|
}
|
|
|
|
.lua-pre,
|
|
.lua-textarea {
|
|
position: absolute;
|
|
inset: 0;
|
|
margin: 0;
|
|
padding: 6px 8px;
|
|
border: none;
|
|
outline: none;
|
|
overflow: auto;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
tab-size: 2;
|
|
font: inherit;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.lua-pre {
|
|
color: #e2e8f0;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.lua-textarea {
|
|
color: transparent;
|
|
caret-color: #e2e8f0;
|
|
background: transparent;
|
|
resize: none;
|
|
z-index: 1;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.lua-textarea:focus {
|
|
outline: none;
|
|
box-shadow: inset 0 0 0 1px #4a9eff;
|
|
}
|
|
|
|
/* Syntax token colours */
|
|
.lua-kw { color: #c792ea; font-weight: 600; }
|
|
.lua-str { color: #c3e88d; }
|
|
.lua-cmt { color: #546e7a; font-style: italic; }
|
|
.lua-num { color: #f78c6c; }
|
|
|
|
/* ── CUE editor (config rules) ───────────────────────────────────────────────── */
|
|
.cue-editor {
|
|
position: relative;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
background: #0a0d14;
|
|
font-family: ui-monospace, 'Cascadia Code', 'Fira Code', monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
min-height: 6em;
|
|
}
|
|
|
|
.cue-pre,
|
|
.cue-textarea {
|
|
position: absolute;
|
|
inset: 0;
|
|
margin: 0;
|
|
padding: 6px 8px;
|
|
border: none;
|
|
outline: none;
|
|
overflow: auto;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
tab-size: 2;
|
|
font: inherit;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.cue-pre {
|
|
color: #e2e8f0;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cue-textarea {
|
|
color: transparent;
|
|
caret-color: #e2e8f0;
|
|
background: transparent;
|
|
resize: none;
|
|
z-index: 1;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.cue-textarea:focus {
|
|
outline: none;
|
|
box-shadow: inset 0 0 0 1px #4a9eff;
|
|
}
|
|
|
|
.cue-kw { color: #c792ea; font-weight: 600; }
|
|
.cue-type { color: #82aaff; }
|
|
.cue-attr { color: #ffcb6b; }
|
|
.cue-str { color: #c3e88d; }
|
|
.cue-cmt { color: #546e7a; font-style: italic; }
|
|
.cue-num { color: #f78c6c; }
|
|
|
|
.cue-ac {
|
|
position: fixed;
|
|
z-index: 2000;
|
|
margin: 0;
|
|
padding: 2px;
|
|
list-style: none;
|
|
background: #131826;
|
|
border: 1px solid #3d4f6e;
|
|
border-radius: 4px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
|
|
max-height: 14em;
|
|
overflow: auto;
|
|
font-family: ui-monospace, 'Cascadia Code', 'Fira Code', monospace;
|
|
font-size: 12px;
|
|
min-width: 8em;
|
|
}
|
|
|
|
.cue-ac-item {
|
|
padding: 2px 8px;
|
|
border-radius: 3px;
|
|
color: #cdd6e4;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.cue-ac-item.active,
|
|
.cue-ac-item:hover {
|
|
background: #2a4d7a;
|
|
color: #fff;
|
|
}
|
|
|
|
/* ── Config rules ────────────────────────────────────────────────────────────── */
|
|
.cfg-rule-set {
|
|
font-size: 11px;
|
|
opacity: 0.75;
|
|
margin-left: auto;
|
|
margin-right: 6px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
max-width: 9em;
|
|
}
|
|
|
|
.cfg-rule-help {
|
|
margin: 4px 0 6px;
|
|
line-height: 1.5;
|
|
}
|
|
.cfg-rule-help code {
|
|
background: #111726;
|
|
border: 1px solid #2a3550;
|
|
border-radius: 3px;
|
|
padding: 0 3px;
|
|
font-family: ui-monospace, monospace;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.cfg-rule-check {
|
|
margin-top: 8px;
|
|
padding: 6px 10px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
}
|
|
.cfg-rule-check-ok {
|
|
background: #11271a;
|
|
border: 1px solid #2e6b46;
|
|
color: #b6f0c8;
|
|
}
|
|
.cfg-rule-check-err {
|
|
background: #2a1416;
|
|
border: 1px solid #7a3038;
|
|
color: #ffc7cd;
|
|
}
|
|
.cfg-rule-violations {
|
|
margin: 4px 0 0;
|
|
padding-left: 18px;
|
|
}
|
|
.cfg-rule-violations code,
|
|
.cfg-rule-derived code {
|
|
background: rgba(0, 0, 0, 0.3);
|
|
border-radius: 3px;
|
|
padding: 0 3px;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
.cfg-rule-derived {
|
|
display: inline-block;
|
|
margin: 0 4px;
|
|
}
|
|
|
|
/* wizard is already wide enough and resizable — no extra :has() rule needed */
|
|
|
|
/* ── Synthetic pipeline ─────────────────────────────────────────────────────── */
|
|
|
|
.synth-pipeline-node {
|
|
background: #1a2234;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
padding: 0.5rem 0.6rem;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.synth-node-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.synth-node-index {
|
|
font-size: 0.7rem;
|
|
color: #64748b;
|
|
background: #2d3748;
|
|
border-radius: 3px;
|
|
padding: 0.1rem 0.35rem;
|
|
min-width: 1.2rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.synth-node-label {
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
flex: 1;
|
|
}
|
|
|
|
.synth-node-actions {
|
|
display: flex;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
.synth-add-node-row {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
align-items: center;
|
|
margin-top: 0.6rem;
|
|
padding-top: 0.6rem;
|
|
border-top: 1px solid #2d3748;
|
|
}
|
|
.synth-add-node-row .prop-select { flex: 1; }
|
|
|
|
.wizard-field-inline {
|
|
flex-direction: row !important;
|
|
align-items: center;
|
|
gap: 0.5rem !important;
|
|
}
|
|
.wizard-field-inline label {
|
|
min-width: 7rem;
|
|
flex-shrink: 0;
|
|
}
|
|
.wizard-field-inline .prop-input { flex: 1; }
|
|
|
|
/* Edit button on synthetic signal items */
|
|
.signal-edit-btn {
|
|
margin-left: auto;
|
|
font-size: 0.75rem;
|
|
opacity: 0;
|
|
transition: opacity 0.15s;
|
|
flex-shrink: 0;
|
|
}
|
|
.signal-item:hover .signal-edit-btn { opacity: 1; }
|
|
/* When edit button is present, remove-btn should not auto-margin */
|
|
.signal-edit-btn + .signal-remove-btn { margin-left: 0; }
|
|
|
|
/* ── Properties Pane ─────────────────────────────────────────────────────── */
|
|
|
|
.props-panel {
|
|
width: 240px;
|
|
min-width: 240px;
|
|
}
|
|
|
|
.props-body {
|
|
overflow-y: auto;
|
|
flex: 1;
|
|
padding: 0.5rem 0;
|
|
}
|
|
|
|
.props-section {
|
|
padding: 0 0 0.75rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.props-section:last-child { border-bottom: none; }
|
|
|
|
.props-section-title {
|
|
font-size: 0.7rem;
|
|
font-weight: 700;
|
|
color: #64748b;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
padding: 0.4rem 0.6rem 0.3rem;
|
|
}
|
|
|
|
.prop-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
padding: 0.2rem 0.6rem;
|
|
}
|
|
|
|
.prop-label {
|
|
font-size: 0.75rem;
|
|
color: #64748b;
|
|
width: 60px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.prop-input {
|
|
flex: 1;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
padding: 0.15rem 0.35rem;
|
|
outline: none;
|
|
font-family: system-ui, sans-serif;
|
|
min-width: 0;
|
|
}
|
|
|
|
.prop-input:focus { border-color: #4a9eff; }
|
|
|
|
.prop-input-num { width: 70px; flex: none; }
|
|
|
|
/* Column wrapper: input on top, hint below — avoids squeezing input */
|
|
.prop-field-col {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.15rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
.prop-select {
|
|
flex: 1;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
padding: 0.15rem 0.35rem;
|
|
outline: none;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
.prop-sig {
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
font-family: ui-monospace, monospace;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ── InterfaceList item actions ─────────────────────────────────────────── */
|
|
|
|
.iface-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.iface-item-name {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.iface-item-actions {
|
|
display: none;
|
|
gap: 2px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.iface-item:hover .iface-item-actions { display: flex; }
|
|
|
|
.iface-item[draggable="true"] .iface-item-name { cursor: grab; }
|
|
|
|
/* Drag-and-drop reorder / move-to-folder affordances */
|
|
.iface-item.drop-target {
|
|
box-shadow: inset 0 2px 0 0 #3b82f6;
|
|
}
|
|
.iface-folder-header.drop-target,
|
|
.iface-list.drop-target {
|
|
background: rgba(59, 130, 246, 0.15);
|
|
outline: 1px dashed #3b82f6;
|
|
}
|
|
|
|
.iface-delete { color: #ef4444 !important; }
|
|
.iface-delete:hover { background: rgba(239, 68, 68, 0.15) !important; }
|
|
|
|
/* ── Panel sharing / folders (access control) ───────────────────────────── */
|
|
|
|
.iface-badge {
|
|
display: inline-block;
|
|
margin-left: 6px;
|
|
padding: 0 4px;
|
|
font-size: 0.6rem;
|
|
line-height: 1.3;
|
|
color: #94a3b8;
|
|
background: #1e293b;
|
|
border: 1px solid #334155;
|
|
border-radius: 3px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.iface-folder { list-style: none; }
|
|
|
|
.iface-folder-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.iface-folder-name {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
color: #cbd5e1;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.iface-folder:hover .iface-item-actions { display: flex; }
|
|
|
|
.iface-sublist {
|
|
margin-left: 0.75rem;
|
|
border-left: 1px solid #2d3748;
|
|
padding-left: 0.4rem;
|
|
}
|
|
|
|
/* ── Phase 7 additions ───────────────────────────────────────────────────── */
|
|
|
|
/* Rubber-band selection rectangle */
|
|
.rubber-band {
|
|
position: absolute;
|
|
pointer-events: none;
|
|
border: 1px solid #60a5fa;
|
|
background: rgba(96, 165, 250, 0.08);
|
|
z-index: 50;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Edit toolbar tools (center section) */
|
|
.edit-toolbar-tools {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
}
|
|
|
|
.toolbar-sep {
|
|
width: 1px;
|
|
height: 18px;
|
|
background: #2d3748;
|
|
margin: 0 0.1rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.toolbar-btn.icon-only {
|
|
padding: 0.25rem 0.45rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.toolbar-btn:disabled {
|
|
opacity: 0.35;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Snap-to-grid toggle */
|
|
.snap-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
font-size: 0.78rem;
|
|
color: #94a3b8;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.snap-toggle input { cursor: pointer; accent-color: #4a9eff; }
|
|
|
|
/* Insert dropdown */
|
|
.toolbar-dropdown {
|
|
position: relative;
|
|
}
|
|
|
|
.toolbar-dropdown-menu {
|
|
position: absolute;
|
|
top: calc(100% + 4px);
|
|
left: 0;
|
|
z-index: 9000;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
|
min-width: 140px;
|
|
padding: 4px 0;
|
|
}
|
|
|
|
/* Right-aligned variant (toolbar-right dropdowns expand leftward to stay
|
|
on-screen instead of overflowing the viewport edge). */
|
|
.toolbar-dropdown-menu-right { left: auto; right: 0; }
|
|
|
|
/* Align toolbar */
|
|
.align-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
/* ── Help Manual button (📖) in toolbar ─────────────────────────────────── */
|
|
|
|
.help-manual-btn {
|
|
font-size: 1rem;
|
|
line-height: 1;
|
|
padding: 0.15rem 0.35rem;
|
|
opacity: 0.8;
|
|
transition: opacity 0.15s;
|
|
}
|
|
.help-manual-btn:hover { opacity: 1; }
|
|
|
|
/* ── Help Modal ──────────────────────────────────────────────────────────── */
|
|
|
|
.help-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.65);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 500;
|
|
}
|
|
|
|
.help-modal {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 10px;
|
|
width: min(960px, 96vw);
|
|
height: min(720px, 94vh);
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.help-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.75rem 1.25rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.help-title {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.help-close {
|
|
font-size: 1rem;
|
|
color: #64748b;
|
|
}
|
|
.help-close:hover { color: #e2e8f0; }
|
|
|
|
.help-body {
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Sidebar navigation */
|
|
.help-sidebar {
|
|
width: 188px;
|
|
min-width: 188px;
|
|
border-right: 1px solid #2d3748;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0.5rem 0;
|
|
overflow-y: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.help-nav-item {
|
|
display: block;
|
|
width: 100%;
|
|
text-align: left;
|
|
padding: 0.55rem 1.1rem;
|
|
font-size: 0.85rem;
|
|
color: #94a3b8;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
transition: background 0.12s, color 0.12s;
|
|
border-left: 3px solid transparent;
|
|
}
|
|
.help-nav-item:hover { background: #0f1117; color: #cbd5e1; }
|
|
.help-nav-item.active {
|
|
color: #4a9eff;
|
|
background: rgba(74, 158, 255, 0.08);
|
|
border-left-color: #4a9eff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Content area */
|
|
.help-content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 1.5rem 2rem 2rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.65;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.help-h2 {
|
|
font-size: 1.2rem;
|
|
font-weight: 700;
|
|
color: #e2e8f0;
|
|
margin-bottom: 1rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
}
|
|
|
|
.help-h3 {
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: #e2e8f0;
|
|
margin: 1.2rem 0 0.4rem;
|
|
}
|
|
|
|
.help-lead {
|
|
color: #94a3b8;
|
|
margin-bottom: 1rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.help-list {
|
|
padding-left: 1.2rem;
|
|
margin: 0.4rem 0 0.8rem;
|
|
}
|
|
.help-list li { margin-bottom: 0.3rem; }
|
|
|
|
/* SVG diagrams */
|
|
.help-diagram {
|
|
display: block;
|
|
width: 100%;
|
|
max-width: 580px;
|
|
height: auto;
|
|
border-radius: 8px;
|
|
margin: 1rem 0 0.25rem;
|
|
border: 1px solid #2d3748;
|
|
}
|
|
.help-diagram-narrow {
|
|
max-width: 280px;
|
|
}
|
|
|
|
.help-caption {
|
|
font-size: 0.75rem;
|
|
color: #64748b;
|
|
margin-bottom: 1rem;
|
|
font-style: italic;
|
|
}
|
|
|
|
.help-callout {
|
|
border-left: 3px solid #2563eb;
|
|
background: #1a2236;
|
|
padding: 0.6rem 0.85rem;
|
|
margin: 0.85rem 0;
|
|
border-radius: 4px;
|
|
font-size: 0.85rem;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
/* Getting started cards */
|
|
.help-cards {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
margin: 0.75rem 0 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.help-card {
|
|
flex: 1;
|
|
min-width: 180px;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
padding: 0.75rem 1rem;
|
|
}
|
|
|
|
.help-card-title {
|
|
font-weight: 600;
|
|
color: #e2e8f0;
|
|
margin-bottom: 0.35rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Widget reference table */
|
|
.help-widget-table {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0;
|
|
margin: 0.75rem 0;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.help-widget-row {
|
|
display: flex;
|
|
gap: 1rem;
|
|
padding: 0.45rem 0.75rem;
|
|
border-bottom: 1px solid #1e2535;
|
|
}
|
|
.help-widget-row:last-child { border-bottom: none; }
|
|
.help-widget-row:nth-child(odd) { background: #0f1117; }
|
|
|
|
.help-widget-name {
|
|
font-weight: 600;
|
|
color: #4a9eff;
|
|
min-width: 120px;
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.help-widget-desc {
|
|
color: #94a3b8;
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
/* Two-column layout for signals section */
|
|
.help-two-col {
|
|
display: flex;
|
|
gap: 1.5rem;
|
|
align-items: flex-start;
|
|
}
|
|
.help-two-col > div:first-child { flex: 1; }
|
|
|
|
/* Shortcut table */
|
|
.help-shortcut-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 0.75rem 0;
|
|
font-size: 0.83rem;
|
|
}
|
|
|
|
.help-shortcut-table th {
|
|
text-align: left;
|
|
padding: 0.4rem 0.75rem;
|
|
background: #0f1117;
|
|
color: #64748b;
|
|
font-weight: 600;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.help-shortcut-table td {
|
|
padding: 0.4rem 0.75rem;
|
|
border-bottom: 1px solid #1e2535;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.help-shortcut-table tr:last-child td { border-bottom: none; }
|
|
.help-shortcut-table tr:nth-child(odd) td { background: rgba(15, 17, 23, 0.5); }
|
|
|
|
.help-kbd {
|
|
display: inline-block;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 4px;
|
|
padding: 0.1rem 0.4rem;
|
|
font-family: monospace;
|
|
font-size: 0.8rem;
|
|
color: #e2e8f0;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Inline code */
|
|
.help-content code {
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
padding: 0.1rem 0.35rem;
|
|
font-size: 0.82rem;
|
|
font-family: monospace;
|
|
color: #4a9eff;
|
|
}
|
|
|
|
/* Config block */
|
|
.help-pre {
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
padding: 0.75rem 1rem;
|
|
font-family: monospace;
|
|
font-size: 0.8rem;
|
|
color: #94a3b8;
|
|
white-space: pre-wrap;
|
|
margin: 0.75rem 0;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* kbd element in content */
|
|
kbd {
|
|
display: inline-block;
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
padding: 0 0.35rem;
|
|
font-size: 0.8rem;
|
|
font-family: monospace;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
/* ── Manual: Quick Tips list ─────────────────────────────────────────────── */
|
|
|
|
.help-tips-list {
|
|
list-style: none;
|
|
margin: 0 0 1rem;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
}
|
|
|
|
.help-tip-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
width: 100%;
|
|
text-align: left;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
padding: 0.55rem 0.7rem;
|
|
color: #cbd5e1;
|
|
font-size: 0.85rem;
|
|
line-height: 1.45;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s, background 0.15s;
|
|
}
|
|
.help-tip-item:hover {
|
|
border-color: #4a9eff;
|
|
background: #1e2540;
|
|
}
|
|
|
|
.help-tip-icon {
|
|
flex-shrink: 0;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.help-tip-text { flex: 1; }
|
|
|
|
.help-tip-go {
|
|
flex-shrink: 0;
|
|
color: #4a9eff;
|
|
font-weight: 700;
|
|
}
|
|
|
|
|
|
/* ── Historical time-nav bar (below main toolbar, hidden by default) ──────── */
|
|
|
|
.time-nav-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.35rem 1rem;
|
|
background: #161b27;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.time-input {
|
|
font-size: 0.75rem;
|
|
background: #1a2236;
|
|
border: 1px solid #2d3748;
|
|
color: #e2e8f0;
|
|
border-radius: 4px;
|
|
padding: 0.25rem 0.4rem;
|
|
cursor: pointer;
|
|
height: 28px;
|
|
box-sizing: border-box;
|
|
}
|
|
.time-input:focus { outline: none; border-color: #63b3ed; }
|
|
.time-input::-webkit-calendar-picker-indicator { filter: invert(0.8); }
|
|
|
|
.time-sep {
|
|
color: #475569;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
/* ── Fullscreen mode ──────────────────────────────────────────────────────── */
|
|
|
|
.fs-view {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
overflow: auto;
|
|
background: #0f1117;
|
|
display: flex;
|
|
}
|
|
|
|
.fs-error {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #f87171;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
/* ── Signal drop menu (drop onto existing widget) ─────────────────────────── */
|
|
|
|
.signal-drop-backdrop {
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 9500;
|
|
}
|
|
|
|
.signal-drop-menu {
|
|
position: fixed;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.6);
|
|
min-width: 220px;
|
|
z-index: 9600;
|
|
overflow: hidden;
|
|
transform: translateY(4px);
|
|
}
|
|
|
|
.signal-drop-header {
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.75rem;
|
|
color: #64748b;
|
|
border-bottom: 1px solid #2d3748;
|
|
}
|
|
|
|
.signal-drop-header strong {
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.ctx-cancel {
|
|
color: #6b7280;
|
|
border-top: 1px solid #2d3748;
|
|
}
|
|
|
|
/* ── Button widget: pressed / mode hint ──────────────────────────────────── */
|
|
|
|
.btn-pressed {
|
|
background: #1e40af !important;
|
|
border-color: #3b82f6 !important;
|
|
color: #93c5fd !important;
|
|
}
|
|
|
|
.btn-mode-hint {
|
|
font-size: 0.65rem;
|
|
opacity: 0.7;
|
|
margin-left: 0.35rem;
|
|
}
|
|
|
|
/* ── PropertiesPane: signals list + hint text ─────────────────────────────── */
|
|
|
|
.prop-signals-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2rem;
|
|
width: 100%;
|
|
}
|
|
|
|
.prop-signal-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.prop-sig-remove {
|
|
font-size: 0.65rem;
|
|
opacity: 0.6;
|
|
flex-shrink: 0;
|
|
}
|
|
.prop-sig-remove:hover { opacity: 1; color: #f87171; }
|
|
|
|
.prop-hint {
|
|
display: block;
|
|
font-size: 0.65rem;
|
|
color: #475569;
|
|
margin-top: 0.15rem;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
/* ── View tabs ─────────────────────────────────────────────────────────── */
|
|
|
|
.view-content-area {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* ── InfoPanel ─────────────────────────────────────────────────────────── */
|
|
|
|
.info-panel {
|
|
position: fixed;
|
|
top: 60px;
|
|
right: 16px;
|
|
z-index: 8000;
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 8px;
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
|
|
min-width: 260px;
|
|
max-width: 340px;
|
|
max-height: calc(100vh - 80px);
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-family: system-ui, sans-serif;
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.info-panel-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0.75rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.info-panel-title {
|
|
font-weight: 600;
|
|
color: #e2e8f0;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.info-panel-close {
|
|
background: none;
|
|
border: none;
|
|
color: #64748b;
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
padding: 0.1rem 0.3rem;
|
|
border-radius: 3px;
|
|
}
|
|
.info-panel-close:hover { background: #2d3748; color: #e2e8f0; }
|
|
|
|
.info-panel-body {
|
|
overflow-y: auto;
|
|
padding: 0.5rem 0;
|
|
}
|
|
|
|
.info-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.info-key {
|
|
padding: 0.2rem 0.75rem;
|
|
color: #64748b;
|
|
font-size: 0.75rem;
|
|
white-space: nowrap;
|
|
vertical-align: top;
|
|
width: 36%;
|
|
}
|
|
|
|
.info-val {
|
|
padding: 0.2rem 0.75rem 0.2rem 0;
|
|
color: #cbd5e1;
|
|
font-size: 0.8rem;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.info-mono {
|
|
font-family: ui-monospace, monospace;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.info-sep {
|
|
height: 1px;
|
|
background: #1e293b;
|
|
margin: 0.4rem 0;
|
|
}
|
|
|
|
.info-section-hdr {
|
|
padding: 0.2rem 0.75rem;
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
color: #475569;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.info-desc {
|
|
padding: 0.25rem 0.75rem;
|
|
color: #94a3b8;
|
|
font-size: 0.78rem;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* ── Zoom control ─────────────────────────────────────────────────────────── */
|
|
|
|
.zoom-control {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 2px;
|
|
}
|
|
|
|
.zoom-btn {
|
|
background: #1e293b;
|
|
border: 1px solid #2d3748;
|
|
color: #94a3b8;
|
|
cursor: pointer;
|
|
font-size: 0.75rem;
|
|
padding: 2px 7px;
|
|
border-radius: 4px;
|
|
line-height: 1.4;
|
|
}
|
|
.zoom-btn:hover { color: #e2e8f0; border-color: #475569; background: #273244; }
|
|
|
|
.zoom-pct {
|
|
font-size: 0.72rem;
|
|
color: #64748b;
|
|
width: 2.8rem;
|
|
text-align: center;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* ── Searchable Select ────────────────────────────────────────────────────── */
|
|
|
|
.search-select {
|
|
position: relative;
|
|
width: 100%;
|
|
}
|
|
|
|
.search-select-trigger {
|
|
background: #0f1117;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
padding: 0.15rem 0.35rem;
|
|
font-size: 0.8rem;
|
|
color: #e2e8f0;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
min-height: 1.5rem;
|
|
}
|
|
|
|
.search-select-trigger:hover {
|
|
border-color: #4a5568;
|
|
}
|
|
|
|
.search-select-arrow {
|
|
font-size: 0.6rem;
|
|
color: #64748b;
|
|
margin-left: 0.25rem;
|
|
}
|
|
|
|
/* Muted placeholder text inside the trigger. Unlike .hint it adds no padding,
|
|
so an empty select is exactly as tall as one showing a selected value. */
|
|
.search-select-placeholder {
|
|
color: #475569;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.search-select-dropdown {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
right: 0;
|
|
background: #1a1f2e;
|
|
border: 1px solid #4a9eff;
|
|
border-radius: 4px;
|
|
margin-top: 2px;
|
|
z-index: 1000;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.5);
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0.25rem;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.search-select-list {
|
|
max-height: 180px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.search-select-item {
|
|
padding: 0.2rem 0.4rem;
|
|
font-size: 0.75rem;
|
|
color: #cbd5e1;
|
|
cursor: pointer;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.search-select-item:hover {
|
|
background: #2d3748;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.search-select-item-selected {
|
|
background: rgba(74, 158, 255, 0.15);
|
|
color: #4a9eff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.search-select-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 999;
|
|
}
|
|
|
|
/* ── Signal Tree Refinements ────────────────────────────────────────────── */
|
|
|
|
.signal-tree-toolbar select.prop-select {
|
|
border-color: #2d3748;
|
|
background-color: #0f1117;
|
|
color: #94a3b8;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.signal-tree-toolbar select.prop-select:hover {
|
|
border-color: #4a5568;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.signal-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.2rem 0.5rem;
|
|
font-size: 0.8rem;
|
|
color: #cbd5e1;
|
|
border-radius: 4px;
|
|
cursor: grab;
|
|
gap: 0.4rem;
|
|
}
|
|
|
|
.signal-item:hover {
|
|
background: #2d3748;
|
|
}
|
|
|
|
.signal-name {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.signal-unit {
|
|
font-size: 0.7rem;
|
|
color: #64748b;
|
|
background: #1a1f2e;
|
|
padding: 0 4px;
|
|
border-radius: 3px;
|
|
border: 1px solid #2d3748;
|
|
}
|
|
|
|
.panel-btn.icon-only {
|
|
padding: 0 0.35rem;
|
|
min-width: 1.6rem;
|
|
width: auto;
|
|
height: 1.6rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.app-root {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.view-panel-container {
|
|
display: none;
|
|
flex: 1;
|
|
min-height: 0;
|
|
position: relative;
|
|
}
|
|
|
|
.view-panel-container.active {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* ── Plot panels (split layout) ─────────────────────────────────────────── */
|
|
|
|
/* Edit surface: fills the editor body flex slot. */
|
|
.plot-panel-edit {
|
|
flex: 1;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
position: relative;
|
|
overflow: hidden;
|
|
display: flex;
|
|
background: #0a0d14;
|
|
}
|
|
|
|
/* View/fullscreen surface: fills the (relative) canvas container. */
|
|
.plot-panel-view {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
}
|
|
|
|
.split-root {
|
|
flex: 1;
|
|
display: flex;
|
|
width: 100%;
|
|
height: 100%;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
|
|
.split-row { display: flex; flex-direction: row; flex: 1; min-width: 0; min-height: 0; }
|
|
.split-col { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }
|
|
|
|
.split-child {
|
|
display: flex;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.split-leaf {
|
|
flex: 1;
|
|
display: flex;
|
|
position: relative;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
|
|
.split-divider {
|
|
flex: 0 0 auto;
|
|
background: #1e293b;
|
|
transition: background 0.12s;
|
|
}
|
|
.split-divider-h { width: 6px; cursor: col-resize; }
|
|
.split-divider-v { height: 6px; cursor: row-resize; }
|
|
.split-divider:hover { background: #4a9eff; }
|
|
.split-divider-static { pointer-events: none; }
|
|
|
|
/* Neutralize the free-form absolute positioning of plot widgets so they fill
|
|
their split pane responsively (the chart uses a ResizeObserver). */
|
|
.split-leaf .plot-widget {
|
|
position: relative !important;
|
|
left: auto !important;
|
|
top: auto !important;
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
border-radius: 0;
|
|
}
|
|
.split-leaf .chart-area {
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
}
|
|
|
|
/* Editable pane chrome. */
|
|
.plot-pane {
|
|
position: relative;
|
|
flex: 1;
|
|
display: flex;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
background: #0f1117;
|
|
outline: 1px solid transparent;
|
|
}
|
|
/* Dim panes that are not the one currently being edited. */
|
|
.plot-panel-edit .plot-pane:not(.plot-pane-selected)::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(10, 14, 22, 0.45);
|
|
z-index: 4;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.plot-pane-selected {
|
|
outline: 3px solid #4a9eff;
|
|
outline-offset: -3px;
|
|
box-shadow: inset 0 0 0 1px rgba(74, 158, 255, 0.6),
|
|
inset 0 0 18px rgba(74, 158, 255, 0.35);
|
|
}
|
|
|
|
.plot-pane-badge {
|
|
position: absolute;
|
|
top: 4px;
|
|
left: 4px;
|
|
z-index: 6;
|
|
padding: 1px 7px;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.04em;
|
|
text-transform: uppercase;
|
|
color: #0b1018;
|
|
background: #4a9eff;
|
|
border-radius: 3px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.plot-pane-empty,
|
|
.plot-pane-hint {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: #475569;
|
|
font-size: 0.82rem;
|
|
text-align: center;
|
|
padding: 1rem;
|
|
pointer-events: none;
|
|
}
|
|
.plot-pane-hint { top: auto; bottom: 0.6rem; transform: translateX(-50%); }
|
|
|
|
.plot-pane-overlay {
|
|
position: absolute;
|
|
top: 4px;
|
|
right: 4px;
|
|
display: flex;
|
|
gap: 2px;
|
|
z-index: 5;
|
|
opacity: 0;
|
|
transition: opacity 0.12s;
|
|
}
|
|
.plot-pane:hover .plot-pane-overlay,
|
|
.plot-pane-selected .plot-pane-overlay {
|
|
opacity: 1;
|
|
}
|
|
|
|
.plot-pane-btn {
|
|
background: #1e293b;
|
|
border: 1px solid #2d3748;
|
|
color: #94a3b8;
|
|
cursor: pointer;
|
|
font-size: 0.8rem;
|
|
line-height: 1;
|
|
padding: 3px 6px;
|
|
border-radius: 3px;
|
|
}
|
|
.plot-pane-btn:hover { color: #e2e8f0; border-color: #4a9eff; }
|
|
.plot-pane-btn:disabled { opacity: 0.35; cursor: default; }
|
|
|
|
/* ── Control logic editor (server-side flows) ──────────────────────────────── */
|
|
.cl-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.65);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 600;
|
|
}
|
|
|
|
.cl-modal {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 10px;
|
|
width: min(1200px, 97vw);
|
|
height: min(820px, 95vh);
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cl-modal-full {
|
|
width: 98vw;
|
|
height: 96vh;
|
|
max-width: none;
|
|
max-height: none;
|
|
}
|
|
|
|
.cl-confirm-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.55);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 650;
|
|
}
|
|
|
|
.cl-confirm {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 10px;
|
|
padding: 1.25rem 1.5rem;
|
|
width: min(440px, 92vw);
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
}
|
|
|
|
.cl-confirm-title {
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.cl-confirm-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
margin-top: 1.25rem;
|
|
}
|
|
|
|
.cl-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.75rem 1.25rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── Audit log viewer ──────────────────────────────────────────────────── */
|
|
.audit-modal {
|
|
width: min(1300px, 98vw);
|
|
}
|
|
|
|
.audit-filters {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
padding: 0.6rem 1.25rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.audit-filter {
|
|
background: #0f1420;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 5px;
|
|
color: #e2e8f0;
|
|
padding: 0.3rem 0.5rem;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.audit-filter-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.audit-body {
|
|
flex: 1;
|
|
overflow: auto;
|
|
padding: 0 0 0.5rem;
|
|
}
|
|
|
|
.audit-empty {
|
|
padding: 1.5rem 1.25rem;
|
|
}
|
|
|
|
.audit-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.audit-table th,
|
|
.audit-table td {
|
|
text-align: left;
|
|
padding: 0.35rem 0.6rem;
|
|
border-bottom: 1px solid #232b3a;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.audit-table th {
|
|
position: sticky;
|
|
top: 0;
|
|
background: #161c2a;
|
|
color: #94a3b8;
|
|
font-weight: 600;
|
|
z-index: 1;
|
|
}
|
|
|
|
.audit-table tbody tr:hover {
|
|
background: #1d2433;
|
|
}
|
|
|
|
.audit-row-error td {
|
|
background: rgba(220, 38, 38, 0.08);
|
|
}
|
|
|
|
.audit-time {
|
|
color: #94a3b8;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.audit-signal,
|
|
.audit-detail {
|
|
max-width: 18rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.audit-value {
|
|
max-width: 10rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
|
|
.audit-actor-tag {
|
|
display: inline-block;
|
|
font-size: 0.65rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
padding: 0.05rem 0.35rem;
|
|
border-radius: 3px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.audit-actor-user {
|
|
background: #1e3a5f;
|
|
color: #93c5fd;
|
|
}
|
|
|
|
.audit-actor-system {
|
|
background: #4a2d6b;
|
|
color: #d8b4fe;
|
|
}
|
|
|
|
.audit-result-ok {
|
|
color: #4ade80;
|
|
}
|
|
|
|
.audit-result-err {
|
|
color: #f87171;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.cl-title {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.cl-subtitle { font-size: 0.8rem; }
|
|
|
|
.cl-header-actions {
|
|
margin-left: auto;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.cl-dirty {
|
|
font-size: 0.75rem;
|
|
color: #fbbf24;
|
|
}
|
|
|
|
.cl-error {
|
|
padding: 0.5rem 1.25rem;
|
|
background: #3b1d1d;
|
|
color: #fca5a5;
|
|
font-size: 0.82rem;
|
|
border-bottom: 1px solid #5b2a2a;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.cl-body {
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cl-list {
|
|
width: 230px;
|
|
min-width: 230px;
|
|
border-right: 1px solid #2d3748;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow-y: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.cl-list-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0.75rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.cl-list-empty { padding: 0.75rem; font-size: 0.8rem; }
|
|
|
|
.cl-list-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.45rem 0.75rem;
|
|
cursor: pointer;
|
|
border-bottom: 1px solid #232a3a;
|
|
}
|
|
.cl-list-item:hover { background: #232a3a; }
|
|
.cl-list-item-active { background: #2a3450; }
|
|
|
|
.cl-status-dot {
|
|
width: 9px;
|
|
height: 9px;
|
|
border-radius: 50%;
|
|
background: #475569;
|
|
flex-shrink: 0;
|
|
}
|
|
.cl-status-on { background: #34d399; box-shadow: 0 0 5px #34d399; }
|
|
|
|
.cl-list-name {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
color: #e2e8f0;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.cl-mini-btn {
|
|
color: #64748b;
|
|
font-size: 0.8rem;
|
|
padding: 1px 4px;
|
|
border-radius: 3px;
|
|
flex-shrink: 0;
|
|
}
|
|
.cl-mini-btn:hover { color: #e2e8f0; background: #1a1f2e; }
|
|
|
|
.cl-editor-wrap {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cl-empty {
|
|
padding: 1.5rem;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.cl-graph-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.6rem 0.9rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.cl-name-input { width: 240px; }
|
|
|
|
.cfg-desc {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
resize: vertical;
|
|
min-height: 2.4rem;
|
|
max-height: 6.5rem;
|
|
font-family: inherit;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.cl-enable {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
color: #cbd5e1;
|
|
font-size: 0.85rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ── Logic dialogs (action.dialog.* user interaction) ──────────────────────── */
|
|
.logic-dialog-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 700;
|
|
}
|
|
|
|
.logic-dialog {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-top: 3px solid #4a9eff;
|
|
border-radius: 8px;
|
|
min-width: 320px;
|
|
max-width: 460px;
|
|
padding: 1rem 1.25rem 0.9rem;
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
}
|
|
.logic-dialog-error { border-top-color: #ef4444; }
|
|
.logic-dialog-setpoint { border-top-color: #34d399; }
|
|
|
|
.logic-dialog-header {
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
color: #e2e8f0;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.logic-dialog-error .logic-dialog-header { color: #fca5a5; }
|
|
|
|
.logic-dialog-message {
|
|
color: #cbd5e1;
|
|
font-size: 0.85rem;
|
|
line-height: 1.4;
|
|
white-space: pre-wrap;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.logic-dialog-input {
|
|
width: 100%;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* A single field row (input or display) in a multi-value dialog. */
|
|
.logic-dialog-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2rem;
|
|
margin-bottom: 0.6rem;
|
|
}
|
|
.logic-dialog-label {
|
|
font-size: 0.8rem;
|
|
color: #94a3b8;
|
|
}
|
|
.logic-dialog-value {
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: #e2e8f0;
|
|
padding: 0.2rem 0;
|
|
}
|
|
|
|
.logic-dialog-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
}
|
|
.logic-dialog-actions .panel-btn { flex: 0 0 auto; min-width: 5rem; }
|
|
|
|
.panel-btn-primary {
|
|
background: #2563eb;
|
|
}
|
|
.panel-btn-primary:hover { background: #3b82f6; }
|
|
|
|
/* ── Configuration manager ─────────────────────────────────────────────── */
|
|
.cfg-tabs {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
margin-left: 0.5rem;
|
|
}
|
|
.cfg-tab {
|
|
background: transparent;
|
|
border: 1px solid transparent;
|
|
color: #94a3b8;
|
|
font-size: 0.82rem;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
}
|
|
.cfg-tab:hover { color: #e2e8f0; background: #232a3a; }
|
|
.cfg-tab-active {
|
|
color: #e2e8f0;
|
|
background: #2d3748;
|
|
border-color: #3d4a63;
|
|
}
|
|
.cfg-badge {
|
|
display: inline-block;
|
|
min-width: 1.1rem;
|
|
text-align: center;
|
|
font-size: 0.7rem;
|
|
color: #94a3b8;
|
|
background: #232a3a;
|
|
border-radius: 8px;
|
|
padding: 0 0.35rem;
|
|
margin-left: 0.4rem;
|
|
}
|
|
|
|
.cfg-editor {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.6rem;
|
|
padding: 0.75rem 1rem;
|
|
overflow-y: auto;
|
|
height: 100%;
|
|
}
|
|
.cfg-edit-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
.cfg-edit-bar .panel-btn { flex: 0 0 auto; }
|
|
|
|
.cfg-section-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-top: 0.5rem;
|
|
padding-bottom: 0.25rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-size: 0.82rem;
|
|
font-weight: 600;
|
|
color: #cbd5e1;
|
|
}
|
|
.cfg-section-head .panel-btn { flex: 0 0 auto; }
|
|
|
|
.cfg-params {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
.cfg-param {
|
|
background: #151a26;
|
|
border: 1px solid #232a3a;
|
|
border-radius: 6px;
|
|
padding: 0.5rem;
|
|
position: relative;
|
|
}
|
|
.cfg-param-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
align-items: flex-end;
|
|
}
|
|
.cfg-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.15rem;
|
|
min-width: 0;
|
|
}
|
|
.cfg-field > label {
|
|
font-size: 0.68rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
color: #64748b;
|
|
}
|
|
.cfg-field-key { width: 8rem; }
|
|
.cfg-field-label { flex: 1; min-width: 8rem; }
|
|
.cfg-field-type { width: 7rem; }
|
|
.cfg-field-target { flex: 2; min-width: 12rem; }
|
|
.cfg-field-default { width: 8rem; }
|
|
.cfg-field-enum { flex: 1; min-width: 10rem; }
|
|
.cfg-field-num { width: 6rem; }
|
|
|
|
.cfg-mandatory {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
font-size: 0.75rem;
|
|
color: #94a3b8;
|
|
white-space: nowrap;
|
|
padding-bottom: 0.25rem;
|
|
}
|
|
.cfg-param-del {
|
|
background: transparent;
|
|
border: none;
|
|
color: #64748b;
|
|
cursor: pointer;
|
|
font-size: 1rem;
|
|
padding: 0 0.25rem;
|
|
}
|
|
.cfg-param-del:hover { color: #f87171; }
|
|
|
|
.cfg-unit {
|
|
font-size: 0.72rem;
|
|
color: #64748b;
|
|
margin-left: 0.25rem;
|
|
}
|
|
|
|
.cfg-list-actions {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
/* Type is auto-derived from the bound signal — shown read-only. */
|
|
.cfg-type-ro {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 1.9rem;
|
|
padding: 0 0.5rem;
|
|
border: 1px dashed #2d3748;
|
|
border-radius: 4px;
|
|
background: #11151f;
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ── Parameter tree (group / subgroup organiser) ─────────────────────────── */
|
|
.cfg-tree {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
}
|
|
.cfg-tree-toolbar {
|
|
display: flex;
|
|
gap: 0.4rem;
|
|
}
|
|
.cfg-tree-group {
|
|
border: 1px solid #232a3a;
|
|
border-radius: 6px;
|
|
background: #12161f;
|
|
}
|
|
.cfg-tree-ghead {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.3rem 0.5rem;
|
|
background: #1a2030;
|
|
border-bottom: 1px solid #232a3a;
|
|
border-radius: 6px 6px 0 0;
|
|
}
|
|
.cfg-tree-glabel {
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
flex: 1;
|
|
}
|
|
.cfg-tree-name {
|
|
flex: 1;
|
|
min-width: 0;
|
|
font-weight: 600;
|
|
}
|
|
.cfg-tree-ghead-actions {
|
|
display: flex;
|
|
gap: 0.3rem;
|
|
flex: 0 0 auto;
|
|
}
|
|
.cfg-tree-sub {
|
|
margin: 0.3rem 0 0.3rem 0.75rem;
|
|
border-left: 2px solid #232a3a;
|
|
}
|
|
.cfg-tree-shead {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
padding: 0.25rem 0.5rem;
|
|
}
|
|
.cfg-tree-sicon { color: #475569; }
|
|
.cfg-tree-items {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.3rem;
|
|
padding: 0.3rem 0.5rem 0.4rem;
|
|
}
|
|
.cfg-tree-param {
|
|
border: 1px solid #232a3a;
|
|
border-radius: 5px;
|
|
background: #151a26;
|
|
}
|
|
.cfg-tree-param.dragging { opacity: 0.45; }
|
|
.cfg-tree-param.drop-over { border-top: 2px solid #8b5cf6; }
|
|
.cfg-tree-ghead.drop-over,
|
|
.cfg-tree-shead.drop-over { outline: 2px dashed #8b5cf6; outline-offset: -2px; }
|
|
.cfg-tree-phead {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
padding: 0.35rem 0.5rem;
|
|
cursor: grab;
|
|
}
|
|
.cfg-tree-phead:active { cursor: grabbing; }
|
|
.cfg-drag-handle {
|
|
color: #475569;
|
|
cursor: grab;
|
|
font-size: 0.9rem;
|
|
user-select: none;
|
|
}
|
|
.cfg-tree-toggle {
|
|
background: transparent;
|
|
border: none;
|
|
color: #94a3b8;
|
|
cursor: pointer;
|
|
font-size: 0.8rem;
|
|
padding: 0 0.15rem;
|
|
}
|
|
.cfg-tree-pkey {
|
|
font-family: var(--mono, monospace);
|
|
font-size: 0.8rem;
|
|
color: #e2e8f0;
|
|
}
|
|
.cfg-tree-plabel { font-size: 0.78rem; color: #94a3b8; }
|
|
.cfg-tree-ptype {
|
|
font-size: 0.68rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
color: #818cf8;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 3px;
|
|
padding: 0 0.3rem;
|
|
}
|
|
.cfg-tree-psig { margin-left: auto; font-size: 0.72rem; }
|
|
|
|
/* ── Instance values ───────────────────────────────────────────────────── */
|
|
.cfg-values {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.35rem;
|
|
}
|
|
.cfg-value-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
padding: 0.3rem 0.4rem;
|
|
border-radius: 5px;
|
|
}
|
|
.cfg-value-row:hover { background: #151a26; }
|
|
.cfg-value-label {
|
|
width: 14rem;
|
|
flex: 0 0 auto;
|
|
font-size: 0.82rem;
|
|
color: #cbd5e1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.cfg-req { color: #f87171; margin-left: 0.15rem; }
|
|
.cfg-value-input { width: 10rem; flex: 0 0 auto; }
|
|
/* Constrain the editing control to its column so it can't overflow and cover
|
|
the adjacent signal-name label. */
|
|
.cfg-value-input .prop-input,
|
|
.cfg-value-input .prop-select { width: 100%; box-sizing: border-box; }
|
|
.cfg-value-target {
|
|
flex: 0 1 auto;
|
|
min-width: 0;
|
|
font-size: 0.72rem;
|
|
color: #64748b;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ── Apply result ──────────────────────────────────────────────────────── */
|
|
.cfg-apply-result {
|
|
border: 1px solid #232a3a;
|
|
border-radius: 6px;
|
|
margin-top: 0.5rem;
|
|
overflow: hidden;
|
|
}
|
|
.cfg-apply-head {
|
|
display: flex;
|
|
gap: 1rem;
|
|
padding: 0.4rem 0.6rem;
|
|
background: #151a26;
|
|
font-size: 0.8rem;
|
|
color: #cbd5e1;
|
|
}
|
|
.cfg-apply-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.78rem;
|
|
}
|
|
.cfg-apply-table th,
|
|
.cfg-apply-table td {
|
|
text-align: left;
|
|
padding: 0.25rem 0.6rem;
|
|
border-top: 1px solid #1e2433;
|
|
}
|
|
.cfg-apply-table th { color: #64748b; font-weight: 500; }
|
|
.cfg-ok { color: #4ade80; }
|
|
.cfg-fail { color: #f87171; }
|
|
|
|
/* ── Version panel ─────────────────────────────────────────────────────── */
|
|
.cfg-versions {
|
|
border-top: 1px solid #2d3748;
|
|
margin-top: 0.5rem;
|
|
padding-top: 0.4rem;
|
|
}
|
|
.cfg-versions-toggle {
|
|
background: transparent;
|
|
border: none;
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
cursor: pointer;
|
|
padding: 0.2rem 0;
|
|
}
|
|
.cfg-versions-toggle:hover { color: #e2e8f0; }
|
|
.cfg-versions-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
margin-top: 0.4rem;
|
|
}
|
|
.cfg-version-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
padding: 0.25rem 0.4rem;
|
|
border: 1px solid #232a3a;
|
|
border-radius: 5px;
|
|
font-size: 0.78rem;
|
|
}
|
|
.cfg-version-current {
|
|
border-color: #2563eb;
|
|
background: #15203a;
|
|
}
|
|
.cfg-version-num { font-weight: 600; color: #cbd5e1; min-width: 3rem; }
|
|
.cfg-version-tag { color: #94a3b8; flex: 1; }
|
|
.cfg-version-time { color: #64748b; font-size: 0.72rem; }
|
|
.cfg-compare {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
margin-top: 0.4rem;
|
|
font-size: 0.78rem;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
/* ── Diff modal ────────────────────────────────────────────────────────── */
|
|
.cfg-diff-modal {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 10px;
|
|
width: min(760px, 92vw);
|
|
max-height: 85vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
}
|
|
.cfg-diff-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.6rem 1rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-size: 0.85rem;
|
|
color: #e2e8f0;
|
|
}
|
|
.cfg-diff-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.78rem;
|
|
overflow-y: auto;
|
|
}
|
|
.cfg-diff-table th,
|
|
.cfg-diff-table td {
|
|
text-align: left;
|
|
padding: 0.3rem 0.7rem;
|
|
border-top: 1px solid #1e2433;
|
|
vertical-align: top;
|
|
}
|
|
.cfg-diff-table th { color: #64748b; font-weight: 500; }
|
|
.cfg-diff-status {
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
.cfg-diff-added { background: rgba(34, 197, 94, 0.08); }
|
|
.cfg-diff-added .cfg-diff-status { color: #4ade80; }
|
|
.cfg-diff-removed { background: rgba(239, 68, 68, 0.08); }
|
|
.cfg-diff-removed .cfg-diff-status { color: #f87171; }
|
|
.cfg-diff-changed { background: rgba(234, 179, 8, 0.08); }
|
|
.cfg-diff-changed .cfg-diff-status { color: #facc15; }
|
|
.cfg-diff-unchanged .cfg-diff-status { color: #64748b; }
|
|
|
|
/* ── Version history tree (slick git-style pane) ───────────────────────────── */
|
|
.ver-tree {
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-size: 0.78rem;
|
|
}
|
|
.ver-empty { padding: 0.4rem 0; }
|
|
.ver-node {
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 0.6rem;
|
|
min-height: 2rem;
|
|
}
|
|
/* The rail holds the circle and the connector line to the next node below. */
|
|
.ver-rail {
|
|
position: relative;
|
|
flex: 0 0 16px;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
.ver-dot {
|
|
position: relative;
|
|
z-index: 1;
|
|
width: 10px;
|
|
height: 10px;
|
|
margin-top: 0.45rem;
|
|
border-radius: 50%;
|
|
border: 2px solid #475569;
|
|
background: #1a1f2e;
|
|
box-sizing: border-box;
|
|
flex: 0 0 auto;
|
|
}
|
|
/* Selected (the revision that is executed/shown) → filled. */
|
|
.ver-dot-current { background: #2563eb; border-color: #2563eb; }
|
|
/* Active (the revision currently viewed/edited) → larger. */
|
|
.ver-dot-active {
|
|
width: 16px;
|
|
height: 16px;
|
|
margin-top: 0.3rem;
|
|
border-color: #60a5fa;
|
|
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.18);
|
|
}
|
|
.ver-dot-unsaved { background: transparent; border-style: dashed; border-color: #f59e0b; }
|
|
.ver-line {
|
|
position: absolute;
|
|
top: 0.45rem;
|
|
bottom: -0.55rem;
|
|
width: 2px;
|
|
background: #2d3748;
|
|
z-index: 0;
|
|
}
|
|
.ver-line-dashed {
|
|
background: repeating-linear-gradient(to bottom, #f59e0b 0, #f59e0b 3px, transparent 3px, transparent 6px);
|
|
}
|
|
.ver-body {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.55rem;
|
|
flex: 1;
|
|
padding: 0.3rem 0;
|
|
border-bottom: 1px solid #1a2030;
|
|
min-width: 0;
|
|
}
|
|
.ver-node-active .ver-body { background: rgba(96, 165, 250, 0.05); border-radius: 4px; }
|
|
.ver-num {
|
|
background: transparent;
|
|
border: none;
|
|
color: #cbd5e1;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
min-width: 2.6rem;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
padding: 0;
|
|
}
|
|
.ver-num:hover { color: #fff; }
|
|
.ver-badge {
|
|
font-size: 0.62rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
background: #2563eb;
|
|
color: #fff;
|
|
border-radius: 3px;
|
|
padding: 0.05rem 0.3rem;
|
|
}
|
|
.ver-badge-view { background: #475569; }
|
|
.ver-tag { color: #94a3b8; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.ver-time { color: #64748b; font-size: 0.7rem; white-space: nowrap; }
|
|
.ver-actions { display: flex; gap: 0.3rem; flex: 0 0 auto; }
|
|
.ver-unsaved .ver-num, .ver-node-unsaved .ver-num { color: #f59e0b; font-weight: 500; font-style: italic; }
|
|
.ver-compare {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
margin-top: 0.5rem;
|
|
padding-top: 0.45rem;
|
|
border-top: 1px solid #2d3748;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
/* ── Version pane wrappers (embedded sidebars in the editors) ──────────────── */
|
|
/* Control-logic editor: FlowEditor + history sidebar side by side. */
|
|
.cl-editor-main {
|
|
flex: 1;
|
|
display: flex;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
.cl-editor-main .flow-editor { flex: 1; min-width: 0; }
|
|
.ver-pane {
|
|
flex: 0 0 20rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: auto;
|
|
padding: 0.75rem 0.9rem;
|
|
border-left: 1px solid #2d3748;
|
|
background: #11151f;
|
|
}
|
|
.ver-pane-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
font-weight: 600;
|
|
color: #cbd5e1;
|
|
margin-bottom: 0.6rem;
|
|
}
|
|
/* Synthetic editor: history floats over the right edge of the modal. */
|
|
.synth-ver-pane {
|
|
position: absolute;
|
|
top: 3rem;
|
|
right: 0;
|
|
bottom: 3.2rem;
|
|
z-index: 5;
|
|
box-shadow: -6px 0 18px rgba(0, 0, 0, 0.35);
|
|
}
|
|
|
|
/* ── Version diff viewer (unified / side-by-side text diff) ────────────────── */
|
|
.ver-diff-modal {
|
|
background: #1a1f2e;
|
|
border: 1px solid #2d3748;
|
|
border-radius: 10px;
|
|
width: min(1100px, 96vw);
|
|
max-height: 88vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
}
|
|
.ver-diff-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
padding: 0.6rem 1rem;
|
|
border-bottom: 1px solid #2d3748;
|
|
font-size: 0.85rem;
|
|
color: #e2e8f0;
|
|
}
|
|
.ver-diff-head .cl-confirm-title { flex: 1; }
|
|
.ver-diff-stats { font-family: ui-monospace, monospace; font-size: 0.78rem; }
|
|
.ver-diff-add { color: #4ade80; }
|
|
.ver-diff-del { color: #f87171; }
|
|
.ver-diff-modes { display: flex; gap: 0.3rem; }
|
|
.ver-diff-loading { padding: 1rem; }
|
|
.ver-diff {
|
|
overflow: auto;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 0.74rem;
|
|
line-height: 1.45;
|
|
}
|
|
.ver-diff-row { display: flex; white-space: pre; }
|
|
.ver-diff-ln {
|
|
flex: 0 0 3rem;
|
|
text-align: right;
|
|
padding: 0 0.5rem;
|
|
color: #475569;
|
|
user-select: none;
|
|
background: #151a27;
|
|
}
|
|
.ver-diff-sign { flex: 0 0 1.2rem; text-align: center; color: #64748b; }
|
|
.ver-diff-text { flex: 1; padding-right: 1rem; }
|
|
.ver-diff-add { background: rgba(34, 197, 94, 0.12); }
|
|
.ver-diff-del { background: rgba(239, 68, 68, 0.12); }
|
|
.ver-diff-equal { color: #94a3b8; }
|
|
.ver-diff-row.ver-diff-add .ver-diff-text { color: #bbf7d0; }
|
|
.ver-diff-row.ver-diff-del .ver-diff-text { color: #fecaca; }
|
|
/* Side-by-side grid */
|
|
.ver-diff-splitrow { display: grid; grid-template-columns: 3rem 1fr 3rem 1fr; white-space: pre; }
|
|
.ver-diff-cell { padding: 0 0.6rem; min-width: 0; overflow-x: hidden; }
|
|
.ver-diff-cell.ver-diff-add { background: rgba(34, 197, 94, 0.12); color: #bbf7d0; }
|
|
.ver-diff-cell.ver-diff-del { background: rgba(239, 68, 68, 0.12); color: #fecaca; }
|
|
.ver-diff-cell.ver-diff-equal { color: #94a3b8; }
|
|
.ver-diff-cell.ver-diff-empty { background: #141824; }
|
|
|
|
/* ── Config manager: array value editor ────────────────────────────────── */
|
|
.cfg-value-input-array { width: auto; flex: 1; }
|
|
.cfg-array { display: flex; flex-direction: column; gap: 0.35rem; }
|
|
.cfg-array-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
}
|
|
.cfg-spark {
|
|
background: #0f1117;
|
|
border: 1px solid #232a3a;
|
|
border-radius: 4px;
|
|
flex: 0 0 auto;
|
|
}
|
|
.cfg-array-info { flex: 0 0 auto; min-width: 4rem; }
|
|
|
|
.cfg-array-table {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
padding: 0.4rem;
|
|
background: #0f1117;
|
|
border: 1px solid #232a3a;
|
|
border-radius: 5px;
|
|
max-height: 12rem;
|
|
overflow-y: auto;
|
|
}
|
|
.cfg-array-pt {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
}
|
|
.cfg-array-idx { width: 2rem; text-align: right; flex: 0 0 auto; }
|
|
.cfg-array-pt .prop-input { width: 7rem; flex: 0 0 auto; }
|
|
|
|
.cfg-array-csv {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
padding: 0.4rem;
|
|
background: #0f1117;
|
|
border: 1px solid #232a3a;
|
|
border-radius: 5px;
|
|
}
|
|
.cfg-array-textarea {
|
|
width: 100%;
|
|
resize: vertical;
|
|
font-family: ui-monospace, monospace;
|
|
flex: none;
|
|
}
|
|
|
|
.cfg-array-plot-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
padding: 1rem;
|
|
}
|
|
.cfg-array-stats {
|
|
display: flex;
|
|
gap: 1.25rem;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
/* Invalid value highlighting */
|
|
.cfg-value-invalid .cfg-value-label { color: #fca5a5; }
|
|
.cfg-value-err { color: #f87171; cursor: help; margin-left: 0.25rem; }
|