/* Signal Flow Planner
   ---------------------------------------------------------------------
   An editor needs room, so this page bends the tool shell: the app body
   loses its padding, the window fills most of the viewport, and the article
   stays underneath it even on the ultrawide layouts that normally put it
   beside the tool. Canvas colours are their own tokens, because device
   port tabs stay light in dark mode (like the labels on real gear). */

.sfp {
    --sfp-canvas-bg: #eef1f5;
    --sfp-grid: #c3cad5;
    --sfp-port-bg: #ffffff;
    --sfp-port-text: #1a1a1a;
    --sfp-port-line: #c9ccd2;
    --sfp-frame: #1a1a1a;
    --sfp-shadow: rgba(26, 26, 26, 0.18);
    --sfp-select: #f7b32b;
    --sfp-ok: #16a34a;
    --sfp-warn: #e8a317;
    --sfp-err: #dc2626;
    --sfp-handle: #ffffff;
}

[data-theme="dark"] .sfp {
    --sfp-canvas-bg: #171717;
    --sfp-grid: #3b3b3b;
    --sfp-port-bg: #e7e7e7;
    --sfp-port-line: #a3a3a3;
    --sfp-frame: #000000;
    --sfp-shadow: rgba(0, 0, 0, 0.55);
    --sfp-handle: #171717;
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .sfp {
        --sfp-canvas-bg: #171717;
        --sfp-grid: #3b3b3b;
        --sfp-port-bg: #e7e7e7;
        --sfp-port-line: #a3a3a3;
        --sfp-frame: #000000;
        --sfp-shadow: rgba(0, 0, 0, 0.55);
        --sfp-handle: #171717;
    }
}

/* --- Shell overrides ------------------------------------------------- */

.container:has(.sfp) { max-width: 1800px; }
.app-body:has(.sfp) { padding: 0; }
.tool-page-wrapper:has(.sfp) { display: flex; flex-direction: column; }
@media (min-width: 1600px) {
    .tool-page-wrapper:has(.sfp) .tool-app-window { margin-bottom: 60px; }
    .tool-page-wrapper:has(.sfp) .article-text-container { margin: 0 auto; max-width: 800px; }
    .tool-page-wrapper:has(.sfp) .article-content { column-count: 1; }
}

/* --- Layout ------------------------------------------------------------ */

.sfp {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    height: clamp(560px, calc(100vh - 120px), 1400px);
    font-family: monospace;
}

.sfp-toolbar {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 8px 12px;
    border-bottom: var(--border-width) solid var(--border-color);
    background: var(--surface-alt);
}
.sfp-plan-title { font-weight: bold; font-size: 0.95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40ch; }
.sfp-saved { color: var(--text-muted); font-size: 0.75rem; }
.sfp-toolbar-gap { flex: 1 1 auto; }
.sfp-menu-wrap { position: relative; display: inline-flex; }
.sfp-menu {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;
    display: flex; flex-direction: column; min-width: 230px; padding: 6px 0;
    border: 2px solid var(--border-color); background: var(--surface-alt); box-shadow: 4px 4px 0 var(--border-color);
}
.sfp .sfp-menu button {
    display: flex; justify-content: space-between; gap: 12px; padding: 7px 12px; text-align: left;
    font-size: 0.75rem; text-transform: none; border: 0; background: transparent; color: var(--text-main);
}
.sfp .sfp-menu button span { color: var(--text-muted); }
.sfp .sfp-menu button:hover, .sfp .sfp-menu button:focus-visible { background: var(--primary); color: #1a1a1a; outline: none; }
.sfp .sfp-menu button:hover span, .sfp .sfp-menu button:focus-visible span { color: #1a1a1a; }
.sfp .sfp-menu button:active { transform: none; }
.sfp-menu-check {
    display: flex; align-items: center; gap: 8px; padding: 4px 12px 8px; margin-bottom: 4px;
    font-size: 0.72rem; border-bottom: 1px solid var(--surface-color); cursor: pointer;
}
.sfp-menu-check input { accent-color: var(--primary); }
.sfp-menu-head { padding: 4px 12px 6px; font-size: 0.68rem; font-weight: bold; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.sfp-view-menu .sfp-view-type { padding: 4px 12px; margin: 0; border: 0; font-size: 0.75rem; }
.sfp-view-type .sfp-muted { margin-left: auto; font-size: 0.7rem; }
.sfp-menu-row { display: flex; gap: 6px; padding: 8px 12px 4px; border-top: 1px solid var(--surface-color); margin-top: 4px; }
.sfp-design-row { border-top: 0; margin-top: 0; padding-top: 2px; padding-bottom: 8px; }
.sfp .sfp-menu-row button[aria-pressed="true"] { background: var(--primary); color: #1a1a1a; }
.sfp .sfp-menu-row button { flex: 1 1 auto; justify-content: center; white-space: nowrap; border: 2px solid var(--border-color); }
.sfp-menu-note { display: block; max-width: 230px; padding: 6px 12px 2px; font-size: 0.68rem; line-height: 1.4; color: var(--text-muted); }
.sfp .sfp-btn.is-filtered { background: var(--sfp-warn); color: #1a1a1a; }

.sfp-filter-chip {
    position: absolute; top: 10px; left: 10px; z-index: 2; display: flex; align-items: center; gap: 8px;
    max-width: calc(100% - 20px); margin: 0; padding: 4px 4px 4px 10px; font-size: 0.75rem;
    border: 2px solid var(--border-color); border-left: 6px solid var(--sfp-warn); background: var(--surface-alt); color: var(--text-main);
}
.sfp-filter-chip[hidden] { display: none; }
.sfp .sfp-filter-chip button { padding: 2px 8px; font-size: 0.68rem; border: 2px solid var(--border-color); background: var(--surface-color); color: var(--text-main); }
.sfp .sfp-filter-chip button:hover { background: var(--primary); color: #1a1a1a; }
.sfp-tb-group { display: inline-flex; gap: 4px; padding-left: 8px; border-left: 2px solid var(--surface-color); }
.sfp .sfp-btn:disabled { opacity: 0.35; cursor: default; }
.sfp .sfp-btn-toggle[aria-pressed="true"] { background: var(--primary); color: #1a1a1a; }
.sfp .sfp-btn:disabled:hover { background: var(--surface-color); color: var(--text-main); }
.sfp-zoom { display: inline-flex; align-items: center; gap: 4px; }
.sfp-zoom-level { min-width: 4.5ch; text-align: center; font-size: 0.8rem; }

.sfp .sfp-btn {
    padding: 5px 10px; font-size: 0.75rem; line-height: 1.2;
    border: 2px solid var(--border-color); background: var(--surface-color); color: var(--text-main);
}
.sfp .sfp-btn:hover { background: var(--primary); color: #1a1a1a; }
.sfp .sfp-btn-icon { padding: 5px 8px; min-width: 30px; }
.sfp .sfp-btn-danger:hover { background: var(--sfp-err); color: #ffffff; }
.sfp .sfp-btn-primary { background: var(--primary); color: #1a1a1a; }
.sfp .sfp-btn-primary:hover { background: var(--primary-hover); }

.sfp-main {
    --lib-w: 250px;
    --insp-w: 290px;
    display: grid;
    grid-template-columns: var(--lib-w) minmax(0, 1fr) var(--insp-w);
    grid-template-areas: "lib canvas insp";
    min-height: 0;
}
.sfp-library { grid-area: lib; }
.sfp-canvas-wrap { grid-area: canvas; }
.sfp-inspector { grid-area: insp; }
/* Folded panels: the canvas takes their room. */
.sfp.no-library .sfp-main { --lib-w: 0px; }
.sfp.no-inspector .sfp-main { --insp-w: 0px; }
.sfp.no-library .sfp-library, .sfp.no-inspector .sfp-inspector { display: none; }

.sfp-library, .sfp-inspector {
    min-height: 0; overflow-y: auto;
    background: var(--surface-color);
    font-size: 0.8rem;
}
.sfp-library { border-right: var(--border-width) solid var(--border-color); }
.sfp-inspector { border-left: var(--border-width) solid var(--border-color); padding: 14px 16px 24px; }

.sfp-canvas-wrap { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--sfp-canvas-bg); }
.sfp-svg { display: block; width: 100%; height: 100%; touch-action: none; user-select: none; -webkit-user-select: none; outline: none; }
.sfp-svg:focus-visible { box-shadow: inset 0 0 0 3px var(--primary); }

.sfp-empty, .sfp-status {
    position: absolute; left: 50%; transform: translateX(-50%);
    max-width: min(520px, calc(100% - 32px));
    margin: 0; padding: 8px 12px; text-align: center; font-size: 0.8rem;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
    pointer-events: none;
}
.sfp-empty { top: 40%; }
.sfp-status { bottom: 14px; }
.sfp-status:empty { display: none; }

.sfp-muted { color: var(--text-muted); }
/* Component rules set display on things that are sometimes hidden. */
.sfp [hidden] { display: none !important; }

/* --- Library ------------------------------------------------------------ */

.sfp-lib-head { position: sticky; top: 0; z-index: 1; padding: 10px; background: var(--surface-color); border-bottom: 2px solid var(--border-color); }
.sfp-lib-tools { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.sfp-lib-tools .sfp-btn { padding: 4px 7px; font-size: 0.7rem; }
.sfp-lib-tools [data-lib="new"] { flex: 1 1 auto; }
.sfp-lib-head input {
    width: 100%; padding: 7px 9px; font-family: monospace; font-size: 0.8rem;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-lib-head input:focus { outline: none; border-color: var(--primary); }
.sfp-lib-group h4 {
    margin: 0; padding: 12px 12px 4px;
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted);
}
.sfp-lib-row { display: flex; align-items: stretch; }
.sfp-lib-row:hover { background: var(--surface-alt); }
.sfp .sfp-lib-item {
    display: flex; align-items: center; gap: 10px; flex: 1 1 auto; min-width: 0;
    padding: 7px 12px; text-align: left; text-transform: none; font-weight: normal; font-size: 0.8rem;
    border: 0; border-bottom: 1px solid transparent; background: transparent; color: var(--text-main);
    cursor: grab; touch-action: none;
}
.sfp .sfp-lib-item:hover, .sfp .sfp-lib-item:focus-visible { background: var(--surface-alt); outline: none; }
.sfp .sfp-lib-item:active { transform: none; cursor: grabbing; }
.sfp-lib-swatch { flex: 0 0 auto; width: 14px; height: 22px; border: 2px solid var(--border-color); }
.sfp-lib-text { display: flex; flex-direction: column; min-width: 0; }
.sfp-lib-name { font-weight: bold; line-height: 1.25; }
.sfp-lib-meta { color: var(--text-muted); font-size: 0.7rem; line-height: 1.3; }
.sfp-lib-empty { padding: 12px; }
.sfp-lib-hint { padding: 2px 12px 8px; font-size: 0.72rem; line-height: 1.45; }
.sfp .sfp-lib-act {
    flex: 0 0 auto; width: 30px; padding: 0; font-size: 0.9rem; text-transform: none;
    border: 0; background: transparent; color: var(--text-muted); opacity: 0; cursor: pointer;
}
.sfp-lib-row:hover .sfp-lib-act, .sfp .sfp-lib-act:focus-visible { opacity: 1; }
.sfp .sfp-lib-act:hover { color: var(--text-main); background: var(--primary); }
.sfp .sfp-lib-act:active { transform: none; }
.sfp-lib-mine .sfp-lib-act { opacity: 0.7; }
@media (hover: none) { .sfp .sfp-lib-act { opacity: 0.7; } }

.sfp-ghost {
    position: fixed; left: 0; top: 0; z-index: 1000; pointer-events: none;
    padding: 6px 10px; font-family: monospace; font-size: 0.75rem; font-weight: bold;
    border: 2px solid #1a1a1a; background: #ffffff; color: #1a1a1a;
    box-shadow: 4px 4px 0 #1a1a1a; opacity: 0.6;
}
.sfp-ghost.is-over { opacity: 1; background: var(--primary); }

/* --- Inspector ------------------------------------------------------------ */

.sfp-kicker { margin: 0 0 2px; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.sfp-insp-title { margin: 0 0 2px; font-size: 1rem; line-height: 1.3; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.sfp-inspector h4 { margin: 18px 0 6px; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.sfp-inspector p { margin: 0 0 6px; }
.sfp-hint { color: var(--text-muted); font-size: 0.75rem; margin-top: 12px !important; }

.sfp-field { display: block; margin: 8px 0; }
.sfp-field span { display: block; font-weight: bold; margin-bottom: 4px; }
.sfp-field input {
    width: 100%; padding: 6px 8px; font-family: monospace; font-size: 0.85rem;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-field input:focus { outline: none; border-color: var(--primary); }
.sfp-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 0 10px; }
.sfp-meta .sfp-field { margin: 4px 0; }
.sfp-meta .sfp-meta-title, .sfp-meta .sfp-meta-venue { grid-column: 1 / -1; }
.sfp-meta .sfp-field input { padding: 5px 7px; font-size: 0.8rem; }
.sfp-meta-hint { margin-top: 2px !important; }

.sfp-ports, .sfp-findings, .sfp-legend, .sfp-help { list-style: none; margin: 0; padding: 0; }
.sfp-port-row { padding: 5px 0; border-bottom: 1px solid var(--surface-alt); }
.sfp-port-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.sfp-port-links { display: flex; flex-direction: column; padding-left: 16px; }
.sfp-type-dot { display: inline-block; flex: 0 0 auto; width: 10px; height: 10px; border: 1px solid var(--border-color); }
.sfp .sfp-mini-btn {
    margin-left: auto; padding: 1px 6px; font-size: 0.65rem;
    border: 1.5px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp .sfp-mini-btn:hover { background: var(--primary); color: #1a1a1a; }

.sfp .sfp-link {
    display: inline; padding: 0; border: 0; background: none; color: inherit;
    font: inherit; text-transform: none; text-align: left; cursor: pointer;
}
.sfp .sfp-link:hover { text-decoration: underline; }
.sfp .sfp-link:active { transform: none; }

.sfp-dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; margin: 12px 0; }
.sfp-dl dt { font-weight: bold; }
.sfp-dl dd { margin: 0; }

.sfp-findings li { position: relative; padding: 6px 8px 6px 14px; margin-bottom: 6px; background: var(--surface-alt); border-left: 4px solid var(--sfp-warn); }
.sfp-findings li.is-error { border-left-color: var(--sfp-err); }
.sfp-legend li { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.sfp-help li { padding: 3px 0 3px 14px; text-indent: -14px; }
.sfp-help li::before { content: '› '; color: var(--text-muted); }
.sfp-help kbd { font-family: monospace; font-size: 0.7rem; padding: 0 4px; border: 1px solid var(--border-color); background: var(--surface-alt); }

.sfp-insp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.sfp-insp-actions-top { margin-top: 4px; }
.sfp-cable-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 0 10px; }
.sfp-cable-fields .sfp-field { margin: 4px 0; }
.sfp-cable-fields .sfp-cable-note { grid-column: 1 / -1; }
.sfp-cable-fields input { padding: 5px 7px; font-size: 0.8rem; }
.sfp-field textarea {
    width: 100%; padding: 6px 8px; font-family: monospace; font-size: 0.85rem; line-height: 1.45; resize: vertical;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-field textarea:focus { outline: none; border-color: var(--primary); }
.sfp-swatches { display: flex; flex-wrap: wrap; gap: 6px; }
.sfp .sfp-swatch { width: 26px; height: 26px; padding: 0; border: 2px solid var(--border-color); }
.sfp .sfp-swatch-default { font-size: 0.7rem; text-transform: none; background: var(--surface-alt); color: var(--text-muted); }
.sfp .sfp-swatch.is-on { box-shadow: 0 0 0 2px var(--surface-color), 0 0 0 4px var(--primary); }
.sfp-seg { display: inline-flex; margin: 6px 0 4px; border: 2px solid var(--border-color); }
.sfp .sfp-seg button { padding: 4px 10px; font-size: 0.7rem; border: 0; background: var(--surface-alt); color: var(--text-main); }
.sfp .sfp-seg button + button { border-left: 2px solid var(--border-color); }
.sfp .sfp-seg button[aria-pressed="true"] { background: var(--primary); color: #1a1a1a; }
.sfp-align { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.sfp-align-2 { grid-template-columns: repeat(2, 1fr); margin-top: 4px; }
.sfp-align .sfp-btn { padding: 5px 4px; font-size: 0.68rem; text-transform: none; }

/* --- Canvas ---------------------------------------------------------------- */

.sfp-grid-dot { fill: var(--sfp-grid); }
.sfp-grid-line { fill: none; stroke: var(--sfp-grid); stroke-width: 0.75; opacity: 0.6; }

.sfp-dev-shadow { fill: var(--sfp-shadow); }
.sfp-dev-frame { fill: var(--sfp-port-bg); stroke: var(--sfp-frame); stroke-width: 1.5; }
.sfp-device { cursor: move; }
.sfp-device.is-selected .sfp-dev-frame { stroke: var(--sfp-select); stroke-width: 4; }
.sfp-dev-text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 700; text-anchor: middle; pointer-events: none; }
.sfp-dev-title { font-size: 12px; }
.sfp-dev-sub { font-size: 10px; opacity: 0.85; }
.sfp-dev-small { font-size: 9px; opacity: 0.65; text-transform: uppercase; letter-spacing: 0.04em; }

.sfp-port { cursor: crosshair; }
.sfp-port-cell { fill: var(--sfp-port-bg); stroke: var(--sfp-port-line); stroke-width: 1; }
.sfp-port-text {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 10px; font-weight: 700; text-anchor: middle; fill: var(--sfp-port-text); pointer-events: none;
}
.sfp-port:hover .sfp-port-cell { fill: #fff3cf; }
.sfp-port.is-warn .sfp-port-cell { fill: #fde9b8; }
.sfp-port.is-err .sfp-port-cell { fill: #fbd0d0; }
.sfp-port.is-dim { opacity: 0.45; }
.sfp-port.is-target-ok .sfp-port-cell { fill: #c9f2d6; stroke: var(--sfp-ok); stroke-width: 1.5; }
.sfp-port.is-target-mismatch .sfp-port-cell { fill: #fde9b8; stroke: var(--sfp-warn); stroke-width: 1.5; }
.sfp-port.is-hover .sfp-port-cell { stroke-width: 3; }

.sfp-cable-hit { fill: none; stroke: transparent; stroke-width: 12; cursor: pointer; }
.sfp-cable-line { fill: none; stroke-width: 2; stroke-linejoin: round; pointer-events: none; }
.sfp-cable-arrow { pointer-events: none; }
.sfp-cable.is-selected .sfp-cable-line { stroke-width: 3.5; }
.sfp-cable:hover .sfp-cable-line { stroke-width: 3; }
.sfp-cable-tag { cursor: pointer; }
.sfp-cable-tag rect { fill: var(--sfp-canvas-bg); stroke-width: 1; }
.sfp-cable-tag text {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 9px; font-weight: 700; text-anchor: middle; fill: var(--text-main);
}
.sfp-cable-tag.is-selected rect { stroke-width: 2.5; }
.sfp-handle { fill: var(--sfp-handle); stroke: var(--sfp-select); stroke-width: 2.5; cursor: grab; }
.sfp-handle:hover { fill: var(--sfp-select); }
.sfp-preview { fill: none; stroke-width: 2.5; stroke-dasharray: 6 4; pointer-events: none; }

/* Zones sit behind everything. Only the name tab takes the pointer, so
   empty space inside a zone still pans and box-selects. */
.sfp-zone-area { fill-opacity: 0.1; stroke-opacity: 0.75; stroke-width: 1.5; pointer-events: none; }
.sfp-zone-head { cursor: move; }
.sfp-zone-label {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; pointer-events: none;
}
.sfp-zone.is-selected .sfp-zone-area { stroke: var(--sfp-select); stroke-opacity: 1; stroke-width: 3; }

/* Notes and headings sit on top of everything. */
.sfp-note { cursor: move; }
.sfp-note-bg { fill: #fde68a; stroke: #b45309; stroke-opacity: 0.35; filter: drop-shadow(3px 3px 0 var(--sfp-shadow)); }
.sfp-note-text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; fill: #3b2f0b; white-space: pre; pointer-events: none; }
.sfp-note.is-kind-note .sfp-note-text { font-weight: 600; }
.sfp-note.is-kind-text .sfp-note-text { font-weight: 800; fill: var(--text-main); }
.sfp-note.is-kind-text .sfp-note-bg { fill: transparent; stroke: none; filter: none; }
.sfp-note.is-empty .sfp-note-text { opacity: 0.45; font-style: italic; }
.sfp-note.is-selected .sfp-note-bg { stroke: var(--sfp-select); stroke-opacity: 1; stroke-width: 3; }
.sfp-note.is-kind-text.is-selected .sfp-note-bg { stroke: var(--sfp-select); stroke-dasharray: 4 3; stroke-width: 2; }

.sfp-resize { fill: var(--sfp-handle); stroke: var(--sfp-select); stroke-width: 2.5; }
.sfp-resize-corner { cursor: nwse-resize; }
.sfp-resize-edge { cursor: ew-resize; }
.sfp-box { fill: var(--sfp-select); fill-opacity: 0.08; stroke: var(--sfp-select); stroke-width: 1.5; stroke-dasharray: 5 3; vector-effect: non-scaling-stroke; pointer-events: none; }
.sfp-svg.is-space, .sfp-svg.is-space * { cursor: grab !important; }
.sfp-svg.is-panning, .sfp-svg.is-panning * { cursor: grabbing !important; }

/* --- Designs (see ui/designs.js) ----------------------------------------------
   Classic: each device in its own colours with edge bars, a soft shadow and
   a dot grid. New ("plain"): white devices, or the colour picked for one,
   no edge bars, a heavier frame and a hard offset shadow like the site's
   own cards, and a line grid. Only the rules below differ between them. */

.sfp:not([data-design="plain"]) .sfp-grid-line { display: none; }
.sfp[data-design="plain"] .sfp-grid-dot { display: none; }
.sfp[data-design="plain"] .sfp-dev-frame { stroke: var(--border-color); stroke-width: 2; }
.sfp[data-design="plain"] .sfp-dev-shadow { fill: var(--border-color); }
.sfp[data-design="plain"] .sfp-device.is-selected .sfp-dev-frame { stroke: var(--sfp-select); stroke-width: 4; }
.sfp-lib-swatch { background: var(--swatch-bg); }
.sfp[data-design="plain"] .sfp-note.is-kind-note .sfp-note-bg {
    fill: #ffffff; stroke: var(--border-color); stroke-opacity: 1; stroke-width: 2;
    filter: drop-shadow(4px 4px 0 var(--border-color));
}
.sfp[data-design="plain"] .sfp-note.is-kind-note .sfp-note-text { fill: #1a1a1a; }
.sfp[data-design="plain"] .sfp-note.is-kind-note.is-selected .sfp-note-bg { stroke: var(--sfp-select); stroke-width: 3; }
.sfp[data-design="plain"] .sfp-lib-swatch { background: var(--swatch-fill, #ffffff); }

/* Zoomed far out, port names are unreadable — keep the tabs, drop the text. */
.sfp-svg.is-far .sfp-port-text { display: none; }

/* --- Dropping a file on the editor ------------------------------------------ */

.sfp.is-dropping .sfp-canvas-wrap { box-shadow: inset 0 0 0 4px var(--primary); }
.sfp.is-dropping .sfp-canvas-wrap::after {
    content: 'Drop a plan or device file'; position: absolute; inset: auto 0 45%; text-align: center;
    font-weight: bold; color: var(--text-main); pointer-events: none;
}

/* --- Device builder ----------------------------------------------------------- */

.sfp-builder {
    width: min(980px, calc(100vw - 32px)); max-height: calc(100vh - 32px);
    padding: 0; margin: auto; overflow: hidden;
    border: var(--border-width) solid var(--border-color); box-shadow: 8px 8px 0 var(--border-color);
    background: var(--surface-color); color: var(--text-main); font-family: monospace;
}
.sfp-builder::backdrop { background: rgba(0, 0, 0, 0.45); }
.sfp-b { display: flex; flex-direction: column; max-height: calc(100vh - 36px); }
.sfp-b-head, .sfp-b-foot {
    /* margin: 0 undoes the site's own header and footer spacing. */
    display: flex; align-items: center; gap: 8px; padding: 10px 16px; margin: 0;
    background: var(--surface-alt); flex: 0 0 auto;
}
.sfp-b-head { border-bottom: 2px solid var(--border-color); }
.sfp-b-head h2 { margin: 0; flex: 1 1 auto; font-size: 1rem; }
.sfp-b-foot { border-top: 2px solid var(--border-color); flex-wrap: wrap; }
.sfp-b-note { flex: 1 1 200px; margin: 0; font-size: 0.75rem; }
.sfp-b-scroll { overflow-y: auto; padding: 16px; display: grid; grid-template-columns: 1fr 1fr; gap: 16px 20px; align-content: start; }

.sfp-b-preview {
    grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; gap: 6px;
    padding: 18px 12px 10px; background: var(--sfp-canvas-bg); border: 2px solid var(--border-color);
}
.sfp-b-svg { display: block; max-width: 100%; height: auto; }
.sfp-b-summary { margin: 0; font-size: 0.72rem; }

.sfp-b-fields { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0 16px; }
.sfp-b-fields .sfp-field { margin: 4px 0; font-size: 0.8rem; }
.sfp-field input.is-invalid { border-color: var(--sfp-err); }
.sfp-b-fields .sfp-b-colors { grid-column: 1 / -1; }
.sfp-b-colors label { display: inline-flex; align-items: center; gap: 6px; margin: 0 12px 4px 0; font-weight: normal; }
.sfp-b-colors input[type="color"] { width: 34px; height: 26px; padding: 0 2px; border: 2px solid var(--border-color); background: var(--surface-alt); cursor: pointer; }
.sfp-b-colors input[type="color"]:disabled { opacity: 0.35; cursor: default; }
.sfp-b-colors input[type="checkbox"] { width: auto; padding: 0; accent-color: var(--primary); }

.sfp-b-row h3 { margin: 0 0 6px; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; }
.sfp-b-ports { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.sfp-b-port {
    display: grid; grid-template-columns: 22px minmax(60px, 1fr) 96px 70px auto 26px; gap: 4px; align-items: center;
    padding: 3px; background: var(--surface-alt); border: 1px solid transparent;
}
.sfp-b-port.is-dragging { border-color: var(--primary); box-shadow: 3px 3px 0 var(--border-color); }
.sfp-b-port input[type="text"], .sfp-b-port select {
    width: 100%; min-width: 0; padding: 4px 5px; font-family: monospace; font-size: 0.75rem;
    border: 1.5px solid var(--border-color); background: var(--surface-color); color: var(--text-main);
}
.sfp-b-port input[type="text"]:focus, .sfp-b-port select:focus { outline: none; border-color: var(--primary); }
.sfp .sfp-b-grip, .sfp .sfp-b-pdel {
    padding: 0; height: 24px; font-size: 0.85rem; line-height: 1; text-transform: none;
    border: 0; background: transparent; color: var(--text-muted);
}
.sfp .sfp-b-grip { cursor: grab; touch-action: none; }
.sfp .sfp-b-grip:active { cursor: grabbing; transform: none; }
.sfp .sfp-b-pdel:hover { color: #ffffff; background: var(--sfp-err); }
.sfp-b-pswitch { display: inline-flex; align-items: center; gap: 4px; font-size: 0.68rem; color: var(--text-muted); white-space: nowrap; }
.sfp-b-empty { padding: 6px 4px; font-size: 0.75rem; }
.sfp-b-add { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.sfp-b-add .sfp-btn { font-size: 0.7rem; padding: 4px 8px; }
.sfp-b-bulk {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px; margin-top: 8px; padding: 8px;
    border: 2px dashed var(--border-color); font-size: 0.7rem;
}
.sfp-b-bulk label { display: flex; flex-direction: column; gap: 2px; }
.sfp-b-bulk input, .sfp-b-bulk select {
    width: 80px; padding: 4px 5px; font-family: monospace; font-size: 0.75rem;
    border: 1.5px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-b-bulk input[type="number"] { width: 64px; }

@media (max-width: 760px) {
    .sfp-b-scroll { grid-template-columns: 1fr; }
    .sfp-b-port { grid-template-columns: 22px 1fr 1fr 26px; }
    .sfp-b-port .sfp-b-pdir { grid-column: 2; }
    .sfp-b-port .sfp-b-pswitch { grid-column: 3; }
}

/* --- Cable list ------------------------------------------------------------------ */

.sfp-cablelist { width: min(1100px, calc(100vw - 32px)); }
.sfp-cl-tools {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding: 10px 16px; border-bottom: 2px solid var(--border-color); flex: 0 0 auto;
}
.sfp-cl-tools input[type="search"], .sfp-cl-sep select {
    padding: 5px 8px; font-family: monospace; font-size: 0.8rem;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-cl-tools input[type="search"] { flex: 0 1 240px; min-width: 0; }
.sfp-cl-gap { flex: 1 1 auto; }
.sfp-cl-sep { display: inline-flex; align-items: center; gap: 6px; font-size: 0.75rem; color: var(--text-muted); }
.sfp-cl-scroll { overflow: auto; padding: 0 16px 12px; min-height: 120px; }
.sfp-cl-table { width: 100%; margin: 0; border-collapse: collapse; font-size: 0.8rem; font-variant-numeric: tabular-nums; }
/* Undo the site's generic centred, boxed table cells. */
.sfp-cl-table th, .sfp-cl-table td { border: 0; text-align: left; font-family: monospace; }
.sfp-cl-table th {
    position: sticky; top: 0; z-index: 1; padding: 10px 8px 6px; text-align: left;
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted);
    background: var(--surface-color); border-bottom: 2px solid var(--border-color);
}
.sfp-cl-table td { padding: 4px 8px; border-bottom: 1px solid var(--surface-alt); vertical-align: middle; }
.sfp-cl-table td:nth-child(4) { width: 96px; }
.sfp-cl-table td:nth-child(5) { width: 30%; }
.sfp-cl-table td input {
    width: 100%; padding: 4px 6px; font-family: monospace; font-size: 0.8rem;
    border: 1.5px solid transparent; background: transparent; color: var(--text-main);
}
.sfp-cl-table td input:hover { border-color: var(--surface-alt); }
.sfp-cl-table td input:focus { outline: none; border-color: var(--primary); background: var(--surface-alt); }
.sfp-cl-cable { white-space: nowrap; }
.sfp .sfp-cl-tag {
    padding: 2px 6px; font-size: 0.75rem; text-transform: none; letter-spacing: 0.02em;
    border: 1.5px solid var(--tag); border-left-width: 5px; background: var(--surface-alt); color: var(--text-main);
}
.sfp .sfp-cl-tag:hover { background: var(--primary); color: #1a1a1a; }
.sfp .sfp-cl-tag:active { transform: none; }
.sfp-cl-warn {
    display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px;
    font-size: 0.7rem; font-weight: bold; color: #1a1a1a; background: var(--sfp-warn); cursor: help;
}
.sfp-cl-empty { padding: 16px 0; }
.sfp-cl-totals { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; font-size: 0.75rem; flex: 1 1 auto; }
.sfp-cl-msg { margin: 0; font-size: 0.75rem; color: var(--text-muted); }

/* --- ATEM port naming --------------------------------------------------------- */

.sfp-atem { width: min(820px, calc(100vw - 32px)); }
.sfp-atem-intro { padding: 12px 16px 4px; font-size: 0.8rem; flex: 0 0 auto; }
.sfp-atem-intro p { margin: 0 0 10px; line-height: 1.5; }
.sfp-atem-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.sfp-atem-notes { margin: 10px 0 0; padding: 0; list-style: none; }
.sfp-atem-notes li { padding: 5px 8px; margin-bottom: 4px; background: var(--surface-alt); border-left: 4px solid var(--sfp-warn); }
.sfp-atem-table td:first-child { width: 28px; }
.sfp-atem-table input[type="checkbox"] { width: auto; accent-color: var(--primary); }
.sfp-atem-table .sfp-atem-section th {
    position: static; padding: 12px 8px 4px; border-bottom: 1px solid var(--border-color); background: transparent;
}
.sfp-atem-table tr.is-same td { opacity: 0.55; }
.sfp-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* --- Narrow screens --------------------------------------------------------- */

@media (max-width: 980px) {
    .sfp { height: auto; grid-template-rows: auto auto; }
    .sfp-main { grid-template-columns: 1fr; grid-template-areas: "canvas" "lib" "insp"; }
    .sfp-canvas-wrap { order: -1; height: 65vh; min-height: 380px; }
    .sfp-library { max-height: 340px; border-right: 0; border-top: var(--border-width) solid var(--border-color); }
    .sfp-inspector { border-left: 0; border-top: var(--border-width) solid var(--border-color); }
}

/* --- Printing ----------------------------------------------------------------
   While printing, everything but a copy of the drawing is hidden; see
   printSheet() in app.js. @page margin is 0 and the margin is padding on
   the print root instead, because some browsers ignore @page margins. */

#sfp-print-root { display: none; }
/* --- Embed link window ------------------------------------------------- */

.sfp-share { width: min(620px, calc(100vw - 32px)); }
.sfp-share-body { display: flex; flex-direction: column; gap: 10px; padding: 14px 16px; overflow-y: auto; font-size: 0.8rem; line-height: 1.5; }
.sfp-share-body p { margin: 0; }
.sfp-share-options { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; }
.sfp-share-check { display: inline-flex; align-items: center; gap: 6px; font-size: 0.75rem; cursor: pointer; }
.sfp-share-check input { accent-color: var(--primary); }
.sfp-share-label { font-size: 0.68rem; font-weight: bold; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.sfp-share-link {
    width: 100%; min-height: 5.5em; padding: 8px; resize: vertical; word-break: break-all;
    font: 0.72rem/1.4 monospace; border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-share-facts { font-size: 0.72rem; font-variant-numeric: tabular-nums; }
.sfp-share-notes { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: 4px; font-size: 0.75rem; }
.sfp-b-foot a.sfp-btn { font-weight: normal; text-decoration: none; }

/* --- Read-only viewer (/signal-flow/view/) ---------------------------
   A shared drawing on its own, filling whatever frame embeds it. The
   caption and view buttons float over the canvas, so the drawing gets the
   whole frame. */

html:has(.sfp-viewer), body.bare-body { height: 100%; }
body.bare-body { overflow: hidden; }
.sfp.sfp-viewer { display: block; height: 100%; }
.sfp-viewer .sfp-canvas-wrap { height: 100%; }
.sfp-viewer .sfp-svg { cursor: grab; }
.sfp-viewer .sfp-svg.is-panning, .sfp-viewer .sfp-svg.is-panning * { cursor: grabbing !important; }
.sfp-viewer .sfp-svg * { cursor: inherit; }

.sfp-viewer-caption {
    position: absolute; top: 8px; left: 8px; z-index: 2; max-width: calc(100% - 16px);
    margin: 0; padding: 3px 10px; font-size: 0.75rem; line-height: 1.5;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
}
.sfp-viewer-caption .sfp-muted { color: var(--text-muted); }
.sfp-viewer-tools {
    position: absolute; right: 8px; bottom: 8px; z-index: 2; display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end;
}
.sfp-viewer-tools .sfp-btn { box-shadow: 2px 2px 0 var(--border-color); }
.sfp-viewer-tools a.sfp-btn { display: inline-flex; align-items: center; font-weight: normal; text-decoration: none; }
.sfp-viewer-message {
    position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; padding: 16px;
}
.sfp-viewer-message > div {
    max-width: 46ch; padding: 14px 18px; font-size: 0.85rem; line-height: 1.5;
    border: 2px solid var(--border-color); background: var(--surface-alt); color: var(--text-main);
    box-shadow: 4px 4px 0 var(--border-color);
}
.sfp-viewer-message a { text-decoration: underline; }

@media print {
    body.sfp-printing > *:not(#sfp-print-root) { display: none !important; }
    body.sfp-printing { background: #ffffff !important; margin: 0; }
    body.sfp-printing #sfp-print-root {
        display: flex; align-items: center; justify-content: center;
        box-sizing: border-box; width: 100vw; height: 100vh; padding: 10mm;
        break-inside: avoid; page-break-inside: avoid; overflow: hidden;
    }
    #sfp-print-root img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; }

    /* The cable list prints as a document: it may run over several pages,
       and its table header repeats on each. */
    body.sfp-printing #sfp-print-root.is-list {
        display: block; width: auto; height: auto; padding: 0; overflow: visible;
        font-family: ui-sans-serif, system-ui, -apple-system, sans-serif; font-size: 9.5pt; color: #1a1a1a;
    }
    .sfp-pl-head { margin-bottom: 6mm; }
    .sfp-pl-kicker { margin: 0; font-size: 8pt; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #555; }
    .sfp-pl-head h1 { margin: 1mm 0 2mm; font-size: 16pt; }
    .sfp-pl-facts, .sfp-pl-totals { display: flex; flex-wrap: wrap; gap: 2mm 6mm; margin: 0; font-size: 9pt; }
    .sfp-pl-totals { margin-top: 4mm; }
    .sfp-pl-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
    .sfp-pl-table thead { display: table-header-group; }
    .sfp-pl-table tr { break-inside: avoid; page-break-inside: avoid; }
    .sfp-pl-table th {
        text-align: left; padding: 1.5mm 2mm; font-size: 7.5pt; text-transform: uppercase; letter-spacing: 0.05em;
        border-bottom: 1.5pt solid #1a1a1a;
    }
    .sfp-pl-table td { padding: 1.5mm 2mm; border-bottom: 0.5pt solid #bbb; vertical-align: top; }
    .sfp-pl-label {
        font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 700; white-space: nowrap;
        border-left: 3pt solid var(--tag); -webkit-print-color-adjust: exact; print-color-adjust: exact;
    }
    .sfp-pl-num { text-align: right; }
}
