diff --git a/game.py b/game.py
index c602cb0..953906f 100644
--- a/game.py
+++ b/game.py
@@ -6001,6 +6001,7 @@ PATCH_NOTES = [
("fix", "Dungeons wait for the leader to press Start, so groups of 3 and 4 can form. No one can join once it starts."),
("fix", "Combat page shows your health potion: drunk on its own, no need to equip. The other card now reads \"No combat potion\"."),
("fix", "Combat page no longer jumps around: cast bars hold their space and the fight log stays 7 lines tall."),
+ ("new", "Enemy casts that can't be interrupted show a ๐ and a grey bar. Stuns still stop them, except on bosses."),
]},
{"date": "2026-10-24", "title": "Dungeon loot", "notes": [
("new", "Masterwork patterns: every dungeon boss can drop one of 7 (15% from a mini-boss, 35% from the last boss, "
diff --git a/static/app.js b/static/app.js
index 8bb4593..1518f40 100644
--- a/static/app.js
+++ b/static/app.js
@@ -1129,7 +1129,13 @@ function animateFight(now) {
if (castEl.dataset.key !== key) {
castEl.dataset.key = key;
castEl.classList.toggle("stopped", !!stopped);
- castEl.innerHTML = cast ? `${spec.icon} ${esc(spec.name)}`
+ // A cast no interrupt can stop gets a padlock; stuns still stop it on all but bosses.
+ const foe = f.pack[+el.dataset.u.slice(1)];
+ const locked = cast && spec.interrupt === false;
+ const boss = foe && (foe.boss || foe.archetype === "boss" || foe.archetype === "dragon");
+ castEl.classList.toggle("locked", !!locked);
+ castEl.title = locked ? `Can't be interrupted${boss ? "" : " ยท stuns stop it"}` : "";
+ castEl.innerHTML = cast ? `${spec.icon} ${esc(spec.name)}${locked ? ` ${glyph("padlock", "currentColor")}` : ""}`
: stopped ? `โ ${spec.icon} ${esc(spec.name)}interrupted` : "";
}
if (cast) castEl.querySelector(".bar > span").style.width = `${Math.min(100, (t - cast.from) / (cast.until - cast.from) * 100)}%`;
diff --git a/static/styles.css b/static/styles.css
index f71d775..6dd93e0 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -598,6 +598,7 @@ button.sheet-skill:hover { background: var(--panel-2); }
.hitnum.good { color: var(--good); }
.hitnum.crit { font-size: 1.15em; }
.cast.stopped { color: var(--muted); }
+.foe-unit .cast.locked .bar > span { background: var(--muted); }
.cast.stopped s { text-decoration-thickness: 2px; }
.eat-below { display: flex; flex-wrap: wrap; gap: 4px; }
.eat-below .btn.on { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }