{% comment %} _includes/attack-flow.html ────────────────────────────────────────────────────────────────────── SVG swimlane attack-flow diagram, driven entirely from page.stages[]. Each stage may declare these optional fields (in addition to label/id): mitre_tactic – string, e.g. "TA0001" mitre_techniques – array of {id, name} detection_status – "blocked" | "detected" | "exploited" | "unknown" attacker_action – short string shown inside the stage box systems – short string shown in the detection row detection_signals – array of strings (used in the hover tooltip) Requires: assets/js/attack-flow.js, .af-* rules in style.css {% endcomment %} {% if page.stages %} {%- comment -%} ── Layout constants ──────────────────────────────── {%- endcomment -%} {% assign _n = page.stages | size %} {% assign _box_w = 160 %} {% assign _gap_px = 50 %} {% assign _col_w = 210 %} {%- comment -%} = box_w + gap_px {%- endcomment -%} {% assign _half_bw = 80 %} {%- comment -%} = box_w / 2 {%- endcomment -%} {% assign _box_h = 68 %} {% assign _left_w = 74 %} {%- comment -%} swimlane label column width {%- endcomment -%} {% assign _right_p = 16 %} {% assign _svg_h = 284 %} {%- comment -%} svg_w = left_w + n*box_w + (n-1)*gap + right_p {%- endcomment -%} {% assign _n_minus_1 = _n | minus: 1 %} {% assign _stages_w = _n | times: _box_w %} {% assign _gaps_w = _n_minus_1 | times: _gap_px %} {% assign _svg_w = _stages_w | plus: _gaps_w | plus: _left_w | plus: _right_p %} {%- comment -%} ── Swimlane Y boundaries ─────────────────────────── {%- endcomment -%} {%- comment -%} Lane 1 (Attacker): y=0 → 107 (box at y=14, h=68) {%- endcomment -%} {%- comment -%} Lane 2 (ATT&CK): y=107 → 188 {%- endcomment -%} {%- comment -%} Lane 3 (Detection): y=188 → 284 {%- endcomment -%}