- Modular block files: split into blocks-algo, blocks-data, blocks-proc - New modules: sections.js (labelled canvas areas), proc-browser.js (procedure tree modal), lib-loader.js (lazy library loading), templates.js (project templates), errno-data.js (errno table) - Test infrastructure: browser test suite (28 tests) and Node pure-function tests (75 tests) - Warning system: unified .block-warn for disconnected inputs, unconnected error hooks, and zero-exit-in-error-path - Error path highlighting: red flow paths and block borders for error-only subgraphs - Input hooks: hidden by default, shown during linking; outputs always at bottom - Block editor modal: pencil icon, colour picker for accent, compact field labels - Doc generation: standalone node script extracts JSDoc -> docs/API.md (124 declarations) - Persistence: save/restore sections, errno selection, block colours - Fixes: _segmentsIntersect bug, WCEnd crash from closest(this), drawpath guard on detached elements
1339 lines
48 KiB
CSS
1339 lines
48 KiB
CSS
:root {
|
|
--grid-size: 25px;
|
|
--bg: #fff;
|
|
--surface: #f5f5f5;
|
|
--text: #333;
|
|
--muted: #999;
|
|
--border: #ccc;
|
|
--accent: #4a90d9;
|
|
}
|
|
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
|
|
html, body {
|
|
margin: 0; padding: 0; height: 100%;
|
|
background: var(--bg); color: var(--text);
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
font-size: 14px; line-height: 1.4;
|
|
}
|
|
body { display: flex; flex-direction: column; }
|
|
|
|
h1 {
|
|
font-size: 1rem; padding: 0.5rem 1rem; margin: 0;
|
|
background: var(--surface); border-bottom: 1px solid var(--border); font-weight: 600;
|
|
}
|
|
|
|
.tab-bar {
|
|
display: flex; border-bottom: 1px solid var(--border);
|
|
background: var(--surface); flex-shrink: 0;
|
|
}
|
|
.tab-btn {
|
|
display: flex; align-items: center; gap: 0.35rem;
|
|
padding: 0.5rem 1rem; border: none; background: transparent;
|
|
cursor: pointer; font: inherit; font-size: 0.9rem;
|
|
border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--muted);
|
|
}
|
|
.tab-btn:hover { background: #e8e8e8; color: var(--text); }
|
|
.tab-btn.active { background: #e0e0e0; border-bottom-color: var(--accent); color: var(--text); }
|
|
.tab-icon { display: block; }
|
|
|
|
.tab-body { flex: 1; position: relative; min-height: 0; }
|
|
.tab-pane { display: none; height: 100%; flex-direction: column; }
|
|
.tab-pane.active { display: flex; }
|
|
|
|
.pane-toolbar {
|
|
display: flex; gap: 0.25rem; padding: 0.3rem;
|
|
flex-shrink: 0; flex-wrap: wrap;
|
|
background: var(--surface); border-bottom: 1px solid var(--border);
|
|
}
|
|
.pane-toolbar button {
|
|
padding: 0.3rem; font: inherit; font-size: 0.75rem; cursor: pointer;
|
|
background: var(--bg); color: var(--text); border: 1px solid var(--border);
|
|
border-radius: 3px; display: inline-flex; align-items: center; justify-content: center;
|
|
line-height: 0;
|
|
}
|
|
.pane-toolbar button:hover { background: #e8e8e8; }
|
|
.pane-toolbar button svg,
|
|
.pane-toolbar button img { display: block; }
|
|
|
|
.btn-group { position: relative; display: inline-flex; }
|
|
.submenu {
|
|
display: none; position: absolute; top: 100%; left: 0; z-index: 100;
|
|
margin-top: 2px; background: var(--bg); border: 1px solid var(--border);
|
|
border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
|
min-width: 100px; overflow: hidden;
|
|
}
|
|
.submenu.open { display: block; }
|
|
.submenu button {
|
|
display: block; width: 100%; padding: 0.35rem 0.75rem; border: none;
|
|
border-radius: 0; text-align: left; font-size: 0.8rem; line-height: 1.4;
|
|
}
|
|
.submenu button:hover { background: #e8e8e8; }
|
|
.submenu button:not(:last-child) { border-bottom: 1px solid var(--border); }
|
|
|
|
/* ── Library sub-tab system ── */
|
|
.lib-tab-bar {
|
|
display: flex; border-bottom: 1px solid var(--border);
|
|
background: var(--surface); flex-shrink: 0;
|
|
}
|
|
.lib-tab {
|
|
padding: 0.3rem 0.7rem; border: none; background: transparent;
|
|
cursor: pointer; font: inherit; font-size: 0.8rem;
|
|
border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--muted);
|
|
}
|
|
.lib-tab:hover { background: #e8e8e8; color: var(--text); }
|
|
.lib-tab.active { background: #e0e0e0; border-bottom-color: var(--accent); color: var(--text); }
|
|
|
|
.lib-pane { display: none; flex: 1; flex-direction: column; min-height: 0; }
|
|
.lib-pane.active { display: flex; }
|
|
|
|
/* ── WCProcedure ── */
|
|
wc-procedure { gap: 0.35rem; min-width: 200px; }
|
|
wc-procedure .proc-header {
|
|
display: flex; flex-direction: column; align-items: flex-start; gap: 0.1rem; width: 100%;
|
|
}
|
|
wc-procedure .proc-natural-name {
|
|
font-weight: bold; font-size: 0.85rem;
|
|
border: none; background: transparent;
|
|
width: 100%; padding: 0.1rem; cursor: pointer;
|
|
}
|
|
wc-procedure .proc-natural-name:focus {
|
|
border: 1px solid var(--border); background: var(--bg); cursor: text;
|
|
outline: none;
|
|
}
|
|
wc-procedure .proc-tech-name {
|
|
font-size: 0.65rem; color: var(--muted);
|
|
font-family: 'Courier New', monospace;
|
|
padding: 0 0.3rem; line-height: 1.2;
|
|
}
|
|
wc-procedure .proc-params {
|
|
display: flex; gap: 0.5rem; width: 100%;
|
|
}
|
|
wc-procedure .proc-params-col {
|
|
flex: 1; display: flex; flex-direction: column; gap: 0.2rem;
|
|
}
|
|
wc-procedure .proc-params-heading {
|
|
font-size: 0.65rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em;
|
|
}
|
|
wc-procedure .proc-param-row {
|
|
display: flex; align-items: center; gap: 0.2rem;
|
|
}
|
|
wc-procedure .proc-param-row input {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.7rem; padding: 0.1rem 0.2rem; text-align: center;
|
|
min-width: 0;
|
|
}
|
|
wc-procedure .proc-param-name { width: 4em; }
|
|
wc-procedure .proc-param-type { width: 5em; }
|
|
wc-procedure .proc-param-del {
|
|
width: 16px; height: 16px; border-radius: 50%;
|
|
border: 1px solid #ccc; background: #fff; color: #999;
|
|
font-size: 11px; line-height: 1; cursor: pointer; padding: 0;
|
|
display: flex; align-items: center; justify-content: center;
|
|
}
|
|
wc-procedure .proc-param-del:hover { background: #d32f2f; color: #fff; border-color: #d32f2f; }
|
|
wc-procedure .proc-add-input, wc-procedure .proc-add-output {
|
|
font-size: 0.7rem; padding: 0.15rem 0.4rem; cursor: pointer;
|
|
background: var(--bg); border: 1px dashed var(--border);
|
|
border-radius: 3px; color: var(--muted);
|
|
}
|
|
wc-procedure .proc-add-input:hover, wc-procedure .proc-add-output:hover {
|
|
background: #e8e8e8; color: var(--text);
|
|
}
|
|
.proc-arrow {
|
|
font-size: 1.6rem;
|
|
font-weight: bold;
|
|
color: var(--muted);
|
|
line-height: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
align-self: center;
|
|
padding: 0 0.15rem;
|
|
flex-shrink: 0;
|
|
}
|
|
/* Return style selector */
|
|
wc-procedure .proc-return-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
width: 100%;
|
|
}
|
|
wc-procedure .proc-return-label {
|
|
font-size: 0.65rem;
|
|
font-weight: 600;
|
|
color: var(--muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
white-space: nowrap;
|
|
}
|
|
wc-procedure .proc-return-style {
|
|
font-size: 0.7rem;
|
|
padding: 0.1rem 0.3rem;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 3px;
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
flex: 1;
|
|
}
|
|
wc-procedure .proc-return-style:focus {
|
|
outline: none;
|
|
border-color: var(--accent, #1976d2);
|
|
}
|
|
wc-procedure[data-readonly] .proc-return-style {
|
|
display: none;
|
|
}
|
|
/* Collapsible description */
|
|
wc-procedure .proc-description {
|
|
width: 100%;
|
|
font-size: 0.72rem;
|
|
color: var(--muted);
|
|
margin-top: 0.15rem;
|
|
}
|
|
wc-procedure .proc-desc-summary {
|
|
cursor: pointer;
|
|
font-size: 0.65rem;
|
|
font-weight: 600;
|
|
color: var(--muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
padding: 0.1rem 0;
|
|
user-select: none;
|
|
}
|
|
wc-procedure .proc-desc-summary:hover {
|
|
color: var(--text);
|
|
}
|
|
wc-procedure .proc-desc-body {
|
|
padding: 0.3rem 0.5rem;
|
|
line-height: 1.5;
|
|
color: var(--text);
|
|
font-size: 0.72rem;
|
|
background: var(--surface);
|
|
border-radius: 3px;
|
|
margin-top: 0.15rem;
|
|
}
|
|
/* List-view: two-column procedure row with arrow */
|
|
.procedures-area > wc-procedure {
|
|
gap: 0.3rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.procedures-area > wc-procedure .proc-header {
|
|
width: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
.procedures-area > wc-procedure .proc-params {
|
|
width: auto;
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0;
|
|
}
|
|
.procedures-area > wc-procedure .proc-params-col {
|
|
flex: none;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.15rem;
|
|
}
|
|
.procedures-area > wc-procedure .proc-params-col:first-of-type {
|
|
margin-right: 0.5rem;
|
|
}
|
|
.procedures-area > wc-procedure .proc-params-heading {
|
|
white-space: nowrap;
|
|
margin-right: 0.15rem;
|
|
}
|
|
.procedures-area > wc-procedure .proc-param-row input {
|
|
width: 4em;
|
|
}
|
|
.procedures-area > wc-procedure .proc-add-input,
|
|
.procedures-area > wc-procedure .proc-add-output {
|
|
white-space: nowrap;
|
|
font-size: 0.65rem;
|
|
padding: 0.1rem 0.3rem;
|
|
}
|
|
|
|
/* Read-only (external library) procedure styles */
|
|
wc-procedure[data-readonly] .proc-param-row input {
|
|
background: transparent;
|
|
border: none;
|
|
cursor: default;
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
wc-procedure[data-readonly] .proc-param-row input:focus {
|
|
outline: none;
|
|
}
|
|
wc-procedure[data-readonly] .proc-add-input,
|
|
wc-procedure[data-readonly] .proc-add-output,
|
|
wc-procedure[data-readonly] .proc-param-del {
|
|
display: none;
|
|
}
|
|
wc-procedure[data-readonly] .proc-natural-name:focus {
|
|
outline: none;
|
|
}
|
|
wc-procedure[data-readonly] .proc-tech-name {
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* ── WCProcCall ── */
|
|
wc-proccall { position: relative; gap: 0.25rem; min-width: 160px; padding-top: 1.2rem; padding-bottom: 1.2rem; }
|
|
wc-proccall .proccall-header { display: flex; align-items: center; gap: 0.25rem; width: 100%; }
|
|
wc-proccall .proccall-icon {
|
|
width: 16px; height: 16px; flex-shrink: 0; object-fit: contain;
|
|
border-radius: 2px;
|
|
}
|
|
wc-proccall .proccall-label {
|
|
font-weight: 600; font-size: 0.55rem; color: var(--muted); letter-spacing: 0.06em;
|
|
flex-shrink: 0; opacity: 0.7; text-transform: uppercase;
|
|
}
|
|
wc-proccall .proccall-nat-name {
|
|
flex: 1; font-size: 0.85rem; font-weight: 700; cursor: pointer;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
|
|
color: var(--text); line-height: 1.3;
|
|
}
|
|
wc-proccall .proccall-nat-name:hover { color: var(--accent); }
|
|
wc-proccall .proccall-tech-name {
|
|
font-size: 0.6rem; color: var(--muted); white-space: nowrap;
|
|
overflow: hidden; text-overflow: ellipsis; max-width: 100px; flex-shrink: 0;
|
|
font-family: monospace; opacity: 0.75;
|
|
}
|
|
wc-proccall .proccall-change-btn {
|
|
font-size: 0.55rem; padding: 0.08rem 0.25rem; cursor: pointer;
|
|
background: transparent; border: 1px solid var(--border); border-radius: 3px;
|
|
color: var(--muted); flex-shrink: 0; line-height: 1.3; opacity: 0.6;
|
|
}
|
|
wc-proccall .proccall-change-btn:hover { background: #e8e8e8; color: var(--text); opacity: 1; }
|
|
wc-proccall .proccall-name-row {
|
|
display: flex; align-items: center; gap: 0.25rem; width: 100%;
|
|
}
|
|
wc-proccall .proccall-name {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.7rem; padding: 0.1rem 0.2rem; text-align: center;
|
|
}
|
|
wc-proccall .proccall-container {
|
|
display: flex; gap: 0.5rem; width: 100%;
|
|
}
|
|
wc-proccall .proccall-inputs, wc-proccall .proccall-outputs {
|
|
flex: 1; display: flex; flex-direction: column; gap: 0.25rem;
|
|
}
|
|
wc-proccall .proccall-arg-row {
|
|
display: flex; align-items: center; gap: 0.2rem;
|
|
}
|
|
wc-proccall .proccall-arg-label {
|
|
font-size: 0.65rem; color: var(--text); white-space: nowrap;
|
|
}
|
|
wc-proccall .proccall-arg-input {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.65rem; padding: 0.1rem 0.2rem; text-align: center;
|
|
min-width: 3em;
|
|
}
|
|
/* Data hooks inside proccall arg rows are inline (position: static by default in .hook) */
|
|
wc-proccall .proccall-arg-row .hook {
|
|
position: static !important;
|
|
transform: none !important;
|
|
flex-shrink: 0;
|
|
}
|
|
/* Error hook on proccall — styled like a logic out hook but with red accent */
|
|
wc-proccall .proccall-error-hook {
|
|
background: #E69F00;
|
|
border: 2px solid #B8860B;
|
|
color: #1a1a1a;
|
|
font-size: 0.75rem;
|
|
font-weight: 900;
|
|
line-height: 1;
|
|
display: none;
|
|
}
|
|
wc-proccall button.proccall-error-hook[data-direction="out"] {
|
|
position: absolute;
|
|
right: -11px;
|
|
top: 50%;
|
|
left: auto;
|
|
bottom: auto;
|
|
z-index: 5;
|
|
width: 18px;
|
|
height: 18px;
|
|
transform: translateY(-50%);
|
|
}
|
|
wc-proccall button.proccall-error-hook:hover {
|
|
transform: translateY(-50%) scale(1.3);
|
|
box-shadow: 0 0 6px rgba(230,159,0,0.6);
|
|
}
|
|
wc-proccall button.proccall-error-hook.visible {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
wc-proccall .proccall-fmtargs {
|
|
display: flex; flex-direction: column; gap: 0.15rem; width: 100%;
|
|
border-top: 1px dashed var(--border); padding-top: 0.2rem; margin-top: 0.1rem;
|
|
}
|
|
wc-proccall .proccall-fmtargs-list {
|
|
display: flex; flex-direction: column; gap: 0.15rem;
|
|
}
|
|
wc-proccall .proccall-add-fmtarg {
|
|
font-size: 0.6rem; padding: 0.1rem 0.3rem; cursor: pointer;
|
|
background: transparent; border: 1px dashed var(--border); border-radius: 3px;
|
|
color: var(--muted); align-self: flex-start;
|
|
}
|
|
wc-proccall .proccall-add-fmtarg:hover { background: #e8e8e8; color: var(--text); }
|
|
wc-proccall .proccall-fmtargs .proccall-arg-row .hook {
|
|
position: static !important;
|
|
transform: none !important;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── WCAssign ── */
|
|
wc-assign { gap: 0.25rem; padding-top: 1.2rem; padding-bottom: 1.2rem; }
|
|
wc-assign .assign-header { font-weight: bold; font-size: 0.65rem; color: var(--muted); letter-spacing: 0.05em; }
|
|
wc-assign .assign-row { display: flex; align-items: center; gap: 0.25rem; width: 100%; }
|
|
wc-assign .assign-target {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.1rem 0.2rem;
|
|
}
|
|
wc-assign .assign-eq { font-size: 0.8rem; font-weight: bold; color: var(--text); }
|
|
wc-assign .assign-value {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.15rem 0.3rem; text-align: center;
|
|
min-width: 4em;
|
|
}
|
|
wc-assign .assign-value.hidden { display: none; }
|
|
wc-assign .assign-index-area {
|
|
display: none; align-items: center; gap: 0.2rem; width: 100%;
|
|
justify-content: flex-end;
|
|
}
|
|
wc-assign .assign-index-area .hook {
|
|
position: static !important;
|
|
transform: none !important;
|
|
flex-shrink: 0;
|
|
}
|
|
wc-assign .assign-bracket { font-size: 0.85rem; font-weight: bold; color: var(--muted); }
|
|
wc-assign .assign-index {
|
|
width: 3em; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.15rem 0.3rem; text-align: center;
|
|
}
|
|
wc-assign .assign-index.hidden { display: none; }
|
|
wc-assign .assign-row .hook {
|
|
position: static !important;
|
|
transform: none !important;
|
|
flex-shrink: 0;
|
|
}
|
|
wc-assign #hook-fore[data-direction="in"] {
|
|
left: -7px; top: 50%; transform: translateY(-50%); bottom: auto;
|
|
}
|
|
wc-assign #hook-next[data-direction="out"] {
|
|
right: -7px; top: 50%; transform: translateY(-50%); bottom: auto; left: auto;
|
|
}
|
|
|
|
#draw-area {
|
|
flex: 1; position: relative; min-height: 0;
|
|
overflow: auto;
|
|
background-size: var(--grid-size) var(--grid-size);
|
|
background-image:
|
|
linear-gradient(to right, #eee 1px, transparent 1px),
|
|
linear-gradient(to bottom, #eee 1px, transparent 1px);
|
|
background-color: var(--bg);
|
|
}
|
|
|
|
/* Column headers for list-style containers */
|
|
.list-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
padding: 0.3rem 0.5rem;
|
|
font-size: 0.6rem;
|
|
font-weight: 700;
|
|
color: var(--muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
background: var(--surface);
|
|
border-bottom: 2px solid var(--border);
|
|
flex-shrink: 0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
min-height: 1.8em;
|
|
}
|
|
|
|
/* List-style containers for non-algorithm tabs */
|
|
#data-area, #variable-area, .procedures-area {
|
|
flex: 1; min-height: 0;
|
|
overflow: auto;
|
|
background: var(--bg);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.global-toolbar {
|
|
display: flex; gap: 0.25rem; padding: 0.3rem;
|
|
align-items: flex-start; flex-shrink: 0;
|
|
border-top: 1px solid var(--border); background: var(--surface);
|
|
}
|
|
.global-toolbar button {
|
|
padding: 0.4rem 0.8rem; font: inherit; font-size: 0.8rem; cursor: pointer;
|
|
background: var(--accent); color: #fff; border: none; border-radius: 3px;
|
|
}
|
|
.global-toolbar button:hover { background: #357abd; }
|
|
.global-toolbar .code-output {
|
|
flex: 1; min-height: 80px; max-height: 50vh; overflow: auto; resize: vertical;
|
|
background: var(--bg); border: 1px solid var(--border);
|
|
font-family: 'Courier New', monospace; font-size: 0.8rem; line-height: 1.5;
|
|
padding: 0.3rem; position: relative;
|
|
}
|
|
.global-toolbar .code-output pre {
|
|
margin: 0; white-space: pre; tab-size: 4;
|
|
}
|
|
.global-toolbar .code-output code {
|
|
display: block;
|
|
}
|
|
.global-toolbar .code-output code.hljs {
|
|
background: transparent; padding: 0;
|
|
}
|
|
|
|
|
|
[data-block] {
|
|
border: 1px solid var(--border); padding: 0.5rem; margin: 0;
|
|
position: absolute; display: flex; justify-content: center;
|
|
align-items: center; flex-direction: column; user-select: none;
|
|
background: var(--bg); color: var(--text); min-width: 60px; min-height: 30px;
|
|
overflow: visible; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); z-index: 1;
|
|
}
|
|
|
|
/* Algorithm-tab blocks — wider minimum to avoid hook/button overlap */
|
|
#main-program > [data-block] {
|
|
min-width: 100px;
|
|
}
|
|
|
|
/* List-view blocks (non-algorithm tabs) — horizontal rows, no positioning */
|
|
#variable-area > [data-block],
|
|
#data-area > [data-block],
|
|
.procedures-area > [data-block] {
|
|
position: static;
|
|
width: 100%;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
padding: 0.35rem 0.5rem;
|
|
min-width: auto;
|
|
min-height: auto;
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
border-left: none;
|
|
border-right: none;
|
|
border-top: none;
|
|
border-bottom: 1px solid var(--border);
|
|
margin: 0;
|
|
z-index: auto;
|
|
}
|
|
|
|
/* Flatten internal row wrappers in list-view blocks */
|
|
#variable-area > [data-block] .datum-row,
|
|
#data-area > [data-block] .datum-row {
|
|
display: contents;
|
|
}
|
|
|
|
/* Hide resize handle in list view */
|
|
#variable-area > [data-block] .resize-handle,
|
|
#data-area > [data-block] .resize-handle,
|
|
.procedures-area > [data-block] .resize-handle {
|
|
display: none;
|
|
}
|
|
|
|
/* Inline delete button for list-view blocks */
|
|
#variable-area > [data-block] .delete-btn,
|
|
#data-area > [data-block] .delete-btn,
|
|
.procedures-area > [data-block] .delete-btn {
|
|
position: static;
|
|
opacity: 0.4;
|
|
margin-left: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
[data-block]:hover .resize-handle { opacity: 0.5; }
|
|
.resize-handle {
|
|
position: absolute; right: 0; bottom: 0; width: 14px; height: 14px;
|
|
cursor: nwse-resize; opacity: 0; z-index: 10;
|
|
background: linear-gradient(135deg, transparent 50%, var(--muted) 50%, var(--muted) 60%, transparent 60%);
|
|
transition: opacity 0.15s;
|
|
}
|
|
wc-start { background: #e8f5e9; border-color: #66bb6a; }
|
|
wc-end { background: #fbe9e7; border-color: #ef5350; }
|
|
wc-end[data-exit-error="true"] {
|
|
background: #fff5f5;
|
|
border-color: #ef5350;
|
|
}
|
|
wc-end[data-exit-error="true"] .end-header::after {
|
|
content: " (error)";
|
|
font-weight: normal;
|
|
font-size: 0.65rem;
|
|
color: #e57373;
|
|
}
|
|
wc-end .end-header { font-weight: bold; font-size: 0.75rem; letter-spacing: 0.05em; }
|
|
wc-end .end-exit-row {
|
|
display: flex; align-items: center; gap: 0.3rem; width: 100%;
|
|
}
|
|
wc-end .end-exit-label {
|
|
font-size: 0.65rem; font-weight: 600; color: var(--muted);
|
|
text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap;
|
|
}
|
|
wc-end .end-exit-autocomplete {
|
|
position: relative; flex: 1; min-width: 0;
|
|
}
|
|
wc-end .end-errno-input {
|
|
width: 100%; font-size: 0.7rem; padding: 0.1rem 0.25rem;
|
|
background: var(--bg); border: 1px solid var(--border);
|
|
border-radius: 3px; color: var(--text);
|
|
font-family: 'Courier New', monospace; outline: none;
|
|
}
|
|
wc-end .end-errno-input:focus {
|
|
border-color: var(--accent);
|
|
}
|
|
wc-end .end-errno-suggestions {
|
|
display: none; position: absolute; top: 100%; left: 0; right: 0;
|
|
z-index: 100; background: var(--bg); border: 1px solid var(--border);
|
|
border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
|
max-height: 180px; overflow-y: auto;
|
|
}
|
|
wc-end .end-errno-suggestion {
|
|
padding: 0.2rem 0.4rem; cursor: pointer;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
wc-end .end-errno-suggestion:last-child { border-bottom: none; }
|
|
wc-end .end-errno-suggestion:hover,
|
|
wc-end .end-errno-suggestion.highlighted { background: #e8f0fe; }
|
|
wc-end .end-suggestion-code {
|
|
display: block; font-size: 0.7rem;
|
|
font-family: 'Courier New', monospace;
|
|
}
|
|
wc-end .end-suggestion-desc {
|
|
display: block; font-size: 0.6rem; color: var(--muted); font-style: italic;
|
|
}
|
|
wc-end .end-desc-row {
|
|
display: flex; align-items: center; width: 100%;
|
|
padding: 0 0.3rem; min-height: 1.3em;
|
|
}
|
|
wc-end .end-desc-text {
|
|
font-size: 0.65rem; color: var(--muted); font-style: italic;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
|
|
wc-decision { background: #fff3e0; border-color: #ffa726; }
|
|
wc-decision p { margin: 0.2rem 0; font-weight: 600; }
|
|
wc-decision .decision-row { display: flex; align-items: center; gap: 0.3rem; }
|
|
wc-decision .decision-label { font-size: 0.8rem; font-weight: bold; color: var(--text); }
|
|
/* ── Unified warning system ──────────────────────────────────────────── */
|
|
/* The ⚠ icon (block-warn) is created for every algorithm block.
|
|
It stays hidden until any warning class is active on the block. */
|
|
|
|
.block-warn { display: none; font-size: 1rem; cursor: help; position: absolute; top: 2px; right: 4px; z-index: 3; }
|
|
|
|
/* Warning: block has no incoming logic connection */
|
|
#main-program > [data-block].disconnected { border-color: #e65100; border-width: 2px; background: #fff3e0; }
|
|
#main-program > [data-block].disconnected > .block-warn { display: inline; color: #e65100; }
|
|
|
|
/* Warning: error output hook on wc-proccall is not connected */
|
|
wc-proccall.warn-error-unlinked {
|
|
box-shadow: 0 0 0 2px #ef5350, 0 1px 3px rgba(0,0,0,0.08);
|
|
}
|
|
wc-proccall.warn-error-unlinked > .block-warn { display: inline; color: #ef5350; }
|
|
wc-proccall.warn-error-unlinked .proccall-header::after {
|
|
content: " (unused)"; font-size: 0.65rem; color: #ef5350; font-weight: normal;
|
|
}
|
|
|
|
/* Warning: error-path END block returns 0 (success) */
|
|
wc-end.warn-zero-in-error {
|
|
border-color: #ffa000;
|
|
border-width: 2px;
|
|
background: #fff8e1;
|
|
}
|
|
wc-end.warn-zero-in-error > .block-warn { display: inline; color: #ffa000; }
|
|
wc-end.warn-zero-in-error .end-header::after {
|
|
content: " (success in error path)";
|
|
font-size: 0.6rem; color: #ffa000; font-weight: normal;
|
|
}
|
|
wc-decision .decision-row .hook {
|
|
position: static !important;
|
|
transform: none !important;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
wc-boolean, wc-scalar, wc-vector, wc-string { gap: 0.25rem; }
|
|
wc-boolean .datum-row, wc-scalar .datum-row, wc-vector .datum-row, wc-string .datum-row { display: flex; align-items: center; gap: 0.25rem; width: 100%; }
|
|
wc-boolean input, wc-scalar input, wc-vector input, wc-string input {
|
|
background: var(--bg); border: 1px solid var(--border); font: inherit;
|
|
padding: 0.15rem 0.3rem; width: 4em; text-align: center;
|
|
}
|
|
wc-boolean .var-name, wc-scalar .var-name, wc-vector .var-name, wc-string .var-name, wc-array .var-name {
|
|
border: none; background: transparent; cursor: pointer;
|
|
font-weight: bold; font-size: 0.85rem;
|
|
width: auto; min-width: 2em; padding: 0.1rem;
|
|
}
|
|
wc-boolean .var-name:focus, wc-scalar .var-name:focus, wc-vector .var-name:focus, wc-string .var-name:focus, wc-array .var-name:focus {
|
|
border: 1px solid var(--border); background: var(--bg); cursor: text;
|
|
outline: none; width: 5em;
|
|
}
|
|
wc-boolean .var-comment, wc-scalar .var-comment, wc-vector .var-comment, wc-string .var-comment, wc-array .var-comment {
|
|
border: none; background: transparent;
|
|
font-style: italic; font-size: 0.7rem; color: var(--muted);
|
|
width: 100%; padding: 0.1rem 0.3rem; cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
wc-boolean .var-comment:focus, wc-scalar .var-comment:focus, wc-vector .var-comment:focus, wc-string .var-comment:focus, wc-array .var-comment:focus {
|
|
border: 1px solid var(--border); background: var(--bg);
|
|
font-style: italic; color: var(--text); cursor: text;
|
|
outline: none;
|
|
}
|
|
wc-boolean .var-cname, wc-scalar .var-cname, wc-vector .var-cname, wc-string .var-cname, wc-array .var-cname {
|
|
font-size: 0.65rem; color: var(--muted); font-family: 'Courier New', monospace;
|
|
width: 100%; padding: 0 0.3rem; line-height: 1.2;
|
|
}
|
|
wc-boolean .var-value, wc-scalar .var-value, wc-vector .var-value { width: 8em; }
|
|
wc-string .var-value { width: 8em; }
|
|
wc-array { gap: 0.25rem; background: #e0f2f1; border-color: #26a69a; }
|
|
wc-array .array-row { display: flex; align-items: center; gap: 0.25rem; width: 100%; }
|
|
/* In list view, array elements span full width below the row */
|
|
#variable-area > wc-array .array-elements {
|
|
width: 100%; order: 999; flex-shrink: 0;
|
|
}
|
|
|
|
wc-array .array-type { width: 7em; }
|
|
wc-array .array-bracket { font-size: 0.85rem; font-weight: bold; }
|
|
wc-array .array-count { font-size: 0.7rem; color: var(--muted); margin-left: auto; white-space: nowrap; }
|
|
wc-array .array-elements {
|
|
display: flex; flex-direction: column; gap: 0.15rem; width: 100%;
|
|
overflow: visible;
|
|
}
|
|
wc-array .array-element-row {
|
|
display: flex; align-items: center; gap: 0.25rem;
|
|
}
|
|
wc-array .array-element-idx {
|
|
font-size: 0.7rem; color: var(--muted); width: 1.5em; text-align: right; flex-shrink: 0;
|
|
font-family: 'Courier New', monospace;
|
|
}
|
|
wc-array .array-element-value {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.1rem 0.3rem; text-align: center;
|
|
min-width: 3em;
|
|
}
|
|
wc-array .array-element-del {
|
|
width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
|
|
border: 1px solid #ccc; background: #fff; color: #999;
|
|
font-size: 11px; line-height: 1; cursor: pointer; padding: 0;
|
|
display: flex; align-items: center; justify-content: center;
|
|
}
|
|
wc-array .array-element-del:hover { background: #d32f2f; color: #fff; border-color: #d32f2f; }
|
|
wc-array .array-vec-row { font-size: 0.7rem; color: var(--muted); white-space: nowrap; margin-left: auto; }
|
|
wc-array .array-vec-dim { width: 2.5em; text-align: center; font: inherit; font-size: 0.75rem; background: var(--bg); border: 1px solid var(--border); padding: 0.1rem 0.2rem; }
|
|
wc-scalar .var-si, wc-vector .var-si { font-size: 0.75rem; color: var(--muted); white-space: nowrap; }
|
|
wc-scalar .var-type, wc-scalar .var-unit, wc-vector .var-type, wc-vector .var-unit {
|
|
background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.1rem 0.2rem;
|
|
}
|
|
wc-vector .var-dim { width: 2.5em; text-align: center; }
|
|
|
|
wc-expression { gap: 0.25rem; }
|
|
wc-expression .expr-row { display: flex; align-items: center; gap: 0.25rem; width: 100%; }
|
|
wc-expression input {
|
|
background: var(--bg); border: 1px solid var(--border); font: inherit;
|
|
padding: 0.15rem 0.3rem; text-align: center;
|
|
}
|
|
wc-expression .expr-name { width: 3em; }
|
|
wc-expression .expr-formula-container {
|
|
display: flex; gap: 0.25rem; width: 100%;
|
|
}
|
|
wc-expression .expr-latex {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font-family: 'Courier New', monospace; font-size: 0.75rem;
|
|
padding: 0.2rem; resize: vertical; min-width: 4em;
|
|
}
|
|
wc-expression .expr-rendered {
|
|
min-width: 3em; min-height: 2em; display: flex; align-items: center;
|
|
justify-content: center; background: #fafafa; border: 1px solid #eee;
|
|
border-radius: 3px; padding: 0.2rem 0.4rem; font-size: 0.8rem;
|
|
}
|
|
wc-expression .expr-varhooks {
|
|
position: absolute; top: -7px; left: 0; right: 0; z-index: 3;
|
|
display: flex; justify-content: center; gap: 6px;
|
|
pointer-events: none; height: 14px;
|
|
}
|
|
wc-expression .expr-varhooks .hook {
|
|
position: static; pointer-events: auto; flex-shrink: 0;
|
|
transform: none !important;
|
|
}
|
|
|
|
wc-varref { gap: 0.25rem; padding-bottom: 1rem; }
|
|
wc-varref .varref-label { font-weight: bold; font-size: 0.65rem; color: var(--muted); letter-spacing: 0.05em; }
|
|
wc-varref .varref-select {
|
|
background: var(--bg); border: 1px solid var(--border); font: inherit;
|
|
font-size: 0.75rem; padding: 0.15rem 0.2rem; width: 100%;
|
|
}
|
|
|
|
wc-quantity { gap: 0.25rem; }
|
|
wc-quantity .quantity-header { display: flex; align-items: center; gap: 0.3rem; width: 100%; }
|
|
wc-quantity .quantity-label { font-weight: bold; font-size: 0.7rem; }
|
|
wc-quantity .quantity-name {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; padding: 0.15rem 0.3rem; text-align: center;
|
|
}
|
|
wc-quantity .dims { display: flex; flex-wrap: wrap; gap: 0.2rem; justify-content: center; }
|
|
wc-quantity .dims label { display: flex; align-items: center; gap: 0.1rem; font-size: 0.75rem; font-weight: bold; }
|
|
wc-quantity .dims input {
|
|
width: 2.5em; background: var(--bg); border: 1px solid var(--border);
|
|
padding: 0.1rem; font: inherit; text-align: center;
|
|
}
|
|
wc-quantity .range { display: flex; gap: 0.5rem; font-size: 0.75rem; }
|
|
wc-quantity .range input {
|
|
width: 4em; background: var(--bg); border: 1px solid var(--border);
|
|
padding: 0.1rem 0.2rem; font: inherit; text-align: center;
|
|
}
|
|
wc-quantity .quantity-footer { width: 100%; font-size: 0.75rem; }
|
|
wc-quantity .quantity-footer select {
|
|
width: 100%; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; padding: 0.1rem 0.2rem;
|
|
}
|
|
/* List-view: flatten quantity internals into a row */
|
|
#data-area > wc-quantity .quantity-header,
|
|
#data-area > wc-quantity .dims,
|
|
#data-area > wc-quantity .range,
|
|
#data-area > wc-quantity .quantity-footer {
|
|
display: contents;
|
|
}
|
|
|
|
wc-unit { gap: 0.25rem; }
|
|
wc-unit .unit-header { display: flex; align-items: center; gap: 0.3rem; width: 100%; }
|
|
wc-unit .unit-label { font-weight: bold; font-size: 0.7rem; }
|
|
wc-unit .unit-fullname {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; padding: 0.15rem 0.3rem; text-align: center;
|
|
}
|
|
wc-unit .unit-body { display: flex; flex-direction: column; gap: 0.2rem; width: 100%; }
|
|
wc-unit .unit-body label { display: flex; align-items: center; gap: 0.3rem; font-size: 0.8rem; }
|
|
wc-unit .unit-body select, wc-unit .unit-body input {
|
|
flex: 1; background: var(--bg); border: 1px solid var(--border);
|
|
font: inherit; padding: 0.1rem 0.2rem; text-align: center;
|
|
}
|
|
wc-unit .unit-si { width: 7em; }
|
|
wc-unit .unit-resolved { font-size: 0.75rem; color: var(--muted); align-self: flex-end; }
|
|
/* List-view: flatten unit internals */
|
|
#data-area > wc-unit .unit-header,
|
|
#data-area > wc-unit .unit-body {
|
|
display: contents;
|
|
}
|
|
#data-area > wc-unit .unit-body label {
|
|
display: inline-flex;
|
|
}
|
|
|
|
.error-overlay {
|
|
display: none; position: fixed; z-index: 99999;
|
|
top: 0; left: 0; right: 0; bottom: 0;
|
|
background: rgba(0,0,0,0.45);
|
|
align-items: center; justify-content: center;
|
|
}
|
|
.error-overlay.active { display: flex; }
|
|
.error-box {
|
|
background: #d32f2f; color: #fff; padding: 2rem;
|
|
border-radius: 8px; max-width: 400px; width: 90%;
|
|
box-shadow: 0 4px 24px rgba(0,0,0,0.35);
|
|
text-align: center; position: relative;
|
|
}
|
|
.error-ack {
|
|
font-size: 2.2rem; font-weight: 900;
|
|
font-family: 'Courier New', monospace;
|
|
letter-spacing: 0.1em; margin-bottom: 0.75rem;
|
|
}
|
|
.error-close {
|
|
position: absolute; top: 0.3rem; right: 0.75rem;
|
|
cursor: pointer; font-size: 1.8rem; line-height: 1;
|
|
opacity: 0.8;
|
|
}
|
|
.error-close:hover { opacity: 1; }
|
|
.error-msg { font-size: 1rem; line-height: 1.5; }
|
|
|
|
svg#connections {
|
|
z-index: 0; background: transparent; position: absolute;
|
|
top: 0; left: 0; width: 100%; height: 100%;
|
|
overflow: visible; pointer-events: none;
|
|
}
|
|
svg#connections path.flow, svg#connections path.flow-data {
|
|
pointer-events: stroke;
|
|
}
|
|
path.flow { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; transition: stroke 0.1s, stroke-width 0.1s; }
|
|
path.flow:hover { stroke: #d32f2f; stroke-width: 3; cursor: pointer; }
|
|
path.flow-shadow { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 5 3; pointer-events: none; opacity: 0.6; }
|
|
path.flow-data { fill: none; stroke: #43a047; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; transition: stroke 0.1s, stroke-width 0.1s; }
|
|
path.flow-data:hover { stroke: #d32f2f; stroke-width: 3; cursor: pointer; }
|
|
path.flow-shadow-data { fill: none; stroke: #43a047; stroke-width: 1.5; stroke-dasharray: 5 3; pointer-events: none; opacity: 0.6; }
|
|
|
|
/* ── Logic sections ── */
|
|
.section-bg { fill: #e8e8e8; fill-opacity: 0.5; stroke: #ccc; stroke-width: 1; stroke-dasharray: 4 2; cursor: pointer; }
|
|
.section-bg:hover { stroke: #999; stroke-width: 1.5; }
|
|
.section-bg.selected-section { stroke: #666; stroke-width: 2; stroke-dasharray: none; fill-opacity: 0.6; }
|
|
.section-label { font-size: 11px; font-family: sans-serif; fill: #888; cursor: pointer; user-select: none; pointer-events: auto; }
|
|
.section-label:hover { fill: #555; }
|
|
.section-handle { fill: #666; stroke: #fff; stroke-width: 1.5; cursor: move; }
|
|
.section-preview-bg { fill: #e0e0e0; fill-opacity: 0.4; stroke: #aaa; stroke-width: 1; stroke-dasharray: 4 3; }
|
|
.section-preview-line { stroke: #888; stroke-width: 1.5; stroke-dasharray: 4 3; }
|
|
.section-ghost { fill: #888; }
|
|
.section-title-input { font-size: 11px; border: 1px solid #aaa; border-radius: 2px; padding: 1px 4px; background: #fff; }
|
|
|
|
/* Edit-mode overlay greys out blocks/links */
|
|
.section-edit-overlay { position: absolute; inset: 0; z-index: 4; background: transparent; pointer-events: none; }
|
|
#draw-area.section-editing [data-block] { opacity: 0.3; pointer-events: none; }
|
|
#draw-area.section-editing path.flow, #draw-area.section-editing path.flow-data, #draw-area.section-editing path.flow-shadow, #draw-area.section-editing path.flow-shadow-data { opacity: 0.2; pointer-events: none; }
|
|
#draw-area.section-editing .section-bg { pointer-events: auto; fill-opacity: 0.7; }
|
|
#draw-area.section-editing .section-label { pointer-events: auto; }
|
|
#draw-area.section-editing .section-handle { pointer-events: auto; }
|
|
#draw-area.section-editing .section-preview-bg { pointer-events: none; }
|
|
#draw-area.section-editing .section-preview-line { pointer-events: none; }
|
|
#draw-area.section-editing .section-ghost { pointer-events: none; }
|
|
|
|
.toolbar-sep { display: inline-block; width: 1px; height: 18px; background: var(--border); margin: 0 4px; vertical-align: middle; }
|
|
|
|
button.hook {
|
|
display: block; width: 14px; height: 14px; border-radius: 50%;
|
|
cursor: pointer; padding: 0; z-index: 2;
|
|
transition: transform 0.1s, box-shadow 0.1s;
|
|
}
|
|
|
|
/* Hook row for bottom-placed output hooks (side by side) */
|
|
.hook-row {
|
|
display: flex; gap: 8px; justify-content: center;
|
|
position: absolute; bottom: -7px; left: 0; right: 0;
|
|
pointer-events: none;
|
|
}
|
|
.hook-row > .hook { position: static; pointer-events: auto; }
|
|
|
|
button.hook[data-direction="out"] {
|
|
background: var(--accent); border: 2px solid var(--accent);
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
position: absolute; bottom: -7px; left: 50%; transform: translateX(-50%);
|
|
}
|
|
.hook-row > button.hook[data-direction="out"] {
|
|
position: static; transform: none;
|
|
}
|
|
button.hook[data-direction="out"]:hover {
|
|
transform: translateX(-50%) scale(1.3);
|
|
box-shadow: 0 0 8px rgba(74,144,217,0.5), 0 1px 3px rgba(0,0,0,0.2);
|
|
}
|
|
.hook-row > button.hook[data-direction="out"]:hover {
|
|
transform: scale(1.3);
|
|
}
|
|
|
|
button.hook[data-direction="in"] {
|
|
background: transparent;
|
|
border: 2px dashed var(--muted);
|
|
position: absolute;
|
|
}
|
|
button.hook[data-direction="in"][data-exit="up"] {
|
|
top: -7px; left: 50%; transform: translateX(-50%);
|
|
}
|
|
button.hook[data-direction="in"][data-exit="left"] {
|
|
top: 50%; left: -7px; transform: translateY(-50%);
|
|
}
|
|
button.hook[data-direction="in"][data-exit="right"] {
|
|
top: 50%; right: -7px; transform: translateY(-50%);
|
|
}
|
|
|
|
/* Empty input hooks hidden by default; shown during linking */
|
|
button.hook[data-direction="in"]:not([data-connected]) {
|
|
display: none;
|
|
}
|
|
#draw-area.linking button.hook[data-direction="in"],
|
|
#draw-area.linking button.hook[data-direction="in"]:not([data-connected]) {
|
|
display: block;
|
|
}
|
|
button.hook[data-direction="in"]:hover {
|
|
border-color: var(--accent); border-style: solid;
|
|
}
|
|
button.hook[data-direction="in"][data-connected] {
|
|
display: block;
|
|
background: #e8f0fe;
|
|
border-color: var(--accent);
|
|
border-style: solid;
|
|
}
|
|
|
|
button.hook:not([data-direction]) {
|
|
opacity: 0.2; pointer-events: none;
|
|
}
|
|
|
|
button.hook[data-link-type="data"][data-direction="out"] {
|
|
background: #43a047; border-color: #43a047;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
}
|
|
button.hook[data-link-type="data"][data-direction="out"]:hover {
|
|
transform: translateX(-50%) scale(1.3);
|
|
box-shadow: 0 0 8px rgba(67,160,71,0.5), 0 1px 3px rgba(0,0,0,0.2);
|
|
}
|
|
button.hook[data-link-type="data"][data-direction="in"] {
|
|
background: transparent;
|
|
border: 2px dashed #43a047;
|
|
}
|
|
button.hook[data-link-type="data"][data-direction="in"]:hover {
|
|
border-style: solid;
|
|
}
|
|
button.hook[data-link-type="data"][data-direction="in"][data-connected] {
|
|
background: #e8f5e9;
|
|
border-color: #43a047;
|
|
border-style: solid;
|
|
}
|
|
|
|
/* Error hook on wc-proccall — red to match WCEnd border */
|
|
button.hook.proccall-error-hook,
|
|
button.hook.proccall-error-hook[data-direction="out"] {
|
|
background: #ef5350; border-color: #ef5350;
|
|
}
|
|
button.hook.proccall-error-hook[data-direction="out"]:hover {
|
|
transform: scale(1.3);
|
|
box-shadow: 0 0 8px rgba(239,83,80,0.5), 0 1px 3px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
/* Error flow paths — red */
|
|
path.flow.flow-error { stroke: #ef5350; }
|
|
|
|
/* Blocks only reachable via error paths */
|
|
[data-block].error-path {
|
|
border-color: #ef5350;
|
|
background: #fff5f5;
|
|
}
|
|
|
|
wc-decision #hook-fore[data-direction="in"] {
|
|
left: -7px; top: 50%; transform: translateY(-50%); bottom: auto;
|
|
}
|
|
|
|
.selected {
|
|
box-shadow: 0 0 0 2px var(--accent), 0 1px 3px rgba(0,0,0,0.08);
|
|
}
|
|
|
|
/* Compact field display (replaces input/select inside blocks) */
|
|
#main-program > [data-block] .field-display {
|
|
font-size: 0.75rem; color: var(--text); white-space: nowrap;
|
|
overflow: hidden; text-overflow: ellipsis; max-width: 100%;
|
|
display: inline-block; line-height: 1.4;
|
|
}
|
|
|
|
.delete-btn {
|
|
position: absolute; top: -8px; right: -8px;
|
|
width: 18px; height: 18px; border-radius: 50%;
|
|
border: 1px solid #ccc; background: #fff; color: #999;
|
|
font-size: 13px; line-height: 1; cursor: pointer; padding: 0;
|
|
display: flex; align-items: center; justify-content: center;
|
|
z-index: 20; opacity: 0; transition: opacity 0.12s;
|
|
}
|
|
.delete-btn:hover {
|
|
opacity: 1 !important; background: #d32f2f; color: #fff; border-color: #d32f2f;
|
|
}
|
|
[data-block]:hover .delete-btn, .selected .delete-btn {
|
|
opacity: 0.6;
|
|
}
|
|
|
|
/* Edit (pencil) button — sits left of the delete button */
|
|
.edit-btn {
|
|
position: absolute; top: -8px; right: 14px;
|
|
width: 18px; height: 18px; border-radius: 50%;
|
|
border: 1px solid #ccc; background: #fff; color: #999;
|
|
cursor: pointer; padding: 0;
|
|
display: flex; align-items: center; justify-content: center;
|
|
z-index: 20; opacity: 0; transition: opacity 0.12s;
|
|
}
|
|
.edit-btn:hover {
|
|
opacity: 1 !important; background: var(--accent); color: #fff; border-color: var(--accent);
|
|
}
|
|
[data-block]:hover .edit-btn, .selected .edit-btn {
|
|
opacity: 0.6;
|
|
}
|
|
|
|
textarea { white-space: pre-wrap; }
|
|
select {
|
|
background: var(--bg); color: var(--text); border: 1px solid var(--border);
|
|
font: inherit; font-size: 0.75rem; padding: 0.1rem 0.2rem;
|
|
}
|
|
select option { background: var(--bg); color: var(--text); }
|
|
input { color-scheme: light; }
|
|
* { scrollbar-color: var(--border) var(--bg); scrollbar-width: thin; }
|
|
|
|
/* ── Procedure Browser Modal ── */
|
|
.proc-browser-overlay {
|
|
display: none; position: fixed; z-index: 99998;
|
|
top: 0; left: 0; right: 0; bottom: 0;
|
|
background: rgba(0,0,0,0.45);
|
|
align-items: center; justify-content: center;
|
|
}
|
|
.proc-browser-overlay.active { display: flex; }
|
|
|
|
.proc-browser-box {
|
|
background: #fff; color: #333;
|
|
border-radius: 8px; max-width: 500px; width: 90%;
|
|
max-height: 70vh; display: flex; flex-direction: column;
|
|
box-shadow: 0 4px 24px rgba(0,0,0,0.35);
|
|
}
|
|
|
|
.proc-browser-header {
|
|
padding: 0.75rem 1rem; font-weight: 600; font-size: 0.9rem;
|
|
border-bottom: 1px solid var(--border);
|
|
display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0;
|
|
}
|
|
|
|
.proc-browser-search {
|
|
flex: 1; padding: 0.3rem 0.5rem; border: 1px solid var(--border);
|
|
border-radius: 4px; font: inherit; font-size: 0.8rem;
|
|
outline: none; min-width: 0; color-scheme: light;
|
|
}
|
|
.proc-browser-search:focus { border-color: var(--accent); }
|
|
|
|
.proc-browser-tree {
|
|
flex: 1; overflow-y: auto; padding: 0.25rem 0;
|
|
min-height: 120px;
|
|
}
|
|
|
|
.proc-browser-empty {
|
|
padding: 2rem; text-align: center; color: var(--muted);
|
|
font-size: 0.85rem; display: none; line-height: 1.6;
|
|
}
|
|
.proc-browser-empty a {
|
|
color: var(--accent); text-decoration: underline; cursor: pointer;
|
|
}
|
|
|
|
/* Tree group (collapsible section for each library) */
|
|
.proc-browser-tree-group-header {
|
|
display: flex; align-items: center; gap: 0.3rem;
|
|
padding: 0.25rem 0.75rem; cursor: pointer;
|
|
user-select: none; font-size: 0.8rem;
|
|
border-top: 1px solid #eee; border-bottom: 1px solid #eee;
|
|
margin-top: -1px;
|
|
}
|
|
.proc-browser-tree-group-header:hover { background: #f5f5f5; }
|
|
.proc-browser-tree-group-header.user-defined {
|
|
font-weight: 700; border-top: 2px solid var(--accent); background: #f8faff;
|
|
}
|
|
|
|
.proc-browser-tree-arrow {
|
|
font-size: 0.55rem; color: var(--muted);
|
|
width: 0.8em; flex-shrink: 0;
|
|
}
|
|
|
|
.proc-browser-tree-group-name { font-weight: 600; }
|
|
|
|
.proc-browser-tree-group-count {
|
|
font-size: 0.65rem; color: var(--muted); margin-left: auto;
|
|
}
|
|
|
|
.proc-browser-tree-group-items { padding: 0; }
|
|
|
|
/* Tree leaf (individual procedure) */
|
|
.proc-browser-tree-leaf {
|
|
display: flex; align-items: center; gap: 0.5rem;
|
|
padding: 0.25rem 0.75rem 0.25rem 1.75rem;
|
|
cursor: pointer; font-size: 0.8rem;
|
|
border-left: 3px solid transparent;
|
|
}
|
|
.proc-browser-tree-leaf:hover { background: #f0f4ff; }
|
|
.proc-browser-tree-leaf.selected {
|
|
background: #e3f0ff; border-left-color: var(--accent); font-weight: 600;
|
|
}
|
|
.proc-browser-tree-leaf-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
.proc-browser-tree-leaf-qname {
|
|
font-size: 0.65rem; color: var(--muted);
|
|
font-family: 'Courier New', monospace; flex-shrink: 0;
|
|
}
|
|
|
|
.proc-browser-footer {
|
|
display: flex; gap: 0.5rem; justify-content: flex-end;
|
|
padding: 0.75rem 1rem;
|
|
border-top: 1px solid var(--border); flex-shrink: 0;
|
|
}
|
|
.proc-browser-footer button {
|
|
padding: 0.4rem 0.8rem; font: inherit; font-size: 0.8rem;
|
|
cursor: pointer; border-radius: 3px;
|
|
}
|
|
.proc-browser-cancel {
|
|
background: var(--bg); color: var(--text);
|
|
border: 1px solid var(--border);
|
|
}
|
|
.proc-browser-cancel:hover { background: #e8e8e8; }
|
|
.proc-browser-select {
|
|
background: var(--accent); color: #fff; border: none;
|
|
}
|
|
.proc-browser-select:hover { background: #357abd; }
|
|
|
|
/* ── In-app test panel ── */
|
|
#apptest-panel {
|
|
position: fixed; top: 0; right: 0; width: 380px; max-height: 100vh;
|
|
background: #1e1e2e; color: #cdd6f4; font-family: monospace; font-size: 0.75rem;
|
|
z-index: 10000; display: flex; flex-direction: column;
|
|
border-left: 2px solid #45475a; box-shadow: -4px 0 12px rgba(0,0,0,0.4);
|
|
}
|
|
#apptest-panel .apptest-toolbar {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 0.4rem 0.6rem; background: #181825; border-bottom: 1px solid #45475a;
|
|
}
|
|
#apptest-panel .apptest-title { font-weight: bold; font-size: 0.8rem; }
|
|
#apptest-panel .apptest-close {
|
|
background: none; border: none; color: #cdd6f4; cursor: pointer;
|
|
font-size: 1rem; padding: 0 0.3rem;
|
|
}
|
|
#apptest-panel .apptest-close:hover { color: #f38ba8; }
|
|
#apptest-panel .apptest-copy {
|
|
background: none; border: 1px solid #585b70; border-radius: 0.3rem;
|
|
color: #cdd6f4; cursor: pointer; font-size: 0.7rem; padding: 0.15rem 0.5rem;
|
|
margin-left: auto; margin-right: 0.5rem;
|
|
}
|
|
#apptest-panel .apptest-copy:hover { background: #313244; }
|
|
#apptest-panel .apptest-body {
|
|
flex: 1; overflow-y: auto; padding: 0.3rem 0;
|
|
}
|
|
#apptest-panel .apptest-group {
|
|
font-weight: bold; padding: 0.4rem 0.6rem 0.15rem;
|
|
color: #89b4fa; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
|
|
}
|
|
#apptest-panel .apptest-row {
|
|
display: flex; align-items: baseline; gap: 0.3rem;
|
|
padding: 0.15rem 0.6rem 0.15rem 1.2rem; line-height: 1.5;
|
|
}
|
|
#apptest-panel .apptest-icon { flex-shrink: 0; font-weight: bold; }
|
|
#apptest-panel .apptest-pass .apptest-icon { color: #a6e3a1; }
|
|
#apptest-panel .apptest-fail .apptest-icon { color: #f38ba8; }
|
|
#apptest-panel .apptest-name { }
|
|
#apptest-panel .apptest-detail {
|
|
color: #f38ba8; font-size: 0.65rem; margin-left: auto;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
#apptest-panel .apptest-summary {
|
|
padding: 0.5rem 0.6rem; font-weight: bold; text-align: center;
|
|
border-bottom: 1px solid #45475a;
|
|
}
|
|
#apptest-panel .apptest-summary.apptest-pass { color: #a6e3a1; }
|
|
#apptest-panel .apptest-summary.apptest-fail { color: #f38ba8; }
|
|
|
|
/* New Project modal */
|
|
.modal-overlay {
|
|
position: fixed; inset: 0; z-index: 100;
|
|
background: rgba(0,0,0,0.5);
|
|
display: flex; align-items: center; justify-content: center;
|
|
}
|
|
.modal {
|
|
background: var(--surface); border: 1px solid var(--border);
|
|
border-radius: 0.5rem; padding: 1.2rem 1.5rem;
|
|
min-width: 380px; max-width: 440px;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
|
|
}
|
|
.modal h2 { margin: 0 0 1rem; font-size: 1.1rem; }
|
|
.modal-field { margin-bottom: 1rem; }
|
|
.modal-field label {
|
|
display: block; font-size: 0.8rem; font-weight: 600;
|
|
margin-bottom: 0.3rem; color: var(--muted);
|
|
}
|
|
.modal-input {
|
|
width: 100%; padding: 0.4rem 0.5rem;
|
|
border: 1px solid var(--border); border-radius: 0.3rem;
|
|
font-size: 0.9rem; background: var(--bg); color: var(--text);
|
|
}
|
|
.template-list { display: flex; flex-direction: column; gap: 0.4rem; }
|
|
.template-card {
|
|
display: flex; align-items: center; gap: 0.6rem;
|
|
padding: 0.5rem 0.7rem; border: 1px solid var(--border);
|
|
border-radius: 0.3rem; cursor: pointer; user-select: none;
|
|
transition: border-color 0.15s, background 0.15s;
|
|
}
|
|
.template-card:hover { border-color: var(--accent); }
|
|
.template-card.selected {
|
|
border-color: var(--accent); background: #e8f0fe;
|
|
}
|
|
.template-card.selected .template-icon::after {
|
|
content: " \2713"; font-size: 0.85rem; color: var(--accent);
|
|
}
|
|
.template-icon { font-size: 1.3rem; flex-shrink: 0; }
|
|
.template-name { font-weight: 600; font-size: 0.85rem; }
|
|
.template-desc {
|
|
font-size: 0.7rem; color: var(--muted); margin-left: auto;
|
|
white-space: nowrap;
|
|
}
|
|
.modal-actions {
|
|
display: flex; justify-content: flex-end; gap: 0.5rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
.modal-btn {
|
|
padding: 0.4rem 1rem; border: 1px solid var(--border);
|
|
border-radius: 0.3rem; cursor: pointer; font-size: 0.85rem;
|
|
background: var(--bg); color: var(--text);
|
|
}
|
|
.modal-btn:hover { background: var(--surface); }
|
|
.modal-create { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
.modal-create:hover { opacity: 0.9; }
|
|
|
|
/* ── Block editor modal ── */
|
|
.block-editor-overlay {
|
|
position: fixed; inset: 0; z-index: 110;
|
|
background: rgba(0,0,0,0.4);
|
|
display: none; align-items: center; justify-content: center;
|
|
}
|
|
.block-editor-overlay.active { display: flex; }
|
|
.block-editor-modal {
|
|
background: var(--surface); border: 1px solid var(--border);
|
|
border-radius: 0.5rem; min-width: 360px; max-width: 480px;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
|
|
display: flex; flex-direction: column; max-height: 80vh;
|
|
}
|
|
.block-editor-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border);
|
|
}
|
|
.block-editor-title { font-weight: 600; font-size: 0.9rem; }
|
|
.block-editor-close {
|
|
background: none; border: none; font-size: 1.2rem; cursor: pointer;
|
|
color: var(--muted); padding: 0 0.2rem;
|
|
}
|
|
.block-editor-close:hover { color: var(--text); }
|
|
.block-editor-body {
|
|
padding: 0.8rem; overflow-y: auto; overflow-x: hidden; flex: 1;
|
|
}
|
|
.block-editor-body > [data-block] {
|
|
position: static !important;
|
|
width: 100% !important;
|
|
height: auto !important;
|
|
border: 1px solid var(--border);
|
|
background: var(--bg);
|
|
display: flex; flex-direction: column; gap: 0.4rem;
|
|
border-radius: 0.3rem; padding: 0.5rem;
|
|
}
|
|
.block-editor-body input,
|
|
.block-editor-body select,
|
|
.block-editor-body textarea {
|
|
width: 100%; box-sizing: border-box;
|
|
}
|
|
.block-editor-footer {
|
|
display: flex; justify-content: flex-end; gap: 0.4rem;
|
|
padding: 0.6rem 0.8rem; border-top: 1px solid var(--border);
|
|
}
|
|
.block-editor-footer button {
|
|
padding: 0.35rem 0.8rem; border-radius: 0.3rem; cursor: pointer;
|
|
font-size: 0.8rem; border: 1px solid var(--border);
|
|
background: var(--bg); color: var(--text);
|
|
}
|
|
.block-editor-footer .block-editor-apply {
|
|
background: var(--accent); color: #fff; border-color: var(--accent);
|
|
}
|
|
.block-editor-footer .block-editor-apply:hover { opacity: 0.9; }
|
|
.block-editor-footer .block-editor-cancel:hover { background: var(--surface); }
|
|
|
|
/* Colour picker row inside block editor */
|
|
.block-editor-color-row {
|
|
display: flex; align-items: center; gap: 0.5rem;
|
|
padding: 0.4rem 0.5rem; margin-bottom: 0.5rem;
|
|
background: var(--bg); border: 1px solid var(--border);
|
|
border-radius: 0.3rem; flex-wrap: wrap; box-sizing: border-box;
|
|
max-width: 100%;
|
|
}
|
|
.block-editor-color-label {
|
|
font-size: 0.75rem; font-weight: 600; color: var(--muted);
|
|
white-space: nowrap;
|
|
}
|
|
.block-editor-color-picker {
|
|
width: 32px; height: 24px; padding: 0; border: 1px solid var(--border);
|
|
border-radius: 3px; cursor: pointer; flex-shrink: 0; max-width: 100%;
|
|
}
|
|
.block-editor-color-reset {
|
|
font-size: 0.7rem; padding: 0.2rem 0.5rem;
|
|
border: 1px solid var(--border); border-radius: 3px;
|
|
cursor: pointer; background: var(--bg); color: var(--text);
|
|
}
|
|
.block-editor-color-reset:hover { background: var(--surface); }
|