diff --git a/docs/presentations/nova-autonomous-cloud-delivery.html b/docs/presentations/nova-autonomous-cloud-delivery.html
index 97ee68e..9642cb5 100644
--- a/docs/presentations/nova-autonomous-cloud-delivery.html
+++ b/docs/presentations/nova-autonomous-cloud-delivery.html
@@ -462,7 +462,7 @@ section.title .benefit { color: #fff; }
;" data-marpit-pagination-total="22">
How intent becomes verified infrastructure — fail-fast policy scanning before the plan, runtime scanning after it.
-
+
- Contract → resolver → adapter → Checkov on static code (before plan) → terraform plan → Wiz on the plan → confidence signal → stage gate → apply → evidence + ledger
- Fail-fast, quick feedback — Checkov runs on the authored Terraform code before
terraform plan so developers get immediate policy feedback
@@ -734,7 +734,7 @@ section.title .benefit { color: #fff; }
;" data-marpit-pagination-total="22">
Slide 11 — Telemetry & Live Ops
Every metric in this deck is traceable to a real emitted signal — the live-ops dashboard makes operations visible in PowerBI.
-
+
- Platform components → CloudEvents envelope → event log + decision ledger + run records → collector → cold store → PowerBI views → live ops dashboard
- The live ops dashboard (PowerBI) surfaces the four CTO-grade metrics (Lead Time, Vulnerability Count, MTTR, Cloud Spend) alongside trust metrics (Decision Ledger coverage, Attestation coverage) and efficiency metrics (touchless resolution, escalation frequency)
diff --git a/docs/presentations/nova-autonomous-cloud-delivery.pptx b/docs/presentations/nova-autonomous-cloud-delivery.pptx
index f94ee63..87bdd82 100644
Binary files a/docs/presentations/nova-autonomous-cloud-delivery.pptx and b/docs/presentations/nova-autonomous-cloud-delivery.pptx differ
diff --git a/scripts/inline_images.py b/scripts/inline_images.py
new file mode 100644
index 0000000..9f5f537
--- /dev/null
+++ b/scripts/inline_images.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""scripts/inline_images.py — base64-embed all relative-path images in an
+HTML file so it becomes self-contained (redistributable without the
+assets/ folder).
+
+Usage: python scripts/inline_images.py
+
+Stdlib only (base64, re, mimetypes, sys, pathlib).
+"""
+from __future__ import annotations
+
+import base64
+import mimetypes
+import re
+import sys
+from pathlib import Path
+
+IMG_SRC_RE = re.compile(
+ r'(
]*\bsrc=")(assets/[^"]+)("[^>]*>)',
+ re.IGNORECASE,
+)
+
+
+def _mime_for(path: Path) -> str:
+ ext = path.suffix.lower()
+ if ext == ".svg":
+ return "image/svg+xml"
+ guessed, _ = mimetypes.guess_type(str(path))
+ return guessed or "application/octet-stream"
+
+
+def inline(html_path: Path) -> int:
+ html = html_path.read_text(encoding="utf-8")
+ repo_root = html_path.parent.parent.parent
+
+ count = 0
+
+ def replacer(match: re.Match[str]) -> str:
+ nonlocal count
+ prefix, rel_src, suffix = match.group(1), match.group(2), match.group(3)
+ img_path = html_path.parent / rel_src
+ if not img_path.exists():
+ print(f" WARNING: image not found: {rel_src}", file=sys.stderr)
+ return match.group(0)
+ mime = _mime_for(img_path)
+ data = base64.b64encode(img_path.read_bytes()).decode("ascii")
+ count += 1
+ return f'{prefix}data:{mime};base64,{data}{suffix}'
+
+ new_html = IMG_SRC_RE.sub(replacer, html)
+
+ if count > 0:
+ html_path.write_text(new_html, encoding="utf-8")
+
+ return count
+
+
+def main() -> int:
+ if len(sys.argv) != 2:
+ print("Usage: python scripts/inline_images.py ", file=sys.stderr)
+ return 1
+ html_path = Path(sys.argv[1])
+ if not html_path.exists():
+ print(f"ERROR: {html_path} not found", file=sys.stderr)
+ return 1
+ count = inline(html_path)
+ print(f"Inlined {count} image(s) into {html_path}", file=sys.stderr)
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
\ No newline at end of file
diff --git a/scripts/render_slides.sh b/scripts/render_slides.sh
index 715eace..b820484 100755
--- a/scripts/render_slides.sh
+++ b/scripts/render_slides.sh
@@ -2,7 +2,8 @@
# scripts/render_slides.sh — render the Nova presentation deck end-to-end:
# 1. Mermaid .mmd → .png (S&P-themed via sp-theme.json)
# 2. Marp .md → .html + .pptx (S&P-themed via inline style: block in frontmatter)
-# 3. Stage all rendered artifacts to git.
+# 3. Inline images → base64-embed all images in the HTML (self-contained).
+# 4. Stage all rendered artifacts to git.
#
# Usage:
# bash scripts/render_slides.sh [deck-name]
@@ -71,7 +72,13 @@ echo " PPTX → $PPTX"
npx --yes @marp-team/marp-cli@4.5.0 --allow-local-files "$SRC" -o "$PPTX" 2>&1 | tail -3
echo ""
-# --- Step 3: stage ---
-echo "=== Step 3: Staging rendered artifacts ==="
+# --- Step 3: inline images into HTML (base64-embed for redistribution) ---
+# REQ-268: makes the HTML self-contained (no assets/ folder needed).
+echo "=== Step 3: Inlining images into HTML ==="
+python3 scripts/inline_images.py "$HTML" 2>&1
+echo ""
+
+# --- Step 4: stage ---
+echo "=== Step 4: Staging rendered artifacts ==="
git add "$PNG_DIR"/*.png "$HTML" "$PPTX" 2>/dev/null || true
echo "=== Done: staged $(ls "$PNG_DIR"/*.png 2>/dev/null | wc -l) PNGs + $HTML + $PPTX ==="