diff --git a/system.json b/system.json
index 8d069b7..a272b7e 100644
--- a/system.json
+++ b/system.json
@@ -2,7 +2,7 @@
"id": "vanity",
"title": "VANITY — the Vanity Role-Playing Game",
"description": "A generic d6 RPG where ego is a resource and the universe keeps score. Pool = Attribute + Knack + situation; 5–6 = a Success; fail with two 1s = a Stumble that banks a Bane of Karma (Draft 13). No hit points — Grit. Vanity, Karma and Glory drive play. Includes the full Draft 13 rulebook, all spells and gear, the starter bestiary, a 100-item Treasures & Relics library, twenty ready-to-play characters (each with cameo art, token and backstory), ten animal companions with the d10 Bond table and the one-shot adventure The Vain Crown.",
- "version": "0.10.1",
+ "version": "0.10.2",
"compatibility": {
"minimum": 13,
"verified": "14.364"
diff --git a/vanity.mjs b/vanity.mjs
index 0b4d2e1..14646fa 100644
--- a/vanity.mjs
+++ b/vanity.mjs
@@ -376,7 +376,7 @@ function renderRollCard({ label, sublabel, results, threshold, pushed, context,
? `
` : ""}
@@ -389,11 +389,14 @@ function renderRollCard({ label, sublabel, results, threshold, pushed, context,
* charge of the fiction — Subdue, mercy and "he was already down" all live in
* the beat between the roll and the click.
*/
-function targetBlock(target, results, spend) {
+function targetBlock(target, results, spend, context = "attack") {
if (!target) return "";
const successes = results.filter(r => r >= 5).length;
const net = Math.max(0, successes - (spend?.defence ?? target.successes ?? 0));
- const damage = spend?.damage ?? 0;
+ // In an exchange the first net Success IS the hit — 1 Grit before anything is
+ // bought. Only a spell starts from nothing, because its Threshold bought the
+ // effect instead. Mirrors the arithmetic in renderSpendPanel.
+ const damage = net > 0 ? (context === "spell" ? 0 : 1) + (spend?.damage ?? 0) : 0;
const pips = (target.results ?? []).map(r =>
`${DIE_FACES[r] ?? r}`).join("");
const pierceNote = target.piercing