/* The architecture profile: components on the canvas, their outline and
   inspector, and the tree chrome that has no meaning here, put away.
   app.js sets data-profile on the workspace. */

/* Tree-only chrome: the importance legend, cut sets, charts, controls, assets
   and the tree's structure tools. */
.workspace[data-profile="architecture"] .tree-only { display: none !important; }
.workspace:not([data-profile="architecture"]) .architecture-only { display: none !important; }
/* An architecture has two views, set by app.js as data-view: the components,
   and the attack graph generated from them. */
.workspace:not([data-view="attack"]) .attack-only { display: none !important; }
.workspace[data-view="attack"] .architecture-view-only { display: none !important; }

/* A component, as an investigation graph draws an entity: its kind's icon,
   white on a plate in its family's colour, the name under it — no box, no
   fault symbol, no importance colour. The halo ring is quiet until the
   component is selected; a value still owed dashes it, as a tree leaf's
   outline is dashed. */
.node-component .plate { stroke: none; }
.node-component.family-network .plate { fill: var(--viz-family-network); }
.node-component.family-compute .plate { fill: var(--viz-family-compute); }
.node-component.family-identity .plate { fill: var(--viz-family-identity); }
.node-component.family-data .plate { fill: var(--viz-family-data); }
.node-component.family-none .plate { fill: var(--viz-outline); }
.node-component .glyph { fill: none; stroke: var(--viz-family-ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.node-component .halo { fill: var(--viz-canvas); stroke: transparent; stroke-width: 2; }
.node-component:hover .halo { stroke: var(--viz-outline); }
.node-component.is-unquantified .halo { stroke: var(--viz-outline); stroke-dasharray: 5 3; }
/* A ring outside the halo per state a component is in (after Reactor's
   exposure ring): vulnerable, an unpatched product; exposed, what runs it. */
.node-component .ring { fill: none; stroke-width: 3; }
.node-component .ring-vulnerable { stroke: var(--color-danger); }
.node-component .ring-exposed { stroke: var(--color-exposed); }
/* Every way to the target passes here: a thin double line, outside. */
.node-component .ring-choke { stroke: var(--color-fg-primary); stroke-width: 1.25; stroke-dasharray: 8 2 1 2; }
.node.is-choke .shape { stroke-width: 2; }
/* A cluster (clustering spec §4.1): a plate behind its plate, and its ring
   in sectors, one per member: vulnerable, exposed, unknown inputs, or none. */
.node-component .plate-behind { opacity: 0.5; }
.node-component .sector-vulnerable { stroke: var(--color-danger); }
.node-component .sector-exposed { stroke: var(--color-exposed); }
/* Dashed as well as amber: under red-green colour blindness amber and the
   danger red are nearly one colour (light theme). */
.node-component .sector-unknown { stroke: var(--color-warning); stroke-dasharray: 5 3; }
.node-component .sector-none { stroke: var(--viz-edge); }

/* An open cluster: a quiet outline round its members, taking the pointer
   on its line and its name only. */
.cluster-outline .outline { fill: none; stroke: var(--viz-edge); stroke-width: 1.5; stroke-dasharray: 6 4; pointer-events: none; }
.cluster-outline .outline-hit { fill: none; stroke: transparent; stroke-width: 14; pointer-events: stroke; cursor: pointer; }
.cluster-outline .outline-tab { fill: var(--color-bg-surface); stroke: var(--color-border-strong); stroke-width: 1; cursor: pointer; }
.cluster-outline .outline-label { font-size: 11px; fill: var(--color-fg-secondary); pointer-events: none; }
.cluster-outline:hover .outline { stroke: var(--color-fg-muted); }
.cluster-outline:hover .outline-tab { stroke: var(--color-fg-muted); }
.cluster-outline.hl-selected .outline { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: none; }
.cluster-outline.hl-selected .outline-tab { stroke: var(--color-accent); }
.cluster-outline.hl-selected .outline-label { fill: var(--color-accent); }
.node-component.hl-selected .halo { stroke: var(--color-accent); stroke-width: 2.5; stroke-dasharray: none; }
/* A selected flow's route: the networks and routers it passes through. */
.node-component.hl-route .halo { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
/* The name reads over lines that pass under it. */
.node-component .label-line { paint-order: stroke; stroke: var(--viz-canvas); stroke-width: 3px; stroke-linejoin: round; }
.node-component .count { fill: var(--viz-canvas); stroke: var(--viz-outline); stroke-width: 1; stroke-dasharray: 3 2; }
.node-component .blocked-mark { fill: var(--color-warning); stroke: var(--viz-canvas); stroke-width: 1.5; }
.outline .blocked { flex: none; color: var(--color-warning); font-size: var(--text-xs); }
.node-component .count-text { fill: var(--color-fg-secondary); font-family: var(--font-mono); font-size: 9.5px; font-weight: 600; text-anchor: middle; }

/* The icons outside the canvas — the Add menu, the legend — are lines in the
   colour of the words beside them. */
.kind-icon { flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
.menu .kind-icon { margin-right: 8px; color: var(--color-fg-secondary); }
/* The legend shows them as the canvas does: white on the family's plate. */
.kind-icon.is-plate { padding: 3px; border-radius: 50%; color: var(--viz-family-ink); background: var(--viz-outline); stroke-width: 1.6; }
.kind-icon.is-plate.family-network { background: var(--viz-family-network); }
.kind-icon.is-plate.family-compute { background: var(--viz-family-compute); }
.kind-icon.is-plate.family-identity { background: var(--viz-family-identity); }
.kind-icon.is-plate.family-data { background: var(--viz-family-data); }
.help-legend { margin-top: 12px; }
.help-legend dt { display: flex; align-items: center; }
.help-legend .legend-meaning { display: block; max-width: 46ch; margin: 0 0 4px; }

/* A flow is traffic, not structure: twice a relationship's weight, a solid
   chevron at its middle for the way it runs (renderer-svg.js). */
.edge[data-id^="flow/"], .edge[data-id^="flows/"] { stroke-width: 3; }
.flow-chevron { fill: var(--viz-edge); stroke: none; }
/* A firewall's permission on a flow: dotted, in the firewall's own colour,
   ending in a dot where it lands on the flow — so it never reads as another
   flow. Its word says allows, blocks or ?. */
.edge.permit { stroke: var(--viz-family-network); stroke-dasharray: 1.5 3.5; stroke-linecap: round; stroke-width: 1.75; }
.edge.permit.hl-selected { stroke: var(--color-accent); stroke-dasharray: 1.5 3.5; }
.permit-dot { fill: var(--viz-family-network); pointer-events: none; }
.edge-label.permit-label { font-style: italic; }

/* The bottom bar's legend for an architecture: the families, the lines — and
   the permission, which is also the switch that hides them. */
.swatch-network { background: var(--viz-family-network); border-color: transparent; }
.swatch-compute { background: var(--viz-family-compute); border-color: transparent; }
.swatch-identity { background: var(--viz-family-identity); border-color: transparent; }
.swatch-data { background: var(--viz-family-data); border-color: transparent; }
.line-sample { display: inline-block; width: 18px; height: 0; margin-right: 5px; border-top: 1.5px solid var(--viz-edge); vertical-align: middle; }
.line-flow { position: relative; border-top-width: 3px; }
.line-flow::after { content: ""; position: absolute; left: 5px; top: -6.5px; width: 0; height: 0; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 8px solid var(--viz-edge); }
.line-permit { border-top: 2px dotted var(--viz-family-network); }
.outline-sample { display: inline-block; width: 14px; height: 9px; margin-right: 5px; border: 1.5px dashed var(--color-border-strong); border-radius: 4px; vertical-align: middle; }
.ring-sample { display: inline-block; width: 9px; height: 9px; margin-right: 5px; border-radius: 50%; border: 2.5px solid var(--color-danger); vertical-align: middle; }
.ring-sample.is-exposed { border-color: var(--color-exposed); }
.ring-sample.is-unknown { border-color: var(--color-warning); border-style: dashed; }
.ring-sample.is-blocked { border: 2px dotted var(--color-fg-primary); }
.ring-sample.is-choke { border: 1.5px dashed var(--color-fg-primary); }
/* The attack graph's keys drawn as its boxes and badges are. */
.box-sample { display: inline-block; width: 14px; height: 9px; margin-right: 5px; border: 1.25px solid var(--viz-outline); border-radius: 2px; background: var(--color-bg-elevated); vertical-align: middle; }
.box-sample.is-seeded { background: var(--color-bg-active); }
.box-sample.is-unreachable { opacity: 0.45; }
.legend-tag.is-badge { background: none; color: var(--color-fg-primary); box-shadow: inset 0 0 0 1px var(--color-fg-primary); }
.legend-toggle, .legend-kinds { padding: 1px 6px; font-size: var(--text-xs); }
.legend-kinds { display: inline-flex; align-items: center; gap: 5px; }
.legend-toggle[aria-pressed="false"] { color: var(--color-fg-muted); text-decoration: line-through; }
.legend-toggle[aria-pressed="false"] .line-sample { opacity: 0.4; }

/* The outline: kind, then label. */
.outline .kind-word { flex: none; width: 6.5em; color: var(--color-fg-muted); font-size: var(--text-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Parameters: one line each, one opened at a time to be edited. */
.parameters { grid-column: 1 / -1; margin: 0; padding: 0; list-style: none; }
.parameters > li { border-top: 1px solid var(--color-border); }
.parameter-head { display: grid; grid-template-columns: 1fr auto; gap: 8px; width: 100%; padding: 3px 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.parameter-head:hover { color: var(--color-fg-primary); background: var(--color-bg-hover); }
.parameter-head .slot { font-family: var(--font-mono); font-size: var(--text-xs); }
.parameter-head .rests-on { color: var(--color-accent); font-weight: 600; }
.parameter-head .given { color: var(--color-fg-secondary); font-family: var(--font-mono); font-size: var(--text-xs); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14em; }
.parameter-head .given.is-unknown { color: var(--color-fg-muted); }
.parameter-form { display: grid; grid-template-columns: auto 1fr; gap: 5px 8px; align-items: center; padding: 4px 0 8px; }
.parameter-form .actions { grid-column: 1 / -1; display: flex; gap: 6px; }
.diagnostics { grid-column: 1 / -1; margin: 0; padding: 0; list-style: none; color: var(--color-fg-muted); font-size: var(--text-xs); }
.diagnostics li::before { content: "· "; }
.diagnostics li.is-blocking { color: var(--color-fg-primary); }
.diagnostics li.is-blocking::before { content: "■ "; color: var(--color-warning); }
.diagnostic-hint { display: block; padding-left: 1ch; color: var(--color-accent); }

/* Relationship lines carry a few words: the relation, a flow's name — and an
   arrowhead; a component is moved by dragging it. */
.edge-label { fill: var(--color-fg-muted); font-size: 10px; text-anchor: middle; pointer-events: none; }
.arrow-head { fill: var(--viz-edge); }
.graph.is-moving { cursor: grabbing; }

/* A component's links and flows: one line each, a + to add. */
.link-block { grid-column: 1 / -1; border-top: 1px solid var(--color-border); padding-top: 4px; }
.link-head { display: flex; align-items: center; justify-content: space-between; color: var(--color-fg-muted); font-size: var(--text-xs); }
.link-list { margin: 0; padding: 0; list-style: none; }
.link-list li { display: flex; align-items: baseline; }
.link-list .unlink { flex: none; padding: 0 4px; border: 0; background: none; color: var(--color-fg-muted); font: inherit; cursor: pointer; }
.link-list .unlink:hover, .link-list .unlink:focus-visible { color: var(--color-fg-primary); background: var(--color-bg-hover); }
.link-list .empty { color: var(--color-fg-muted); font-size: var(--text-xs); }
.link-row { display: flex; gap: 6px; align-items: baseline; width: 100%; padding: 2px 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.link-row:hover { color: var(--color-fg-primary); background: var(--color-bg-hover); }
.link-row .arrow, .route .arrow { color: var(--color-fg-muted); }
.link-row .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-row .privilege { flex: none; color: var(--color-fg-muted); font-size: var(--text-xs); }
.link-row.end { width: auto; padding: 0; text-decoration: underline dotted; }
.link-add { min-width: 1.6em; padding: 0 4px; }
.route { display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline; }
.route .empty, .properties .empty { color: var(--color-fg-muted); }

/* The generated attack graph (spec 10). Steps are neutral: the junction is
   the symbol's word (ALL, ANY), the state is a word beside it and a stroke
   pattern — blocked dotted, unknown dashed, unreachable faded and dashed —
   never a colour alone. Lines point from a prerequisite to what it enables. */
.node.is-blocked .shape { stroke-dasharray: 1.5 3; }
.node.is-unknown .shape { stroke-dasharray: 5 3; }
.node:not(.node-component) .badge { fill: none; stroke: var(--color-fg-primary); stroke-width: 1; }
.node:not(.node-component) .badge + .tag-text { fill: var(--color-fg-primary); }
/* Held at once (a foothold, and what follows from it alone): a quiet
   ground, not a state to act on. */
.node.is-seeded .box { fill: var(--color-bg-active); }
/* A component's steps, lit from the architecture's selection; a step's own
   component and support, lit from the step's. Lit is a tinted plate and a
   heavy stroke; while anything is lit, the rest recedes. */
.node.hl-steps .shape, .node.hl-steps .stem { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
.edge.hl-steps { stroke: var(--color-accent); stroke-width: 2.25; stroke-dasharray: 5 3; }
.graph.has-hl-steps .node:not(.hl-steps):not(.hl-selected),
.graph.has-hl-steps .edge:not(.hl-steps) { opacity: 0.3; }
/* A scenario, while Compare is open: what it blocks dotted, as a blocked
   step is; in the attack graph what stays open to the target stays, the
   rest recedes. */
.node.hl-blocked .shape, .node.hl-blocked .stem { stroke: var(--color-fg-primary); stroke-width: 2; stroke-dasharray: 1.5 3; }
.node-component.hl-blocked .halo { stroke: var(--color-fg-primary); stroke-width: 2.5; stroke-dasharray: 1.5 3.5; stroke-linecap: round; }
.graph.has-hl-open .node:not(.hl-open):not(.hl-selected),
.graph.has-hl-open .edge:not(.hl-open) { opacity: 0.3; }
.node.hl-path .shape, .node.hl-path .stem { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
.edge.hl-path { stroke: var(--color-accent); stroke-width: 2.25; stroke-dasharray: 5 3; }
.node-component.hl-path .halo { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
.graph.has-hl-path .node:not(.hl-path):not(.hl-selected),
.graph.has-hl-path .edge:not(.hl-path) { opacity: 0.35; }
.route-order-disc { fill: var(--color-accent); }
.route-order-text { fill: var(--viz-canvas); font-family: var(--font-mono); font-size: 10px; font-weight: 600; }
.node.hl-lineage .shape, .node.hl-lineage .stem { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
.edge.hl-lineage { stroke: var(--color-accent); stroke-width: 2.25; stroke-dasharray: 5 3; }
.graph.has-hl-lineage .node:not(.hl-lineage):not(.hl-selected),
.graph.has-hl-lineage .edge:not(.hl-lineage) { opacity: 0.35; }
.node-component.hl-steps .halo { stroke: var(--color-accent); stroke-width: 2; stroke-dasharray: 4 2.5; }
.line-blocked { border-top: 1.5px dotted var(--viz-outline); }
.line-unknown { border-top: 1.5px dashed var(--viz-outline); }

/* Architecture or attack graph: two words, the one shown pressed. */
/* An architecture's two views, on the canvas they switch: top left. */
.hud-top-left { top: 10px; left: 10px; }
.view-switch { gap: 0; padding: 2px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-bg-elevated); }
.view-switch .btn { border: 0; border-radius: var(--radius-sm); background: none; padding: 5px 10px; font-size: var(--text-xs); }
.view-switch .btn[aria-pressed="true"] { background: var(--color-accent-dim); color: var(--color-accent); }

/* A step in the inspector, and the attack results: a few words and values,
   each source a link back into the architecture. */
.step-facts { grid-column: 1 / -1; display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin: 0; font-size: var(--text-sm); }
.step-facts dt { color: var(--color-fg-muted); }
.step-facts dd { margin: 0; overflow-wrap: anywhere; }
.source-link { display: block; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-size: var(--text-xs); text-align: left; text-decoration: underline dotted; cursor: pointer; overflow-wrap: anywhere; }
.source-link:hover, .source-link:focus-visible { color: var(--color-fg-primary); background: var(--color-bg-hover); }
.attack-results h3 { margin: 12px 0 4px; color: var(--color-fg-muted); font-size: var(--text-xs); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }
/* Detail folded under the answer: a heading that opens it. */
.results-fold { margin-top: 12px; }
.results-fold > summary { list-style: none; cursor: pointer; margin: 0 0 4px; color: var(--color-fg-muted); font-size: var(--text-xs); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }
.results-fold > summary::-webkit-details-marker { display: none; }
.results-fold > summary::before { content: "›"; display: inline-block; width: 1em; transition: transform 120ms ease-out; }
.results-fold[open] > summary::before { transform: rotate(90deg); }
.results-fold > summary:hover { color: var(--color-fg-secondary); }
.results-fold > summary .count { margin-left: 6px; }
.attack-headline { display: flex; align-items: baseline; gap: 8px; margin: 0; }
.attack-headline .stat { font-family: var(--font-mono); font-size: 20px; }
.attack-results .hint { margin: 2px 0 0; color: var(--color-fg-muted); font-size: var(--text-xs); }
.attack-results .analysis-table tbody tr { cursor: pointer; }
.attack-results .analysis-table tbody tr:hover, .attack-results .analysis-table tbody tr:focus-visible { background: var(--color-bg-hover); }
.attack-results .analysis-table tr.is-selected { background: var(--color-bg-active); box-shadow: inset 2px 0 0 var(--color-accent); }
.step-search, .outline-find { display: block; width: 100%; min-width: 0; margin: 0 0 4px; padding: 3px 5px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-bg-base); color: var(--color-fg-primary); font: inherit; font-size: var(--text-sm); }
.assumptions { margin: 0; padding: 0; list-style: none; }
/* The routes taken most: a row each, the one drawn open with its actions. */
.routes { margin: 0; padding: 0; list-style: none; }
.route-row { display: flex; justify-content: space-between; width: calc(100% + 8px); margin: 0 -4px; padding: 3px 4px; border: 0; border-bottom: 1px solid var(--color-border-subtle); background: none; color: inherit; font: inherit; font-size: var(--text-sm); text-align: left; cursor: pointer; }
.route-row:hover, .route-row:focus-visible { background: var(--color-bg-hover); }
.route-row[aria-pressed="true"] { background: var(--color-bg-active); box-shadow: inset 2px 0 0 var(--color-accent); }
.routes li.is-shown { margin-bottom: 8px; }
.assumption { display: block; width: calc(100% + 8px); margin: 0 -4px; padding: 3px 4px; border: 0; border-bottom: 1px solid var(--color-border-subtle); border-radius: 0; background: none; color: inherit; font: inherit; font-size: var(--text-sm); text-align: left; cursor: pointer; }
.assumption:hover, .assumption:focus-visible { background: var(--color-bg-hover); }
.assumption-what { display: block; overflow-wrap: anywhere; }
.assumption-how { display: flex; flex-wrap: wrap; gap: 0 8px; color: var(--color-fg-muted); font-size: var(--text-xs); }
.assumption-how .mono { font-family: var(--font-mono); }


/* Attacker pins (attacker-pins.js): a foothold and a target in the canvas
   corner, dragged onto a component; on a component, picked up to move or
   dropped off it to take away. */
.pin-tray { display: inline-flex; gap: 4px; margin-left: 6px; padding-left: 8px; border-left: 1px solid var(--color-border); }
.pin-source {
  display: inline-flex; align-items: center; gap: 4px; padding: 0 8px;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-bg-surface); color: var(--color-fg-secondary);
  font: 600 0.6875rem/1 var(--font-sans); cursor: grab; user-select: none; touch-action: none;
}
.pin-source:hover { color: var(--color-fg-primary); background: var(--color-bg-hover); }
.pin-source svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.node-component .pin { cursor: grab; }
.node-component .pin:hover .tag { fill: var(--color-accent); }
.pin-ghost {
  position: fixed; left: 0; top: 0; z-index: var(--z-drag); pointer-events: none;
  transform: translate(calc(var(--pin-x) + 10px), calc(var(--pin-y) + 6px));
  padding: 3px 6px; border-radius: 3px;
  background: var(--color-fg-primary); color: var(--color-bg-base);
  font: 600 9px/1.2 var(--font-mono); letter-spacing: 0.04em;
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.2);
}
body.is-pinning, body.is-pinning * { cursor: grabbing !important; }
.node-component.hl-pin-drop .halo { stroke: var(--color-accent); stroke-width: 3; stroke-dasharray: none; }
/* No attack graph yet: the button and the chip open what to finish. */
.view-switch #view-attack.is-blocked { text-decoration: underline dotted var(--color-warning); text-underline-offset: 3px; }
.topbar > .status.is-blocked { color: var(--color-warning); text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }

/* The nmap dialog: level, range, command, paste; then the preview. Inputs
   look like the inspector's, words are the app's sizes, hints are muted. */
.nmap-dialog { width: min(40rem, 94vw); font-size: var(--text-sm); }
.nmap-dialog p { margin: 0 0 8px; }
.nmap-dialog label { color: var(--color-fg-muted); }
.nmap-dialog .hint { color: var(--color-fg-muted); font-size: var(--text-xs); line-height: 1.35; }
.nmap-dialog .hint:empty { display: none; }
.nmap-dialog input[type="text"], .nmap-dialog textarea {
  display: block; width: 100%; min-width: 0; margin-top: 4px;
  padding: 3px 5px;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-bg-base); color: var(--color-fg-primary);
  font: var(--text-xs)/1.4 var(--font-mono);
}
.nmap-dialog textarea { resize: vertical; min-height: 7em; }
.nmap-dialog input[type="radio"], .nmap-dialog input[type="checkbox"] { margin: 0; accent-color: var(--color-accent); }
.nmap-dialog :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 0; }
.nmap-levels { border: 0; padding: 0; margin: 10px 0 12px; display: grid; gap: 2px; }
.nmap-levels legend { padding: 0; margin-bottom: 4px; }
.nmap-level { display: grid; grid-template-columns: auto 5.5rem 1fr; gap: 8px; align-items: baseline; padding: 2px 0; cursor: pointer; }
.nmap-level > span:nth-child(2) { color: var(--color-fg-primary); }
.nmap-command {
  display: flex; gap: 8px; align-items: center; margin: 4px 0 12px;
  padding: 4px 4px 4px 8px;
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm);
  background: var(--color-bg-base);
}
.nmap-command code { flex: 1; min-width: 0; font: var(--text-xs)/1.4 var(--font-mono); overflow-wrap: anywhere; user-select: all; }
.nmap-command code:empty::before { content: "—"; color: var(--color-fg-muted); }
.nmap-actions { display: flex; gap: 8px; margin-top: 12px; }
.nmap-rows, .nmap-ports { list-style: none; margin: 0; padding: 0; }
.nmap-rows { max-height: 50vh; overflow: auto; margin: 4px 0 10px; }
.nmap-host { padding: 6px 0; border-bottom: 1px solid var(--color-border-subtle); }
.nmap-ports { padding-left: 22px; font-size: var(--text-xs); }
.nmap-row { display: flex; gap: 8px; align-items: baseline; padding: 1px 0; color: var(--color-fg-primary); }
.nmap-ports .nmap-row { color: var(--color-fg-secondary); }
#nmap-problem { color: var(--color-warning); font-size: var(--text-xs); margin-top: 6px; }
.nmap-row span { overflow-wrap: anywhere; min-width: 0; }
.nmap-row .pick.nmap-merge { width: auto; margin-left: auto; flex: none; }
.nmap-merge-state { display: flex; gap: 8px; align-items: baseline; margin-left: auto; flex: none; }
.nmap-merge-state .pick.nmap-merge { margin-left: 0; }
.nmap-role { display: flex; gap: 8px; align-items: baseline; margin-left: auto; flex: none; }
.nmap-role .pick.nmap-merge { margin-left: 0; }
.nmap-role + .nmap-merge, .nmap-role + .nmap-merge-state, .nmap-role + .hint { margin-left: 0; }
.nmap-level .warning { color: var(--color-warning); }
.nmap-findings { list-style: none; margin: 0; padding: 0 0 0 22px; }
.nmap-findings .nmap-row { color: var(--color-fg-muted); }

/* The light bulb in the canvas's corner: a suggestion, quiet, dismissable. */
.hud-bottom-right { right: 10px; bottom: 10px; }
.hud-hint {
  align-items: center; gap: 2px; padding: 2px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  font-size: var(--text-sm);
}
.hud-hint button {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--color-fg-secondary); font: inherit; cursor: pointer;
}
.hud-hint button:hover { background: var(--color-bg-hover); color: var(--color-fg-primary); }
.hud-hint .hint-go svg { width: 16px; height: 16px; fill: none; stroke: var(--color-fg-secondary); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.hud-hint .hint-close { padding: 4px; }
.hud-hint .hint-close svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
/* A node gliding into a cluster as it closes. */
.ghosts .is-leaving { pointer-events: none; }
/* The selection rectangle (Shift + drag). */
.marquee { fill: var(--color-accent-dim); stroke: var(--color-accent); stroke-width: 1; stroke-dasharray: 4 3; pointer-events: none; }
.graph.is-picking { cursor: crosshair; }
/* Several selected, or a cluster's members, in the inspector. */
.cluster-members { list-style: none; margin: 4px 0 0; padding: 0; }
.cluster-members li { display: flex; align-items: center; gap: 8px; padding: 3px 4px; border-radius: 4px; cursor: pointer; }
.cluster-members li:hover { background: var(--color-bg-hover); }
/* Muted text is under AA on a hovered row: it steps up, as elsewhere. */
.cluster-members li:hover .member-out { color: var(--color-fg-secondary); }
.cluster-members .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cluster-members .member-out { padding: 0 6px; line-height: 1.4; color: var(--color-fg-muted); }
.cluster-members .member-out:hover { color: var(--color-fg-primary); }
.member-ghost { font-family: var(--font-sans); letter-spacing: 0; }
.node-component.is-cluster.hl-pin-drop .halo { stroke: var(--color-accent); stroke-width: 3; stroke-dasharray: none; }
/* A component in hand lets the pointer see what it is dropped on. */
.node.is-in-hand { pointer-events: none; }
.cluster-outline.hl-pin-drop .outline { stroke: var(--color-accent); stroke-width: 2.5; stroke-dasharray: none; }
/* The node a dragged one would merge with. */
.node-component.is-merge-target .halo { stroke: var(--color-accent); stroke-width: 4; stroke-dasharray: none; }
.node-component.is-merge-target .plate { filter: brightness(1.08); }
.cluster-outline.is-merge-target .outline { stroke: var(--color-accent); stroke-width: 2.5; stroke-dasharray: none; }
.legend-toggle[aria-pressed="false"] .outline-sample { opacity: 0.4; }
