# Room Enchantments System — Design Spec

> Describes the Room Enchantments system: a semi-combat, semi-preparation system for the
> Enchanter attunement. Footwear enchantments passively stamp the room with elemental auras
> during combat. The longer the fight, the more the room becomes the Enchanter's weapon.

---

## 1. Objective

The Enchanter currently has no active combat system. The enchanting pipeline (Design →
Prepare → Apply) is entirely offline. The Room Enchantments system adds an **always-on
combat presence** that scales with time: as the Enchanter fights in a room, their enchanted
footwear gradually covers the room with elemental aura effects that damage enemies, apply
debuffs, or buff the player.

**Design goals:**
- Give the Enchanter an active combat identity distinct from Invocation (parallel cast
  track) and Golemancy (summoned units): the **environmental controller**
- Create a "semi-combat, semi-preparation" loop: choose footwear enchantments offline,
  then they work passively during combat with no active input required
- Give transference mana a combat application through the `boots_sigil_transference`
  enchantment and the coverage-rate discipline
- Make longer fights (especially guardians) more rewarding the longer they go
- Keep the system simple: one coverage meter, linear scaling, no thresholds or activation
  decisions during combat

---

## 2. Identity

| Property | Value |
|---|---|
| **System name** | Room Enchantments |
| **Attunement** | Enchanter |
| **Equipment slot** | Feet |
| **Core resource** | Coverage meter (0–100) per room |
| **Primary mana** | Transference (discipline fuel + transference sigil regen) |
| **Combat role** | Environmental aura control — scales with time-in-combat |
| **Preparation** | Enchant boots via the existing Design → Prepare → Apply pipeline |
| **Active element** | None — entirely passive during combat |

### Attunement Comparison

| Attunement | Combat Identity | Scaling | Player Input |
|---|---|---|---|
| Invoker | Parallel auto-cast (guardian spells) | Charge meter fill/spend | Auto-activate |
| Fabricator | Summoned golems (independent actors) | Golem maintenance | Design golems offline |
| **Enchanter** | **Environmental aura control** | **Time-in-combat coverage** | **Enchant boots offline** |

---

## 3. Core Mechanic: The Coverage Meter

### 3.1 The Meter

Each room has a single **coverage meter** from 0 to 100, stored on `FloorState`:

```typescript
// Addition to FloorState in types/game.ts
roomEnchantment: {
  coverage: number;   // 0-100, current coverage percentage
} | null;             // null when no footwear room enchantments are equipped
```

- `null` when the player has no footwear with room enchantment sigils equipped.
- Initialized to `{ coverage: 0 }` on room entry if footwear has room enchantments.
- Resets to 0 on every room transition (fresh room, fresh canvas).

### 3.2 Coverage Growth

Coverage grows by a flat amount per combat tick:

```
coveragePerTick = baseRate + disciplineBonus

where:
  baseRate = 0.2
  disciplineBonus = roomCoverageRateBonus (from the `room-coverage-rate` capped perk)
```

At base rate (no discipline bonus):
- 0.2 per tick → 500 ticks to reach 100
- At 200ms/tick → **100 seconds real time** to full coverage

Coverage growth requires ALL of the following:
1. Player is in `climb` action
2. Current room has living enemies (`floorHP > 0`)
3. Player has at least one footwear room enchantment equipped

Coverage does **NOT** scale with cast speed, attack speed, transference spending, or any
other stat. It is purely time-based. This is intentional — the system is designed to be
zero-input during combat.

### 3.3 Coverage Cap

Coverage is hard-capped at 100. Once full, room enchantments operate at full strength and
stop accumulating.

---

## 4. Enchantment Definitions

### 4.1 Effect Category

Room enchantments use `category: 'special'` with unique `specialId` values, following the
exact same pattern as existing equipment effects (e.g., `sword_fire` → `specialId:
'fireBlade'`). They are defined alongside existing enchantment definitions.

Allowed equipment category: `['feet']` only.

### 4.2 Effect Structure

```typescript
// Room enchantment effects use the same EnchantmentEffectDef type
// category: 'special'
// effect.type: 'special'
// effect.specialId: a unique string handled by the room enchantment tick processor
```

The `specialId` is a new convention: `room_<element>_<effectType>` (e.g.,
`room_fire_damage`, `room_frost_debuff`, `room_transference_buff`).

> **Note:** Room enchantment `specialId` values use the game's existing mana type names
> (e.g., `death` not `poison`, `transference` not `arcane`) for consistency with the
> 22 defined mana types.

### 4.3 Scaling Formula

Each room enchantment's effect scales linearly with coverage:

```
effectMagnitude = baseMagnitude × (coverage / 100)
```

Examples:
- `boots_sigil_fire` at 25% coverage: burn = 5 × 0.25 = **1.25 damage/tick** to all enemies
- `boots_sigil_fire` at 50% coverage: burn = 5 × 0.50 = **2.5 damage/tick** to all enemies
- `boots_sigil_fire` at 100% coverage: burn = 5 × 1.00 = **5 damage/tick** to all enemies

All magnitudes are floating-point. Damage per tick is applied as-is (not rounded per
tick; rounding only occurs on display).

### 4.4 Enchantment Table

| Enchant ID | Name | specialId | Effect Type | Base Magnitude (at 100%) | Capacity Cost |
|---|---|---|---|---|---|
| `boots_sigil_fire` | Blazing Footsteps | `room_fire_damage` | Room DoT (burn all enemies) | 5 dmg/tick | 30 |
| `boots_sigil_frost` | Frozen Trail | `room_frost_debuff` | Enemy slow | 10% slow | 25 |
| `boots_sigil_death` | Necrotic Tread | `room_death_damage` | Room DoT (death all enemies) | 3 dmg/tick | 25 |
| `boots_sigil_lightning` | Shocking Stride | `room_lightning_damage` | Single-target chain dmg | 3 dmg/tick random enemy | 28 |
| `boots_sigil_dark` | Shadow Patch | `room_dark_dodge_debuff` | Enemy dodge reduction | −10% dodge | 22 |
| `boots_sigil_earth` | Scoured Earth | `room_earth_armor_debuff` | Enemy armor reduction | −5% armor | 28 |
| `boots_sigil_transference_ground` | Transference Grounds | `room_transference_buff` | Player cast speed | +5% cast speed | 20 |
| `boots_sigil_transference_path` | Conductive Path | `room_transference_regen` | Transference mana regen | +10%/hr regen | 20 |

All costs fit within footwear capacity range (15–35), meaning players can fit 1–2 room
enchantments per pair of boots.

### 4.5 Effect Application Rules

**DoT effects** (damage over time: fire, death, lightning):
- Applied to ALL living enemies in the room each tick
- Bypass armor — room-wide DoT ignores enemy armor, dodge, and barrier
- Do NOT apply to dead enemies (hp ≤ 0)
- For single-target effects (lightning): target is chosen randomly among living enemies
  each tick

**Debuff effects** (frost slow, dark dodge reduction, dark armor reduction):
- Applied as a modifier to all living enemies, recalculated each tick based on current
  coverage
- Slow: reduces enemy dodge chance (negative value subtracted from base dodge)
- Dodge reduction: directly reduces enemy dodge chance
- Armor reduction: directly reduces enemy effectiveArmor (minimum 0)
- Applied at the end of the room enchantment phase (after the DoT/debuff phase). Debuffs
  take effect on the **next** tick — there is a one-tick delay before reduced dodge/armor
  affects incoming attacks. This is intentional: the room enchantment phase runs late in
  the tick pipeline.

**Buff/Regen effects** (transference cast speed, transference regen):
- Applied as a modifier to the player's combat bonuses, recalculated each tick
- Stored in the combat tick result and factored into existing `computeAllEffects()` math
- Cast speed: added to `attackSpeedMultiplier` as `1 + (baseBonus × coverage%)`
- Transference regen: added to transference mana regen per hour as `baseRegen × coverage%`

> **Note on debuff timing:** Because the room enchantment phase runs after the DoT/debuff
> phase in the tick pipeline, debuffs (frost slow, dark dodge reduction, dark armor reduction)
> are applied to enemy state at the end of the tick. The modified enemy stats take effect
> on the **following** tick when the enemy defense pipeline runs. This means there is always
> a one-tick delay between coverage growth and debuff impact on incoming attacks.

### 4.6 Stacking Multiple Enchantments

If the player has two room enchantments on their boots (e.g., `boots_sigil_fire` +
`boots_sigil_frost`):
- Both share the same coverage meter (there is only one)
- Both scale off the same coverage percentage
- Both apply their effects independently each tick
- Total capacity cost must fit within the footwear's total capacity

---

## 5. State Changes

### 5.1 FloorState (`types/game.ts`)

```typescript
export interface FloorState {
  // ... all existing fields ...

  // Room enchantment state — null when no footwear room enchants are equipped
  roomEnchantment: {
    coverage: number;   // 0-100
  } | null;
}
```

### 5.2 Combat Store Additions

The combat store needs a new field to persist the previous room's coverage across room
transitions (for the `resonant-stamps` perk). Add to `CombatState` in
`combat-state.types.ts`:

```typescript
// Room enchantment carryover (for resonant-stamps perk)
lastRoomCoverage: number;  // 0-20, carryover from previous room, resets on spire exit
```

And the corresponding action:

```typescript
setLastRoomCoverage: (value: number) => void;
```

### 5.3 Combat Processing

The room enchantment tick is processed in `combat-actions.ts` → `processCombatTick()`,
executed in the tick pipeline immediately after the DoT/debuff phase:

```
Tick order in processCombatTick:
  1. Golem maintenance
  2. Active spell casting
  3. Equipment spell states
  4. Invocation tick
  5. Melee attacks
  6. Golem attacks
  7. DoT/debuff tick processing
  8. ── Room enchantment tick ← NEW

> **File size note:** `combat-actions.ts` is currently 377 lines. Adding the room
> enchantment phase may push it toward the 400-line limit. If so, extract the phase
> logic into a new file (e.g., `combat-room-enchantments.ts`) and call it from
> `processCombatTick`.
```

### 5.4 New Utility File

A new file `src/lib/game/utils/room-enchantments-utils.ts` exports:

```typescript
// Compute coverage per tick from discipline stats
export function computeCoveragePerTick(disciplineBonus: number): number;

// Apply all room enchantment effects for one tick
// Returns updated { enemies, rawMana, elementStates, playerBuffs }
export function applyRoomEnchantmentTick(params: {
  coverage: number;
  auraMagnitude: number;  // roomEnchantmentAuraMagnitude from discipline effects
  equippedRoomEnchantments: Array<{ specialId: string; baseMagnitude: number }>;
  enemies: EnemyState[];
  rawMana: number;
  elements: Record<string, { current: number; max: number; unlocked: boolean }>;
}): {
  enemies: EnemyState[];
  rawMana: number;
  elements: Record<string, { current: number; max: number; unlocked: boolean }>;
  playerBuffs: {
    castSpeedBonus: number;
    transferenceRegenBonus: number;
  };
};

// Get list of room enchantment effects from equipped footwear
export function getEquippedRoomEnchantments(
  equippedInstances: Record<string, string | null>,
  equipmentInstances: Record<string, EquipmentInstance>,
): Array<{ specialId: string; baseMagnitude: number }>;
```

### 5.5 Room Transition Behavior

Coverage resets on every room transition. This is handled in the existing
`advanceRoomOrFloor()` flow in `combat-descent-actions.ts`:

- When a new `FloorState` is generated (via `generateSpireFloorState()`), the new room
  starts with `roomEnchantment: null`
- Just before the `FloorState` is finalized, the current room's coverage is saved to
  `lastRoomCoverage` on the combat store (capped at 20 if `resonant-stamps` perk is
  active, otherwise 0)
- At the start of the combat tick, if `roomEnchantment` is null and the player has
  footwear room enchantments equipped, it is initialized to
  `{ coverage: lastRoomCoverage }`
- If the player has no footwear room enchantments, it stays null and the room
  enchantment tick is skipped entirely
- `lastRoomCoverage` resets to 0 on spire exit

---

## 6. Discipline Integration

### 6.1 New Discipline: Room Enchanting

A new Enchanter discipline that directly enhances the Room Enchantment system.

**Definition:**

| Field | Value |
|---|---|
| **ID** | `room-enchanting` |
| **Name** | Room Enchanting |
| **Attunement** | `enchanter` |
| **Mana Type** | `transference` |
| **Base Cost** | 10 |
| **Stat Bonus** | `roomEnchantmentAuraMagnitude` +0.10 (base) |
| **Scaling Factor** | 100 |
| **Difficulty Factor** | 150 |
| **Drain Base** | 3 |

**Main stat: `roomEnchantmentAuraMagnitude`**

This stat is a multiplier on all room enchantment aura magnitudes:

```
effectMagnitude = baseMagnitude × coverage% × (1 + roomEnchantmentAuraMagnitude)
```

The stat scales with XP via the standard discipline math:

```
StatBonus = baseValue × (XP / scalingFactor)^0.65
          = 0.10 × (XP / 100)^0.65
```

This replaces the old `empowered-auras` perk — the main stat now continuously scales
aura strength, while a new capped perk handles coverage rate.

**Magnitude scaling at key XP levels:**

| XP | Stat Bonus | Magnitude Multiplier | Fire DoT @ 100% coverage |
|---|---|---|---|
| 0 | +0.000 | 1.000× | 5.00 dmg/tick |
| 100 | +0.100 | 1.100× | 5.50 dmg/tick |
| 300 | +0.204 | 1.204× | 6.02 dmg/tick |
| 500 | +0.285 | 1.285× | 6.42 dmg/tick |
| 1000 | +0.447 | 1.447× | 7.23 dmg/tick |
| 2000 | +0.701 | 1.701× | 8.50 dmg/tick |

**Perks:**

| Perk ID | Type | Threshold | Bonus | Description |
|---|---|---|---|---|
| `room-coverage-rate` | `capped` | 100 | Coverage rate +0.03/tick per tier, max 4 tiers | Room fills faster with each tier |
| `resonant-stamps` | `once` | 500 | Carry 20% coverage between rooms (max 20% starting coverage) | Head start on each room, but never instant |

**Perk details:**

- **`room-coverage-rate`** (capped, threshold 100 XP, interval 150 XP, max 4 tiers): Each
  tier adds +0.03/tick to the coverage growth rate. Tier progression: 1 tier at 100 XP,
  2 tiers at 250 XP, 3 tiers at 400 XP, 4 tiers at 550 XP (capped).

  | Tiers | Rate Bonus | Total Rate | Seconds to Fill |
  |---|---|---|---|
  | 0 (no perk) | +0.00 | 0.20/tick | 100.0s |
  | 1 (100 XP) | +0.03 | 0.23/tick | 87.0s |
  | 2 (250 XP) | +0.06 | 0.26/tick | 76.9s |
  | 3 (400 XP) | +0.09 | 0.29/tick | 69.0s |
  | 4 (550 XP) | +0.12 | 0.32/tick | 62.5s |

  At max tier (4), the room fills in ~62.5 seconds instead of 100 seconds — a 37.5%
  speedup. The perk is capped so coverage always requires meaningful combat time.

- **`resonant-stamps`** (once @ 500 XP): When transitioning between rooms on the same
  floor, the carryover is computed as `min(20, previousRoom.coverage × 0.2)`. This means
  20% of the previous room's coverage value carries over, capped at a maximum of 20
  percentage points. Examples: ending at 80% → next room starts at 16%; ending at 100% →
  next room starts at 20% (the cap). This ensures the player always needs to actively
  build coverage during combat — the perk provides a head start but never eliminates the
  buildup phase.

  **State persistence:** The carryover value is stored in `lastRoomCoverage` on the
  combat store (see §5.2). When `advanceRoomOrFloor()` generates a new `FloorState`
  with `roomEnchantment: null`, the room enchantment tick reads `lastRoomCoverage` to
  initialize the new room's starting coverage. This field persists across room
  transitions within a climb but resets to 0 on spire exit.

**Combined progression at key XP levels (stat + capped perk):**

| XP | Coverage Rate | Magnitude | Fire DoT @ 100% | Time to Fill |
|---|---|---|---|---|
| 0 | 0.20/tick | 1.000× | 5.00 dmg/tick | 100.0s |
| 100 | 0.23/tick | 1.100× | 5.50 dmg/tick | 87.0s |
| 300 | 0.26/tick | 1.204× | 6.02 dmg/tick | 76.9s |
| 500 | 0.29/tick | 1.285× | 6.42 dmg/tick | 69.0s |
| 1000 | 0.32/tick | 1.447× | 7.23 dmg/tick | 62.5s |
| 2000 | 0.32/tick | 1.701× | 8.50 dmg/tick | 62.5s |

The capped perk maxes out at 550 XP (4 tiers, 0.32/tick, 62.5s). Beyond that, only the
main stat continues to grow, increasing aura magnitude. At 2000 XP, the room still takes
62.5 seconds to fill but fire does 8.50 dmg/tick instead of 5.00 — a 70% damage
increase from the main stat alone.

### 6.2 Discipline Dependency

```
room-enchanting (root — no prerequisites)
```

This is a root discipline with no prerequisites, making it available as soon as the
Enchanter attunement is active.

### 6.3 Stat Registration

The new stat `roomEnchantmentAuraMagnitude` must be added to:
- `KNOWN_BONUS_STATS` in `discipline-effects.ts`
- The `addBonus()` routing in `computeDisciplineEffects()` (no special routing needed —
  it's a standard bonus stat)

### 6.4 Enchantment Unlock Perks

Room enchantment effects are unlocked via perks on the new discipline:

| Perk ID | Type | Threshold | Unlocks |
|---|---|---|---|
| `room-sigil-fire` | `once` | 50 | `boots_sigil_fire` |
| `room-sigil-frost` | `once` | 75 | `boots_sigil_frost` |
| `room-sigil-death` | `once` | 100 | `boots_sigil_death` |
| `room-sigil-lightning` | `once` | 125 | `boots_sigil_lightning` |
| `room-sigil-dark` | `once` | 150 | `boots_sigil_dark` |
| `room-sigil-earth` | `once` | 175 | `boots_sigil_earth` |
| `room-sigil-transference-ground` | `once` | 100 | `boots_sigil_transference_ground` |
| `room-sigil-transference-path` | `once` | 125 | `boots_sigil_transference_path` |

---

## 7. Data Flow Summary

```
gameStore.tick()
  → buildTickContext() [snapshots all stores]
  → processCombatTick() [combat-actions.ts]
    → ... (golem, spell, equipment, invocation, melee, DoT phases) ...
    → Room Enchantment Phase:
        1. If roomEnchantment is null and player has footwear room enchants:
             Initialize roomEnchantment = { coverage: lastRoomCoverage }
        2. If roomEnchantment is not null AND floorHP > 0:
             a. coverage += 0.2 + roomCoverageRateBonus
             b. Clamp coverage to 100
             c. Magnitude multiplier = 1.0 + roomEnchantmentAuraMagnitude
             d. For each equipped room enchantment:
                - Compute magnitude = baseMagnitude × (coverage / 100) × magnitude multiplier
             e. Apply to enemies (DoT/debuffs) or player (buffs)
             f. Recalculate floorHP from updated enemy HP
    → applyTickWrites() [writes combat store changes back]

On room transition (advanceRoomOrFloor):
  → Before generating new FloorState, save current coverage to combat store:
     lastRoomCoverage = resonant-stamps active ? min(20, currentRoom.coverage * 0.2) : 0
  → New FloorState generated with roomEnchantment: null
  → Room enchantment tick reads lastRoomCoverage to initialize starting coverage
```

---

## 8. UI Changes

### 8.1 RoomDisplay Component

Add a **Room Enchantment Bar** to the combat room display in `RoomDisplay.tsx`, shown
only when the player has footwear room enchantments equipped and the room has living
enemies:

```
┌─────────────────────────────────────────────┐
│ 🔥 Blazing Footsteps ████████████░░░░ 62%   │
│    → Enemies burning: 3.1 dmg/tick          │
│❄️ Frozen Trail     ████████████░░░░ 62%    │
│    → Enemies slowed: 6.2%                   │
└─────────────────────────────────────────────┘
```

- Progress bar showing coverage percentage (0–100%)
- Color-coded by element (fire = red, frost = blue, etc.)
- Shows current effect magnitude in text below each bar
- Only displayed when `roomEnchantment` is not null

### 8.2 Enchantment Designer

Room enchantment effects appear in the existing `EffectSelector` component under a new
"Room" filter category (or under "Special" with a "Room Only" tag). They are only
selectable when the equipment type being designed for is in the `feet` category.

### 8.3 No New Tabs

The room enchantment system does not require a new tab. All information is visible in
the existing SpireCombatPage layout and the existing CraftingTab enchantment designer.

---

## 9. Acceptance Criteria

| # | Criterion |
|---|---|
| AC-1 | `roomEnchantment` field exists on `FloorState` and defaults to `null`. |
| AC-2 | Coverage initializes to `{ coverage: 0 }` on room entry when footwear has room enchantments equipped. |
| AC-3 | Coverage resets to 0 on every room transition (new room = fresh coverage). |
| AC-4 | Coverage grows at 0.2 per tick while in `climb` action with living enemies. |
| AC-5 | Coverage is hard-capped at 100. |
| AC-6 | Coverage does NOT grow when `floorHP <= 0` or `currentAction !== 'climb'`. |
| AC-7 | At base rate (no discipline), coverage reaches 100 in ~100 seconds real time (500 ticks). |
| AC-8 | Room DoT effects (fire, death, lightning) apply to ALL living enemies each tick, bypassing armor. |
| AC-9 | Room debuff effects (frost slow, dark dodge reduction, earth armor reduction) modify enemy stats at end of room enchantment phase (one-tick delay before affecting incoming attacks). |
| AC-10 | Room buff effects (transference cast speed, transference regen) are factored into player stat computation. |
| AC-11 | Effect magnitudes scale linearly: `baseMagnitude × (coverage / 100)`. |
| AC-12 | Multiple room enchantments on one pair of boots share the same coverage meter and apply independently. |
| AC-13 | Total capacity cost of room enchantments must fit within footwear capacity (15–35). |
| AC-14 | The `room-enchanting` discipline uses transference mana and has `roomEnchantmentAuraMagnitude` as its stat. |
| AC-15 | `room-coverage-rate` capped perk adds +0.03/tick per tier, max 4 tiers. |
| AC-16 | `room-coverage-rate` capped perk reaches max 4 tiers at 550 XP (0.12/tick, 62.5s to fill). |
| AC-17 | `resonant-stamps` once perk computes carryover as `min(20, previousRoom.coverage × 0.2)`, stored in `lastRoomCoverage` on the combat store. |
| AC-18 | Room enchantment effects are unlocked via discipline perks at the specified XP thresholds. |
| AC-19 | Room enchantment effects only appear in the EffectSelector when designing for `feet` equipment. |
| AC-20 | RoomDisplay shows coverage bar and current effect magnitudes when room enchantments are active. |
| AC-21 | Existing saves without `roomEnchantment` field default to `null` (backward compatible). |
| AC-22 | Existing saves without `roomEnchantmentAuraMagnitude` stat default to 0 (backward compatible). |

---

## 10. Files Reference

| File | Role |
|---|---|
| `src/lib/game/types/game.ts` | Add `roomEnchantment` field to `FloorState` |
| `src/lib/game/data/enchantments/special-effects.ts` | Add room enchantment effect definitions (8 effects) |
| `src/lib/game/data/disciplines/enchanter.ts` | Add `room-enchanting` discipline definition with perks |

> **Implementation note:** `enchanter.ts` currently has 4 disciplines (146 lines). Adding
> `room-enchanting` with its ~8 unlock perks may push it toward the 400-line limit.
> If so, create a new file `enchanter-combat.ts` (following the existing pattern of
> `enchanter-utility.ts`, `enchanter-spells.ts`, etc.) and re-export from
> `data/disciplines/index.ts`.
| `src/lib/game/effects/discipline-effects.ts` | Add `roomEnchantmentAuraMagnitude` to `KNOWN_BONUS_STATS` |
| `src/lib/game/stores/combat-actions.ts` | Add room enchantment phase in `processCombatTick` (after DoT phase) |
| `src/lib/game/utils/room-enchantments-utils.ts` | **NEW** — Coverage computation, effect application, equipment scanning |
| `src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx` | Add coverage bar and effect magnitude display |
| `src/components/game/crafting/EnchantmentDesigner/EffectSelector.tsx` | Show room enchantments when designing for feet |
| `docs/specs/attunements/enchanter/systems/room-enchantments-spec.md` | **THIS FILE** |

---

## 11. Out of Scope

- Active player input during combat (no button to spend transference for faster coverage)
- Coverage scaling with cast speed, attack speed, or any combat stat
- Coverage persisting between rooms at launch (added only via `resonant-stamps` perk)
- Room enchantments on non-footwear equipment slots
- Room enchantments interacting with golem combat
- Room enchantments affecting non-combat rooms (library, recovery, treasure, puzzle)
- Visual effects / animations for the coverage bar (UI-only indicator in v1)
- Room enchantment effects that heal the player (violates no-healing rule)
- More than 8 room enchantment types in v1
- Composite or exotic element room sigils in v1 (base 7 + transference only)
